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(const char* 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(const char* 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(const char* 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, const char* 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 00177 Snd_ID lookup(const char* name) const; 00178 //!Looks to see if @a name matches any of the sounds in sndlist (assumes is absolute path) 00179 Snd_ID lookupPath(const char* path) const; 00180 00181 //!prepends config.sound.root to the name if necessary 00182 static const char* makePath(const char* name, char tmp[MAX_NAME_LEN]); 00183 00184 //!selects which of the channels are actually to be mixed together, depending on queue_mode 00185 void selectChannels(std::vector<Play_ID>& mix); 00186 00187 //!update the offsets of sounds which weren't mixed (when needed depending on queue_mode) 00188 void updateChannels(const std::vector<Play_ID>& mixs,size_t used); 00189 00190 //!called when a buffer end is reached, may reset buffer to next in chain, or just StopPlay() 00191 bool endPlay(Play_ID id); 00192 00193 //!Holds data about the loaded sounds 00194 struct SoundData { 00195 SoundData(); //!<constructor 00196 RCRegion * rcr; //!<shared region - don't need to share among processes, just collect in SoundPlay 00197 byte* data; //!<point to data in region (for convenience, only valid in SoundPlay) 00198 unsigned int len; //!<size of the sound 00199 unsigned int ref; //!<reference counter 00200 char name[SoundManager::MAX_NAME_LEN]; //!<stores the path to the file, empty if from a buffer 00201 private: 00202 SoundData(const SoundData&); //!< don't call 00203 SoundData operator=(const SoundData&); //!< don't call 00204 }; 00205 //!For convenience 00206 typedef ListMemBuf<SoundData,MAX_SND,Snd_ID> sndlist_t; 00207 //!Holds a list of all currently loaded sounds 00208 sndlist_t sndlist; 00209 00210 //!Holds data about sounds currently being played 00211 struct PlayState { 00212 PlayState(); //!<constructor 00213 Snd_ID snd_id; //!<index of sound 00214 unsigned int offset; //!<position in the sound 00215 unsigned int cumulative;//!<total time of playing (over queued sounds) 00216 Play_ID next_id; //!<lets you queue for continuous sound, or loop 00217 }; 00218 //!For convenience 00219 typedef ListMemBuf<PlayState,MAX_PLAY,Play_ID> playlist_t; 00220 //!Holds a list of all sounds currently enqueued 00221 playlist_t playlist; 00222 //!For convenience 00223 typedef ListMemBuf<Play_ID,MAX_PLAY,Play_ID> chanlist_t; 00224 //!Holds a list of all currently playing sounds, ordered newest (front) to oldest(back) 00225 chanlist_t chanlist; 00226 00227 //!Current mixing mode, set by SetMode(); 00228 MixMode_t mix_mode; 00229 00230 //!Current queuing mode, set by SetMode(); 00231 QueueMode_t queue_mode; 00232 00233 //!Current maximum number of sounds to mix together 00234 unsigned int max_chan; 00235 00236 //!Prevents multiple processes from accessing at the same time 00237 mutable MutexLock<ProcessID::NumProcesses> lock; 00238 00239 //!For automatic transmission of shared regions to SoundPlay 00240 OSubject * subjs[ProcessID::NumProcesses]; 00241 00242 SoundManager(const SoundManager&); //!< don't call 00243 SoundManager operator=(const SoundManager&); //!< don't call 00244 }; 00245 00246 //! lets you play a sound from anywhere in your code - just a one liner! 00247 extern SoundManager * sndman; 00248 00249 /*! @file 00250 * @brief Describes SoundManager, which provides sound effects and caching services, as well as mixing buffers for the SoundPlay process 00251 * @author ejt (Creator) 00252 * 00253 * $Author: ejt $ 00254 * $Name: tekkotsu-2_1 $ 00255 * $Revision: 1.11 $ 00256 * $State: Exp $ 00257 * $Date: 2004/02/09 22:45:28 $ 00258 */ 00259 00260 #endif |
Tekkotsu v2.1 |
Generated Tue Mar 16 23:19:15 2004 by Doxygen 1.3.5 |