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