Homepage | Demos | Overview | Downloads | Dev. Resources | 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 "IPC/RCRegion.h" 00006 #include "Shared/ODataFormats.h" 00007 00008 #include <string> 00009 #include <vector> 00010 #include "IPC/ListMemBuf.h" 00011 #include "IPC/MutexLock.h" 00012 #include "SoundManagerMsg.h" 00013 #include "IPC/ProcessID.h" 00014 00015 #ifdef PLATFORM_APERIOS 00016 class OSubject; 00017 class ONotifyEvent; 00018 #else 00019 # include "IPC/MessageQueue.h" 00020 #endif 00021 00022 //! Provides sound effects and caching services, as well as mixing buffers for the SoundPlay process 00023 /*! Provides easy methods for playing back sounds, either from files 00024 * on the memory stick, or from dynamically generated buffers. You 00025 * can chain playback commands so that when one sound finishes, 00026 * another picks up automatically. This might be handy if, say, 00027 * someone wants to write an MP3 player ;) The sounds would be too 00028 * large to load into memory all at once, but you could load a block 00029 * at a time and chain them so it seamlessly moves from one to the 00030 * other. 00031 * 00032 * You can also preload sounds (LoadFile()) before playing them so 00033 * there's no delay while loading after you request a sound to be 00034 * played. Just be sure to release the file (ReleaseFile()) again 00035 * when you're done with it ;) 00036 * 00037 * All functions will attempt to lock the SoundManager. Remember, 00038 * this is running in a shared memory region, accessible by the 00039 * SoundPlay process and both the Main and Motion processes (so 00040 * MotionCommands can play sounds!) 00041 * 00042 * One could be tempted to draw parallels to the MotionManager, and 00043 * envision a system with SoundCommands that are handed over and can 00044 * dynamically compute sound buffers as needed. If you have the time 00045 * and inclination, the job's all yours... (Midi players, speech 00046 * synthesizer, ...?) 00047 * 00048 * @todo Volume control, variable playback speed, support more wav 00049 * file formats (latter two are the same thing if you think about it 00050 * - need to be able to resample on the fly) 00051 * 00052 * @todo Add functions to hand out regions to be filled out to avoid 00053 * copying into the buffer. 00054 */ 00055 class SoundManager { 00056 public: 00057 virtual ~SoundManager(); 00058 00059 //!constructor, should only be called by the receiving process (SoundPlay) 00060 SoundManager(); 00061 #ifdef PLATFORM_APERIOS 00062 //!Each process needs to call this before it can send sounds to the SoundPlay process 00063 void InitAccess(OSubject* subj); 00064 #else //PLATFORM_LOCAL 00065 //!Each process (except SoundPlay) needs to call this before it can send sounds to the SoundPlay process 00066 void InitAccess(MessageQueueBase& sndbufq); 00067 #endif 00068 00069 //!This is used for referring to sound data so you can start playing it or release it 00070 typedef SoundManagerMsg::Snd_ID Snd_ID; 00071 static const Snd_ID invalid_Snd_ID=(Snd_ID)-1; //!< for reporting errors 00072 static const Snd_ID MAX_SND=50; //!< the number of sounds that can be loaded at any given time 00073 00074 //!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) 00075 typedef unsigned short Play_ID; 00076 static const Play_ID invalid_Play_ID=(Play_ID)-1; //!< for reporting errors 00077 static const Play_ID MAX_PLAY=256; //!< the number of sounds that can be enqueued at the same time (see MixMode_t) 00078 00079 static const unsigned int MAX_NAME_LEN=128; //!<maximum length of a path 00080 00081 //!Used to set the mode for mixing multiple sound channels 00082 /*!Feel free to add a higher quality mixer if you're an audiophile - I'm pretty new to sound processing*/ 00083 enum MixMode_t { 00084 // there's some prototype code for a bit-shifting 'Faster' quality level, but it hasn't been finished... 'Fast' is the default for now. 00085 Fast, //!< uses real division to maintain volume level, without increasing intermediary precision, which causes low-order bit error in exchange for less CPU usage 00086 Quality //!< uses real division to maintain volume level, using an intermediary higher precision buffer for mixing 00087 }; 00088 00089 enum QueueMode_t { 00090 Enqueue, //!< newer sounds are played when a channel opens up (when old sound finishes) 00091 Pause, //!< newer sounds pause oldest sound, which continues when a channel opens 00092 Stop, //!< newer sounds stop oldest sound 00093 Override, //!< older sounds have play heads advanced, but don't get mixed until a channel opens 00094 }; 00095 00096 //!loads a wav file (if it matches Config::sound_config settings - can't do resampling yet) 00097 /*!Since the SoundManager does the loading, if the same file is being played more than once, only once copy is stored in memory 00098 * @param name can be either a full path, or a partial path relative to Config::sound_config::root 00099 * @return ID number for future references (can also use name) 00100 * The sound data will be cached until ReleaseFile() or Release() is called a matching number of times*/ 00101 Snd_ID LoadFile(std::string const &name); 00102 00103 //!loads raw samples from a buffer (assumes matches Config::sound_config settings) 00104 /*!The sound data will be cached until Release() is called a matching number of times.\n 00105 * This function is useful for dynamic sound sources. A copy will be made. */ 00106 Snd_ID LoadBuffer(const char buf[], unsigned int len); 00107 00108 //!Marks the sound buffer to be released after the last play command completes (or right now if not being played) 00109 void ReleaseFile(std::string const &name); 00110 00111 //!Marks the sound buffer to be released after the last play command completes (or right now if not being played) 00112 void Release(Snd_ID id); 00113 00114 //!play a wav file (if it matches Config::sound_config settings - can't do resampling yet) 00115 /*!Will do a call to LoadFile() first, and then automatically release the sound again when complete. 00116 * @param name can be either a full path, or a partial path relative to Config::sound_config::root 00117 * @return ID number for future references 00118 * The sound data will not be cached after done playing unless a call to LoadFile is made*/ 00119 Play_ID PlayFile(std::string const &name); 00120 00121 //!loads raw samples from a buffer (assumes buffer matches Config::sound_config settings) 00122 /*!The sound data will be released after done playing*/ 00123 Play_ID PlayBuffer(const char buf[], unsigned int len); 00124 00125 //!plays a previously loaded buffer or file 00126 Play_ID Play(Snd_ID id); 00127 00128 //!allows automatic queuing of sounds - good for dynamic sound sources! 00129 /*!if you chain more than once to the same base, the new buffers are appended 00130 * to the end of the chain - the new buffer doesn't replace the current chain 00131 * @return @a base - just for convenience of multiple calls*/ 00132 Play_ID ChainFile(Play_ID base, std::string const &next); 00133 00134 //!allows automatic queuing of sounds - good for dynamic sound sources! 00135 /*!if you chain more than once to the same base, the new buffers are appended 00136 * to the end of the chain - the new buffer doesn't replace the current chain 00137 * @return @a base - just for convenience of multiple calls*/ 00138 Play_ID ChainBuffer(Play_ID base, const char buf[], unsigned int len); 00139 00140 //!allows automatic queuing of sounds - good for dynamic sound sources! 00141 /*!if you chain more than once to the same base, the new buffers are appended 00142 * to the end of the chain - the new buffer doesn't replace the current chain 00143 * @return @a base - just for convenience of multiple calls*/ 00144 Play_ID Chain(Play_ID base, Snd_ID next); 00145 00146 //!Lets you stop playback of all sounds 00147 void StopPlay(); 00148 00149 //!Lets you stop playback of a sound 00150 void StopPlay(Play_ID id); 00151 00152 //!Lets you pause playback 00153 void PausePlay(Play_ID id); 00154 00155 //!Lets you resume playback 00156 void ResumePlay(Play_ID id); 00157 00158 //!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) 00159 void SetMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode); 00160 00161 //!Gives the time until the sound finishes, in milliseconds. Subtract 32 to get guarranteed valid time for this ID. 00162 /*!You should be passing the beginning of a chain to get proper results...\n 00163 * May be slightly conservative (will report too small a time) because this 00164 * does not account for delay until SoundPlay picks up the message that a 00165 * sound has been added.\n 00166 * However, it is slighly optimistic (will report too large a time) because 00167 * it processes a buffer all at one go, so it could mark the sound as finished 00168 * (and cause the ID to go invalid) up to RobotInfo::SoundBufferTime (32 ms) 00169 * before the sound finishes. So subtract SoundBufferTime if you want to be 00170 * absolutely sure the ID will still valid. */ 00171 unsigned int GetRemainTime(Play_ID id) const; 00172 00173 #ifdef PLATFORM_APERIOS 00174 //!Copies the sound data to the OPENR buffer, ready to be passed to the system, only called by SoundPlay 00175 /*!@return the number of active sounds */ 00176 unsigned int CopyTo(OSoundVectorData* data); 00177 00178 //!updates internal data structures on the SoundPlay side - you shouldn't be calling this 00179 void ReceivedMsg(const ONotifyEvent& event); 00180 #endif 00181 00182 //!Copies the sound data to the specified memory buffer, ready to be passed to the system 00183 /*!@return the number of active sounds */ 00184 unsigned int CopyTo(void * dest, size_t destSize); 00185 00186 //!updates internal data structures on the SoundPlay side - you shouldn't be calling this 00187 void ProcessMsg(RCRegion * rcr); 00188 00189 //! returns number of sounds currently playing 00190 unsigned int GetNumPlaying() { return chanlist.size(); } 00191 00192 protected: 00193 //!Mixes the channel into the buffer 00194 void MixChannel(Play_ID channelId, void* buf, size_t size); 00195 00196 //!Mixes the channel into the buffer additively 00197 /*!If mode is Quality, then the size of the buffer should be double the normal 00198 * size. */ 00199 void MixChannelAdditively(Play_ID channelId, int bitsPerSample, MixMode_t mode, short scalingFactor, void* buf, size_t size); 00200 00201 //!The intermediate mixer buffer used for Quality mode mixing 00202 int* mixerBuffer; 00203 00204 //!Size (in bytes) of the intermediate mixer buffer 00205 size_t mixerBufferSize; 00206 00207 //!Sets up a shared region to hold a sound - rounds to nearest page size 00208 RCRegion* initRegion(unsigned int size); 00209 00210 //!Looks to see if @a name matches any of the sounds in sndlist (converts to absolute path if not already) 00211 Snd_ID lookupPath(std::string const &name) const; 00212 00213 //!selects which of the channels are actually to be mixed together, depending on queue_mode 00214 void selectChannels(std::vector<Play_ID>& mix); 00215 00216 //!update the offsets of sounds which weren't mixed (when needed depending on queue_mode) 00217 void updateChannels(const std::vector<Play_ID>& mixs,size_t used); 00218 00219 //!called when a buffer end is reached, may reset buffer to next in chain, or just StopPlay() 00220 bool endPlay(Play_ID id); 00221 00222 //!Holds data about the loaded sounds 00223 struct SoundData { 00224 SoundData(); //!<constructor 00225 RCRegion * rcr; //!<shared region - don't need to share among processes, just collect in SoundPlay 00226 byte* data; //!<point to data in region (for convenience, only valid in SoundPlay) 00227 unsigned int len; //!<size of the sound 00228 unsigned int ref; //!<reference counter 00229 unsigned int sn; //!<serial number, allows us to verify that a given message buffer does indeed match this sound, and wasn't delayed in processing 00230 char name[SoundManager::MAX_NAME_LEN]; //!<stores the path to the file, empty if from a buffer 00231 private: 00232 SoundData(const SoundData&); //!< don't call 00233 SoundData operator=(const SoundData&); //!< don't call 00234 }; 00235 //!For convenience 00236 typedef ListMemBuf<SoundData,MAX_SND,Snd_ID> sndlist_t; 00237 //!Holds a list of all currently loaded sounds 00238 sndlist_t sndlist; 00239 00240 //!Holds data about sounds currently being played 00241 struct PlayState { 00242 PlayState(); //!<constructor 00243 Snd_ID snd_id; //!<index of sound 00244 unsigned int offset; //!<position in the sound 00245 unsigned int cumulative;//!<total time of playing (over queued sounds) 00246 Play_ID next_id; //!<lets you queue for continuous sound, or loop 00247 }; 00248 //!For convenience 00249 typedef ListMemBuf<PlayState,MAX_PLAY,Play_ID> playlist_t; 00250 //!Holds a list of all sounds currently enqueued 00251 playlist_t playlist; 00252 //!For convenience 00253 typedef ListMemBuf<Play_ID,MAX_PLAY,Play_ID> chanlist_t; 00254 //!Holds a list of all currently playing sounds, ordered newest (front) to oldest(back) 00255 chanlist_t chanlist; 00256 00257 //!Current mixing mode, set by SetMode(); 00258 MixMode_t mix_mode; 00259 00260 //!Current queuing mode, set by SetMode(); 00261 QueueMode_t queue_mode; 00262 00263 //!Current maximum number of sounds to mix together 00264 unsigned int max_chan; 00265 00266 //!Prevents multiple processes from accessing at the same time 00267 mutable MutexLock<ProcessID::NumProcesses> lock; 00268 00269 //!A serial number, incremented for each sound which is created 00270 /*! This is used to verify that a sound message from a process 00271 * refers to a current sound. If you imaging a pathological 00272 * process, which rapidly creates and releases sounds, it would 00273 * run through the sndlist ids, possibly before the sound process 00274 * can process the incoming buffers. So this is used to ensure 00275 * that a given message refers to the current sound, and not one 00276 * that was already released and then reassigned. */ 00277 unsigned int sn; 00278 00279 //!the size of a SoundManagerMsg, which is prefixed before each region sent/received by SoundManager (rounded up to nearest even word boundary) 00280 static const unsigned int MSG_SIZE=((sizeof(SoundManagerMsg)-1)/8+1)*8; 00281 00282 #ifdef PLATFORM_APERIOS 00283 //!Storage of each process's subject object, used to internally transmit sound buffers to SoundPlay 00284 OSubject * subjs[ProcessID::NumProcesses]; 00285 #else //PLATFORM_LOCAL 00286 //!Storage of each process's attachment of the message queue, used to internally transmit sound buffers to SoundPlay 00287 MessageQueueBase * subjs[ProcessID::NumProcesses]; 00288 #endif 00289 00290 private: 00291 SoundManager(const SoundManager&); //!< don't call 00292 SoundManager operator=(const SoundManager&); //!< don't call 00293 }; 00294 00295 //! lets you play a sound from anywhere in your code - just a one liner! 00296 extern SoundManager * sndman; 00297 00298 /*! @file 00299 * @brief Describes SoundManager, which provides sound effects and caching services, as well as mixing buffers for the SoundPlay process 00300 * @author ejt (Creator) 00301 * 00302 * $Author: ejt $ 00303 * $Name: tekkotsu-2_4_1 $ 00304 * $Revision: 1.3 $ 00305 * $State: Exp $ 00306 * $Date: 2005/08/07 04:11:04 $ 00307 */ 00308 00309 #endif |
Tekkotsu v2.4.1 |
Generated Tue Aug 16 16:32:49 2005 by Doxygen 1.4.4 |