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 virtual ~SoundManager(); 00056 00057 //!This is used for referring to sound data so you can start playing it or release it 00058 typedef SoundManagerMsg::Snd_ID Snd_ID; 00059 static const Snd_ID invalid_Snd_ID=(Snd_ID)-1; //!< for reporting errors 00060 static const Snd_ID MAX_SND=50; //!< the number of sounds that can be loaded at any given time 00061 00062 //!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) 00063 typedef unsigned short Play_ID; 00064 static const Play_ID invalid_Play_ID=(Play_ID)-1; //!< for reporting errors 00065 static const Play_ID MAX_PLAY=256; //!< the number of sounds that can be enqueued at the same time (see MixMode_t) 00066 00067 static const unsigned int MAX_NAME_LEN=64; //!<maximum length of a path 00068 00069 //!Used to set the mode for mixing multiple sound channels 00070 /*!Feel free to add a higher quality mixer if you're an audiophile - I'm pretty new to sound processing*/ 00071 enum MixMode_t { 00072 // there's some prototype code for a bit-shifting 'Faster' quality level, but it hasn't been finished... 'Fast' is the default for now. 00073 Fast, //!< uses real division to maintain volume level, without increasing intermediary precision, which causes low-order bit error in exchange for less CPU usage 00074 Quality //!< uses real division to maintain volume level, using an intermediary higher precision buffer for mixing 00075 }; 00076 00077 enum QueueMode_t { 00078 Enqueue, //!< newer sounds are played when a channel opens up (when old sound finishes) 00079 Pause, //!< newer sounds pause oldest sound, which continues when a channel opens 00080 Stop, //!< newer sounds stop oldest sound 00081 Override, //!< older sounds have play heads advanced, but don't get mixed until a channel opens 00082 }; 00083 00084 //!Needed to send sounds to the SoundPlay process 00085 void InitAccess(OSubject* subj); 00086 00087 //!loads a wav file (if it matches Config::sound_config settings - can't do resampling yet) 00088 /*!Since the SoundManager does the loading, if the same file is being played more than once, only once copy is stored in memory 00089 * @param name can be either a full path, or a partial path relative to Config::sound_config::root 00090 * @return ID number for future references (can also use name) 00091 * The sound data will be cached until ReleaseFile() or Release() is called a matching number of times*/ 00092 Snd_ID LoadFile(std::string const &name); 00093 00094 //!loads raw samples from a buffer (assumes matches Config::sound_config settings) 00095 /*!The sound data will be cached until Release() is called a matching number of times.\n 00096 * This function is useful for dynamic sound sources. A copy will be made. */ 00097 Snd_ID LoadBuffer(const char buf[], unsigned int len); 00098 00099 //!Marks the sound buffer to be released after the last play command completes (or right now if not being played) 00100 void ReleaseFile(std::string const &name); 00101 00102 //!Marks the sound buffer to be released after the last play command completes (or right now if not being played) 00103 void Release(Snd_ID id); 00104 00105 //!play a wav file (if it matches Config::sound_config settings - can't do resampling yet) 00106 /*!Will do a call to LoadFile() first, and then automatically release the sound again when complete. 00107 * @param name can be either a full path, or a partial path relative to Config::sound_config::root 00108 * @return ID number for future references 00109 * The sound data will not be cached after done playing unless a call to LoadFile is made*/ 00110 Play_ID PlayFile(std::string const &name); 00111 00112 //!loads raw samples from a buffer (assumes buffer matches Config::sound_config settings) 00113 /*!The sound data will be released after done playing*/ 00114 Play_ID PlayBuffer(const char buf[], unsigned int len); 00115 00116 //!plays a previously loaded buffer or file 00117 Play_ID Play(Snd_ID id); 00118 00119 //!allows automatic queuing of sounds - good for dynamic sound sources! 00120 /*!if you chain more than once to the same base, the new buffers are appended 00121 * to the end of the chain - the new buffer doesn't replace the current chain 00122 * @return @a base - just for convenience of multiple calls*/ 00123 Play_ID ChainFile(Play_ID base, std::string const &next); 00124 00125 //!allows automatic queuing of sounds - good for dynamic sound sources! 00126 /*!if you chain more than once to the same base, the new buffers are appended 00127 * to the end of the chain - the new buffer doesn't replace the current chain 00128 * @return @a base - just for convenience of multiple calls*/ 00129 Play_ID ChainBuffer(Play_ID base, const char buf[], unsigned int len); 00130 00131 //!allows automatic queuing of sounds - good for dynamic sound sources! 00132 /*!if you chain more than once to the same base, the new buffers are appended 00133 * to the end of the chain - the new buffer doesn't replace the current chain 00134 * @return @a base - just for convenience of multiple calls*/ 00135 Play_ID Chain(Play_ID base, Snd_ID next); 00136 00137 //!Lets you stop playback of all sounds 00138 void StopPlay(); 00139 00140 //!Lets you stop playback of a sound 00141 void StopPlay(Play_ID id); 00142 00143 //!Lets you pause playback 00144 void PausePlay(Play_ID id); 00145 00146 //!Lets you resume playback 00147 void ResumePlay(Play_ID id); 00148 00149 //!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) 00150 void SetMode(unsigned int max_channels, MixMode_t mixer_mode, QueueMode_t queuing_mode); 00151 00152 //!Gives the time until the sound finishes, in milliseconds. Subtract 32 to get guarranteed valid time for this ID. 00153 /*!You should be passing the beginning of a chain to get proper results...\n 00154 * May be slightly conservative (will report too small a time) because this 00155 * does not account for delay until SoundPlay picks up the message that a 00156 * sound has been added.\n 00157 * However, it is slighly optimistic (will report too large a time) because 00158 * it processes a buffer all at one go, so it could mark the sound as finished 00159 * (and cause the ID to go invalid) up to RobotInfo::SoundBufferTime (32 ms) 00160 * before the sound finishes. So subtract SoundBufferTime if you want to be 00161 * absolutely sure the ID will still valid. */ 00162 unsigned int GetRemainTime(Play_ID id) const; 00163 00164 //!Copies the sound data to the OPENR buffer, ready to be passed to the system, only called by SoundPlay 00165 /*!@return the number of active sounds */ 00166 unsigned int CopyTo(OSoundVectorData* data); 00167 00168 //!updates internal data structures on the SoundPlay side - you shouldn't be calling this 00169 void ReceivedMsg(const ONotifyEvent& event); 00170 00171 //! returns number of sounds currently playing 00172 unsigned int GetNumPlaying() { return chanlist.size(); } 00173 00174 protected: 00175 //!Mixes the channel into the buffer 00176 void MixChannel(Play_ID channelId, void* buf, size_t size); 00177 00178 //!Mixes the channel into the buffer additively 00179 /*!If mode is Quality, then the size of the buffer should be double the normal 00180 * size. */ 00181 void MixChannelAdditively(Play_ID channelId, int bitsPerSample, MixMode_t mode, short scalingFactor, void* buf, size_t size); 00182 00183 //!The intermediate mixer buffer used for Quality mode mixing 00184 int* mixerBuffer; 00185 00186 //!Size (in bytes) of the intermediate mixer buffer 00187 size_t mixerBufferSize; 00188 00189 //!Sets up a shared region to hold a sound - rounds to nearest page size 00190 static RCRegion* initRegion(unsigned int size); 00191 00192 //!Looks to see if @a name matches any of the sounds in sndlist (converts to absolute path if not already) 00193 Snd_ID lookupPath(std::string const &name) const; 00194 00195 //!selects which of the channels are actually to be mixed together, depending on queue_mode 00196 void selectChannels(std::vector<Play_ID>& mix); 00197 00198 //!update the offsets of sounds which weren't mixed (when needed depending on queue_mode) 00199 void updateChannels(const std::vector<Play_ID>& mixs,size_t used); 00200 00201 //!called when a buffer end is reached, may reset buffer to next in chain, or just StopPlay() 00202 bool endPlay(Play_ID id); 00203 00204 //!Holds data about the loaded sounds 00205 struct SoundData { 00206 SoundData(); //!<constructor 00207 RCRegion * rcr; //!<shared region - don't need to share among processes, just collect in SoundPlay 00208 byte* data; //!<point to data in region (for convenience, only valid in SoundPlay) 00209 unsigned int len; //!<size of the sound 00210 unsigned int ref; //!<reference counter 00211 char name[SoundManager::MAX_NAME_LEN]; //!<stores the path to the file, empty if from a buffer 00212 private: 00213 SoundData(const SoundData&); //!< don't call 00214 SoundData operator=(const SoundData&); //!< don't call 00215 }; 00216 //!For convenience 00217 typedef ListMemBuf<SoundData,MAX_SND,Snd_ID> sndlist_t; 00218 //!Holds a list of all currently loaded sounds 00219 sndlist_t sndlist; 00220 00221 //!Holds data about sounds currently being played 00222 struct PlayState { 00223 PlayState(); //!<constructor 00224 Snd_ID snd_id; //!<index of sound 00225 unsigned int offset; //!<position in the sound 00226 unsigned int cumulative;//!<total time of playing (over queued sounds) 00227 Play_ID next_id; //!<lets you queue for continuous sound, or loop 00228 }; 00229 //!For convenience 00230 typedef ListMemBuf<PlayState,MAX_PLAY,Play_ID> playlist_t; 00231 //!Holds a list of all sounds currently enqueued 00232 playlist_t playlist; 00233 //!For convenience 00234 typedef ListMemBuf<Play_ID,MAX_PLAY,Play_ID> chanlist_t; 00235 //!Holds a list of all currently playing sounds, ordered newest (front) to oldest(back) 00236 chanlist_t chanlist; 00237 00238 //!Current mixing mode, set by SetMode(); 00239 MixMode_t mix_mode; 00240 00241 //!Current queuing mode, set by SetMode(); 00242 QueueMode_t queue_mode; 00243 00244 //!Current maximum number of sounds to mix together 00245 unsigned int max_chan; 00246 00247 //!Prevents multiple processes from accessing at the same time 00248 mutable MutexLock<ProcessID::NumProcesses> lock; 00249 00250 //!For automatic transmission of shared regions to SoundPlay 00251 OSubject * subjs[ProcessID::NumProcesses]; 00252 00253 SoundManager(const SoundManager&); //!< don't call 00254 SoundManager operator=(const SoundManager&); //!< don't call 00255 }; 00256 00257 //! lets you play a sound from anywhere in your code - just a one liner! 00258 extern SoundManager * sndman; 00259 00260 /*! @file 00261 * @brief Describes SoundManager, which provides sound effects and caching services, as well as mixing buffers for the SoundPlay process 00262 * @author ejt (Creator) 00263 * 00264 * $Author: ejt $ 00265 * $Name: tekkotsu-2_2_2 $ 00266 * $Revision: 1.14 $ 00267 * $State: Exp $ 00268 * $Date: 2004/11/04 05:24:03 $ 00269 */ 00270 00271 #endif |
Tekkotsu v2.2.2 |
Generated Tue Jan 4 15:43:15 2005 by Doxygen 1.4.0 |