/******************************************************************************* * 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 #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 */