|
|
//========= 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 ); }
|