windows-nt/Source/XPSP1/NT/enduser/speech/tts/msttsdrv/engine/reverbfx.cpp
2020-09-26 16:20:57 +08:00

970 lines
29 KiB
C++

/*******************************************************************************
* ReverbFX.cpp *
*-------------*
* Description:
* This module is the implementation file for the CReverbFX class.
*-------------------------------------------------------------------------------
* Created By: mc Date: 03/12/99
* Copyright (C) 1999 Microsoft Corporation
* All Rights Reserved
*
*******************************************************************************/
#include "stdafx.h"
#ifndef __spttseng_h__
#include "spttseng.h"
#endif
#ifndef SPDebug_h
#include <spdebug.h>
#endif
#ifndef ReverbFX_H
#include "ReverbFX.h"
#endif
/*****************************************************************************
* CReverbFX::DecibelToPercent *
*-----------------------------*
* Description:
* Converts Voltage percentage from dB
* v = 10^(dB/20)
*
********************************************************************** MC ***/
REVERBL CReverbFX::DecibelToPercent( float flDecibel )
{
SPDBG_FUNC( "CReverbFX::DecibelToPercent" );
float fltIntVol;
if( flDecibel >= REVERB_MIN_DB )
{
fltIntVol = (float) pow( 10.0, (double)flDecibel / 20.0 );
}
else
{
fltIntVol = 0.0;
}
#ifdef FLOAT_REVERB
return fltIntVol;
#else
fltIntVol = fltIntVol * REVERB_VOL_LEVELS;
return (REVERBL)fltIntVol;
#endif
} /* CReverbFX::DecibelToPercent */
/*****************************************************************************
* CReverbFX::ClearReverb *
*------------------------*
* Description:
* Fills the delay line with silence.
*
********************************************************************** MC ***/
void CReverbFX::ClearReverb( LP_Reverb_Mod mod )
{
SPDBG_FUNC( "CReverbFX::ClearReverb" );
long i;
REVERBT *dPtr;
dPtr = mod->psDelayBuffer;
for( i = 0; i < mod->dwDelayBufferSize; i++ )
{
*dPtr++ = 0;
}
} /* CReverbFX::ClearReverb */
/*****************************************************************************
* CReverbFX::AllocReverbModule *
*------------------------------*
* Description:
*
********************************************************************** MC ***/
short CReverbFX::AllocReverbModule
(
LP_Reverb_Mod mod,
REVERBL lGain, // Gain of the amplifiers.
long dwDelay, // Length of the delay line.
long dwDelayBufferSize // Size of the delay buffer.
)
{
SPDBG_FUNC( "CReverbFX::AllocReverbModule" );
short result;
result = KREVERB_NOERROR;
mod->lGain = lGain;
mod->dwDelay = dwDelay;
mod->dwDelayBufferSize = dwDelayBufferSize;
mod->psDelayBuffer = new REVERBT[mod->dwDelayBufferSize];
if( mod->psDelayBuffer == NULL )
{
result = KREVERB_MEMERROR;
}
else
{
mod->psDelayEnd = mod->psDelayBuffer + mod->dwDelayBufferSize;
mod->psDelayOut = mod->psDelayBuffer;
if( mod->dwDelayBufferSize == mod->dwDelay )
{
mod->psDelayIn = mod->psDelayBuffer;
}
else
{
mod->psDelayIn = mod->psDelayBuffer + mod->dwDelay;
}
ClearReverb( mod );
}
return result;
} /* CReverbFX::AllocReverbModule */
/*****************************************************************************
* CReverbFX::CreateReverbModules *
*--------------------------------*
* Description:
* Creates an array of reverb modules.
*
********************************************************************** MC ***/
short CReverbFX::CreateReverbModules
(
short wModules, // Number of modules to create.
LP_Reverb_Mod *mods,
float * pfltDelay, // Array of delay values for the modules.
float * pfltDB, // Array of gain values for the modules.
float fltSamplesPerMS // Number of samples per millisecond.
)
{
SPDBG_FUNC( "CReverbFX::CreateReverbModules" );
long dwDelay, i;
float tempF;
REVERBL vol;
short result = KREVERB_NOERROR;
if( wModules > 0 )
{
for( i = 0; i < wModules; i++ )
{
mods[i] = new Reverb_Mod;
if( !mods[i] )
{
//---------------------------------------
// Not enough memory
//---------------------------------------
result = KREVERB_MEMERROR;
break;
}
else
{
tempF = *pfltDelay++ * fltSamplesPerMS;
dwDelay = (long) tempF;
if( dwDelay < 2 )
dwDelay = 2; // @@@@
vol = DecibelToPercent( *pfltDB++ );
result = AllocReverbModule( mods[i], vol, dwDelay, dwDelay );
if( result != KREVERB_NOERROR )
break;
}
}
}
return result;
} /* CReverbFX::CreateReverbModules */
/*****************************************************************************
* CReverbFX::DeleteReverbModules *
*--------------------------------*
* Description:
* Deletes an array of reverb modules.
*
********************************************************************** MC ***/
void CReverbFX::DeleteReverbModules( )
{
SPDBG_FUNC( "CReverbFX::DeleteReverbModules" );
long i;
for( i = 0; i < KMAXREVBMODS; i++ )
{
if( m_Reverb_Mods[i] != NULL )
{
if( m_Reverb_Mods[i]->psDelayBuffer != NULL )
{
delete m_Reverb_Mods[i]->psDelayBuffer;
}
delete m_Reverb_Mods[i];
m_Reverb_Mods[i] = NULL;
}
}
if( m_pWorkBuf != NULL )
{
delete m_pWorkBuf;
m_pWorkBuf = NULL;
}
} /* CReverbFX::DeleteReverbModules */
/*****************************************************************************
* CReverbFX::GetReverbConfig *
*----------------------------*
* Description:
*
********************************************************************** MC ***/
LPREVERBCONFIG CReverbFX::GetReverbConfig( REVERBTYPE dwReverbConfig )
{
SPDBG_FUNC( "CReverbFX::GetReverbConfig" );
LPREVERBCONFIG pReverbConfig = NULL;
switch( dwReverbConfig )
{
//-----------------------------
// Hall
//-----------------------------
case REVERB_TYPE_HALL:
{
static float afltLeftDelay[] = { (float)(float)(30.6), (float)(20.83), (float)(14.85), (float)(10.98) };
static float afltLeftGain[] = { (float)(-2.498), (float)(-2.2533), (float)(-2.7551), (float)(-2.5828) };
static REVERBCONFIG reverbConfig =
{
(-17.0), // Wet
(-2.0), // Dry
4,
afltLeftDelay,
afltLeftGain,
(float)0.0,
};
pReverbConfig = &reverbConfig;
}
break;
//-----------------------------
// Stadium
//-----------------------------
case REVERB_TYPE_STADIUM:
{
static float afltLeftDelay[] = { (float)(40.6*4), (float)(27.65*4), (float)(17.85*4), (float)(10.98*4) };
static float afltLeftGain[] = { (float)(-2.498), (float)(-2.2533), (float)(-2.7551), (float)(-2.5828) };
static REVERBCONFIG reverbConfig =
{
(-3.0), // Wet
(-5.0), // Dry
4,
afltLeftDelay,
afltLeftGain,
(float)0.0,
};
pReverbConfig = &reverbConfig;
}
break;
//-----------------------------
// Church
//-----------------------------
case REVERB_TYPE_CHURCH:
{
static float afltLeftDelay[] = { (float)(40.6*2), (float)(27.65*2), (float)(17.85*2), (float)(10.98*2) };
static float afltLeftGain[] = { (float)(-2.498), (float)(-2.2533), (float)(-2.7551), (float)(-2.5828) };
static REVERBCONFIG reverbConfig =
{
(-5.0), // Wet
(-5.0), // Dry
4,
afltLeftDelay,
afltLeftGain,
(float)0.0,
};
pReverbConfig = &reverbConfig;
}
break;
//-----------------------------
// Bathtub
//-----------------------------
case REVERB_TYPE_BATHTUB:
{
static float afltLeftDelay[] = { (float)(10.0) };
static float afltLeftGain[] = { (float)(-0.5) };
static REVERBCONFIG reverbConfig =
{
(7.0), // Wet
(9.0), // Dry
1,
afltLeftDelay,
afltLeftGain,
(float)0.0,
};
pReverbConfig = &reverbConfig;
}
break;
//-----------------------------
// Room
//-----------------------------
case REVERB_TYPE_ROOM:
{
static float afltLeftDelay[] = { (float)(10.6) };
static float afltLeftGain[] = { (float)(-10.498) };
static REVERBCONFIG reverbConfig =
{
(0.0), // Wet
(0.0), // Dry
1,
afltLeftDelay,
afltLeftGain,
(float)0.0,
};
pReverbConfig = &reverbConfig;
}
break;
//-----------------------------
// Echo
//-----------------------------
case REVERB_TYPE_ECHO:
{
static float afltLeftDelay[] = { (float)(400.6) };
static float afltLeftGain[] = { (float)(-10.498) };
static REVERBCONFIG reverbConfig =
{
(-10.0), // Wet
(0.0), // Dry
1,
afltLeftDelay,
afltLeftGain,
(float)0.0,
};
pReverbConfig = &reverbConfig;
}
break;
//-----------------------------
// Sequencer
//-----------------------------
case REVERB_TYPE_ROBOSEQ:
{
static float afltLeftDelay[] = { (float)(10.0) };
static float afltLeftGain[] = { (float)(-0.5) };
static REVERBCONFIG reverbConfig =
{
(6.5), // Wet
(9.0), // Dry
1,
afltLeftDelay,
afltLeftGain,
(float)0.05,
};
pReverbConfig = &reverbConfig;
}
break;
}
return pReverbConfig;
} /* CReverbFX::GetReverbConfig */
/*****************************************************************************
* CReverbFX::Reverb_Init *
*------------------------*
* Description:
* Initialize a reverberator array.
*
********************************************************************** MC ***/
short CReverbFX::Reverb_Init( REVERBTYPE reverbPreset, long nSamplesPerSec, long stereoOut )
{
SPDBG_FUNC( "CReverbFX::Reverb_Init" );
short result = KREVERB_NOERROR;
float fltSamplesPerMS;
m_StereoOut = stereoOut;
if( reverbPreset > REVERB_TYPE_OFF )
{
//----------------------------------------------
// Get params from preset number
//----------------------------------------------
m_pReverbConfig = GetReverbConfig( reverbPreset );
m_numOfMods = m_pReverbConfig->numOfReflect;
//----------------------------------------------
// Convert dB's to linear gain
//----------------------------------------------
m_wetVolGain = DecibelToPercent( m_pReverbConfig->wetGain_dB );
m_dryVolGain = DecibelToPercent( m_pReverbConfig->dryGain_dB );
fltSamplesPerMS = (float)nSamplesPerSec / (float)1000.0;
result = CreateReverbModules
(
(short)m_numOfMods,
(LP_Reverb_Mod*)&m_Reverb_Mods,
m_pReverbConfig->gain_ms_Array,
m_pReverbConfig->gain_dB_Array,
fltSamplesPerMS
);
if( result != KREVERB_NOERROR )
{
//--------------------------------
// Failure! Not enough memory
//--------------------------------
return result;
}
if( m_pWorkBuf == NULL )
{
m_pWorkBuf = new REVERBT[m_dwWorkBufferSize];
if( m_pWorkBuf == NULL )
{
//--------------------------------
// Failure! Not enough memory
//--------------------------------
result = KREVERB_MEMERROR;
return result;
}
}
}
else
{
DeleteReverbModules( );
result = KREVERB_OFF;
}
return result;
} /* CReverbFX::Reverb_Init */
/*****************************************************************************
* CReverbFX::CReverbFX *
*----------------------*
* Description:
*
********************************************************************** MC ***/
CReverbFX::CReverbFX( void )
{
SPDBG_FUNC( "CReverbFX::CReverbFX" );
long i;
//--------------------------------
// Initilize
//--------------------------------
m_dwWorkBufferSize = KWORKBUFLEN;
m_pWorkBuf = NULL;
m_wetVolGain = 0;
m_dryVolGain = 0;
m_numOfMods = 0;
m_Count = 0;
m_StereoOut = false;
for( i = 0; i < KMAXREVBMODS; i++ )
{
m_Reverb_Mods[i] = NULL;
}
} /* CReverbFX::CReverbFX */
/*****************************************************************************
* CReverbFX::~CReverbFX *
*-----------------------*
* Description:
*
********************************************************************** MC ***/
CReverbFX::~CReverbFX( void )
{
SPDBG_FUNC( "CReverbFX::~CReverbFX" );
DeleteReverbModules( );
} /* CReverbFX::~CReverbFX */
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Run-time
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/*****************************************************************************
* CReverbFX::CopyWithGain *
*-------------------------*
* Description:
* Copies audio buffer with gain
*
********************************************************************** MC ***/
void CReverbFX::CopyWithGain
( REVERBT *psDest,
REVERBT *psSource,
long dwSamples,
REVERBL gain)
{
SPDBG_FUNC( "CReverbFX::CopyWithGain" );
if( gain <= REVERB_VOL_OFF )
{
//----------------------------------------
// Clear buffer, gain = 0
//----------------------------------------
memset( psDest, 0, sizeof(REVERBT) * dwSamples );
}
else if( gain == REVERB_VOL_UNITY )
{
//----------------------------------------
// Copy buffer, gain = 1
//----------------------------------------
memcpy( psDest, psSource, sizeof(REVERBT) * dwSamples );
}
else
{
//----------------------------------------
// Copy with gain
//----------------------------------------
while( dwSamples )
{
#ifdef FLOAT_REVERB
*psDest++ = (*psSource++) * gain;
#else
*psDest++ = (short) (( (long)(*psSource++) * (long)gain) >> REVERB_VOL_SHIFT);
#endif
dwSamples--;
}
}
} /* CReverbFX::CopyWithGain */
/*****************************************************************************
* CReverbFX::MixWithGain_MONO *
*-----------------------------*
* Description:
* (psDest * gain) + psSource -> psDest
* Clipping is performed.
*
********************************************************************** MC ***/
void CReverbFX::MixWithGain_MONO
(
REVERBT *pWet,
REVERBT *pDry,
short *pDest,
long dwSamples,
REVERBL gain
)
{
SPDBG_FUNC( "CReverbFX::MixWithGain_MONO" );
REVERBL lSample; // long or float
if( gain <= REVERB_VOL_OFF )
{
//----------------------------------
// Do nothing...I guess
//----------------------------------
}
else if( gain == REVERB_VOL_UNITY )
{
//----------------------------------
// Don't apply any gain (= 1.0)
//----------------------------------
while( dwSamples )
{
lSample = (REVERBL)(*pWet++) + *pDry;
//------------------------------------
// Clip signal if overflow
//------------------------------------
if( lSample < -32768 )
{
lSample = -32768;
}
else if( lSample > 32767 )
{
lSample = 32767;
}
*pDest++ = (short)lSample;
pDry++;
dwSamples--;
}
}
else
{
while( dwSamples )
{
//----------------------------------
// Mix with gain on source audio
//----------------------------------
#ifdef FLOAT_REVERB
lSample = ((*pDry) * gain) + *pWet++;
#else
lSample = ((long)(*pDry * (long)(gain)) >> REVERB_VOL_SHIFT) + *pWet++;
#endif
//------------------------------------
// Clip signal if overflow
//------------------------------------
if( lSample < -32768 )
{
lSample = -32768;
}
else if( lSample > 32767 )
{
lSample = 32767;
}
*pDest++ = (short)lSample;
pDry++;
dwSamples--;
}
}
} /* CReverbFX::MixWithGain_MONO */
/*****************************************************************************
* CReverbFX::MixWithGain_STEREO *
*-------------------------------*
* Description:
*
********************************************************************** MC ***/
void CReverbFX::MixWithGain_STEREO
(
REVERBT *pWet,
REVERBT *pDry,
short *pDest,
long dwSamples,
REVERBL gain
)
{
SPDBG_FUNC( "CReverbFX::MixWithGain_STEREO" );
REVERBL lSample, hold; // long or float
REVERBL lSample_B; // long or float
if( gain <= REVERB_VOL_OFF )
{
//----------------------------------
// Do nothing...I guess
//----------------------------------
}
else if( gain == REVERB_VOL_UNITY )
{
//----------------------------------
// Don't apply any gain (= 1.0)
//----------------------------------
while( dwSamples )
{
lSample = (REVERBL)(*pWet++) + (*pDry++);
//------------------------------------
// Clip signal if overflow
//------------------------------------
if( lSample < -32768 )
{
lSample = -32768;
}
else if( lSample > 32767 )
{
lSample = 32767;
}
*pDest++ = (short)lSample;
*pDest++ = (short)(0 - (short)lSample);
dwSamples--;
}
}
else
{
while( dwSamples )
{
//----------------------------------
// Mix with gain on source audio
//----------------------------------
#ifdef FLOAT_REVERB
hold = ((*pDry) * gain);
lSample = hold + *pWet;
lSample_B = hold - *pWet++;
//lSample_B = 0 - lSample_B;
//lSample_B = (0 - hold) - *pWet++;
#else
lSample = ((long)(*pDry * (long)(gain)) >> REVERB_VOL_SHIFT) + *pWet;
lSample_B = ((long)(*pDry * (long)(gain)) >> REVERB_VOL_SHIFT) - *pWet++;
#endif
//------------------------------------
// Clip signal if overflow
//------------------------------------
if( lSample < -32768 )
{
lSample = -32768;
}
else if( lSample > 32767 )
{
lSample = 32767;
}
*pDest++ = (short)lSample;
if( lSample < -32768 )
{
lSample = -32768;
}
else if( lSample > 32767 )
{
lSample = 32767;
}
*pDest++ = (short)lSample_B;
pDry++;
dwSamples--;
}
}
} /* CReverbFX::MixWithGain_STEREO */
/*****************************************************************************
* CReverbFX::ProcessReverbModule *
*-------------------*
* Description:
* Process one delay buffer
*
********************************************************************** MC ***/
void CReverbFX::ProcessReverbModule
(
LP_Reverb_Mod mod,
long dwDestSamples, // Number of samples to process.
REVERBT *pSource, // Source sample buffer.
REVERBT *pDestination // Destination sample buffer.
)
{
SPDBG_FUNC( "CReverbFX::ProcessReverbModule" );
REVERBT sDelayOut;
REVERBT sDelayIn;
REVERBT *psDelayEnd;
//(void) QueryPerformanceCounter (&g_StartTime );
psDelayEnd = mod->psDelayBuffer + (long)((float)mod->dwDelayBufferSize * m_LenScale);
dwDestSamples++;
while( --dwDestSamples )
{
//----------------------------------------
// Delay + current --> delay buffer
//----------------------------------------
sDelayOut = *mod->psDelayOut;
#ifdef FLOAT_REVERB
sDelayIn = (sDelayOut * mod->lGain) + *pSource;
//------------------------------------------------------------
// Take this test out and you'll die in about 10 sec...
//------------------------------------------------------------
if( sDelayIn > 0)
{
if( sDelayIn < 0.001 )
sDelayIn = 0;
}
else if( sDelayIn > -0.001 )
{
sDelayIn = 0;
}
#else
sDelayIn = ((sDelayOut * mod->lGain) >> REVERB_VOL_SHIFT) + *pSource;
#endif
*mod->psDelayIn++ = sDelayIn;
//----------------------------------------
// Delay - (Delay + current) --> current
//----------------------------------------
#ifdef FLOAT_REVERB
*pDestination = sDelayOut - (sDelayIn * mod->lGain);
#else
*pDestination = sDelayOut - ((sDelayIn * mod->lGain) >> REVERB_VOL_SHIFT);
#endif
//---------------------------------------
// Wrap circular buffer ptrs
//---------------------------------------
if( mod->psDelayIn >= psDelayEnd )
{
mod->psDelayIn = mod->psDelayBuffer;
}
mod->psDelayOut++;
if( mod->psDelayOut >= psDelayEnd )
{
mod->psDelayOut = mod->psDelayBuffer;
}
pSource++;
pDestination++;
}
//(void) QueryPerformanceCounter (&g_EndTime);
//g_LapseTime.QuadPart = (g_EndTime.QuadPart - g_StartTime.QuadPart);
} /* CReverbFX::ProcessReverbModule */
//----------------------------------------------------------------------------
// Applies an array of reverb modules to a block of samples.
//----------------------------------------------------------------------------
/*****************************************************************************
* CReverbFX::ProcessReverbBuffer *
*--------------------------------*
* Description:
* Applies an array of reverb modules to a block of samples.
*
********************************************************************** MC ***/
void CReverbFX::ProcessReverbBuffer
( REVERBT *psSample, // Samples to process (in/out).
long dwSamples, // Number of samples to process.
LP_Reverb_Mod *mods // Array of modules to apply.
)
{
SPDBG_FUNC( "CReverbFX::ProcessReverbBuffer" );
short i;
for (i = 0; i < KMAXREVBMODS; i++)
{
if( mods[i] != NULL )
{
ProcessReverbModule( mods[i], dwSamples, psSample, psSample );
}
else
break;
}
} /* CReverbFX::ProcessReverbBuffer */
/*****************************************************************************
* CReverbFX::Reverb_Process *
*---------------------------*
* Description:
*
********************************************************************** MC ***/
short CReverbFX::Reverb_Process( float *sampleBuffer,
long dwSamplesRemaining, float audioGain )
{
SPDBG_FUNC( "CReverbFX::Reverb_Process" );
long dwSamplesToProcess;
short *pOutBuffer;
REVERBL totalWetGain, totalDryGain;
if( m_numOfMods )
{
#ifdef FLOAT_REVERB
totalWetGain = m_wetVolGain * audioGain;
if (totalWetGain < REVERB_MIN_MIX)
totalWetGain = REVERB_MIN_MIX;
totalDryGain = m_dryVolGain * audioGain;
if (totalDryGain < REVERB_MIN_MIX)
totalDryGain = REVERB_MIN_MIX;
#else
totalWetGain = (REVERBL)(m_wetVolGain * audioGain * (float)REVERB_VOL_LEVELS);
totalDryGain = (REVERBL)(m_dryVolGain * audioGain * (float)REVERB_VOL_LEVELS);
#endif
pOutBuffer = (short*)sampleBuffer;
m_LenScale = (float)1.0 - (m_Count * m_pReverbConfig->seqIndex);
while( dwSamplesRemaining > 0 )
{
//----------------------------------------------------------------------------
// Process client's buffer using 'work buffer' chunks
//----------------------------------------------------------------------------
if( dwSamplesRemaining < m_dwWorkBufferSize )
{
dwSamplesToProcess = dwSamplesRemaining;
}
else
{
dwSamplesToProcess = m_dwWorkBufferSize;
}
//-----------------------------------------------------------------
// Copy audio into WET buffer with wet gain
// sampleBuffer * totalWetGain --> m_pWorkBuf
//-----------------------------------------------------------------
CopyWithGain( m_pWorkBuf, sampleBuffer, dwSamplesToProcess, totalWetGain );
//-----------------------------------------------------------------
// Perform reverb processing on the work buffer
//-----------------------------------------------------------------
ProcessReverbBuffer
(
m_pWorkBuf,
dwSamplesToProcess,
(LP_Reverb_Mod*)&m_Reverb_Mods
);
//-----------------------------------------------------------------
// Mix the dry with wet samples
// (sampleBuffer * totalDryGain) + m_pWorkBuf --> sampleBuffer
//-----------------------------------------------------------------
if( m_StereoOut )
{
MixWithGain_STEREO( m_pWorkBuf, sampleBuffer, pOutBuffer, dwSamplesToProcess, totalDryGain );
pOutBuffer += dwSamplesToProcess * 2;
}
else
{
MixWithGain_MONO( m_pWorkBuf, sampleBuffer, pOutBuffer, dwSamplesToProcess, totalDryGain );
pOutBuffer += dwSamplesToProcess;
}
sampleBuffer += dwSamplesToProcess;
dwSamplesRemaining -= dwSamplesToProcess;
}
}
m_Count = (float)rand() / (float)4096; // 0 - 32K -> 0 - 8
return 0;
} /* CReverbFX::Reverb_Process */