Files
itgmania212121/stepmania/src/RageSound.h
T

227 lines
7.6 KiB
C++
Raw Normal View History

2005-06-08 21:22:08 +00:00
/* RageSound - High-level sound object. */
2004-05-06 02:40:33 +00:00
#ifndef RAGE_SOUND_H
#define RAGE_SOUND_H
2002-12-13 07:44:34 +00:00
#include <deque>
2004-04-16 22:28:01 +00:00
#include "RageThreads.h"
#include "RageTimer.h"
2004-01-14 09:38:14 +00:00
#include "RageUtil_CircularBuffer.h"
#include "RageSoundPosMap.h"
2002-12-13 07:44:34 +00:00
2002-12-27 23:15:39 +00:00
class SoundReader;
2004-01-15 02:28:58 +00:00
/* Driver interface for sounds: this is what drivers see. */
2004-01-15 02:31:09 +00:00
class RageSoundBase
2004-01-15 02:28:58 +00:00
{
public:
2004-01-15 02:31:09 +00:00
virtual ~RageSoundBase() { }
virtual void SoundIsFinishedPlaying() = 0;
2004-03-18 03:30:36 +00:00
virtual bool GetDataToPlay( int16_t *buffer, int size, int &pos, int &got_bytes ) = 0;
2004-02-28 00:14:16 +00:00
virtual int GetPCM( char *buffer, int size, int64_t frameno ) = 0;
2004-01-15 02:28:58 +00:00
virtual int GetSampleRate() const = 0;
virtual RageTimer GetStartTime() const { return RageZeroTimer; }
2004-01-22 06:52:44 +00:00
virtual float GetVolume() const = 0;
2004-03-18 01:31:34 +00:00
virtual int GetID() const = 0;
2004-01-15 02:28:58 +00:00
virtual CString GetLoadedFilePath() const = 0;
2004-08-21 07:01:54 +00:00
virtual bool IsStreamingFromDisk() const = 0;
2004-01-15 02:28:58 +00:00
};
2004-02-28 01:02:06 +00:00
/* These are parameters to play a sound. These are normally changed before playing begins,
* and are constant from then on. */
struct RageSoundParams
2002-12-13 07:44:34 +00:00
{
2004-02-28 01:02:06 +00:00
RageSoundParams();
/* The amount of data to play (or loop): */
float m_StartSecond;
float m_LengthSeconds;
/* Number of seconds to spend fading out. */
2004-02-28 01:02:06 +00:00
float m_FadeLength;
void SetNoFade() { m_FadeLength = 0; }
2004-02-28 01:02:06 +00:00
float m_Volume;
/* Pan: -1, left; 1, right */
float m_Balance;
/* Number of samples input and output when changing speed. Currently,
* this is either 1/1, 5/4 or 4/5. */
int speed_input_samples, speed_output_samples;
void SetPlaybackRate( float fScale );
2004-02-28 01:02:06 +00:00
bool AccurateSync;
/* Optional driver feature: time to actually start playing sounds. If zero, or if not
* supported, it'll start immediately. */
RageTimer StartTime;
2005-06-08 21:22:08 +00:00
/*
* M_STOP (default) stops the sound at the end.
2004-02-28 00:14:16 +00:00
* M_LOOP restarts.
2005-06-08 21:22:08 +00:00
* M_CONTINUE feeds silence, which is useful to continue timing longer than the actual sound.
*/
2002-12-27 23:15:39 +00:00
enum StopMode_t {
2005-06-08 21:22:08 +00:00
M_STOP, /* stop when finished */
M_LOOP, /* loop */
M_CONTINUE, /* keep playing silence */
2005-06-08 21:22:08 +00:00
M_AUTO /* obey filename hints */
2004-02-28 01:02:06 +00:00
} StopMode;
};
2002-12-27 23:15:39 +00:00
2004-02-28 01:02:06 +00:00
class RageSound: public RageSoundBase
{
public:
2002-12-27 23:15:39 +00:00
RageSound();
~RageSound();
2005-06-08 04:47:03 +00:00
RageSound( const RageSound &cpy );
RageSound &operator=( const RageSound &cpy );
2002-12-27 23:15:39 +00:00
2005-06-08 21:22:08 +00:00
/*
* If bPrecache == true, we'll preload the entire file into memory if
* small enough. If this is done, a large number of copies of the sound
* can be played without much performance penalty. This is useful for
* efficiently playing keyed sounds, and for rapidly-repeating sound
* effects, such as the music wheel.
2003-01-21 02:44:35 +00:00
*
2005-06-08 21:22:08 +00:00
* If cache == false, we'll always stream the sound on demand, which
* makes loads much faster.
2003-01-21 02:44:35 +00:00
*
2002-12-27 23:15:39 +00:00
* If the file failed to load, false is returned, Error() is set
2005-06-08 21:22:08 +00:00
* and a null sample will be loaded. This makes failed loads nonfatal;
2002-12-27 23:15:39 +00:00
* they can be ignored most of the time, so we continue to work if a file
2005-06-08 21:22:08 +00:00
* is broken or missing.
*/
2005-06-08 04:47:03 +00:00
bool Load( CString sFile, bool bPrecache );
2005-03-16 04:10:10 +00:00
/*
* Using this version means the "don't care" about caching. Currently,
* this always will not cache the sound; this may become a preference.
*/
2005-06-08 04:47:03 +00:00
bool Load( CString sFile );
/* Load a SoundReader that you've set up yourself. Sample rate conversion will
* be set up only if needed. Doesn't fail. */
void LoadSoundReader( SoundReader *pSound );
2002-12-27 23:15:39 +00:00
void Unload();
2004-12-04 21:20:02 +00:00
bool IsLoaded() const;
2002-12-27 23:15:39 +00:00
void StartPlaying();
void StopPlaying();
2005-06-08 04:47:03 +00:00
CString GetError() const { return m_sError; }
bool Error() const { return !m_sError.empty(); }
2002-12-27 23:15:39 +00:00
RageSound *Play( const RageSoundParams *params=NULL );
2002-12-27 23:15:39 +00:00
void Stop();
/* Cleanly pause or unpause the sound. If the sound wasn't already playing,
* return true and do nothing. */
bool Pause( bool bPause );
2002-12-27 23:15:39 +00:00
float GetLengthSeconds();
2004-01-18 04:01:52 +00:00
float GetPositionSeconds( bool *approximate=NULL, RageTimer *Timestamp=NULL ) const;
2003-04-24 23:51:05 +00:00
int GetSampleRate() const;
2004-08-21 07:01:54 +00:00
bool IsStreamingFromDisk() const;
bool SetPositionSeconds( float fSeconds );
2004-02-28 01:02:06 +00:00
CString GetLoadedFilePath() const { return m_sFilePath; }
2005-06-08 04:47:03 +00:00
bool IsPlaying() const { return m_bPlaying; }
2004-02-28 01:02:06 +00:00
/* Lock and unlock this sound. */
void LockSound();
void UnlockSound();
2004-02-28 00:14:16 +00:00
float GetPlaybackRate() const;
RageTimer GetStartTime() const;
float GetVolume() const;
2005-06-08 04:47:03 +00:00
int GetID() const { return m_iID; }
void SetParams( const RageSoundParams &p );
const RageSoundParams &GetParams() const { return m_Param; }
2002-12-27 23:15:39 +00:00
private:
mutable RageMutex m_Mutex;
2005-06-08 04:47:03 +00:00
SoundReader *m_pSource;
CircBuf<char> m_DataBuffer;
int FillBuf( int iBytes );
2002-12-13 07:44:34 +00:00
/* We keep track of sound blocks we've sent out recently through GetDataToPlay. */
2005-06-08 04:47:03 +00:00
pos_map_queue m_PositionMapping;
2004-01-18 02:07:58 +00:00
2002-12-13 07:44:34 +00:00
CString m_sFilePath;
2004-02-28 01:02:06 +00:00
RageSoundParams m_Param;
2002-12-27 23:15:39 +00:00
2004-04-11 04:01:07 +00:00
/* Current position of the output sound, in frames. If < 0, nothing will play
* until it becomes positive. */
2005-06-08 04:47:03 +00:00
int m_iDecodePosition;
2003-01-25 09:01:42 +00:00
/* Hack: When we stop a playing sound, we can't ask the driver the position
* (we're not playing); and we can't seek back to the current playing position
* when we stop (too slow), but we want to be able to report the position we
* were at when we stopped without jumping to the last position we buffered.
* Keep track of the position after a seek or stop, so we can return a sane
* position when stopped, and when playing but pos_map hasn't yet been filled. */
2005-06-08 04:47:03 +00:00
int m_iStoppedPosition;
bool m_bPlaying;
2002-12-13 07:44:34 +00:00
/* Keep track of the max SOUNDMAN->GetPosition result (see GetPositionSecondsInternal). */
2005-06-08 04:47:03 +00:00
mutable int64_t m_iMaxDriverFrame;
2004-03-18 01:31:34 +00:00
/* Unique ID number for this instance of RageSound. */
2005-06-08 04:47:03 +00:00
int m_iID;
2004-03-18 01:31:34 +00:00
2005-06-08 04:47:03 +00:00
CString m_sError;
2002-12-18 06:44:56 +00:00
2005-06-08 04:47:03 +00:00
int64_t GetPositionSecondsInternal( bool *bApproximate=NULL ) const;
2004-02-28 00:14:16 +00:00
bool SetPositionFrames( int frames = -1 );
2005-06-08 04:47:03 +00:00
int GetData( char *pBuffer, int iSize );
void Fail( CString sReason );
2002-12-27 23:15:39 +00:00
int Bytes_Available() const;
RageSoundParams::StopMode_t GetStopMode() const; /* resolves M_AUTO */
2002-12-22 08:13:33 +00:00
void SoundIsFinishedPlaying(); // called by sound drivers
2005-06-08 04:47:03 +00:00
static void RateChange( char *pBuf, int &iCount, int iInputSpeed, int iOutputSpeed, int iChannels );
2003-01-02 06:52:39 +00:00
2002-12-13 07:44:34 +00:00
public:
2005-06-08 21:22:08 +00:00
/* These functions are called only by sound drivers. */
/* Returns the number of bytes actually put into pBuffer. If less than iSize is
* returned, it signals the stream to stop; once it's flushed, SoundStopped will
* be called. Until then, SOUNDMAN->GetPosition can still be called; the sound
* is still playing. */
int GetPCM( char *pBuffer, int iSize, int64_t iFrameno );
2005-06-08 04:47:03 +00:00
bool GetDataToPlay( int16_t *pBuffer, int iSize, int &iPosition, int &iBytesRead );
void CommitPlayingPosition( int64_t iFrameno, int iPosition, int iBytesRead );
2002-12-13 07:44:34 +00:00
};
#endif
2004-05-06 02:40:33 +00:00
2003-03-15 23:27:34 +00:00
/*
2004-05-06 02:40:33 +00:00
* Copyright (c) 2002-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/