2002-12-13 07:44:34 +00:00
|
|
|
#ifndef RAGE_SOUND_OBJ_H
|
|
|
|
|
#define RAGE_SOUND_OBJ_H
|
|
|
|
|
|
2002-12-21 02:08:49 +00:00
|
|
|
#include <deque>
|
2004-01-10 10:41:29 +00:00
|
|
|
#include "RageTimer.h"
|
2004-01-14 09:38:14 +00:00
|
|
|
#include "RageUtil_CircularBuffer.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() { }
|
2004-01-15 02:28:58 +00:00
|
|
|
virtual void StopPlaying() = 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-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;
|
|
|
|
|
|
|
|
|
|
/* Amount of time to fade out at the end. */
|
|
|
|
|
float m_FadeLength;
|
2004-02-28 02:09:46 +00:00
|
|
|
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;
|
2004-02-28 02:09:46 +00:00
|
|
|
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;
|
|
|
|
|
|
2004-02-28 00:14:16 +00:00
|
|
|
/* M_STOP (default) stops the sound at the end.
|
|
|
|
|
* M_LOOP restarts.
|
|
|
|
|
* 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 {
|
2004-02-28 02:09:46 +00:00
|
|
|
M_STOP, /* stop when finished */
|
|
|
|
|
M_LOOP, /* loop */
|
|
|
|
|
M_CONTINUE, /* keep playing silence */
|
|
|
|
|
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();
|
|
|
|
|
RageSound(const RageSound &cpy);
|
|
|
|
|
|
2003-01-21 02:44:35 +00:00
|
|
|
/* If cache == true (1), we'll preload the entire file into memory if
|
|
|
|
|
* it's small enough. If this is done, a large number of copies of the
|
|
|
|
|
* sound can be played without much performance penalty. This is useful
|
2004-01-14 09:38:14 +00:00
|
|
|
* for BM (keyed sounds), and for rapidly-repeating sound effects, such
|
2003-01-21 02:44:35 +00:00
|
|
|
* as the music wheel.
|
|
|
|
|
*
|
|
|
|
|
* If cache == false (0), we'll never preload the file (always stream
|
|
|
|
|
* it). This makes loads much faster.
|
|
|
|
|
*
|
|
|
|
|
* If cache is 2 (the default), it means "don't care". Currently, this
|
|
|
|
|
* means false; this may become a preference.
|
2002-12-27 23:15:39 +00:00
|
|
|
*
|
|
|
|
|
* If the file failed to load, false is returned, Error() is set
|
|
|
|
|
* and a null sample will be loaded. (This makes failed loads nonfatal;
|
|
|
|
|
* they can be ignored most of the time, so we continue to work if a file
|
|
|
|
|
* is broken or missing.) */
|
2003-01-21 02:44:35 +00:00
|
|
|
bool Load(CString fn, int precache = 2);
|
2002-12-27 23:15:39 +00:00
|
|
|
void Unload();
|
|
|
|
|
|
|
|
|
|
void StartPlaying();
|
|
|
|
|
void StopPlaying();
|
|
|
|
|
|
|
|
|
|
CString GetError() const { return error; }
|
|
|
|
|
bool Error() const { return !error.empty(); }
|
|
|
|
|
|
2004-02-28 02:09:46 +00:00
|
|
|
RageSound *Play( const RageSoundParams *params=NULL );
|
2002-12-27 23:15:39 +00:00
|
|
|
void Stop();
|
|
|
|
|
|
|
|
|
|
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-02-28 02:09:46 +00:00
|
|
|
bool SetPositionSeconds( float fSeconds );
|
2004-02-28 01:02:06 +00:00
|
|
|
CString GetLoadedFilePath() const { return m_sFilePath; }
|
|
|
|
|
bool IsPlaying() const { return playing; }
|
|
|
|
|
|
2004-02-28 00:14:16 +00:00
|
|
|
float GetPlaybackRate() const;
|
|
|
|
|
RageTimer GetStartTime() const;
|
2004-02-28 02:09:46 +00:00
|
|
|
float GetVolume() const;
|
2004-03-18 01:31:34 +00:00
|
|
|
int GetID() const { return ID; }
|
2004-02-28 02:09:46 +00:00
|
|
|
void SetParams( const RageSoundParams &p );
|
|
|
|
|
const RageSoundParams &GetParams() const { return m_Param; }
|
2002-12-27 23:15:39 +00:00
|
|
|
|
|
|
|
|
private:
|
2002-12-22 08:13:33 +00:00
|
|
|
/* If we were copied from another RageSound, this will point to it; otherwise
|
|
|
|
|
* this is ourself. */
|
|
|
|
|
RageSound *original;
|
|
|
|
|
|
2003-04-23 18:22:16 +00:00
|
|
|
SoundReader *Sample;
|
2004-01-14 09:38:14 +00:00
|
|
|
CircBuf<char> databuf;
|
2002-12-27 23:15:39 +00:00
|
|
|
int FillBuf(int bytes);
|
2002-12-13 07:44:34 +00:00
|
|
|
|
|
|
|
|
/* Sound blocks we've sent out recently through GetPCM. We keep track
|
|
|
|
|
* of each block for the last four calls of GetPCM. */
|
2004-02-28 00:14:16 +00:00
|
|
|
struct pos_map_t
|
|
|
|
|
{
|
2004-01-19 22:21:02 +00:00
|
|
|
/* Frame number from the POV of the sound driver: */
|
|
|
|
|
int64_t frameno;
|
2002-12-13 07:44:34 +00:00
|
|
|
|
|
|
|
|
/* Actual sound position within the sample: */
|
2004-01-19 22:21:02 +00:00
|
|
|
int64_t position;
|
2002-12-13 07:44:34 +00:00
|
|
|
|
2004-01-19 22:21:02 +00:00
|
|
|
/* The number of frames in this block: */
|
|
|
|
|
int64_t frames;
|
2002-12-13 07:44:34 +00:00
|
|
|
|
2004-03-18 03:30:36 +00:00
|
|
|
pos_map_t() { frameno=0; position=0; frames=0; }
|
|
|
|
|
pos_map_t( int64_t frame, int pos, int cnt ) { frameno=frame; position=pos; frames=cnt; }
|
2002-12-13 07:44:34 +00:00
|
|
|
};
|
2002-12-21 02:08:49 +00:00
|
|
|
deque<pos_map_t> pos_map;
|
2004-01-19 22:21:02 +00:00
|
|
|
static int64_t SearchPosMap( const deque<pos_map_t> &pos_map, int64_t cur_frames, bool *approximate );
|
2004-01-19 20:37:14 +00:00
|
|
|
static void CleanPosMap( deque<pos_map_t> &pos_map );
|
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
|
|
|
|
2002-12-13 07:44:34 +00:00
|
|
|
/* Current position of the output sound; if < 0, nothing will play until it
|
2004-02-28 00:14:16 +00:00
|
|
|
* becomes positive. This is recorded in frames, to avoid rounding error. */
|
2002-12-13 07:44:34 +00:00
|
|
|
int position;
|
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
|
2004-04-04 04:06:05 +00:00
|
|
|
* 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. */
|
|
|
|
|
int stopped_position;
|
2002-12-13 07:44:34 +00:00
|
|
|
bool playing;
|
|
|
|
|
|
2004-03-18 01:31:34 +00:00
|
|
|
/* Unique ID number for this instance of RageSound. */
|
|
|
|
|
int ID;
|
|
|
|
|
|
2002-12-27 23:15:39 +00:00
|
|
|
CString error;
|
2002-12-18 06:44:56 +00:00
|
|
|
|
2004-01-19 22:21:02 +00:00
|
|
|
int64_t GetPositionSecondsInternal( bool *approximate=NULL ) const;
|
2004-02-28 00:14:16 +00:00
|
|
|
bool SetPositionFrames( int frames = -1 );
|
2002-12-27 23:15:39 +00:00
|
|
|
int GetData(char *buffer, int size);
|
|
|
|
|
void Fail(CString reason);
|
|
|
|
|
int Bytes_Available() const;
|
2004-02-28 02:09:46 +00:00
|
|
|
RageSoundParams::StopMode_t GetStopMode() const; /* resolves M_AUTO */
|
2002-12-22 08:13:33 +00:00
|
|
|
|
2004-02-28 00:14:16 +00:00
|
|
|
static void RateChange(char *buf, int &cnt, int speed_input_samples, int speed_output_samples, int channels);
|
2003-01-02 06:52:39 +00:00
|
|
|
|
2002-12-13 07:44:34 +00:00
|
|
|
public:
|
2002-12-22 08:13:33 +00:00
|
|
|
/* Used by RageSoundManager: */
|
|
|
|
|
RageSound *GetOriginal() { return original; }
|
2002-12-20 01:45:41 +00:00
|
|
|
|
|
|
|
|
/* Called only by the sound drivers: */
|
|
|
|
|
/* This function should return the number of bytes actually put into buffer.
|
|
|
|
|
* If less than size 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). */
|
2004-01-19 22:21:02 +00:00
|
|
|
int GetPCM( char *buffer, int size, int64_t frameno );
|
2004-03-18 03:30:36 +00:00
|
|
|
bool GetDataToPlay( int16_t *buffer, int size, int &pos, int &got_bytes );
|
|
|
|
|
void CommitPlayingPosition( int64_t frameno, int pos, int got_bytes );
|
2002-12-20 01:45:41 +00:00
|
|
|
void Update(float delta);
|
2002-12-13 07:44:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|
2003-03-15 23:27:34 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
2004-02-28 00:14:16 +00:00
|
|
|
Copyright (c) 2002-2004 by the person(s) listed below. All rights reserved.
|
2003-03-15 23:27:34 +00:00
|
|
|
Glenn Maynard
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|