Homepage | Demos | Overview | Downloads | Tutorials | Reference | Credits |
SoundManager.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_SoundManager_h_ 00003 #define INCLUDED_SoundManager_h_ 00004 00005 #include <OPENR/RCRegion.h> 00006 #include <OPENR/ODataFormats.h> 00007 00008 #include <string> 00009 #include <vector> 00010 #include "Shared/ListMemBuf.h" 00011 #include "Shared/MutexLock.h" 00012 #include "SoundManagerMsg.h" 00013 #include "Shared/ProcessID.h" 00014 00015 class OSubject; 00016 class ONotifyEvent; 00017 00018 //! Provides sound effects and caching services, as well as mixing buffers for the SoundPlay process 00019 /*! Provides easy methods for playing back sounds, either from files 00020 * on the memory stick, or from dynamically generated buffers. You 00021 * can chain playback commands so that when one sound finishes, 00022 * another picks up automatically. This might be handy if, say, 00023 * someone wants to write an MP3 player ;) The sounds would be too 00024 * large to load into memory all at once, but you could load a block 00025 * at a time and chain them so it seamlessly moves from one to the 00026 * other. 00027 * 00028 * You can also preload sounds (LoadFile()) before playing them so 00029 * there's no delay while loading after you request a sound to be 00030 * played. Just be sure to release the file (ReleaseFile()) again 00031 * when you're done with it ;) 00032 * 00033 * All functions will attempt to lock the SoundManager. Remember, 00034 * this is running in a shared memory region, accessible by the 00035 * SoundPlay process and both the Main and Motion processes (so 00036 * MotionCommands can play sounds!) 00037 * 00038 * One could be tempted to draw parallels to the MotionManager, and 00039 * envision a system with SoundCommands that are handed over and can 00040 * dynamically compute sound buffers as needed. If you have the time 00041 * and inclination, the job's all yours... (Midi players, speech 00042 * synthesizer, ...?) 00043 * 00044 * @todo Volume control, variable playback speed, support more wav 00045 * file formats (latter two are the same thing if you think about it 00046 * - need to be able to resample on the fly) 00047 * 00048 * @todo Add functions to hand out regions to be filled out to avoid 00049 * copying into the buffer. 00050 */ 00051 class SoundManager { 00052 public: 00053 //!constructor 00054 SoundManager(); 00055 00056 //!This is used for referring to sound data so you can start playing it or release it 00057 typedef SoundManagerMsg::Snd_ID Snd_ID; 00058 static const Snd_ID invalid_Snd_ID=(Snd_ID)-1; //!< for reporting errors 00059 static const Snd_ID MAX_SND=50; //!< the number of sounds that can be loaded at any given time 00060 00061 //!This is for referring to instances of the play command so you can stop, pause, or monitor progress (later versions will send events upon completion) 00062 typedef unsigned short Play_ID; 00063 static const Play_ID invalid_Play_ID=(Play_ID)-1; //!< for reporting errors 00064 static const Play_ID MAX_PLAY=256; //!< the number of sounds that can be enqueued at the same time (see MixMode_t) 00065 00066 static const unsigned int MAX_NAME_LEN=64; //!<maximum length of a path 00067 00068 //!Used to set the mode for mixing multiple sound channels 00069 /*!Feel free to add a higher quality mixer if you're an audiophile - I'm pretty new to sound processing*/ 00070 enum MixMode_t { 00071 Fast, //!< uses bit shifting trick, but can result in reduced volume with more active channels, best if you set max_channels to a power of 2 00072 Quality //!< uses real division to maintain volume level, although still a rather naive (but relatively fast) algorithm 00073 }; 00074 00075 enum QueueMode_t { 00076 Enqueue, //!< newer sounds are played when a channel opens up (when old sound finishes) 00077 Pause, //!< newer sounds pause oldest sound, which continues when a channel opens 00078 Stop, //!< newer sounds stop oldest sound 00079 Override, //!< older sounds have play heads advanced, but don't get mixed until a channel opens 00080 }; 00081 00082 //!Needed to send sounds to the SoundPlay process 00083 void InitAccess(OSubject* subj); 00084 00085 //!loads a wav file (if it matches Config::sound_config settings - can't do resampling yet) 00086 /*!Since the SoundManager does the loading, if the same file is being played more than once, only once copy is stored in memory 00087 * @param name can be either a full path, or a partial path relative to Config::sound_config::root 00088 * @return ID number for future references (can also use name) 00089 * The sound data will be cached until ReleaseFile() or Release() is called a matching number of times*/ 00090 Snd_ID LoadFile(std::string const &name); 00091 00092 //!loads raw samples from a buffer (assumes matches Config::sound_config settings) 00093 /*!The sound data will be cached until Release() is called a matching number of times.\n 00094 * This function is useful for dynamic sound sources. A copy will be made. */ 00095 Snd_ID LoadBuffer(const char buf[], unsigned int len); 00096 00097 //!Marks the sound buffer to be released after the last play command completes (or right now if not being played) 00098 void ReleaseFile(std::string const &name); 00099 00100 //!Marks the sound buffer to be released after the last play command completes (or right now if not being played) 00101 void Release(Snd_ID id); 00102 00103 //!play a wav file (if it matches Config::sound_config settings - can't do resampling yet) 00104 /*!Will do a call to LoadFile() first, and then automatically release the sound again when complete. 00105 * @param name can be either a full path, or a partial path relative to Config::sound_config::root 00106 * @return ID number for future references 00107 * The sound data will not be cached after done playing unless a call to LoadFile is made*/ 00108 Play_ID PlayFile(std::string const &name); 00109 00110 //!loads raw samples from a buffer (assumes buffer matches Config::sound_config settings) 00111 /*!The sound data will be released after done playing*/ 00112 Play_ID PlayBuffer(const char buf[], unsigned int len); 00113 00114 //!plays a previously loaded buffer or file 00115 Play_ID Play(Snd_ID id); 00116 00117 //!allows automatic queuing of sounds - good for dynamic sound sources! 00118 /*!if you chain more than once to the same base, the new buffers are appended 00119 * to the end of the chain - the new buffer doesn't replace the current chain 00120 * @return @a base - just for convenience of multiple calls*/ 00121 Play_ID ChainFile(Play_ID base, std::string const &next); 00122 00123 //!allows automatic queuing of sounds - good for dynamic sound sources! 00124 /*!if you chain more than once to the same base, the new buffers are appended 00125 * to the end of the chain - the new buffer doesn't replace the current chain 00126 * @return @a base - just for convenience of multiple calls*/ 00127 Play_ID ChainBuffer(Play_ID base, const char buf[], unsigned int len); 00128 00129 //!allows automatic queuing of sounds - good for dynamic sound sources! 00130 /*!if you chain more than once to the same base, the new buffers are appended 00131 * to the end of the chain - the new buffer doesn't replace the current chain 00132 * @return @a base - just for convenience of multiple calls*/ 00133 Play_ID Chain(Play_ID base, Snd_ID next); 00134 00135 //!Lets you stop playback of all sounds 00136 void StopPlay(); 00137 00138 //!Lets you stop playback of a sound 00139 void StopPlay(Play_ID id); 00140 00141 //!Lets you pause playback 00142 void PausePlay(Play_ID id); 00143 00144 //!Lets you resume playback 00145 void ResumePlay(Play_ID id); 00146 00147 //!Lets you control the maximum number of channels (currently playing sounds), method for mixing (applies when max_chan>1), and queuing method (for when overflow channels) 00148 void SetMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode); 00149 00150 //!Gives the time until the sound finishes, in milliseconds. Subtract 32 to get guarranteed valid time for this ID. 00151 /*!You should be passing the beginning of a chain to get proper results...\n 00152 * May be slightly conservative (will report too small a time) because this 00153 * does not account for delay until SoundPlay picks up the message that a 00154 * sound has been added.\n 00155 * However, it is slighly optimistic (will report too large a time) because 00156 * it processes a buffer all at one go, so it could mark the sound as finished 00157 * (and cause the ID to go invalid) up to RobotInfo::SoundBufferTime (32 ms) 00158 * before the sound finishes. So subtract SoundBufferTime if you want to be 00159 * absolutely sure the ID will still valid. */ 00160 unsigned int GetRemainTime(Play_ID id) const; 00161 00162 //!Copies the sound data to the OPENR buffer, ready to be passed to the system, only called by SoundPlay 00163 /*!@return the number of active sounds */ 00164 unsigned int CopyTo(OSoundVectorData* data); 00165 00166 //!updates internal data structures on the SoundPlay side - you shouldn't be calling this 00167 void ReceivedMsg(const ONotifyEvent& event); 00168 00169 //! returns number of sounds currently playing 00170 unsigned int GetNumPlaying() { return chanlist.size(); } 00171 00172 protected: 00173 //!Sets up a shared region to hold a sound - rounds to nearest page size 00174 static RCRegion* initRegion(unsigned int size); 00175 00176 //!Looks to see if @a name matches any of the sounds in sndlist (converts to absolute path if not already) 00177 Snd_ID lookupPath(std::string const &name) const; 00178 00179 //!selects which of the channels are actually to be mixed together, depending on queue_mode 00180 void selectChannels(std::vector<Play_ID>& mix); 00181 00182 //!update the offsets of sounds which weren't mixed (when needed depending on queue_mode) 00183 void updateChannels(const std::vector<Play_ID>& mixs,size_t used); 00184 00185 //!called when a buffer end is reached, may reset buffer to next in chain, or just StopPlay() 00186 bool endPlay(Play_ID id); 00187 00188 //!Holds data about the loaded sounds 00189 struct SoundData { 00190 SoundData(); //!<constructor 00191 RCRegion * rcr; //!<shared region - don't need to share among processes, just collect in SoundPlay 00192 byte* data; //!<point to data in region (for convenience, only valid in SoundPlay) 00193 unsigned int len; //!<size of the sound 00194 unsigned int ref; //!<reference counter 00195 char name[SoundManager::MAX_NAME_LEN]; //!<stores the path to the file, empty if from a buffer 00196 private: 00197 SoundData(const SoundData&); //!< don't call 00198 SoundData operator=(const SoundData&); //!< don't call 00199 }; 00200 //!For convenience 00201 typedef ListMemBuf<SoundData,MAX_SND,Snd_ID> sndlist_t; 00202 //!Holds a list of all currently loaded sounds 00203 sndlist_t sndlist; 00204 00205 //!Holds data about sounds currently being played 00206 struct PlayState { 00207 PlayState(); //!<constructor 00208 Snd_ID snd_id; //!<index of sound 00209 unsigned int offset; //!<position in the sound 00210 unsigned int cumulative;//!<total time of playing (over queued sounds) 00211 Play_ID next_id; //!<lets you queue for continuous sound, or loop 00212 }; 00213 //!For convenience 00214 typedef ListMemBuf<PlayState,MAX_PLAY,Play_ID> playlist_t; 00215 //!Holds a list of all sounds currently enqueued 00216 playlist_t playlist; 00217 //!For convenience 00218 typedef ListMemBuf<Play_ID,MAX_PLAY,Play_ID> chanlist_t; 00219 //!Holds a list of all currently playing sounds, ordered newest (front) to oldest(back) 00220 chanlist_t chanlist; 00221 00222 //!Current mixing mode, set by SetMode(); 00223 MixMode_t mix_mode; 00224 00225 //!Current queuing mode, set by SetMode(); 00226 QueueMode_t queue_mode; 00227 00228 //!Current maximum number of sounds to mix together 00229 unsigned int max_chan; 00230 00231 //!Prevents multiple processes from accessing at the same time 00232 mutable MutexLock<ProcessID::NumProcesses> lock; 00233 00234 //!For automatic transmission of shared regions to SoundPlay 00235 OSubject * subjs[ProcessID::NumProcesses]; 00236 00237 SoundManager(const SoundManager&); //!< don't call 00238 SoundManager operator=(const SoundManager&); //!< don't call 00239 }; 00240 00241 //! lets you play a sound from anywhere in your code - just a one liner! 00242 extern SoundManager * sndman; 00243 00244 /*! @file 00245 * @brief Describes SoundManager, which provides sound effects and caching services, as well as mixing buffers for the SoundPlay process 00246 * @author ejt (Creator) 00247 * 00248 * $Author: dst $ 00249 * $Name: tekkotsu-2_2 $ 00250 * $Revision: 1.12 $ 00251 * $State: Exp $ 00252 * $Date: 2004/10/08 00:07:25 $ 00253 */ 00254 00255 #endif |
Tekkotsu v2.2 |
Generated Tue Oct 19 14:19:16 2004 by Doxygen 1.3.9.1 |