diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /soundsystem/snd_wave_mixer.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'soundsystem/snd_wave_mixer.cpp')
| -rw-r--r-- | soundsystem/snd_wave_mixer.cpp | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/soundsystem/snd_wave_mixer.cpp b/soundsystem/snd_wave_mixer.cpp new file mode 100644 index 0000000..556e65c --- /dev/null +++ b/soundsystem/snd_wave_mixer.cpp @@ -0,0 +1,527 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// +#include <stdio.h> + +#include "snd_dev_wave.h" +#include "snd_wave_source.h" +#include "soundsystem/snd_audio_source.h" +#include "snd_wave_mixer_private.h" +#include "snd_wave_mixer_adpcm.h" +#include "tier2/riff.h" + +//----------------------------------------------------------------------------- +// These mixers provide an abstraction layer between the audio device and +// mixing/decoding code. They allow data to be decoded and mixed using +// optimized, format sensitive code by calling back into the device that +// controls them. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Purpose: maps mixing to 8-bit mono mixer +//----------------------------------------------------------------------------- +class CAudioMixerWave8Mono : public CAudioMixerWave +{ +public: + CAudioMixerWave8Mono( CWaveData *data ) : CAudioMixerWave( data ) {} + virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true ) + { + pDevice->Mix8Mono( pChannel, (char *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: maps mixing to 8-bit stereo mixer +//----------------------------------------------------------------------------- +class CAudioMixerWave8Stereo : public CAudioMixerWave +{ +public: + CAudioMixerWave8Stereo( CWaveData *data ) : CAudioMixerWave( data ) {} + virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true ) + { + pDevice->Mix8Stereo( pChannel, (char *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: maps mixing to 16-bit mono mixer +//----------------------------------------------------------------------------- +class CAudioMixerWave16Mono : public CAudioMixerWave +{ +public: + CAudioMixerWave16Mono( CWaveData *data ) : CAudioMixerWave( data ) {} + virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true ) + { + pDevice->Mix16Mono( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward ); + } +}; + + +//----------------------------------------------------------------------------- +// Purpose: maps mixing to 16-bit stereo mixer +//----------------------------------------------------------------------------- +class CAudioMixerWave16Stereo : public CAudioMixerWave +{ +public: + CAudioMixerWave16Stereo( CWaveData *data ) : CAudioMixerWave( data ) {} + virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true ) + { + pDevice->Mix16Stereo( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward ); + } +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Create an approprite mixer type given the data format +// Input : *data - data access abstraction +// format - pcm or adpcm (1 or 2 -- RIFF format) +// channels - number of audio channels (1 = mono, 2 = stereo) +// bits - bits per sample +// Output : CAudioMixer * abstract mixer type that maps mixing to appropriate code +//----------------------------------------------------------------------------- +CAudioMixer *CreateWaveMixer( CWaveData *data, int format, int channels, int bits ) +{ + if ( format == WAVE_FORMAT_PCM ) + { + if ( channels > 1 ) + { + if ( bits == 8 ) + return new CAudioMixerWave8Stereo( data ); + else + return new CAudioMixerWave16Stereo( data ); + } + else + { + if ( bits == 8 ) + return new CAudioMixerWave8Mono( data ); + else + return new CAudioMixerWave16Mono( data ); + } + } + else if ( format == WAVE_FORMAT_ADPCM ) + { + return CreateADPCMMixer( data ); + } + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Init the base WAVE mixer. +// Input : *data - data access object +//----------------------------------------------------------------------------- +CAudioMixerWave::CAudioMixerWave( CWaveData *data ) : m_pData(data), m_pChannel(NULL) +{ + m_loop = 0; + m_sample = 0; + m_absoluteSample = 0; + m_scubSample = -1; + m_fracOffset = 0; + m_bActive = false; + m_nModelIndex = -1; + m_bForward = true; + m_bAutoDelete = true; + m_pChannel = new channel_t; + m_pChannel->leftvol = 127; + m_pChannel->rightvol = 127; + m_pChannel->pitch = 1.0; +} + +//----------------------------------------------------------------------------- +// Purpose: Frees the data access object (we own it after construction) +//----------------------------------------------------------------------------- +CAudioMixerWave::~CAudioMixerWave( void ) +{ + delete m_pData; + delete m_pChannel; +} + + +//----------------------------------------------------------------------------- +// Purpose: Decode and read the data +// by default we just pass the request on to the data access object +// other mixers may need to buffer or decode the data for some reason +// +// Input : **pData - dest pointer +// sampleCount - number of samples needed +// Output : number of samples available in this batch +//----------------------------------------------------------------------------- +int CAudioMixerWave::GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward /*= true*/ ) +{ + if ( samplePosition != m_sample ) + { + // Seek + m_sample = samplePosition; + m_absoluteSample = samplePosition; + } + + return m_pData->ReadSourceData( pData, m_sample, sampleCount, forward ); +} + + +//----------------------------------------------------------------------------- +// Purpose: calls through the wavedata to get the audio source +// Output : CAudioSource +//----------------------------------------------------------------------------- +CAudioSource *CAudioMixerWave::GetSource( void ) +{ + if ( m_pData ) + return &m_pData->Source(); + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Gets the current sample location in playback +// Output : int (samples from start of wave) +//----------------------------------------------------------------------------- +int CAudioMixerWave::GetSamplePosition( void ) +{ + return m_sample; +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the current sample location in playback +// Output : int (samples from start of wave) +//----------------------------------------------------------------------------- +int CAudioMixerWave::GetScubPosition( void ) +{ + if (m_scubSample != -1) + { + return m_scubSample; + } + return m_sample; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : position - +//----------------------------------------------------------------------------- +bool CAudioMixerWave::SetSamplePosition( int position, bool scrubbing ) +{ + position = max( 0, position ); + + m_sample = position; + m_absoluteSample = position; + m_startpos = m_sample; + if (scrubbing) + { + m_scubSample = position; + } + else + { + m_scubSample = -1; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : position - +//----------------------------------------------------------------------------- +void CAudioMixerWave::SetLoopPosition( int position ) +{ + m_loop = position; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CAudioMixerWave::GetStartPosition( void ) +{ + return m_startpos; +} + +bool CAudioMixerWave::GetActive( void ) +{ + return m_bActive; +} + +void CAudioMixerWave::SetActive( bool active ) +{ + m_bActive = active; +} + +void CAudioMixerWave::SetModelIndex( int index ) +{ + m_nModelIndex = index; +} + +int CAudioMixerWave::GetModelIndex( void ) const +{ + return m_nModelIndex; +} + +void CAudioMixerWave::SetDirection( bool forward ) +{ + m_bForward = forward; +} + +bool CAudioMixerWave::GetDirection( void ) const +{ + return m_bForward; +} + +void CAudioMixerWave::SetAutoDelete( bool autodelete ) +{ + m_bAutoDelete = autodelete; +} + +bool CAudioMixerWave::GetAutoDelete( void ) const +{ + return m_bAutoDelete; +} + +void CAudioMixerWave::SetVolume( float volume ) +{ + int ivolume = (int)( clamp( volume, 0.0f, 1.0f ) * 127.0f ); + + m_pChannel->leftvol = ivolume; + m_pChannel->rightvol = ivolume; +} + +channel_t *CAudioMixerWave::GetChannel() +{ + Assert( m_pChannel ); + return m_pChannel; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pChannel - +// sampleCount - +// outputRate - +//----------------------------------------------------------------------------- +void CAudioMixerWave::IncrementSamples( channel_t *pChannel, int startSample, int sampleCount,int outputRate, bool forward /*= true*/ ) +{ + int inputSampleRate = (int)(pChannel->pitch * m_pData->Source().SampleRate()); + float rate = (float)inputSampleRate / outputRate; + + int startpos = startSample; + + if ( !forward ) + { + int requestedstart = startSample - (int)( sampleCount * rate ); + if ( requestedstart < 0 ) + return; + + startpos = max( 0, requestedstart ); + SetSamplePosition( startpos ); + } + + while ( sampleCount > 0 ) + { + int inputSampleCount; + int outputSampleCount = sampleCount; + + if ( outputRate != inputSampleRate ) + { + inputSampleCount = (int)(sampleCount * rate); + } + else + { + inputSampleCount = sampleCount; + } + + sampleCount -= outputSampleCount; + if ( forward ) + { + m_sample += inputSampleCount; + m_absoluteSample += inputSampleCount; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: The device calls this to request data. The mixer must provide the +// full amount of samples or have silence in its output stream. +// Input : *pDevice - requesting device +// sampleCount - number of samples at the output rate +// outputRate - sampling rate of the request +// Output : Returns true to keep mixing, false to delete this mixer +//----------------------------------------------------------------------------- +bool CAudioMixerWave::SkipSamples( IAudioDevice *pDevice, channel_t *pChannel, + int startSample, int sampleCount, int outputRate, bool forward /*= true*/ ) +{ + int offset = 0; + + int inputSampleRate = (int)(pChannel->pitch * m_pData->Source().SampleRate()); + float rate = (float)inputSampleRate / outputRate; + + sampleCount = min( sampleCount, pDevice->PaintBufferSampleCount() ); + + int startpos = startSample; + + if ( !forward ) + { + int requestedstart = startSample - (int)( sampleCount * rate ); + if ( requestedstart < 0 ) + return false; + + startpos = max( 0, requestedstart ); + SetSamplePosition( startpos ); + } + + while ( sampleCount > 0 ) + { + int availableSamples; + int inputSampleCount; + char *pData = NULL; + int outputSampleCount = sampleCount; + + if ( outputRate != inputSampleRate ) + { + inputSampleCount = (int)(sampleCount * rate); + if ( !forward ) + { + startSample = max( 0, startSample - inputSampleCount ); + } + int availableSamples = GetOutputData( (void **)&pData, startSample, inputSampleCount, forward ); + if ( !availableSamples ) + break; + + if ( availableSamples < inputSampleCount ) + { + outputSampleCount = (int)(availableSamples / rate); + inputSampleCount = availableSamples; + } + + // compute new fraction part of sample index + float offset = (m_fracOffset / FIX_SCALE) + (rate * outputSampleCount); + offset = offset - (float)((int)offset); + m_fracOffset = FIX_FLOAT(offset); + } + else + { + if ( !forward ) + { + startSample = max( 0, startSample - sampleCount ); + } + availableSamples = GetOutputData( (void **)&pData, startSample, sampleCount, forward ); + if ( !availableSamples ) + break; + outputSampleCount = availableSamples; + inputSampleCount = availableSamples; + + } + offset += outputSampleCount; + sampleCount -= outputSampleCount; + if ( forward ) + { + m_sample += inputSampleCount; + m_absoluteSample += inputSampleCount; + } + + if ( m_loop != 0 && m_sample >= m_loop ) + { + SetSamplePosition( m_startpos ); + } + + } + + if ( sampleCount > 0 ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: The device calls this to request data. The mixer must provide the +// full amount of samples or have silence in its output stream. +// Input : *pDevice - requesting device +// sampleCount - number of samples at the output rate +// outputRate - sampling rate of the request +// Output : Returns true to keep mixing, false to delete this mixer +//----------------------------------------------------------------------------- +bool CAudioMixerWave::MixDataToDevice( IAudioDevice *pDevice, channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward /*= true*/ ) +{ + int offset = 0; + + int inputSampleRate = (int)(pChannel->pitch * m_pData->Source().SampleRate()); + float rate = (float)inputSampleRate / outputRate; + fixedint fracstep = FIX_FLOAT( rate ); + + sampleCount = min( sampleCount, pDevice->PaintBufferSampleCount() ); + + int startpos = startSample; + + if ( !forward ) + { + int requestedstart = startSample - (int)( sampleCount * rate ); + if ( requestedstart < 0 ) + return false; + + startpos = max( 0, requestedstart ); + SetSamplePosition( startpos ); + } + + while ( sampleCount > 0 ) + { + int availableSamples; + int inputSampleCount; + char *pData = NULL; + int outputSampleCount = sampleCount; + + + if ( outputRate != inputSampleRate ) + { + inputSampleCount = (int)(sampleCount * rate); + + int availableSamples = GetOutputData( (void **)&pData, startpos, inputSampleCount, forward ); + if ( !availableSamples ) + break; + + if ( availableSamples < inputSampleCount ) + { + outputSampleCount = (int)(availableSamples / rate); + inputSampleCount = availableSamples; + } + + Mix( pDevice, pChannel, pData, offset, m_fracOffset, fracstep, outputSampleCount, 0, forward ); + + // compute new fraction part of sample index + float offset = (m_fracOffset / FIX_SCALE) + (rate * outputSampleCount); + offset = offset - (float)((int)offset); + m_fracOffset = FIX_FLOAT(offset); + } + else + { + availableSamples = GetOutputData( (void **)&pData, startpos, sampleCount, forward ); + if ( !availableSamples ) + break; + + outputSampleCount = availableSamples; + inputSampleCount = availableSamples; + + Mix( pDevice, pChannel, pData, offset, m_fracOffset, FIX(1), outputSampleCount, 0, forward ); + } + offset += outputSampleCount; + sampleCount -= outputSampleCount; + + if ( forward ) + { + m_sample += inputSampleCount; + m_absoluteSample += inputSampleCount; + } + + if ( m_loop != 0 && m_sample >= m_loop ) + { + SetSamplePosition( m_startpos ); + } + + } + + if ( sampleCount > 0 ) + return false; + + return true; +} |