Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

RageSound.h

Go to the documentation of this file.
00001 #ifndef RAGE_SOUND_H 00002 #define RAGE_SOUND_H 00003 00004 #include <deque> 00005 #include "RageThreads.h" 00006 #include "RageTimer.h" 00007 #include "RageUtil_CircularBuffer.h" 00008 #include "RageSoundPosMap.h" 00009 00010 class SoundReader; 00011 00012 /* Driver interface for sounds: this is what drivers see. */ 00013 class RageSoundBase 00014 { 00015 public: 00016 virtual ~RageSoundBase() { } 00017 virtual void SoundIsFinishedPlaying() = 0; 00018 virtual bool GetDataToPlay( int16_t *buffer, int size, int &pos, int &got_bytes ) = 0; 00019 virtual int GetPCM( char *buffer, int size, int64_t frameno ) = 0; 00020 virtual int GetSampleRate() const = 0; 00021 virtual RageTimer GetStartTime() const { return RageZeroTimer; } 00022 virtual float GetVolume() const = 0; 00023 virtual int GetID() const = 0; 00024 virtual CString GetLoadedFilePath() const = 0; 00025 virtual bool IsStreamingFromDisk() const = 0; 00026 }; 00027 00028 /* These are parameters to play a sound. These are normally changed before playing begins, 00029 * and are constant from then on. */ 00030 struct RageSoundParams 00031 { 00032 RageSoundParams(); 00033 00034 /* The amount of data to play (or loop): */ 00035 float m_StartSecond; 00036 float m_LengthSeconds; 00037 00038 /* Number of seconds to spend fading out. */ 00039 float m_FadeLength; 00040 00041 void SetNoFade() { m_FadeLength = 0; } 00042 00043 float m_Volume; 00044 00045 /* Pan: -1, left; 1, right */ 00046 float m_Balance; 00047 00048 /* Number of samples input and output when changing speed. Currently, 00049 * this is either 1/1, 5/4 or 4/5. */ 00050 int speed_input_samples, speed_output_samples; 00051 void SetPlaybackRate( float fScale ); 00052 00053 bool AccurateSync; 00054 00055 /* Optional driver feature: time to actually start playing sounds. If zero, or if not 00056 * supported, it'll start immediately. */ 00057 RageTimer StartTime; 00058 00059 /* M_STOP (default) stops the sound at the end. 00060 * M_LOOP restarts. 00061 * M_CONTINUE feeds silence, which is useful to continue timing longer than the actual sound. */ 00062 enum StopMode_t { 00063 M_STOP, /* stop when finished */ 00064 M_LOOP, /* loop */ 00065 M_CONTINUE, /* keep playing silence */ 00066 M_AUTO /* obey filename hints */ 00067 } StopMode; 00068 }; 00069 00070 class RageSound: public RageSoundBase 00071 { 00072 public: 00073 RageSound(); 00074 ~RageSound(); 00075 RageSound(const RageSound &cpy); 00076 RageSound &operator=( const RageSound &cpy ); 00077 00078 /* If cache == true (1), we'll preload the entire file into memory if 00079 * it's small enough. If this is done, a large number of copies of the 00080 * sound can be played without much performance penalty. This is useful 00081 * for BM (keyed sounds), and for rapidly-repeating sound effects, such 00082 * as the music wheel. 00083 * 00084 * If cache == false (0), we'll never preload the file (always stream 00085 * it). This makes loads much faster. 00086 * 00087 * If cache is 2 (the default), it means "don't care". Currently, this 00088 * means false; this may become a preference. 00089 * 00090 * If the file failed to load, false is returned, Error() is set 00091 * and a null sample will be loaded. (This makes failed loads nonfatal; 00092 * they can be ignored most of the time, so we continue to work if a file 00093 * is broken or missing.) */ 00094 bool Load(CString fn, int precache = 2); 00095 00096 /* Load a SoundReader that you've set up yourself. Sample rate conversion will 00097 * be set up only if needed. Doesn't fail. */ 00098 void LoadSoundReader( SoundReader *pSound ); 00099 void Unload(); 00100 bool IsLoaded() const; 00101 00102 void StartPlaying(); 00103 void StopPlaying(); 00104 00105 CString GetError() const { return error; } 00106 bool Error() const { return !error.empty(); } 00107 00108 RageSound *Play( const RageSoundParams *params=NULL ); 00109 void Stop(); 00110 00111 float GetLengthSeconds(); 00112 float GetPositionSeconds( bool *approximate=NULL, RageTimer *Timestamp=NULL ) const; 00113 int GetSampleRate() const; 00114 bool IsStreamingFromDisk() const; 00115 bool SetPositionSeconds( float fSeconds ); 00116 CString GetLoadedFilePath() const { return m_sFilePath; } 00117 bool IsPlaying() const { return playing; } 00118 00119 /* Lock and unlock this sound. */ 00120 void LockSound(); 00121 void UnlockSound(); 00122 00123 float GetPlaybackRate() const; 00124 RageTimer GetStartTime() const; 00125 float GetVolume() const; 00126 int GetID() const { return ID; } 00127 void SetParams( const RageSoundParams &p ); 00128 const RageSoundParams &GetParams() const { return m_Param; } 00129 00130 private: 00131 mutable RageMutex m_Mutex; 00132 00133 SoundReader *Sample; 00134 CircBuf<char> databuf; 00135 int FillBuf(int bytes); 00136 00137 /* We keep track of sound blocks we've sent out recently through GetDataToPlay. */ 00138 pos_map_queue pos_map; 00139 00140 CString m_sFilePath; 00141 00142 RageSoundParams m_Param; 00143 00144 /* Current position of the output sound, in frames. If < 0, nothing will play 00145 * until it becomes positive. */ 00146 int decode_position; 00147 00148 /* Hack: When we stop a playing sound, we can't ask the driver the position 00149 * (we're not playing); and we can't seek back to the current playing position 00150 * when we stop (too slow), but we want to be able to report the position we 00151 * were at when we stopped without jumping to the last position we buffered. 00152 * Keep track of the position after a seek or stop, so we can return a sane 00153 * position when stopped, and when playing but pos_map hasn't yet been filled. */ 00154 int stopped_position; 00155 bool playing; 00156 00157 /* Keep track of the max SOUNDMAN->GetPosition result (see GetPositionSecondsInternal). */ 00158 mutable int64_t max_driver_frame; 00159 00160 /* Unique ID number for this instance of RageSound. */ 00161 int ID; 00162 00163 CString error; 00164 00165 int64_t GetPositionSecondsInternal( bool *approximate=NULL ) const; 00166 bool SetPositionFrames( int frames = -1 ); 00167 int GetData(char *buffer, int size); 00168 void Fail(CString reason); 00169 int Bytes_Available() const; 00170 RageSoundParams::StopMode_t GetStopMode() const; /* resolves M_AUTO */ 00171 00172 void SoundIsFinishedPlaying(); // called by sound drivers 00173 00174 static void RateChange(char *buf, int &cnt, int speed_input_samples, int speed_output_samples, int channels); 00175 00176 public: 00177 /* Called only by the sound drivers: */ 00178 /* This function should return the number of bytes actually put into buffer. 00179 * If less than size is returned, it signals the stream to stop; once it's 00180 * flushed, SoundStopped will be called. Until then, SOUNDMAN->GetPosition 00181 * can still be called (the sound is still playing). */ 00182 int GetPCM( char *buffer, int size, int64_t frameno ); 00183 bool GetDataToPlay( int16_t *buffer, int size, int &pos, int &got_bytes ); 00184 void CommitPlayingPosition( int64_t frameno, int pos, int got_bytes ); 00185 }; 00186 00187 #endif 00188 00189 /* 00190 * Copyright (c) 2002-2004 Glenn Maynard 00191 * All rights reserved. 00192 * 00193 * Permission is hereby granted, free of charge, to any person obtaining a 00194 * copy of this software and associated documentation files (the 00195 * "Software"), to deal in the Software without restriction, including 00196 * without limitation the rights to use, copy, modify, merge, publish, 00197 * distribute, and/or sell copies of the Software, and to permit persons to 00198 * whom the Software is furnished to do so, provided that the above 00199 * copyright notice(s) and this permission notice appear in all copies of 00200 * the Software and that both the above copyright notice(s) and this 00201 * permission notice appear in supporting documentation. 00202 * 00203 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00204 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00205 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 00206 * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS 00207 * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT 00208 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 00209 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 00210 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00211 * PERFORMANCE OF THIS SOFTWARE. 00212 */

Generated on Thu Jan 27 20:57:28 2005 for StepMania by doxygen 1.3.7