summaryrefslogtreecommitdiff
path: root/soundsystem/snd_wave_mixer.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /soundsystem/snd_wave_mixer.cpp
downloadarchived-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.cpp527
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;
+}