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

Tekkotsu v2.2
Generated Tue Oct 19 14:19:16 2004 by Doxygen 1.3.9.1