Homepage Demos Overview Downloads Tutorials Reference
Credits

SoundManager.h

Go 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 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   //! returns 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-2_0 $
00236  * $Revision: 1.10 $
00237  * $State: Exp $
00238  * $Date: 2004/01/18 10:16:58 $
00239  */
00240 
00241 #endif

Tekkotsu v2.0
Generated Wed Jan 21 03:20:30 2004 by Doxygen 1.3.4