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 /engine/audio/private/snd_dev_wave.cpp | |
| download | archived-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.cpp | 570 |
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 ); +} |