speed optimizations

This commit is contained in:
Volker Fischer 2009-02-14 00:46:58 +00:00
parent 85d37b53b5
commit 55c680e6fd
7 changed files with 186 additions and 172 deletions

View file

@ -27,7 +27,8 @@
/* Implementation *************************************************************/ /* Implementation *************************************************************/
CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ), CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ),
iSndCrdBlockSizeSam ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES ), iSndCrdMonoBlockSizeSam ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES ),
iSndCrdStereoBlockSizeSam ( 2 * MIN_SND_CRD_BLOCK_SIZE_SAMPLES ),
Sound ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES * 2 /* stereo */ ), Sound ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES * 2 /* stereo */ ),
Socket ( &Channel, iPortNumber ), Socket ( &Channel, iPortNumber ),
iAudioInFader ( AUD_FADER_IN_MAX / 2 ), iAudioInFader ( AUD_FADER_IN_MAX / 2 ),
@ -172,30 +173,27 @@ void CClient::OnProtocolStatus ( bool bOk )
void CClient::Init() void CClient::Init()
{ {
// set block size (in samples) // set block size (in samples)
iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES; iMonoBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
iStereoBlockSizeSam = 2 * MIN_BLOCK_SIZE_SAMPLES;
vecsAudioSndCrd.Init ( iSndCrdBlockSizeSam * 2 ); // stereo vecsAudioSndCrd.Init ( iSndCrdStereoBlockSizeSam );
vecdAudioSndCrdL.Init ( iSndCrdBlockSizeSam ); vecdAudioSndCrd.Init ( iSndCrdStereoBlockSizeSam );
vecdAudioSndCrdR.Init ( iSndCrdBlockSizeSam );
vecdAudioL.Init ( iBlockSizeSam ); vecdAudio.Init ( iStereoBlockSizeSam );
vecdAudioR.Init ( iBlockSizeSam );
Sound.InitRecording(); Sound.InitRecording();
Sound.InitPlayback(); Sound.InitPlayback();
// resample objects are always initialized with the input block size // resample objects are always initialized with the input block size
// record // record
ResampleObjDownL.Init ( iSndCrdBlockSizeSam, SND_CRD_SAMPLE_RATE, SYSTEM_SAMPLE_RATE ); ResampleObjDown.Init ( iSndCrdMonoBlockSizeSam, SND_CRD_SAMPLE_RATE, SYSTEM_SAMPLE_RATE );
ResampleObjDownR.Init ( iSndCrdBlockSizeSam, SND_CRD_SAMPLE_RATE, SYSTEM_SAMPLE_RATE );
// playback // playback
ResampleObjUpL.Init ( iBlockSizeSam, SYSTEM_SAMPLE_RATE, SND_CRD_SAMPLE_RATE ); ResampleObjUp.Init ( iMonoBlockSizeSam, SYSTEM_SAMPLE_RATE, SND_CRD_SAMPLE_RATE );
ResampleObjUpR.Init ( iBlockSizeSam, SYSTEM_SAMPLE_RATE, SND_CRD_SAMPLE_RATE );
// init network buffers // init network buffers
vecsNetwork.Init ( iBlockSizeSam ); vecsNetwork.Init ( iMonoBlockSizeSam );
vecdNetwData.Init ( iBlockSizeSam ); vecdNetwData.Init ( iMonoBlockSizeSam );
// init moving average buffer for response time evaluation // init moving average buffer for response time evaluation
RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE ); RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE );
@ -208,7 +206,7 @@ void CClient::Init()
void CClient::run() void CClient::run()
{ {
int i, iInCnt; int i, j;
// Set thread priority (The working thread should have a higher // Set thread priority (The working thread should have a higher
// priority than the GUI) // priority than the GUI)
@ -242,7 +240,7 @@ void CClient::run()
} }
// runtime phase ------------------------------------------------------------ // runtime phase -----------------------------------------------------------
// enable channel // enable channel
Channel.SetEnable ( true ); Channel.SetEnable ( true );
@ -261,21 +259,17 @@ void CClient::run()
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN ); PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN );
} }
// copy data from one stereo buffer in two separate buffers // convert data from short to double
iInCnt = 0; for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ )
for ( i = 0; i < iSndCrdBlockSizeSam; i++ )
{ {
vecdAudioSndCrdL[i] = (double) vecsAudioSndCrd[iInCnt++]; vecdAudioSndCrd[i] = (double) vecsAudioSndCrd[i];
vecdAudioSndCrdR[i] = (double) vecsAudioSndCrd[iInCnt++];
} }
// resample data for each channel seaparately // resample data for each channel seaparately
ResampleObjDownL.Resample ( vecdAudioSndCrdL, vecdAudioL ); ResampleObjDown.Resample ( vecdAudioSndCrd, vecdAudio );
ResampleObjDownR.Resample ( vecdAudioSndCrdR, vecdAudioR );
// update signal level meters // update stereo signal level meter
SignalLevelMeterL.Update ( vecdAudioL ); SignalLevelMeter.Update ( vecdAudio );
SignalLevelMeterR.Update ( vecdAudioR );
// add reverberation effect if activated // add reverberation effect if activated
if ( iReverbLevel != 0 ) if ( iReverbLevel != 0 )
@ -285,44 +279,47 @@ void CClient::run()
if ( bReverbOnLeftChan ) if ( bReverbOnLeftChan )
{ {
for ( i = 0; i < iBlockSizeSam; i++ ) for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
{ {
// left channel // left channel
vecdAudioL[i] += vecdAudio[i] +=
dRevLev * AudioReverb.ProcessSample ( vecdAudioL[i] ); dRevLev * AudioReverb.ProcessSample ( vecdAudio[i] );
} }
} }
else else
{ {
for ( i = 0; i < iBlockSizeSam; i++ ) for ( i = 1; i < iStereoBlockSizeSam; i += 2 )
{ {
// right channel // right channel
vecdAudioR[i] += vecdAudio[i] +=
dRevLev * AudioReverb.ProcessSample ( vecdAudioR[i] ); dRevLev * AudioReverb.ProcessSample ( vecdAudio[i] );
} }
} }
} }
// mix both signals depending on the fading setting // mix both signals depending on the fading setting
const int iMiddleOfFader = AUD_FADER_IN_MAX / 2; const int iMiddleOfFader = AUD_FADER_IN_MAX / 2;
const double dAttFact = const double dAttFact =
(double) ( iMiddleOfFader - abs ( iMiddleOfFader - iAudioInFader ) ) / (double) ( iMiddleOfFader - abs ( iMiddleOfFader - iAudioInFader ) ) /
iMiddleOfFader; iMiddleOfFader;
for ( i = 0; i < iBlockSizeSam; i++ ) if ( iAudioInFader > iMiddleOfFader )
{ {
double dMixedSignal; for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
if ( iAudioInFader > iMiddleOfFader )
{ {
dMixedSignal = vecdAudioL[i] + dAttFact * vecdAudioR[i]; // attenuation on right channel
vecsNetwork[i] =
Double2Short ( vecdAudio[j] + dAttFact * vecdAudio[j + 1] );
} }
else }
else
{
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{ {
dMixedSignal = vecdAudioR[i] + dAttFact * vecdAudioL[i]; // attenuation on left channel
vecsNetwork[i] =
Double2Short ( vecdAudio[j + 1] + dAttFact * vecdAudio[j] );
} }
vecsNetwork[i] = Double2Short ( dMixedSignal );
} }
// send it through the network // send it through the network
@ -344,7 +341,7 @@ void CClient::run()
// fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid); // fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid);
static FILE* pFileDelay = fopen("v.dat", "wb"); static FILE* pFileDelay = fopen("v.dat", "wb");
short sData[2]; short sData[2];
for (i = 0; i < iBlockSizeSam; i++) for (i = 0; i < iMonoBlockSizeSam; i++)
{ {
sData[0] = (short) vecdNetwData[i]; sData[0] = (short) vecdNetwData[i];
fwrite(&sData, size_t(2), size_t(1), pFileDelay); fwrite(&sData, size_t(2), size_t(1), pFileDelay);
@ -356,30 +353,24 @@ fflush(pFileDelay);
if ( Channel.IsConnected() ) if ( Channel.IsConnected() )
{ {
// write mono input signal in both sound-card channels // write mono input signal in both sound-card channels
for ( i = 0; i < iBlockSizeSam; i++ ) for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{ {
vecdAudioL[i] = vecdAudioR[i] = vecdNetwData[i]; vecdAudio[j] = vecdAudio[j + 1] = vecdNetwData[i];
} }
} }
else else
{ {
// if not connected, clear data // if not connected, clear data
for ( i = 0; i < iBlockSizeSam; i++ ) vecdAudio.Reset ( 0.0 );
{
vecdAudioL[i] = vecdAudioR[i] = 0.0;
}
} }
// resample data for each channel separately // resample data
ResampleObjUpL.Resample ( vecdAudioL, vecdAudioSndCrdL ); ResampleObjUp.Resample ( vecdAudio, vecdAudioSndCrd );
ResampleObjUpR.Resample ( vecdAudioR, vecdAudioSndCrdR );
// copy data from one stereo buffer in two separate buffers // convert data from double to short type
iInCnt = 0; for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ )
for ( i = 0; i < iSndCrdBlockSizeSam; i++ )
{ {
vecsAudioSndCrd[iInCnt++] = Double2Short ( vecdAudioSndCrdL[i] ); vecsAudioSndCrd[i] = Double2Short ( vecdAudioSndCrd[i] );
vecsAudioSndCrd[iInCnt++] = Double2Short ( vecdAudioSndCrdR[i] );
} }
// play the new block // play the new block
@ -404,8 +395,7 @@ fflush(pFileDelay);
Sound.Close(); Sound.Close();
// reset current signal level and LEDs // reset current signal level and LEDs
SignalLevelMeterL.Reset(); SignalLevelMeter.Reset();
SignalLevelMeterR.Reset();
PostWinMessage ( MS_RESET_ALL, 0 ); PostWinMessage ( MS_RESET_ALL, 0 );
} }

View file

@ -68,8 +68,8 @@ public:
bool Stop(); bool Stop();
bool IsRunning() { return bRun; } bool IsRunning() { return bRun; }
bool SetServerAddr ( QString strNAddr ); bool SetServerAddr ( QString strNAddr );
double MicLevelL() { return SignalLevelMeterL.MicLevel(); } double MicLevelL() { return SignalLevelMeter.MicLevelLeft(); }
double MicLevelR() { return SignalLevelMeterR.MicLevel(); } double MicLevelR() { return SignalLevelMeter.MicLevelRight(); }
bool IsConnected() { return Channel.IsConnected(); } bool IsConnected() { return Channel.IsConnected(); }
/* We want to return the standard deviation. For that we need to calculate /* We want to return the standard deviation. For that we need to calculate
@ -143,59 +143,54 @@ public:
// settings // settings
QString strIPAddress; QString strIPAddress;
QString strName; QString strName;
protected: protected:
virtual void run(); virtual void run();
void UpdateTimeResponseMeasurement(); void UpdateTimeResponseMeasurement();
void UpdateSocketBufferSize(); void UpdateSocketBufferSize();
// only one channel is needed for client application // only one channel is needed for client application
CChannel Channel; CChannel Channel;
bool bDoAutoSockBufSize; bool bDoAutoSockBufSize;
CSocket Socket; CSocket Socket;
CSound Sound; CSound Sound;
CSignalLevelMeter SignalLevelMeterL; CStereoSignalLevelMeter SignalLevelMeter;
CSignalLevelMeter SignalLevelMeterR;
bool bRun; bool bRun;
CVector<double> vecdNetwData; CVector<double> vecdNetwData;
int iAudioInFader; int iAudioInFader;
bool bReverbOnLeftChan; bool bReverbOnLeftChan;
int iReverbLevel; int iReverbLevel;
CAudioReverb AudioReverb; CAudioReverb AudioReverb;
int iSndCrdBlockSizeSam; int iSndCrdMonoBlockSizeSam;
int iBlockSizeSam; int iSndCrdStereoBlockSizeSam;
int iMonoBlockSizeSam;
int iStereoBlockSizeSam;
int iNetwBufSizeFactIn; int iNetwBufSizeFactIn;
bool bOpenChatOnNewMessage; bool bOpenChatOnNewMessage;
CVector<short> vecsAudioSndCrd; CVector<short> vecsAudioSndCrd;
CVector<double> vecdAudioSndCrdL; CVector<double> vecdAudioSndCrd;
CVector<double> vecdAudioSndCrdR; CVector<double> vecdAudio;
CVector<short> vecsNetwork;
CVector<double> vecdAudioL;
CVector<double> vecdAudioR;
CVector<short> vecsNetwork;
// resample objects // resample objects
CAudioResample ResampleObjDownL; // left channel CStereoAudioResample ResampleObjDown;
CAudioResample ResampleObjDownR; // right channel CStereoAudioResample ResampleObjUp;
CAudioResample ResampleObjUpL; // left channel
CAudioResample ResampleObjUpR; // right channel
// for ping measurement and standard deviation of audio interface // for ping measurement and standard deviation of audio interface
CPreciseTime PreciseTime; CPreciseTime PreciseTime;
// debugging, evaluating // debugging, evaluating
CMovingAv<double> RespTimeMoAvBuf; CMovingAv<double> RespTimeMoAvBuf;
int TimeLastBlock; int TimeLastBlock;
public slots: public slots:
void OnSendProtMessage ( CVector<uint8_t> vecMessage ); void OnSendProtMessage ( CVector<uint8_t> vecMessage );

View file

@ -1,5 +1,5 @@
/******************************************************************************\ /******************************************************************************\
* Copyright (c) 2004-2008 * Copyright (c) 2004-2009
* *
* Author(s): * Author(s):
* Volker Fischer * Volker Fischer
@ -92,10 +92,6 @@
// (just search for the tag in the entire code) // (just search for the tag in the entire code)
#define MAX_NUM_CHANNELS 6 // max number channels for server #define MAX_NUM_CHANNELS 6 // max number channels for server
// sample rate offset estimation algorithm
// time interval for sample rate offset estimation
#define TIME_INT_SAM_OFFS_EST 60 // s
// length of the moving average buffer for response time measurement // length of the moving average buffer for response time measurement
#define TIME_MOV_AV_RESPONSE 30 // seconds #define TIME_MOV_AV_RESPONSE 30 // seconds
#define LEN_MOV_AV_RESPONSE ( TIME_MOV_AV_RESPONSE * 1000 / MIN_BLOCK_DURATION_MS ) #define LEN_MOV_AV_RESPONSE ( TIME_MOV_AV_RESPONSE * 1000 / MIN_BLOCK_DURATION_MS )

View file

@ -86,7 +86,7 @@ int CResample::Resample ( CVector<double>& vecdInput,
// convolution // convolution
double dy1 = 0.0; double dy1 = 0.0;
double dy2 = 0.0; double dy2 = 0.0;
for (int i = 0; i < NUM_TAPS_PER_PHASE1; i++) for ( int i = 0; i < NUM_TAPS_PER_PHASE1; i++ )
{ {
dy1 += fResTaps1[ip1 * INTERP_DECIM_I_D1 + i] * vecdIntBuff[in1 - i]; dy1 += fResTaps1[ip1 * INTERP_DECIM_I_D1 + i] * vecdIntBuff[in1 - i];
dy2 += fResTaps1[ip2 * INTERP_DECIM_I_D1 + i] * vecdIntBuff[in2 - i]; dy2 += fResTaps1[ip2 * INTERP_DECIM_I_D1 + i] * vecdIntBuff[in2 - i];
@ -134,10 +134,10 @@ void CResample::Init ( const int iNewInputBlockSize )
/******************************************************************************\ /******************************************************************************\
* Audio Resampler * * Stereo Audio Resampler *
\******************************************************************************/ \******************************************************************************/
void CAudioResample::Resample ( CVector<double>& vecdInput, void CStereoAudioResample::Resample ( CVector<double>& vecdInput,
CVector<double>& vecdOutput ) CVector<double>& vecdOutput )
{ {
int j; int j;
@ -148,50 +148,58 @@ void CAudioResample::Resample ( CVector<double>& vecdInput,
} }
else else
{ {
const int iTwoTimesNumTaps = 2 * iNumTaps;
/* move old data from the end to the history part of the buffer and /* move old data from the end to the history part of the buffer and
add new data (shift register) */ add new data (shift register) */
// shift old values // shift old values
int iMovLen = iInputBlockSize; int iMovLen = iStereoInputBlockSize;
for ( j = 0; j < iNumTaps; j++ ) for ( j = 0; j < iTwoTimesNumTaps; j++ )
{ {
vecdIntBuff[j] = vecdIntBuff[iMovLen++]; vecdIntBuff[j] = vecdIntBuff[iMovLen++];
} }
// add new block of data // add new block of data
int iBlockEnd = iNumTaps; int iBlockEnd = iTwoTimesNumTaps;
for ( j = 0; j < iInputBlockSize; j++ ) for ( j = 0; j < iStereoInputBlockSize; j++ )
{ {
vecdIntBuff[iBlockEnd++] = vecdInput[j]; vecdIntBuff[iBlockEnd++] = vecdInput[j];
} }
// main loop // main loop
for ( j = 0; j < iOutputBlockSize; j++ ) for ( j = 0; j < iMonoOutputBlockSize; j++ )
{ {
// calculate filter phase // calculate filter phase
const int ip = (int) ( j * iI / dRation ) % iI; const int ip = (int) ( j * iI / dRation ) % iI;
// sample position in input vector // sample position in stereo input vector
const int in = (int) ( j / dRation ) + iNumTaps - 1; const int in = 2 * ( (int) ( j / dRation ) + iNumTaps - 1 );
// convolution // convolution
double dy = 0.0; double dyL = 0.0;
double dyR = 0.0;
for ( int i = 0; i < iNumTaps; i++ ) for ( int i = 0; i < iNumTaps; i++ )
{ {
dy += pFiltTaps[ip + i * iI] * vecdIntBuff[in - i]; const double dCurFiltTap = pFiltTaps[ip + i * iI];
const int iCurSamplePos = in - 2 * i;
dyL += dCurFiltTap * vecdIntBuff[iCurSamplePos];
dyR += dCurFiltTap * vecdIntBuff[iCurSamplePos + 1];
} }
vecdOutput[j] = dy; vecdOutput[2 * j] = dyL;
vecdOutput[2 * j + 1] = dyR;
} }
} }
} }
void CAudioResample::Init ( const int iNewInputBlockSize, void CStereoAudioResample::Init ( const int iNewMonoInputBlockSize,
const int iFrom, const int iFrom,
const int iTo ) const int iTo )
{ {
dRation = ( (double) iTo ) / iFrom; dRation = ( (double) iTo ) / iFrom;
iInputBlockSize = iNewInputBlockSize; iStereoInputBlockSize = 2 * iNewMonoInputBlockSize;
iOutputBlockSize = (int) ( iInputBlockSize * dRation ); iMonoOutputBlockSize = (int) ( iNewMonoInputBlockSize * dRation );
// set correct parameters // set correct parameters
if ( iFrom == SND_CRD_SAMPLE_RATE ) // downsampling case if ( iFrom == SND_CRD_SAMPLE_RATE ) // downsampling case
@ -205,22 +213,22 @@ void CAudioResample::Init ( const int iNewInputBlockSize,
break; break;
case ( SND_CRD_SAMPLE_RATE * 7 / 12 ): // 48 kHz to 28 kHz case ( SND_CRD_SAMPLE_RATE * 7 / 12 ): // 48 kHz to 28 kHz
pFiltTaps = fResTaps12_7; pFiltTaps = fResTaps12_7;
iNumTaps = INTERP_I_12_7 * NUM_TAPS_PER_PHASE12_7; iNumTaps = INTERP_I_12_7 * NUM_TAPS_PER_PHASE12_7;
iI = DECIM_D_12_7; iI = DECIM_D_12_7;
break; break;
case ( SND_CRD_SAMPLE_RATE * 2 / 3 ): // 48 kHz to 32 kHz case ( SND_CRD_SAMPLE_RATE * 2 / 3 ): // 48 kHz to 32 kHz
pFiltTaps = fResTaps3_2; pFiltTaps = fResTaps3_2;
iNumTaps = INTERP_I_3_2 * NUM_TAPS_PER_PHASE3_2; iNumTaps = INTERP_I_3_2 * NUM_TAPS_PER_PHASE3_2;
iI = DECIM_D_3_2; iI = DECIM_D_3_2;
break; break;
case SND_CRD_SAMPLE_RATE: // 48 kHz to 48 kHz case SND_CRD_SAMPLE_RATE: // 48 kHz to 48 kHz
// no resampling needed // no resampling needed
pFiltTaps = NULL; pFiltTaps = NULL;
iNumTaps = 0; iNumTaps = 0;
iI = 1; iI = 1;
break; break;
default: default:
@ -234,21 +242,21 @@ void CAudioResample::Init ( const int iNewInputBlockSize,
switch ( iFrom ) switch ( iFrom )
{ {
case ( SND_CRD_SAMPLE_RATE / 2 ): // 24 kHz to 48 kHz case ( SND_CRD_SAMPLE_RATE / 2 ): // 24 kHz to 48 kHz
pFiltTaps = fResTaps2; pFiltTaps = fResTaps2;
iNumTaps = DECIM_D_2 * NUM_TAPS_PER_PHASE2; iNumTaps = DECIM_D_2 * NUM_TAPS_PER_PHASE2;
iI = INTERP_I_2; iI = INTERP_I_2;
break; break;
case ( SND_CRD_SAMPLE_RATE * 7 / 12 ): // 28 kHz to 48 kHz case ( SND_CRD_SAMPLE_RATE * 7 / 12 ): // 28 kHz to 48 kHz
pFiltTaps = fResTaps12_7; pFiltTaps = fResTaps12_7;
iNumTaps = DECIM_D_12_7 * NUM_TAPS_PER_PHASE12_7; iNumTaps = DECIM_D_12_7 * NUM_TAPS_PER_PHASE12_7;
iI = INTERP_I_12_7; iI = INTERP_I_12_7;
break; break;
case ( SND_CRD_SAMPLE_RATE * 2 / 3 ): // 32 kHz to 48 kHz case ( SND_CRD_SAMPLE_RATE * 2 / 3 ): // 32 kHz to 48 kHz
pFiltTaps = fResTaps3_2; pFiltTaps = fResTaps3_2;
iNumTaps = DECIM_D_3_2 * NUM_TAPS_PER_PHASE3_2; iNumTaps = DECIM_D_3_2 * NUM_TAPS_PER_PHASE3_2;
iI = INTERP_I_3_2; iI = INTERP_I_3_2;
break; break;
default: default:
@ -258,6 +266,8 @@ void CAudioResample::Init ( const int iNewInputBlockSize,
} }
} }
// allocate memory for internal buffer, clear sample history // allocate memory for internal buffer, clear sample history (we have
vecdIntBuff.Init ( iInputBlockSize + iNumTaps, 0.0 ); // to consider stereo data here -> two times the number of taps of
// additional memory is required)
vecdIntBuff.Init ( iStereoInputBlockSize + 2 * iNumTaps, 0.0 );
} }

View file

@ -52,27 +52,27 @@ protected:
int iInputBlockSize; int iInputBlockSize;
}; };
class CAudioResample class CStereoAudioResample
{ {
public: public:
CAudioResample() {} CStereoAudioResample() {}
virtual ~CAudioResample() {} virtual ~CStereoAudioResample() {}
void Init ( const int iNewInputBlockSize, const int iFrom, const int iTo ); void Init ( const int iNewMonoInputBlockSize, const int iFrom, const int iTo );
void Resample ( CVector<double>& vecdInput, CVector<double>& vecdOutput ); void Resample ( CVector<double>& vecdInput, CVector<double>& vecdOutput );
protected: protected:
double dRation; double dRation;
CVector<double> vecdIntBuff; CVector<double> vecdIntBuff;
int iHistorySize; int iHistorySize;
int iInputBlockSize; int iStereoInputBlockSize;
int iOutputBlockSize; int iMonoOutputBlockSize;
float* pFiltTaps; float* pFiltTaps;
int iNumTaps; int iNumTaps;
int iI; int iI;
}; };

View file

@ -27,10 +27,10 @@
/* Implementation *************************************************************/ /* Implementation *************************************************************/
// Input level meter implementation -------------------------------------------- // Input level meter implementation --------------------------------------------
void CSignalLevelMeter::Update ( CVector<double>& vecdAudio ) void CStereoSignalLevelMeter::Update ( CVector<double>& vecdAudio )
{ {
// get the vector size // get the stereo vector size
const int iVecSize = vecdAudio.Size(); const int iStereoVecSize = vecdAudio.Size();
// Get maximum of current block // Get maximum of current block
// //
@ -43,15 +43,29 @@ void CSignalLevelMeter::Update ( CVector<double>& vecdAudio )
// special cases but for the average music signals the following code // special cases but for the average music signals the following code
// should give good results. // should give good results.
// //
double dMax = 0.0; double dMaxL = 0.0;
for ( int i = 0; i < iVecSize; i += 3 ) double dMaxR = 0.0;
for ( int i = 0; i < iStereoVecSize; i += 6 ) // 2 * 3 = 6 -> stereo
{ {
if ( dMax < vecdAudio[i] ) // left channel
if ( dMaxL < vecdAudio[i] )
{ {
dMax = vecdAudio[i]; dMaxL = vecdAudio[i];
}
// right channel
if ( dMaxR < vecdAudio[i + 1] )
{
dMaxR = vecdAudio[i + 1];
} }
} }
dCurLevelL = UpdateCurLevel ( dCurLevelL, dMaxL );
dCurLevelR = UpdateCurLevel ( dCurLevelR, dMaxR );
}
double CStereoSignalLevelMeter::UpdateCurLevel ( double dCurLevel, const double& dMax )
{
// decrease max with time // decrease max with time
if ( dCurLevel >= METER_FLY_BACK ) if ( dCurLevel >= METER_FLY_BACK )
{ {
@ -66,13 +80,17 @@ void CSignalLevelMeter::Update ( CVector<double>& vecdAudio )
// update current level -> only use maximum // update current level -> only use maximum
if ( dMax > dCurLevel ) if ( dMax > dCurLevel )
{ {
dCurLevel = dMax; return dMax;
}
else
{
return dCurLevel;
} }
} }
double CSignalLevelMeter::MicLevel() double CStereoSignalLevelMeter::CalcLogResult ( const double& dLinearLevel )
{ {
const double dNormMicLevel = dCurLevel / _MAXSHORT; const double dNormMicLevel = dLinearLevel / _MAXSHORT;
// logarithmic measure // logarithmic measure
if ( dNormMicLevel > 0 ) if ( dNormMicLevel > 0 )

View file

@ -356,19 +356,24 @@ public slots:
/* Other Classes **************************************************************/ /* Other Classes **************************************************************/
// Signal Level Meter ---------------------------------------------------------- // Stereo Signal Level Meter ---------------------------------------------------
class CSignalLevelMeter class CStereoSignalLevelMeter
{ {
public: public:
CSignalLevelMeter() : dCurLevel ( 0.0 ) {} CStereoSignalLevelMeter() { Reset(); }
virtual ~CSignalLevelMeter() {} virtual ~CStereoSignalLevelMeter() {}
void Update ( CVector<double>& vecdAudio ); void Update ( CVector<double>& vecdAudio );
double MicLevel(); double MicLevelLeft() { return CalcLogResult ( dCurLevelL ); }
void Reset() { dCurLevel = 0.0; } double MicLevelRight() { return CalcLogResult ( dCurLevelR ); }
void Reset() { dCurLevelL = 0.0; dCurLevelR = 0.0; }
protected: protected:
double dCurLevel; double CalcLogResult ( const double& dLinearLevel );
double UpdateCurLevel ( double dCurLevel, const double& dMax );
double dCurLevelL;
double dCurLevelR;
}; };
class CHostAddress class CHostAddress
@ -409,7 +414,7 @@ class CAudioReverb
public: public:
CAudioReverb ( const double rT60 = (double) 5.0 ); CAudioReverb ( const double rT60 = (double) 5.0 );
void Clear(); void Clear();
double ProcessSample ( const double input ); double ProcessSample ( const double input );
protected: protected: