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_dev_wave.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'soundsystem/snd_dev_wave.cpp')
| -rw-r--r-- | soundsystem/snd_dev_wave.cpp | 899 |
1 files changed, 899 insertions, 0 deletions
diff --git a/soundsystem/snd_dev_wave.cpp b/soundsystem/snd_dev_wave.cpp new file mode 100644 index 0000000..478f417 --- /dev/null +++ b/soundsystem/snd_dev_wave.cpp @@ -0,0 +1,899 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#include "snd_dev_wave.h" + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#pragma warning( disable: 4201 ) +#include <mmsystem.h> +#pragma warning( default: 4201 ) +#include <stdio.h> +#include <math.h> +#include "soundsystem/snd_audio_source.h" +#include "soundsystem.h" +#include "soundsystem/snd_device.h" +#include "tier1/utlvector.h" +#include "filesystem.h" +#include "sentence.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CAudioMixer; + + +//----------------------------------------------------------------------------- +// Important constants +//----------------------------------------------------------------------------- + +// 64K is > 1 second at 16-bit, 22050 Hz +// 44k: UNDONE - need to double buffers now that we're playing back at 44100? +#define OUTPUT_CHANNEL_COUNT 2 +#define BYTES_PER_SAMPLE 2 +#define OUTPUT_SAMPLE_RATE SOUND_DMA_SPEED +#define OUTPUT_BUFFER_COUNT 64 +#define OUTPUT_BUFFER_MASK 0x3F +#define OUTPUT_BUFFER_SAMPLE_COUNT (OUTPUT_BUFFER_SIZE_BYTES / BYTES_PER_SAMPLE) +#define OUTPUT_BUFFER_SIZE_BYTES 1024 +#define PAINTBUFFER_SIZE 1024 +#define MAX_CHANNELS 16 + + +//----------------------------------------------------------------------------- +// Implementation of IAudioDevice for WAV files +//----------------------------------------------------------------------------- +class CAudioDeviceWave : public IAudioDevice +{ +public: + // Inherited from IAudioDevice + virtual bool Init( void ); + virtual void Shutdown( void ); + virtual const char *DeviceName( void ) const; + virtual int DeviceChannels( void ) const; + virtual int DeviceSampleBits( void ) const; + virtual int DeviceSampleBytes( void ) const; + virtual int DeviceSampleRate( void ) const; + virtual int DeviceSampleCount( void ) const; + virtual void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ); + virtual void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ); + virtual void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ); + virtual void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward = true ); + virtual int PaintBufferSampleCount( void ) const; + virtual void MixBegin( void ); + + // mix a buffer up to time (time is absolute) + void Update( float time ); + void Flush( void ); + void TransferBufferStereo16( short *pOutput, int sampleCount ); + int GetOutputPosition( void ); + float GetAmountofTimeAhead( void ); + int GetNumberofSamplesAhead( void ); + void AddSource( CAudioMixer *pSource ); + void StopSounds( void ); + int FindSourceIndex( CAudioMixer *pSource ); + CAudioMixer *GetMixerForSource( CAudioSource *source ); + +private: + class CAudioMixerState + { + public: + CAudioMixer *mixer; + }; + + class CAudioBuffer + { + public: + WAVEHDR *hdr; + bool submitted; + int submit_sample_count; + + CUtlVector< CAudioMixerState > m_Referenced; + }; + + struct portable_samplepair_t + { + int left; + int right; + }; + + void OpenWaveOut( void ); + void CloseWaveOut( void ); + void AllocateOutputBuffers(); + void FreeOutputBuffers(); + void* AllocOutputMemory( int nSize, HGLOBAL &hMemory ); + void FreeOutputMemory( HGLOBAL &hMemory ); + + bool ValidWaveOut( void ) const; + CAudioBuffer *GetEmptyBuffer( void ); + void SilenceBuffer( short *pSamples, int sampleCount ); + + void SetChannel( int channelIndex, CAudioMixer *pSource ); + void FreeChannel( int channelIndex ); + + void RemoveMixerChannelReferences( CAudioMixer *mixer ); + void AddToReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer ); + void RemoveFromReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer ); + bool IsSourceReferencedByActiveBuffer( CAudioMixer *mixer ); + bool IsSoundInReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer ); + + // Compute how many samples we've mixed since most recent buffer submission + void ComputeSampleAheadAmount( void ); + + // 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; + float m_mixTime; + float m_baseTime; + int m_sampleIndex; + CAudioBuffer m_buffers[ OUTPUT_BUFFER_COUNT ]; + CAudioMixer *m_sourceList[MAX_CHANNELS]; + int m_nEstimatedSamplesAhead; + + portable_samplepair_t m_paintbuffer[ PAINTBUFFER_SIZE ]; +}; + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +IAudioDevice *Audio_CreateWaveDevice( void ) +{ + return new CAudioDeviceWave; +} + + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +bool CAudioDeviceWave::Init( void ) +{ + m_hWaveData = NULL; + m_hWaveHdr = NULL; + m_waveOutHandle = NULL; + + for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ ) + { + CAudioBuffer *buffer = &m_buffers[ i ]; + Assert( buffer ); + buffer->hdr = NULL; + buffer->submitted = false; + buffer->submit_sample_count = false; + } + + OpenWaveOut(); + + m_mixTime = m_baseTime = -1; + m_sampleIndex = 0; + memset( m_sourceList, 0, sizeof(m_sourceList) ); + + m_nEstimatedSamplesAhead = (int)( ( float ) OUTPUT_SAMPLE_RATE / 10.0f ); + + return true; +} + +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 = 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 ) + { + DWarning( "soundsystem", 1, "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 ) + { + DWarning( "soundsystem", 1, "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 ) + { + DWarning( "soundsystem", 1, "Sound: Out of memory.\n"); + CloseWaveOut(); + return NULL; + } + + HPSTR lpData = (char *)GlobalLock( hMemory ); + if ( !lpData ) + { + DWarning( "soundsystem", 1, "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, free output buffers +//----------------------------------------------------------------------------- +void CAudioDeviceWave::AllocateOutputBuffers() +{ + // Allocate and lock memory for the waveform data. + int nBufferSize = OUTPUT_BUFFER_SIZE_BYTES * OUTPUT_BUFFER_COUNT; + HPSTR lpData = (char *)AllocOutputMemory( nBufferSize, m_hWaveData ); + if ( !lpData ) + return; + + // Allocate and lock memory for the waveform header + int nHdrSize = sizeof( WAVEHDR ) * OUTPUT_BUFFER_COUNT; + LPWAVEHDR lpWaveHdr = (LPWAVEHDR)AllocOutputMemory( nHdrSize, m_hWaveHdr ); + if ( !lpWaveHdr ) + return; + + // After allocation, set up and prepare headers. + for ( int i=0 ; i < OUTPUT_BUFFER_COUNT; i++ ) + { + LPWAVEHDR lpHdr = lpWaveHdr + i; + lpHdr->dwBufferLength = OUTPUT_BUFFER_SIZE_BYTES; + lpHdr->lpData = lpData + (i * OUTPUT_BUFFER_SIZE_BYTES); + + MMRESULT nResult = waveOutPrepareHeader( m_waveOutHandle, lpHdr, sizeof(WAVEHDR) ); + if ( nResult != MMSYSERR_NOERROR ) + { + DWarning( "soundsystem", 1, "Sound: failed to prepare wave headers\n" ); + CloseWaveOut(); + return; + } + + m_buffers[i].hdr = lpHdr; + } +} + + +void CAudioDeviceWave::FreeOutputBuffers() +{ + // Unprepare headers. + for ( int i=0 ; i < OUTPUT_BUFFER_COUNT; i++ ) + { + if ( m_buffers[i].hdr ) + { + waveOutUnprepareHeader( m_waveOutHandle, m_buffers[i].hdr, sizeof(WAVEHDR) ); + m_buffers[i].hdr = NULL; + } + + m_buffers[i].submitted = false; + m_buffers[i].submit_sample_count = 0; + m_buffers[i].m_Referenced.Purge(); + } + + FreeOutputMemory( m_hWaveData ); + FreeOutputMemory( m_hWaveHdr ); +} + + +//----------------------------------------------------------------------------- +// Device parameters +//----------------------------------------------------------------------------- +const char *CAudioDeviceWave::DeviceName( void ) const +{ + return "Windows WAVE"; +} + +int CAudioDeviceWave::DeviceChannels( void ) const +{ + return 2; +} + +int CAudioDeviceWave::DeviceSampleBits( void ) const +{ + return (BYTES_PER_SAMPLE * 8); +} + +int CAudioDeviceWave::DeviceSampleBytes( void ) const +{ + return BYTES_PER_SAMPLE; +} + +int CAudioDeviceWave::DeviceSampleRate( void ) const +{ + return OUTPUT_SAMPLE_RATE; +} + +int CAudioDeviceWave::DeviceSampleCount( void ) const +{ + return OUTPUT_BUFFER_SAMPLE_COUNT; +} + +int CAudioDeviceWave::PaintBufferSampleCount( void ) const +{ + return PAINTBUFFER_SIZE; +} + + +//----------------------------------------------------------------------------- +// Mixing routines +//----------------------------------------------------------------------------- +void CAudioDeviceWave::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward ) +{ + int sampleIndex = 0; + fixedint sampleFrac = inputOffset; + + int fixup = 0; + int fixupstep = 1; + + if ( !forward ) + { + fixup = outCount - 1; + fixupstep = -1; + } + + for ( int i = 0; i < outCount; i++, fixup += fixupstep ) + { + int dest = max( outputOffset + fixup, 0 ); + + m_paintbuffer[ dest ].left += pChannel->leftvol * pData[sampleIndex]; + m_paintbuffer[ dest ].right += pChannel->rightvol * pData[sampleIndex]; + sampleFrac += rateScaleFix; + sampleIndex += FIX_INTPART(sampleFrac); + sampleFrac = FIX_FRACPART(sampleFrac); + } +} + + +void CAudioDeviceWave::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward ) +{ + int sampleIndex = 0; + fixedint sampleFrac = inputOffset; + + int fixup = 0; + int fixupstep = 1; + + if ( !forward ) + { + fixup = outCount - 1; + fixupstep = -1; + } + + for ( int i = 0; i < outCount; i++, fixup += fixupstep ) + { + int dest = max( outputOffset + fixup, 0 ); + + m_paintbuffer[ dest ].left += pChannel->leftvol * pData[sampleIndex]; + m_paintbuffer[ dest ].right += pChannel->rightvol * pData[sampleIndex+1]; + sampleFrac += rateScaleFix; + sampleIndex += FIX_INTPART(sampleFrac)<<1; + sampleFrac = FIX_FRACPART(sampleFrac); + } +} + + +void CAudioDeviceWave::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward ) +{ + int sampleIndex = 0; + fixedint sampleFrac = inputOffset; + + int fixup = 0; + int fixupstep = 1; + + if ( !forward ) + { + fixup = outCount - 1; + fixupstep = -1; + } + + for ( int i = 0; i < outCount; i++, fixup += fixupstep ) + { + int dest = max( outputOffset + fixup, 0 ); + + m_paintbuffer[ dest ].left += (pChannel->leftvol * pData[sampleIndex])>>8; + m_paintbuffer[ dest ].right += (pChannel->rightvol * pData[sampleIndex])>>8; + sampleFrac += rateScaleFix; + sampleIndex += FIX_INTPART(sampleFrac); + sampleFrac = FIX_FRACPART(sampleFrac); + } +} + + +void CAudioDeviceWave::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress, bool forward ) +{ + int sampleIndex = 0; + fixedint sampleFrac = inputOffset; + + int fixup = 0; + int fixupstep = 1; + + if ( !forward ) + { + fixup = outCount - 1; + fixupstep = -1; + } + + for ( int i = 0; i < outCount; i++, fixup += fixupstep ) + { + int dest = max( outputOffset + fixup, 0 ); + + m_paintbuffer[ dest ].left += (pChannel->leftvol * pData[sampleIndex])>>8; + m_paintbuffer[ dest ].right += (pChannel->rightvol * pData[sampleIndex+1])>>8; + + sampleFrac += rateScaleFix; + sampleIndex += FIX_INTPART(sampleFrac)<<1; + sampleFrac = FIX_FRACPART(sampleFrac); + } +} + + +void CAudioDeviceWave::MixBegin( void ) +{ + memset( m_paintbuffer, 0, sizeof(m_paintbuffer) ); +} + +void CAudioDeviceWave::TransferBufferStereo16( short *pOutput, int sampleCount ) +{ + for ( int i = 0; i < sampleCount; i++ ) + { + if ( m_paintbuffer[i].left > 32767 ) + m_paintbuffer[i].left = 32767; + else if ( m_paintbuffer[i].left < -32768 ) + m_paintbuffer[i].left = -32768; + + if ( m_paintbuffer[i].right > 32767 ) + m_paintbuffer[i].right = 32767; + else if ( m_paintbuffer[i].right < -32768 ) + m_paintbuffer[i].right = -32768; + + *pOutput++ = (short)m_paintbuffer[i].left; + *pOutput++ = (short)m_paintbuffer[i].right; + } +} + +void CAudioDeviceWave::RemoveMixerChannelReferences( CAudioMixer *mixer ) +{ + for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ ) + { + RemoveFromReferencedList( mixer, &m_buffers[ i ] ); + } +} + +void CAudioDeviceWave::AddToReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer ) +{ + // Already in list + for ( int i = 0; i < buffer->m_Referenced.Size(); i++ ) + { + if ( buffer->m_Referenced[ i ].mixer == mixer ) + return; + } + + // Just remove it + int idx = buffer->m_Referenced.AddToTail(); + + CAudioMixerState *state = &buffer->m_Referenced[ idx ]; + state->mixer = mixer; +} + +void CAudioDeviceWave::RemoveFromReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer ) +{ + for ( int i = 0; i < buffer->m_Referenced.Size(); i++ ) + { + if ( buffer->m_Referenced[ i ].mixer == mixer ) + { + buffer->m_Referenced.Remove( i ); + break; + } + } +} + +bool CAudioDeviceWave::IsSoundInReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer ) +{ + for ( int i = 0; i < buffer->m_Referenced.Size(); i++ ) + { + if ( buffer->m_Referenced[ i ].mixer == mixer ) + { + return true; + } + } + return false; +} + +bool CAudioDeviceWave::IsSourceReferencedByActiveBuffer( CAudioMixer *mixer ) +{ + if ( !ValidWaveOut() ) + return false; + + CAudioBuffer *buffer; + for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ ) + { + buffer = &m_buffers[ i ]; + if ( !buffer->submitted ) + continue; + + if ( buffer->hdr->dwFlags & WHDR_DONE ) + continue; + + // See if it's referenced + if ( IsSoundInReferencedList( mixer, buffer ) ) + return true; + } + + return false; +} + +CAudioDeviceWave::CAudioBuffer *CAudioDeviceWave::GetEmptyBuffer( void ) +{ + CAudioBuffer *pOutput = NULL; + if ( ValidWaveOut() ) + { + for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ ) + { + if ( !(m_buffers[ i ].submitted ) || + m_buffers[i].hdr->dwFlags & WHDR_DONE ) + { + pOutput = &m_buffers[i]; + pOutput->submitted = true; + pOutput->m_Referenced.Purge(); + break; + } + } + } + + return pOutput; +} + +void CAudioDeviceWave::SilenceBuffer( short *pSamples, int sampleCount ) +{ + int i; + + for ( i = 0; i < sampleCount; i++ ) + { + // left + *pSamples++ = 0; + // right + *pSamples++ = 0; + } +} + +void CAudioDeviceWave::Flush( void ) +{ + waveOutReset( m_waveOutHandle ); +} + +// mix a buffer up to time (time is absolute) +void CAudioDeviceWave::Update( float time ) +{ + if ( !ValidWaveOut() ) + return; + + // reset the system + if ( m_mixTime < 0 || time < m_baseTime ) + { + m_baseTime = time; + m_mixTime = 0; + } + + // put time in our coordinate frame + time -= m_baseTime; + + if ( time > m_mixTime ) + { + CAudioBuffer *pBuffer = GetEmptyBuffer(); + + // no free buffers, mixing is ahead of the playback! + if ( !pBuffer || !pBuffer->hdr ) + { + //Con_Printf( "out of buffers\n" ); + return; + } + + // UNDONE: These numbers are constants + // calc number of samples (2 channels * 2 bytes per sample) + int sampleCount = pBuffer->hdr->dwBufferLength >> 2; + m_mixTime += sampleCount * (1.0f / OUTPUT_SAMPLE_RATE); + + short *pSamples = reinterpret_cast<short *>(pBuffer->hdr->lpData); + + SilenceBuffer( pSamples, sampleCount ); + + int tempCount = sampleCount; + + while ( tempCount > 0 ) + { + if ( tempCount > PaintBufferSampleCount() ) + { + sampleCount = PaintBufferSampleCount(); + } + else + { + sampleCount = tempCount; + } + + MixBegin(); + for ( int i = 0; i < MAX_CHANNELS; i++ ) + { + CAudioMixer *pSource = m_sourceList[i]; + if ( !pSource ) + continue; + + int currentsample = pSource->GetSamplePosition(); + bool forward = pSource->GetDirection(); + + if ( pSource->GetActive() ) + { + if ( !pSource->MixDataToDevice( this, pSource->GetChannel(), currentsample, sampleCount, DeviceSampleRate(), forward ) ) + { + // Source becomes inactive when last submitted sample is finally + // submitted. But it lingers until it's no longer referenced + pSource->SetActive( false ); + } + else + { + AddToReferencedList( pSource, pBuffer ); + } + } + else + { + if ( !IsSourceReferencedByActiveBuffer( pSource ) ) + { + if ( !pSource->GetAutoDelete() ) + { + FreeChannel( i ); + } + } + else + { + pSource->IncrementSamples( pSource->GetChannel(), currentsample, sampleCount, DeviceSampleRate(), forward ); + } + } + + } + + TransferBufferStereo16( pSamples, sampleCount ); + + m_sampleIndex += sampleCount; + tempCount -= sampleCount; + pSamples += sampleCount * 2; + } + // if the buffers aren't aligned on sample boundaries, this will hard-lock the machine! + + pBuffer->submit_sample_count = GetOutputPosition(); + + waveOutWrite( m_waveOutHandle, pBuffer->hdr, sizeof(*(pBuffer->hdr)) ); + } +} + +/* +int CAudioDeviceWave::GetNumberofSamplesAhead( void ) +{ + ComputeSampleAheadAmount(); + return m_nEstimatedSamplesAhead; +} + +float CAudioDeviceWave::GetAmountofTimeAhead( void ) +{ + ComputeSampleAheadAmount(); + return ( (float)m_nEstimatedSamplesAhead / (float)OUTPUT_SAMPLE_RATE ); +} + +// Find the most recent submitted sample that isn't flagged as whdr_done +void CAudioDeviceWave::ComputeSampleAheadAmount( void ) +{ + m_nEstimatedSamplesAhead = 0; + + int newest_sample_index = -1; + int newest_sample_count = 0; + + CAudioBuffer *buffer; + + if ( ValidDevice() ) + { + + for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ ) + { + buffer = &m_buffers[ i ]; + if ( !buffer->submitted ) + continue; + + if ( buffer->hdr->dwFlags & WHDR_DONE ) + continue; + + if ( buffer->submit_sample_count > newest_sample_count ) + { + newest_sample_index = i; + newest_sample_count = buffer->submit_sample_count; + } + } + } + + if ( newest_sample_index == -1 ) + return; + + + buffer = &m_buffers[ newest_sample_index ]; + int currentPos = GetOutputPosition() ; + m_nEstimatedSamplesAhead = currentPos - buffer->submit_sample_count; +} +*/ + +int CAudioDeviceWave::FindSourceIndex( CAudioMixer *pSource ) +{ + for ( int i = 0; i < MAX_CHANNELS; i++ ) + { + if ( pSource == m_sourceList[i] ) + { + return i; + } + } + return -1; +} + +CAudioMixer *CAudioDeviceWave::GetMixerForSource( CAudioSource *source ) +{ + for ( int i = 0; i < MAX_CHANNELS; i++ ) + { + if ( !m_sourceList[i] ) + continue; + + if ( source == m_sourceList[i]->GetSource() ) + { + return m_sourceList[i]; + } + } + return NULL; +} + +void CAudioDeviceWave::AddSource( CAudioMixer *pSource ) +{ + int slot = 0; + for ( int i = 0; i < MAX_CHANNELS; i++ ) + { + if ( !m_sourceList[i] ) + { + slot = i; + break; + } + } + + if ( m_sourceList[slot] ) + { + FreeChannel( slot ); + } + SetChannel( slot, pSource ); + + pSource->SetActive( true ); +} + + +void CAudioDeviceWave::StopSounds( void ) +{ + for ( int i = 0; i < MAX_CHANNELS; i++ ) + { + if ( m_sourceList[i] ) + { + FreeChannel( i ); + } + } +} + + +void CAudioDeviceWave::SetChannel( int channelIndex, CAudioMixer *pSource ) +{ + if ( channelIndex < 0 || channelIndex >= MAX_CHANNELS ) + return; + + m_sourceList[channelIndex] = pSource; +} + +void CAudioDeviceWave::FreeChannel( int channelIndex ) +{ + if ( channelIndex < 0 || channelIndex >= MAX_CHANNELS ) + return; + + if ( m_sourceList[channelIndex] ) + { + RemoveMixerChannelReferences( m_sourceList[channelIndex] ); + + delete m_sourceList[channelIndex]; + m_sourceList[channelIndex] = NULL; + } +} + +int CAudioDeviceWave::GetOutputPosition( void ) +{ + if ( !m_waveOutHandle ) + return 0; + + MMTIME mmtime; + mmtime.wType = TIME_SAMPLES; + waveOutGetPosition( m_waveOutHandle, &mmtime, sizeof( MMTIME ) ); + + // Convert time to sample count + return ( mmtime.u.sample ); +} + |