You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
14 KiB
526 lines
14 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $Workfile: $ |
|
// $Date: $ |
|
// |
|
//----------------------------------------------------------------------------- |
|
// $Log: $ |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef SND_AUDIO_SOURCE_H |
|
#define SND_AUDIO_SOURCE_H |
|
#pragma once |
|
|
|
#if !defined( _X360 ) |
|
#define MP3_SUPPORT 1 |
|
#endif |
|
|
|
#define AUDIOSOURCE_COPYBUF_SIZE 4096 |
|
|
|
struct channel_t; |
|
class CSentence; |
|
class CSfxTable; |
|
|
|
class CAudioSource; |
|
class IAudioDevice; |
|
class CUtlBuffer; |
|
|
|
#include "tier0/vprof.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: This is an instance of an audio source. |
|
// Mixers are attached to channels and reference an audio source. |
|
// Mixers are specific to the sample format and source format. |
|
// Mixers are never re-used, so they can track instance data like |
|
// sample position, fractional sample, stream cache, faders, etc. |
|
//----------------------------------------------------------------------------- |
|
abstract_class CAudioMixer |
|
{ |
|
public: |
|
virtual ~CAudioMixer( void ) {} |
|
|
|
// return number of samples mixed |
|
virtual int MixDataToDevice( IAudioDevice *pDevice, channel_t *pChannel, int sampleCount, int outputRate, int outputOffset ) = 0; |
|
virtual int SkipSamples( channel_t *pChannel, int sampleCount, int outputRate, int outputOffset ) = 0; |
|
virtual bool ShouldContinueMixing( void ) = 0; |
|
|
|
virtual CAudioSource *GetSource( void ) = 0; |
|
|
|
// get the current position (next sample to be mixed) |
|
virtual int GetSamplePosition( void ) = 0; |
|
|
|
// Allow the mixer to modulate pitch and volume. |
|
// returns a floating point modulator |
|
virtual float ModifyPitch( float pitch ) = 0; |
|
virtual float GetVolumeScale( void ) = 0; |
|
|
|
// NOTE: Playback is optimized for linear streaming. These calls will usually cost performance |
|
// It is currently optimal to call them before any playback starts, but some audio sources may not |
|
// guarantee this. Also, some mixers may choose to ignore these calls for internal reasons (none do currently). |
|
|
|
// Move the current position to newPosition |
|
// BUGBUG: THIS CALL DOES NOT SUPPORT MOVING BACKWARD, ONLY FORWARD!!! |
|
virtual void SetSampleStart( int newPosition ) = 0; |
|
|
|
// End playback at newEndPosition |
|
virtual void SetSampleEnd( int newEndPosition ) = 0; |
|
|
|
// How many samples to skip before commencing actual data reading ( to allow sub-frametime sound |
|
// offsets and avoid synchronizing sounds to various 100 msec clock intervals throughout the |
|
// engine and game code) |
|
virtual void SetStartupDelaySamples( int delaySamples ) = 0; |
|
virtual int GetMixSampleSize() = 0; |
|
|
|
// Certain async loaded sounds lazilly load into memory in the background, use this to determine |
|
// if the sound is ready for mixing |
|
virtual bool IsReadyToMix() = 0; |
|
|
|
// NOTE: The "saved" position can be different than the "sample" position |
|
// NOTE: Allows mixer to save file offsets, loop info, etc |
|
virtual int GetPositionForSave() = 0; |
|
virtual void SetPositionFromSaved( int savedPosition ) = 0; |
|
}; |
|
|
|
inline int CalcSampleSize( int bitsPerSample, int _channels ) |
|
{ |
|
return (bitsPerSample >> 3) * _channels; |
|
} |
|
|
|
#include "UtlCachedFileData.h" |
|
|
|
class CSentence; |
|
class CSfxTable; |
|
class CAudioSourceCachedInfo : public IBaseCacheInfo |
|
{ |
|
public: |
|
CAudioSourceCachedInfo(); |
|
CAudioSourceCachedInfo( const CAudioSourceCachedInfo& src ); |
|
|
|
virtual ~CAudioSourceCachedInfo(); |
|
|
|
CAudioSourceCachedInfo& operator =( const CAudioSourceCachedInfo& src ); |
|
|
|
void Clear(); |
|
void RemoveData(); |
|
|
|
virtual void Save( CUtlBuffer& buf ); |
|
virtual void Restore( CUtlBuffer& buf ); |
|
virtual void Rebuild( char const *filename ); |
|
|
|
// A hack, but will work okay |
|
static int s_CurrentType; |
|
static CSfxTable *s_pSfx; |
|
static bool s_bIsPrecacheSound; |
|
|
|
inline int Type() const |
|
{ |
|
return info.m_Type; |
|
} |
|
void SetType( int type ) |
|
{ |
|
info.m_Type = type; |
|
} |
|
|
|
inline int Bits() const |
|
{ |
|
return info.m_bits; |
|
} |
|
void SetBits( int bits ) |
|
{ |
|
info.m_bits = bits; |
|
} |
|
|
|
inline int Channels() const |
|
{ |
|
return info.m_channels; |
|
} |
|
void SetChannels( int _channels ) |
|
{ |
|
info.m_channels = _channels; |
|
} |
|
|
|
inline int SampleSize() const |
|
{ |
|
return info.m_sampleSize; |
|
} |
|
void SetSampleSize( int size ) |
|
{ |
|
info.m_sampleSize = size; |
|
} |
|
|
|
inline int Format() const |
|
{ |
|
return info.m_format; |
|
} |
|
void SetFormat( int format ) |
|
{ |
|
info.m_format = format; |
|
} |
|
|
|
inline int SampleRate() const |
|
{ |
|
return info.m_rate; |
|
} |
|
void SetSampleRate( int rate ) |
|
{ |
|
info.m_rate = rate; |
|
} |
|
|
|
inline int CachedDataSize() const |
|
{ |
|
return (int)m_usCachedDataSize; |
|
} |
|
|
|
void SetCachedDataSize( int size ) |
|
{ |
|
m_usCachedDataSize = (unsigned short)size; |
|
} |
|
|
|
inline const byte *CachedData() const |
|
{ |
|
return m_pCachedData; |
|
} |
|
|
|
void SetCachedData( const byte *data ) |
|
{ |
|
m_pCachedData = ( byte * )data; |
|
flags.m_bCachedData = ( data != NULL ) ? true : false; |
|
} |
|
|
|
inline int HeaderSize() const |
|
{ |
|
return (int)m_usHeaderSize; |
|
} |
|
|
|
void SetHeaderSize( int size ) |
|
{ |
|
m_usHeaderSize = (unsigned short)size; |
|
} |
|
|
|
inline const byte *HeaderData() const |
|
{ |
|
return m_pHeader; |
|
} |
|
|
|
void SetHeaderData( const byte *data ) |
|
{ |
|
m_pHeader = ( byte * )data; |
|
flags.m_bHeader = ( data != NULL ) ? true : false; |
|
} |
|
|
|
inline int LoopStart() const |
|
{ |
|
return m_loopStart; |
|
} |
|
void SetLoopStart( int start ) |
|
{ |
|
m_loopStart = start; |
|
} |
|
|
|
inline int SampleCount() const |
|
{ |
|
return m_sampleCount; |
|
} |
|
|
|
void SetSampleCount( int count ) |
|
{ |
|
m_sampleCount = count; |
|
} |
|
inline int DataStart() const |
|
{ |
|
return m_dataStart; |
|
} |
|
void SetDataStart( int start ) |
|
{ |
|
m_dataStart = start; |
|
} |
|
inline int DataSize() const |
|
{ |
|
return m_dataSize; |
|
} |
|
void SetDataSize( int size ) |
|
{ |
|
m_dataSize = size; |
|
} |
|
inline CSentence *Sentence() const |
|
{ |
|
return m_pSentence; |
|
} |
|
void SetSentence( CSentence *sentence ) |
|
{ |
|
m_pSentence = sentence; |
|
flags.m_bSentence = ( sentence != NULL ) ? true : false; |
|
} |
|
|
|
private: |
|
|
|
union |
|
{ |
|
unsigned int infolong; |
|
struct |
|
{ |
|
unsigned int m_Type : 2; // 0 1 2 or 3 |
|
unsigned int m_bits : 5; // 0 to 31 |
|
unsigned int m_channels : 2; // 1 or 2 |
|
unsigned int m_sampleSize : 3; // 1 2 or 4 |
|
unsigned int m_format : 2; // 1 == PCM, 2 == ADPCM |
|
unsigned int m_rate : 17; // 0 to 64 K |
|
} info; |
|
}; |
|
|
|
union |
|
{ |
|
byte flagsbyte; |
|
struct |
|
{ |
|
bool m_bSentence : 1; |
|
bool m_bCachedData : 1; |
|
bool m_bHeader : 1; |
|
} flags; |
|
}; |
|
|
|
int m_loopStart; |
|
int m_sampleCount; |
|
int m_dataStart; // offset of wave data chunk |
|
int m_dataSize; // size of wave data chunk |
|
|
|
unsigned short m_usCachedDataSize; |
|
unsigned short m_usHeaderSize; |
|
|
|
CSentence *m_pSentence; |
|
byte *m_pCachedData; |
|
byte *m_pHeader; |
|
}; |
|
|
|
class IAudioSourceCache |
|
{ |
|
public: |
|
virtual bool Init( unsigned int memSize ) = 0; |
|
virtual void Shutdown() = 0; |
|
virtual void LevelInit( char const *mapname ) = 0; |
|
virtual void LevelShutdown() = 0; |
|
|
|
// This invalidates the cached size/date info for sounds so it'll regenerate that next time it's accessed. |
|
// Used when you connect to a pure server. |
|
virtual void ForceRecheckDiskInfo() = 0; |
|
|
|
virtual CAudioSourceCachedInfo *GetInfo( int audiosourcetype, bool soundisprecached, CSfxTable *sfx ) = 0; |
|
virtual void RebuildCacheEntry( int audiosourcetype, bool soundisprecached, CSfxTable *sfx ) = 0; |
|
}; |
|
|
|
extern IAudioSourceCache *audiosourcecache; |
|
|
|
FORWARD_DECLARE_HANDLE( memhandle_t ); |
|
|
|
typedef int StreamHandle_t; |
|
enum |
|
{ |
|
INVALID_STREAM_HANDLE = (StreamHandle_t)~0 |
|
}; |
|
|
|
typedef int BufferHandle_t; |
|
enum |
|
{ |
|
INVALID_BUFFER_HANDLE = (BufferHandle_t)~0 |
|
}; |
|
|
|
typedef unsigned int streamFlags_t; |
|
enum |
|
{ |
|
STREAMED_FROMDVD = 0x00000001, // stream buffers are compliant to dvd sectors |
|
STREAMED_SINGLEPLAY = 0x00000002, // non recurring data, buffers don't need to persist and can be recycled |
|
STREAMED_QUEUEDLOAD = 0x00000004, // hint the streamer to load using the queued loader system |
|
}; |
|
|
|
abstract_class IAsyncWavDataCache |
|
{ |
|
public: |
|
virtual bool Init( unsigned int memSize ) = 0; |
|
virtual void Shutdown() = 0; |
|
|
|
// implementation that treats file as monolithic |
|
virtual memhandle_t AsyncLoadCache( char const *filename, int datasize, int startpos, bool bIsPrefetch = false ) = 0; |
|
virtual void PrefetchCache( char const *filename, int datasize, int startpos ) = 0; |
|
virtual bool CopyDataIntoMemory( char const *filename, int datasize, int startpos, void *buffer, int bufsize, int copystartpos, int bytestocopy, bool *pbPostProcessed ) = 0; |
|
virtual bool CopyDataIntoMemory( memhandle_t& handle, char const *filename, int datasize, int startpos, void *buffer, int bufsize, int copystartpos, int bytestocopy, bool *pbPostProcessed ) = 0; |
|
virtual bool IsDataLoadCompleted( memhandle_t handle, bool *pIsValid ) = 0; |
|
virtual void RestartDataLoad( memhandle_t *pHandle, const char *pFilename, int dataSize, int startpos ) = 0; |
|
virtual bool GetDataPointer( memhandle_t& handle, char const *filename, int datasize, int startpos, void **pData, int copystartpos, bool *pbPostProcessed ) = 0; |
|
virtual void SetPostProcessed( memhandle_t handle, bool proc ) = 0; |
|
virtual void Unload( memhandle_t handle ) = 0; |
|
|
|
// alternate multi-buffer streaming implementation |
|
virtual StreamHandle_t OpenStreamedLoad( char const *pFileName, int dataSize, int dataStart, int startPos, int loopPos, int bufferSize, int numBuffers, streamFlags_t flags ) = 0; |
|
virtual void CloseStreamedLoad( StreamHandle_t hStream ) = 0; |
|
virtual int CopyStreamedDataIntoMemory( StreamHandle_t hStream, void *pBuffer, int buffSize, int copyStartPos, int bytesToCopy ) = 0; |
|
virtual bool IsStreamedDataReady( StreamHandle_t hStream ) = 0; |
|
virtual void MarkBufferDiscarded( BufferHandle_t hBuffer ) = 0; |
|
virtual void *GetStreamedDataPointer( StreamHandle_t hStream, bool bSync ) = 0; |
|
virtual bool IsDataLoadInProgress( memhandle_t handle ) = 0; |
|
virtual void Flush() = 0; |
|
virtual void OnMixBegin() = 0; |
|
virtual void OnMixEnd() = 0; |
|
}; |
|
|
|
extern IAsyncWavDataCache *wavedatacache; |
|
|
|
struct CAudioSourceCachedInfoHandle_t |
|
{ |
|
CAudioSourceCachedInfoHandle_t() : |
|
info( NULL ), |
|
m_FlushCount( 0 ) |
|
{ |
|
} |
|
|
|
CAudioSourceCachedInfo *info; |
|
unsigned int m_FlushCount; |
|
|
|
inline CAudioSourceCachedInfo *Get( int audiosourcetype, bool soundisprecached, CSfxTable *sfx, int *pcacheddatasize ) |
|
{ |
|
VPROF("CAudioSourceCachedInfoHandle_t::Get"); |
|
|
|
if ( m_FlushCount != s_nCurrentFlushCount ) |
|
{ |
|
// Reacquire |
|
info = audiosourcecache->GetInfo( audiosourcetype, soundisprecached, sfx ); |
|
|
|
if ( pcacheddatasize ) |
|
{ |
|
*pcacheddatasize = info ? info->CachedDataSize() : 0; |
|
} |
|
|
|
// Tag as current |
|
m_FlushCount = s_nCurrentFlushCount; |
|
} |
|
return info; |
|
} |
|
|
|
inline bool IsValid() |
|
{ |
|
return !!( m_FlushCount == s_nCurrentFlushCount ); |
|
} |
|
|
|
inline CAudioSourceCachedInfo *FastGet() |
|
{ |
|
VPROF("CAudioSourceCachedInfoHandle_t::FastGet"); |
|
|
|
if ( m_FlushCount != s_nCurrentFlushCount ) |
|
{ |
|
return NULL; |
|
} |
|
return info; |
|
} |
|
|
|
static void InvalidateCache(); |
|
static unsigned int s_nCurrentFlushCount; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: A source is an abstraction for a stream, cached file, or procedural |
|
// source of audio. |
|
//----------------------------------------------------------------------------- |
|
abstract_class CAudioSource |
|
{ |
|
public: |
|
enum |
|
{ |
|
AUDIO_SOURCE_UNK = 0, |
|
AUDIO_SOURCE_WAV, |
|
AUDIO_SOURCE_MP3, |
|
AUDIO_SOURCE_VOICE, |
|
|
|
AUDIO_SOURCE_MAXTYPE, |
|
}; |
|
|
|
enum |
|
{ |
|
AUDIO_NOT_LOADED = 0, |
|
AUDIO_IS_LOADED = 1, |
|
AUDIO_LOADING = 2, |
|
}; |
|
|
|
virtual ~CAudioSource( void ) {} |
|
|
|
// Create an instance (mixer) of this audio source |
|
virtual CAudioMixer *CreateMixer( int initialStreamPosition = 0 ) = 0; |
|
|
|
// Serialization for caching |
|
virtual int GetType( void ) = 0; |
|
virtual void GetCacheData( CAudioSourceCachedInfo *info ) = 0; |
|
|
|
// Provide samples for the mixer. You can point pData at your own data, or if you prefer to copy the data, |
|
// you can copy it into copyBuf and set pData to copyBuf. |
|
virtual int GetOutputData( void **pData, int samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] ) = 0; |
|
|
|
virtual int SampleRate( void ) = 0; |
|
|
|
// Returns true if the source is a voice source. |
|
// This affects the voice_overdrive behavior (all sounds get quieter when |
|
// someone is speaking). |
|
virtual bool IsVoiceSource() = 0; |
|
|
|
// Sample size is in bytes. It will not be accurate for compressed audio. This is a best estimate. |
|
// The compressed audio mixers understand this, but in general do not assume that SampleSize() * SampleCount() = filesize |
|
// or even that SampleSize() is 100% accurate due to compression. |
|
virtual int SampleSize( void ) = 0; |
|
|
|
// Total number of samples in this source. NOTE: Some sources are infinite (mic input), they should return |
|
// a count equal to one second of audio at their current rate. |
|
virtual int SampleCount( void ) = 0; |
|
|
|
virtual int Format( void ) = 0; |
|
virtual int DataSize( void ) = 0; |
|
|
|
virtual bool IsLooped( void ) = 0; |
|
virtual bool IsStereoWav( void ) = 0; |
|
virtual bool IsStreaming( void ) = 0; |
|
virtual int GetCacheStatus( void ) = 0; |
|
int IsCached( void ) { return GetCacheStatus() == AUDIO_IS_LOADED ? true : false; } |
|
virtual void CacheLoad( void ) = 0; |
|
virtual void CacheUnload( void ) = 0; |
|
virtual CSentence *GetSentence( void ) = 0; |
|
|
|
// these are used to find good splice/loop points. |
|
// If not implementing these, simply return sample |
|
virtual int ZeroCrossingBefore( int sample ) = 0; |
|
virtual int ZeroCrossingAfter( int sample ) = 0; |
|
|
|
// mixer's references |
|
virtual void ReferenceAdd( CAudioMixer *pMixer ) = 0; |
|
virtual void ReferenceRemove( CAudioMixer *pMixer ) = 0; |
|
|
|
// check reference count, return true if nothing is referencing this |
|
virtual bool CanDelete( void ) = 0; |
|
|
|
virtual void Prefetch() = 0; |
|
|
|
virtual bool IsAsyncLoad() = 0; |
|
|
|
// Make sure our data is rebuilt into the per-level cache |
|
virtual void CheckAudioSourceCache() = 0; |
|
|
|
virtual char const *GetFileName() = 0; |
|
|
|
virtual void SetPlayOnce( bool ) = 0; |
|
virtual bool IsPlayOnce() = 0; |
|
|
|
// Used to identify a word that is part of a sentence mixing operation |
|
virtual void SetSentenceWord( bool bIsWord ) = 0; |
|
virtual bool IsSentenceWord() = 0; |
|
|
|
virtual int SampleToStreamPosition( int samplePosition ) = 0; |
|
virtual int StreamToSamplePosition( int streamPosition ) = 0; |
|
}; |
|
|
|
// Fast method for determining duration of .wav/.mp3, exposed to server as well |
|
extern float AudioSource_GetSoundDuration( char const *pName ); |
|
|
|
// uses wave file cached in memory already |
|
extern float AudioSource_GetSoundDuration( CSfxTable *pSfx ); |
|
|
|
#endif // SND_AUDIO_SOURCE_H
|
|
|