summaryrefslogtreecommitdiff
path: root/engine/audio/private/snd_dev_wave.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 /engine/audio/private/snd_dev_wave.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'engine/audio/private/snd_dev_wave.cpp')
-rw-r--r--engine/audio/private/snd_dev_wave.cpp570
1 files changed, 570 insertions, 0 deletions
diff --git a/engine/audio/private/snd_dev_wave.cpp b/engine/audio/private/snd_dev_wave.cpp
new file mode 100644
index 0000000..92cb439
--- /dev/null
+++ b/engine/audio/private/snd_dev_wave.cpp
@@ -0,0 +1,570 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#include "audio_pch.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern bool snd_firsttime;
+extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
+extern void S_SpatializeChannel( int volume[6], int master_vol, const Vector *psourceDir, float gain, float mono );
+
+// 64K is > 1 second at 16-bit, 22050 Hz
+// 44k: UNDONE - need to double buffers now that we're playing back at 44100?
+#define WAV_BUFFERS 64
+#define WAV_MASK 0x3F
+#define WAV_BUFFER_SIZE 0x0400
+
+
+//-----------------------------------------------------------------------------
+//
+// NOTE: This only allows 16-bit, stereo wave out
+//
+//-----------------------------------------------------------------------------
+class CAudioDeviceWave : public CAudioDeviceBase
+{
+public:
+ bool IsActive( void );
+ bool Init( void );
+ void Shutdown( void );
+ void PaintEnd( void );
+ int GetOutputPosition( void );
+ void ChannelReset( int entnum, int channelIndex, float distanceMod );
+ void Pause( void );
+ void UnPause( void );
+ float MixDryVolume( void );
+ bool Should3DMix( void );
+ void StopAllSounds( void );
+
+ int PaintBegin( float mixAheadTime, int soundtime, int paintedtime );
+ void ClearBuffer( void );
+ void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
+ void MixBegin( int sampleCount );
+ void MixUpsample( int sampleCount, int filtertype );
+ void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
+ void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
+ void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
+ void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
+
+ void TransferSamples( int end );
+ void SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono);
+ void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount );
+
+ const char *DeviceName( void ) { return "Windows WAVE"; }
+ int DeviceChannels( void ) { return 2; }
+ int DeviceSampleBits( void ) { return 16; }
+ int DeviceSampleBytes( void ) { return 2; }
+ int DeviceDmaSpeed( void ) { return SOUND_DMA_SPEED; }
+ int DeviceSampleCount( void ) { return m_deviceSampleCount; }
+
+private:
+ void OpenWaveOut( void );
+ void CloseWaveOut( void );
+ void AllocateOutputBuffers();
+ void FreeOutputBuffers();
+ void* AllocOutputMemory( int nSize, HGLOBAL &hMemory );
+ void FreeOutputMemory( HGLOBAL &hMemory );
+ bool ValidWaveOut( void ) const;
+
+ int m_deviceSampleCount;
+
+ int m_buffersSent;
+ int m_buffersCompleted;
+ int m_pauseCount;
+
+ // This is a single allocation for all wave headers (there are OUTPUT_BUFFER_COUNT of them)
+ HGLOBAL m_hWaveHdr;
+
+ // This is a single allocation for all wave data (there are OUTPUT_BUFFER_COUNT of them)
+ HANDLE m_hWaveData;
+
+ HWAVEOUT m_waveOutHandle;
+
+ // Memory for the wave data + wave headers
+ void *m_pBuffer;
+ LPWAVEHDR m_pWaveHdr;
+};
+
+
+//-----------------------------------------------------------------------------
+// Class factory
+//-----------------------------------------------------------------------------
+IAudioDevice *Audio_CreateWaveDevice( void )
+{
+ CAudioDeviceWave *wave = NULL;
+ if ( !wave )
+ {
+ wave = new CAudioDeviceWave;
+ }
+
+ if ( wave->Init() )
+ return wave;
+
+ delete wave;
+ wave = NULL;
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CAudioDeviceWave::Init( void )
+{
+ m_bSurround = false;
+ m_bSurroundCenter = false;
+ m_bHeadphone = false;
+ m_buffersSent = 0;
+ m_buffersCompleted = 0;
+ m_pauseCount = 0;
+ m_waveOutHandle = 0;
+ m_pBuffer = NULL;
+ m_pWaveHdr = NULL;
+ m_hWaveHdr = NULL;
+ m_hWaveData = NULL;
+
+ OpenWaveOut();
+
+ if ( snd_firsttime )
+ {
+ DevMsg( "Wave sound initialized\n" );
+ }
+ return ValidWaveOut();
+}
+
+void CAudioDeviceWave::Shutdown( void )
+{
+ CloseWaveOut();
+}
+
+
+//-----------------------------------------------------------------------------
+// WAV out device
+//-----------------------------------------------------------------------------
+inline bool CAudioDeviceWave::ValidWaveOut( void ) const
+{
+ return m_waveOutHandle != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Opens the windows wave out device
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::OpenWaveOut( void )
+{
+ WAVEFORMATEX waveFormat;
+ memset( &waveFormat, 0, sizeof(waveFormat) );
+
+ // Select a PCM, 16-bit stereo playback device
+ waveFormat.cbSize = sizeof(waveFormat);
+ waveFormat.wFormatTag = WAVE_FORMAT_PCM;
+ waveFormat.nChannels = DeviceChannels();
+ waveFormat.wBitsPerSample = DeviceSampleBits();
+ waveFormat.nSamplesPerSec = DeviceDmaSpeed(); // DeviceSampleRate
+ waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
+ waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
+
+ MMRESULT errorCode = waveOutOpen( &m_waveOutHandle, WAVE_MAPPER, &waveFormat, 0, 0L, CALLBACK_NULL );
+ while ( errorCode != MMSYSERR_NOERROR )
+ {
+ if ( errorCode != MMSYSERR_ALLOCATED )
+ {
+ DevWarning( "waveOutOpen failed\n" );
+ m_waveOutHandle = 0;
+ return;
+ }
+
+ int nRetVal = MessageBox( NULL,
+ "The sound hardware is in use by another app.\n\n"
+ "Select Retry to try to start sound again or Cancel to run with no sound.",
+ "Sound not available",
+ MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION);
+
+ if ( nRetVal != IDRETRY )
+ {
+ DevWarning( "waveOutOpen failure--hardware already in use\n" );
+ m_waveOutHandle = 0;
+ return;
+ }
+
+ errorCode = waveOutOpen( &m_waveOutHandle, WAVE_MAPPER, &waveFormat, 0, 0L, CALLBACK_NULL );
+ }
+
+ AllocateOutputBuffers();
+}
+
+
+//-----------------------------------------------------------------------------
+// Closes the windows wave out device
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::CloseWaveOut( void )
+{
+ if ( ValidWaveOut() )
+ {
+ waveOutReset( m_waveOutHandle );
+ FreeOutputBuffers();
+ waveOutClose( m_waveOutHandle );
+ m_waveOutHandle = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Alloc output memory
+//-----------------------------------------------------------------------------
+void* CAudioDeviceWave::AllocOutputMemory( int nSize, HGLOBAL &hMemory )
+{
+ // Output memory for waveform data+hdrs must be
+ // globally allocated with GMEM_MOVEABLE and GMEM_SHARE flags.
+ hMemory = GlobalAlloc( GMEM_MOVEABLE | GMEM_SHARE, nSize );
+ if ( !hMemory )
+ {
+ DevWarning( "Sound: Out of memory.\n");
+ CloseWaveOut();
+ return NULL;
+ }
+
+ HPSTR lpData = (char *)GlobalLock( hMemory );
+ if ( !lpData )
+ {
+ DevWarning( "Sound: Failed to lock.\n");
+ GlobalFree( hMemory );
+ hMemory = NULL;
+ CloseWaveOut();
+ return NULL;
+ }
+ memset( lpData, 0, nSize );
+ return lpData;
+}
+
+
+//-----------------------------------------------------------------------------
+// Free output memory
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::FreeOutputMemory( HGLOBAL &hMemory )
+{
+ if ( hMemory )
+ {
+ GlobalUnlock( hMemory );
+ GlobalFree( hMemory );
+ hMemory = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Allocate output buffers
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::AllocateOutputBuffers()
+{
+ // Allocate and lock memory for the waveform data.
+ int nBufferSize = WAV_BUFFER_SIZE * WAV_BUFFERS;
+ HPSTR lpData = (char *)AllocOutputMemory( nBufferSize, m_hWaveData );
+ if ( !lpData )
+ return;
+
+ // Allocate and lock memory for the waveform header
+ int nHdrSize = sizeof( WAVEHDR ) * WAV_BUFFERS;
+ LPWAVEHDR lpWaveHdr = (LPWAVEHDR)AllocOutputMemory( nHdrSize, m_hWaveHdr );
+ if ( !lpWaveHdr )
+ return;
+
+ // After allocation, set up and prepare headers.
+ for ( int i=0 ; i < WAV_BUFFERS; i++ )
+ {
+ LPWAVEHDR lpHdr = lpWaveHdr + i;
+ lpHdr->dwBufferLength = WAV_BUFFER_SIZE;
+ lpHdr->lpData = lpData + (i * WAV_BUFFER_SIZE);
+
+ MMRESULT nResult = waveOutPrepareHeader( m_waveOutHandle, lpHdr, sizeof(WAVEHDR) );
+ if ( nResult != MMSYSERR_NOERROR )
+ {
+ DevWarning( "Sound: failed to prepare wave headers\n" );
+ CloseWaveOut();
+ return;
+ }
+ }
+
+ m_deviceSampleCount = nBufferSize / DeviceSampleBytes();
+
+ m_pBuffer = (void *)lpData;
+ m_pWaveHdr = lpWaveHdr;
+}
+
+
+//-----------------------------------------------------------------------------
+// Free output buffers
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::FreeOutputBuffers()
+{
+ // Unprepare headers.
+ if ( m_pWaveHdr )
+ {
+ for ( int i=0 ; i < WAV_BUFFERS; i++ )
+ {
+ waveOutUnprepareHeader( m_waveOutHandle, m_pWaveHdr+i, sizeof(WAVEHDR) );
+ }
+ }
+ m_pWaveHdr = NULL;
+ m_pBuffer = NULL;
+
+ FreeOutputMemory( m_hWaveData );
+ FreeOutputMemory( m_hWaveHdr );
+}
+
+
+//-----------------------------------------------------------------------------
+// Mixing setup
+//-----------------------------------------------------------------------------
+int CAudioDeviceWave::PaintBegin( float mixAheadTime, int soundtime, int paintedtime )
+{
+ // soundtime - total samples that have been played out to hardware at dmaspeed
+ // paintedtime - total samples that have been mixed at speed
+ // endtime - target for samples in mixahead buffer at speed
+
+ unsigned int endtime = soundtime + mixAheadTime * DeviceDmaSpeed();
+
+ int samps = DeviceSampleCount() >> (DeviceChannels()-1);
+
+ if ((int)(endtime - soundtime) > samps)
+ endtime = soundtime + samps;
+
+ if ((endtime - paintedtime) & 0x3)
+ {
+ // The difference between endtime and painted time should align on
+ // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
+ endtime -= (endtime - paintedtime) & 0x3;
+ }
+
+ return endtime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Actually performs the mixing
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::PaintEnd( void )
+{
+ LPWAVEHDR h;
+ int wResult;
+ int cblocks;
+
+ //
+ // find which sound blocks have completed
+ //
+ while (1)
+ {
+ if ( m_buffersCompleted == m_buffersSent )
+ {
+ //DevMsg ("Sound overrun\n");
+ break;
+ }
+
+ if ( ! (m_pWaveHdr[ m_buffersCompleted & WAV_MASK].dwFlags & WHDR_DONE) )
+ {
+ break;
+ }
+
+ m_buffersCompleted++; // this buffer has been played
+ }
+
+ //
+ // submit a few new sound blocks
+ //
+ // 22K sound support
+ // 44k: UNDONE - double blocks out now that we're at 44k playback?
+ cblocks = 4 << 1;
+
+ while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
+ {
+ h = m_pWaveHdr + ( m_buffersSent&WAV_MASK );
+
+ m_buffersSent++;
+ /*
+ * Now the data block can be sent to the output device. The
+ * waveOutWrite function returns immediately and waveform
+ * data is sent to the output device in the background.
+ */
+ wResult = waveOutWrite( m_waveOutHandle, h, sizeof(WAVEHDR) );
+
+ if (wResult != MMSYSERR_NOERROR)
+ {
+ Warning( "Failed to write block to device\n");
+ Shutdown();
+ return;
+ }
+ }
+}
+
+int CAudioDeviceWave::GetOutputPosition( void )
+{
+ int s = m_buffersSent * WAV_BUFFER_SIZE;
+
+ s >>= SAMPLE_16BIT_SHIFT;
+
+ s &= (DeviceSampleCount()-1);
+
+ return s / DeviceChannels();
+}
+
+
+//-----------------------------------------------------------------------------
+// Pausing
+//-----------------------------------------------------------------------------
+void CAudioDeviceWave::Pause( void )
+{
+ m_pauseCount++;
+ if (m_pauseCount == 1)
+ {
+ waveOutReset( m_waveOutHandle );
+ }
+}
+
+
+void CAudioDeviceWave::UnPause( void )
+{
+ if ( m_pauseCount > 0 )
+ {
+ m_pauseCount--;
+ }
+}
+
+bool CAudioDeviceWave::IsActive( void )
+{
+ return ( m_pauseCount == 0 );
+}
+
+float CAudioDeviceWave::MixDryVolume( void )
+{
+ return 0;
+}
+
+
+bool CAudioDeviceWave::Should3DMix( void )
+{
+ return false;
+}
+
+
+void CAudioDeviceWave::ClearBuffer( void )
+{
+ int clear;
+
+ if ( !m_pBuffer )
+ return;
+
+ clear = 0;
+
+ Q_memset(m_pBuffer, clear, DeviceSampleCount() * DeviceSampleBytes() );
+}
+
+void CAudioDeviceWave::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
+{
+}
+
+
+void CAudioDeviceWave::MixBegin( int sampleCount )
+{
+ MIX_ClearAllPaintBuffers( sampleCount, false );
+}
+
+
+void CAudioDeviceWave::MixUpsample( int sampleCount, int filtertype )
+{
+ paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
+ int ifilter = ppaint->ifilter;
+
+ Assert (ifilter < CPAINTFILTERS);
+
+ S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );
+
+ ppaint->ifilter++;
+}
+
+void CAudioDeviceWave::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
+{
+ int volume[CCHANVOLUMES];
+ paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
+
+ if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1))
+ return;
+
+ Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
+}
+
+
+void CAudioDeviceWave::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
+{
+ int volume[CCHANVOLUMES];
+ paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
+
+ if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
+ return;
+
+ Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
+}
+
+
+void CAudioDeviceWave::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
+{
+ int volume[CCHANVOLUMES];
+ paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
+
+ if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 ))
+ return;
+
+ Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
+}
+
+
+void CAudioDeviceWave::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
+{
+ int volume[CCHANVOLUMES];
+ paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
+
+ if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
+ return;
+
+ Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
+}
+
+
+void CAudioDeviceWave::ChannelReset( int entnum, int channelIndex, float distanceMod )
+{
+}
+
+
+void CAudioDeviceWave::TransferSamples( int end )
+{
+ int lpaintedtime = g_paintedtime;
+ int endtime = end;
+
+ // resumes playback...
+
+ if ( m_pBuffer )
+ {
+ S_TransferStereo16( m_pBuffer, PAINTBUFFER, lpaintedtime, endtime );
+ }
+}
+
+void CAudioDeviceWave::SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono )
+{
+ VPROF("CAudioDeviceWave::SpatializeChannel");
+ S_SpatializeChannel( volume, master_vol, &sourceDir, gain, mono );
+}
+
+void CAudioDeviceWave::StopAllSounds( void )
+{
+}
+
+
+void CAudioDeviceWave::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount )
+{
+ //SX_RoomFX( endtime, filter, timefx );
+ DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount );
+}