📄 sound.cpp
字号:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <math.h>
#include "snd_audio_source.h"
#include "AudioWaveOutput.h"
#include "ifaceposersound.h"
#include "StudioModel.h"
#include "hlfaceposer.h"
#include "expressions.h"
#include "expclass.h"
#include "PhonemeConverter.h"
#include "utlvector.h"
#include "FileSystem.h"
#include "sentence.h"
#include "faceposer_models.h"
#include "iclosecaptionmanager.h"
typedef struct channel_s
{
int leftvol;
int rightvol;
int rleftvol;
int rrightvol;
float pitch;
} channel_t;
#define INPUT_BUFFER_COUNT 32
class CAudioWaveInput : public CAudioInput
{
public:
CAudioWaveInput( void );
~CAudioWaveInput( void );
// Returns the current count of available samples
int SampleCount( void );
// returns the size of each sample in bytes
int SampleSize( void ) { return m_sampleSize; }
// returns the sampling rate of the data
int SampleRate( void ) { return m_sampleRate; }
// returns a pointer to the actual data
void *SampleData( void );
// release the available data (mark as done)
void SampleRelease( void );
// returns the mono/stereo status of this device (true if stereo)
bool IsStereo( void ) { return m_isStereo; }
// begin sampling
void Start( void );
// stop sampling
void Stop( void );
void WaveMessage( HWAVEIN hdevice, UINT uMsg, DWORD dwParam1, DWORD dwParam2 );
private:
void OpenDevice( void );
bool ValidDevice( void ) { return m_deviceId >= 0; }
void ClearDevice( void ) { m_deviceId = -1; }
// returns true if the new format is better
bool BetterFormat( DWORD dwNewFormat, DWORD dwOldFormat );
void InitReadyList( void );
void AddToReadyList( WAVEHDR *pBuffer );
void PopReadyList( void );
WAVEHDR *m_pReadyList;
int m_sampleSize;
int m_sampleRate;
bool m_isStereo;
UINT m_deviceId;
HWAVEIN m_deviceHandle;
WAVEHDR *m_buffers[ INPUT_BUFFER_COUNT ];
};
extern "C" void CALLBACK WaveData( HWAVEIN hwi, UINT uMsg, CAudioWaveInput *pAudio, DWORD dwParam1, DWORD dwParam2 );
CAudioWaveInput::CAudioWaveInput( void )
{
memset( m_buffers, 0, sizeof( m_buffers ) );
int deviceCount = (int)waveInGetNumDevs();
UINT deviceId;
DWORD deviceFormat = 0;
int i;
for ( i = 0; i < deviceCount; i++ )
{
WAVEINCAPS waveCaps;
MMRESULT errorCode = waveInGetDevCaps( (UINT)i, &waveCaps, sizeof(waveCaps) );
if ( errorCode == MMSYSERR_NOERROR )
{
// valid device
if ( BetterFormat( waveCaps.dwFormats, deviceFormat ) )
{
deviceId = i;
deviceFormat = waveCaps.dwFormats;
}
}
}
if ( !deviceFormat )
{
m_deviceId = -1;
m_sampleSize = 0;
m_sampleRate = 0;
m_isStereo = false;
}
else
{
m_deviceId = deviceId;
m_sampleRate = 44100;
m_isStereo = false;
if ( deviceFormat & WAVE_FORMAT_4M16 )
{
m_sampleSize = 2;
}
else if ( deviceFormat & WAVE_FORMAT_4M08 )
{
m_sampleSize = 1;
}
else
{
// ERROR!
}
OpenDevice();
}
InitReadyList();
}
CAudioWaveInput::~CAudioWaveInput( void )
{
if ( ValidDevice() )
{
Stop();
waveInReset( m_deviceHandle );
waveInClose( m_deviceHandle );
for ( int i = 0; i < INPUT_BUFFER_COUNT; i++ )
{
if ( m_buffers[i] )
{
waveInUnprepareHeader( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
delete[] m_buffers[i]->lpData;
delete m_buffers[i];
}
m_buffers[i] = NULL;
}
ClearDevice();
}
}
void CALLBACK WaveData( HWAVEIN hwi, UINT uMsg, CAudioWaveInput *pAudio, DWORD dwParam1, DWORD dwParam2 )
{
if ( pAudio )
{
pAudio->WaveMessage( hwi, uMsg, dwParam1, dwParam2 );
}
}
void CAudioWaveInput::WaveMessage( HWAVEIN hdevice, UINT uMsg, DWORD dwParam1, DWORD dwParam2 )
{
if ( hdevice != m_deviceHandle )
return;
switch( uMsg )
{
case WIM_DATA:
WAVEHDR *pHeader = (WAVEHDR *)dwParam1;
AddToReadyList( pHeader );
break;
}
}
void CAudioWaveInput::OpenDevice( void )
{
if ( !ValidDevice() )
return;
WAVEFORMATEX format;
memset( &format, 0, sizeof(format) );
format.nAvgBytesPerSec = m_sampleRate * m_sampleSize;
format.nChannels = 1;
format.wBitsPerSample = m_sampleSize * 8;
format.nSamplesPerSec = m_sampleRate;
format.wFormatTag = WAVE_FORMAT_PCM;
format.nBlockAlign = m_sampleSize;
MMRESULT errorCode = waveInOpen( &m_deviceHandle, m_deviceId, &format, (DWORD)WaveData, (DWORD)this, CALLBACK_FUNCTION );
if ( errorCode == MMSYSERR_NOERROR )
{
// valid device opened
int bufferSize = m_sampleSize * m_sampleRate / INPUT_BUFFER_COUNT; // total of one second of data
// allocate buffers
for ( int i = 0; i < INPUT_BUFFER_COUNT; i++ )
{
m_buffers[i] = new WAVEHDR;
m_buffers[i]->lpData = new char[ bufferSize ];
m_buffers[i]->dwBufferLength = bufferSize;
m_buffers[i]->dwUser = 0;
m_buffers[i]->dwFlags = 0;
waveInPrepareHeader( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
waveInAddBuffer( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
}
}
else
{
ClearDevice();
}
}
void CAudioWaveInput::Start( void )
{
if ( !ValidDevice() )
return;
waveInStart( m_deviceHandle );
}
void CAudioWaveInput::Stop( void )
{
if ( !ValidDevice() )
return;
waveInStop( m_deviceHandle );
}
void CAudioWaveInput::InitReadyList( void )
{
m_pReadyList = NULL;
}
void CAudioWaveInput::AddToReadyList( WAVEHDR *pBuffer )
{
WAVEHDR **pList = &m_pReadyList;
waveInUnprepareHeader( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
// insert at the tail of the list
while ( *pList )
{
pList = reinterpret_cast<WAVEHDR **>(&((*pList)->dwUser));
}
pBuffer->dwUser = NULL;
*pList = pBuffer;
}
void CAudioWaveInput::PopReadyList( void )
{
if ( m_pReadyList )
{
WAVEHDR *pBuffer = m_pReadyList;
m_pReadyList = reinterpret_cast<WAVEHDR *>(m_pReadyList->dwUser);
waveInPrepareHeader( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
waveInAddBuffer( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
}
}
#define WAVE_FORMAT_STEREO (WAVE_FORMAT_1S08|WAVE_FORMAT_1S16|WAVE_FORMAT_2S08|WAVE_FORMAT_2S16|WAVE_FORMAT_4S08|WAVE_FORMAT_4S16)
#define WAVE_FORMATS_UNDERSTOOD (0xFFF)
#define WAVE_FORMAT_11K (WAVE_FORMAT_1M08|WAVE_FORMAT_1M16)
#define WAVE_FORMAT_22K (WAVE_FORMAT_2M08|WAVE_FORMAT_2M16)
#define WAVE_FORMAT_44K (WAVE_FORMAT_4M08|WAVE_FORMAT_4M16)
static int HighestBit( DWORD dwFlags )
{
int i = 31;
while ( i )
{
if ( dwFlags & (1<<i) )
return i;
i--;
}
return 0;
}
bool CAudioWaveInput::BetterFormat( DWORD dwNewFormat, DWORD dwOldFormat )
{
dwNewFormat &= WAVE_FORMATS_UNDERSTOOD & (~WAVE_FORMAT_STEREO);
dwOldFormat &= WAVE_FORMATS_UNDERSTOOD & (~WAVE_FORMAT_STEREO);
// our target format is 44.1KHz, mono, 16-bit
if ( HighestBit(dwOldFormat) >= HighestBit(dwNewFormat) )
return false;
return true;
}
int CAudioWaveInput::SampleCount( void )
{
if ( !ValidDevice() )
return 0;
if ( m_pReadyList )
{
switch( SampleSize() )
{
case 2:
return m_pReadyList->dwBytesRecorded >> 1;
case 1:
return m_pReadyList->dwBytesRecorded;
default:
break;
}
}
return 0;
}
void *CAudioWaveInput::SampleData( void )
{
if ( !ValidDevice() )
return NULL;
if ( m_pReadyList )
{
return m_pReadyList->lpData;
}
return NULL;
}
// release the available data (mark as done)
void CAudioWaveInput::SampleRelease( void )
{
PopReadyList();
}
// factory to create a suitable audio input for this system
CAudioInput *CAudioInput::Create( void )
{
// sound source is a singleton for now
static CAudioInput *pSource = NULL;
if ( !pSource )
{
pSource = new CAudioWaveInput;
}
return pSource;
}
void CAudioDeviceSWMix::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int 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 CAudioDeviceSWMix::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int 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 CAudioDeviceSWMix::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int 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 CAudioDeviceSWMix::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int 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);
}
}
int CAudioDeviceSWMix::MaxSampleCount( void )
{
return PAINTBUFFER_SIZE;
}
void CAudioDeviceSWMix::MixBegin( void )
{
memset( m_paintbuffer, 0, sizeof(m_paintbuffer) );
}
void CAudioDeviceSWMix::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;
}
}
CAudioWaveOutput::CAudioWaveOutput( void )
{
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;
}
ClearDevice();
OpenDevice();
m_mixTime = -1;
m_sampleIndex = 0;
memset( m_sourceList, 0, sizeof(m_sourceList) );
m_nEstimatedSamplesAhead = (int)( ( float ) OUTPUT_SAMPLE_RATE / 10.0f );
}
void CAudioWaveOutput::RemoveMixerChannelReferences( CAudioMixer *mixer )
{
for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
{
RemoveFromReferencedList( mixer, &m_buffers[ i ] );
}
}
void CAudioWaveOutput::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;
state->submit_mixer_sample = mixer->GetSamplePosition();
}
void CAudioWaveOutput::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 CAudioWaveOutput::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 CAudioWaveOutput::IsSourceReferencedByActiveBuffer( CAudioMixer *mixer )
{
if ( !ValidDevice() )
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 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -