speed optimziation: use mono resampler for audio output

This commit is contained in:
Volker Fischer 2009-02-17 11:58:27 +00:00
parent 1c77e542aa
commit 6299f7ce92
5 changed files with 99 additions and 167 deletions

View file

@ -176,10 +176,11 @@ void CClient::Init()
iMonoBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES; iMonoBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
iStereoBlockSizeSam = 2 * MIN_BLOCK_SIZE_SAMPLES; iStereoBlockSizeSam = 2 * MIN_BLOCK_SIZE_SAMPLES;
vecsAudioSndCrd.Init ( iSndCrdStereoBlockSizeSam ); vecsAudioSndCrdStereo.Init ( iSndCrdStereoBlockSizeSam );
vecdAudioSndCrd.Init ( iSndCrdStereoBlockSizeSam ); vecdAudioSndCrdMono.Init ( iSndCrdMonoBlockSizeSam );
vecdAudioSndCrdStereo.Init ( iSndCrdStereoBlockSizeSam );
vecdAudio.Init ( iStereoBlockSizeSam ); vecdAudioStereo.Init ( iStereoBlockSizeSam );
Sound.InitRecording(); Sound.InitRecording();
Sound.InitPlayback(); Sound.InitPlayback();
@ -250,7 +251,7 @@ void CClient::run()
while ( bRun ) while ( bRun )
{ {
// get audio from sound card (blocking function) // get audio from sound card (blocking function)
if ( Sound.Read ( vecsAudioSndCrd ) ) if ( Sound.Read ( vecsAudioSndCrdStereo ) )
{ {
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED ); PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED );
} }
@ -262,14 +263,14 @@ void CClient::run()
// convert data from short to double // convert data from short to double
for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ ) for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ )
{ {
vecdAudioSndCrd[i] = (double) vecsAudioSndCrd[i]; vecdAudioSndCrdStereo[i] = (double) vecsAudioSndCrdStereo[i];
} }
// resample data for each channel seaparately // resample data for each channel seaparately
ResampleObjDown.Resample ( vecdAudioSndCrd, vecdAudio ); ResampleObjDown.ResampleStereo ( vecdAudioSndCrdStereo, vecdAudioStereo );
// update stereo signal level meter // update stereo signal level meter
SignalLevelMeter.Update ( vecdAudio ); SignalLevelMeter.Update ( vecdAudioStereo );
// add reverberation effect if activated // add reverberation effect if activated
if ( iReverbLevel != 0 ) if ( iReverbLevel != 0 )
@ -282,8 +283,8 @@ void CClient::run()
for ( i = 0; i < iStereoBlockSizeSam; i += 2 ) for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
{ {
// left channel // left channel
vecdAudio[i] += vecdAudioStereo[i] +=
dRevLev * AudioReverb.ProcessSample ( vecdAudio[i] ); dRevLev * AudioReverb.ProcessSample ( vecdAudioStereo[i] );
} }
} }
else else
@ -291,25 +292,24 @@ void CClient::run()
for ( i = 1; i < iStereoBlockSizeSam; i += 2 ) for ( i = 1; i < iStereoBlockSizeSam; i += 2 )
{ {
// right channel // right channel
vecdAudio[i] += vecdAudioStereo[i] +=
dRevLev * AudioReverb.ProcessSample ( vecdAudio[i] ); dRevLev * AudioReverb.ProcessSample ( vecdAudioStereo[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 double dAttFact = const double dAttFact =
(double) ( iMiddleOfFader - abs ( iMiddleOfFader - iAudioInFader ) ) / (double) ( AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) /
iMiddleOfFader; AUD_FADER_IN_MIDDLE;
if ( iAudioInFader > iMiddleOfFader ) if ( iAudioInFader > AUD_FADER_IN_MIDDLE )
{ {
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{ {
// attenuation on right channel // attenuation on right channel
vecsNetwork[i] = vecsNetwork[i] =
Double2Short ( vecdAudio[j] + dAttFact * vecdAudio[j + 1] ); Double2Short ( vecdAudioStereo[j] + dAttFact * vecdAudioStereo[j + 1] );
} }
} }
else else
@ -318,7 +318,7 @@ void CClient::run()
{ {
// attenuation on left channel // attenuation on left channel
vecsNetwork[i] = vecsNetwork[i] =
Double2Short ( vecdAudio[j + 1] + dAttFact * vecdAudio[j] ); Double2Short ( vecdAudioStereo[j + 1] + dAttFact * vecdAudioStereo[j] );
} }
} }
@ -352,29 +352,25 @@ fflush(pFileDelay);
// check if channel is connected // check if channel is connected
if ( Channel.IsConnected() ) if ( Channel.IsConnected() )
{ {
// write mono input signal in both sound-card channels // resample data
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) ResampleObjUp.ResampleMono ( vecdNetwData, vecdAudioSndCrdMono );
// convert data from double to short type and copy mono
// received data in both sound card channels
for ( i = 0, j = 0; i < iSndCrdMonoBlockSizeSam; i++, j += 2 )
{ {
vecdAudio[j] = vecdAudio[j + 1] = vecdNetwData[i]; vecsAudioSndCrdStereo[j] = vecsAudioSndCrdStereo[j + 1] =
Double2Short ( vecdAudioSndCrdMono[i] );
} }
} }
else else
{ {
// if not connected, clear data // if not connected, clear data
vecdAudio.Reset ( 0.0 ); vecsAudioSndCrdStereo.Reset ( 0 );
}
// resample data
ResampleObjUp.Resample ( vecdAudio, vecdAudioSndCrd );
// convert data from double to short type
for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ )
{
vecsAudioSndCrd[i] = Double2Short ( vecdAudioSndCrd[i] );
} }
// play the new block // play the new block
if ( Sound.Write ( vecsAudioSndCrd ) ) if ( Sound.Write ( vecsAudioSndCrdStereo ) )
{ {
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED ); PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED );
} }

View file

@ -49,7 +49,9 @@
/* Definitions ****************************************************************/ /* Definitions ****************************************************************/
// audio in fader range // audio in fader range
#define AUD_FADER_IN_MIN 0
#define AUD_FADER_IN_MAX 100 #define AUD_FADER_IN_MAX 100
#define AUD_FADER_IN_MIDDLE ( AUD_FADER_IN_MAX / 2 )
// audio reverberation range // audio reverberation range
#define AUD_REVERB_MAX 100 #define AUD_REVERB_MAX 100
@ -176,9 +178,10 @@ protected:
bool bOpenChatOnNewMessage; bool bOpenChatOnNewMessage;
CVector<short> vecsAudioSndCrd; CVector<short> vecsAudioSndCrdStereo;
CVector<double> vecdAudioSndCrd; CVector<double> vecdAudioSndCrdMono;
CVector<double> vecdAudio; CVector<double> vecdAudioSndCrdStereo;
CVector<double> vecdAudioStereo;
CVector<short> vecsNetwork; CVector<short> vecsNetwork;
// resample objects // resample objects

View file

@ -115,7 +115,7 @@ CLlconClientDlg::CLlconClientDlg ( CClient* pNCliP, QWidget* parent,
// init slider controls --- // init slider controls ---
// audio in fader // audio in fader
SliderAudInFader->setRange ( 0, AUD_FADER_IN_MAX ); SliderAudInFader->setRange ( AUD_FADER_IN_MIN, AUD_FADER_IN_MAX );
const int iCurAudInFader = pClient->GetAudioInFader(); const int iCurAudInFader = pClient->GetAudioInFader();
SliderAudInFader->setValue ( iCurAudInFader ); SliderAudInFader->setValue ( iCurAudInFader );
SliderAudInFader->setTickInterval ( AUD_FADER_IN_MAX / 9 ); SliderAudInFader->setTickInterval ( AUD_FADER_IN_MAX / 9 );

View file

@ -35,109 +35,11 @@
#include "resample.h" #include "resample.h"
/******************************************************************************\
* General Resampler *
\******************************************************************************/
int CResample::Resample ( CVector<double>& vecdInput,
CVector<double>& vecdOutput,
const double dRation )
{
int i;
/* move old data from the end to the history part of the buffer and
add new data (shift register) */
// shift old values
int iMovLen = iInputBlockSize;
for ( i = 0; i < iHistorySize; i++ )
{
vecdIntBuff[i] = vecdIntBuff[iMovLen++];
}
// add new block of data
int iBlockEnd = iHistorySize;
for ( i = 0; i < iInputBlockSize; i++ )
{
vecdIntBuff[iBlockEnd++] = vecdInput[i];
}
/* sample-interval of new sample frequency in relation to interpolated
sample-interval */
dTStep = (double) INTERP_DECIM_I_D1 / dRation;
// init output counter
int im = 0;
// main loop
do
{
// quantize output-time to interpolated time-index
const int ik = (int) dtOut;
/* Calculate convolutions for the two interpolation-taps ------------ */
// phase for the linear interpolation-taps
const int ip1 = ik % INTERP_DECIM_I_D1;
const int ip2 = ( ik + 1 ) % INTERP_DECIM_I_D1;
// sample positions in input vector
const int in1 = (int) ( ik / INTERP_DECIM_I_D1 );
const int in2 = (int) ( ( ik + 1 ) / INTERP_DECIM_I_D1 );
// convolution
double dy1 = 0.0;
double dy2 = 0.0;
for ( int i = 0; i < NUM_TAPS_PER_PHASE1; i++ )
{
dy1 += fResTaps1[ip1 * INTERP_DECIM_I_D1 + i] * vecdIntBuff[in1 - i];
dy2 += fResTaps1[ip2 * INTERP_DECIM_I_D1 + i] * vecdIntBuff[in2 - i];
}
/* Linear interpolation --------------------------------------------- */
// get numbers after the comma
const double dxInt = dtOut - (int) dtOut;
vecdOutput[im] = ( dy2 - dy1 ) * dxInt + dy1;
// increase output counter
im++;
// increase output-time and index one step
dtOut = dtOut + dTStep;
}
while ( dtOut < dBlockDuration );
// set rtOut back
dtOut -= iInputBlockSize * INTERP_DECIM_I_D1;
return im;
}
void CResample::Init ( const int iNewInputBlockSize )
{
iInputBlockSize = iNewInputBlockSize;
/* history size must be one sample larger, because we use always TWO
convolutions */
iHistorySize = NUM_TAPS_PER_PHASE1 + 1;
// calculate block duration
dBlockDuration = ( iInputBlockSize + iHistorySize - 1 ) * INTERP_DECIM_I_D1;
// allocate memory for internal buffer, clear sample history
vecdIntBuff.Init ( iInputBlockSize + iHistorySize, 0.0 );
// init absolute time for output stream (at the end of the history part
dtOut = (double) ( iHistorySize - 1 ) * INTERP_DECIM_I_D1;
}
/******************************************************************************\ /******************************************************************************\
* Stereo Audio Resampler * * Stereo Audio Resampler *
\******************************************************************************/ \******************************************************************************/
void CStereoAudioResample::Resample ( CVector<double>& vecdInput, void CStereoAudioResample::ResampleStereo ( CVector<double>& vecdInput,
CVector<double>& vecdOutput ) CVector<double>& vecdOutput )
{ {
int j; int j;
@ -156,14 +58,14 @@ void CStereoAudioResample::Resample ( CVector<double>& vecdInput,
int iMovLen = iStereoInputBlockSize; int iMovLen = iStereoInputBlockSize;
for ( j = 0; j < iTwoTimesNumTaps; j++ ) for ( j = 0; j < iTwoTimesNumTaps; j++ )
{ {
vecdIntBuff[j] = vecdIntBuff[iMovLen++]; vecdIntBuffStereo[j] = vecdIntBuffStereo[iMovLen++];
} }
// add new block of data // add new block of data
int iBlockEnd = iTwoTimesNumTaps; int iBlockEnd = iTwoTimesNumTaps;
for ( j = 0; j < iStereoInputBlockSize; j++ ) for ( j = 0; j < iStereoInputBlockSize; j++ )
{ {
vecdIntBuff[iBlockEnd++] = vecdInput[j]; vecdIntBuffStereo[iBlockEnd++] = vecdInput[j];
} }
// main loop // main loop
@ -183,8 +85,8 @@ void CStereoAudioResample::Resample ( CVector<double>& vecdInput,
const double dCurFiltTap = pFiltTaps[ip + i * iI]; const double dCurFiltTap = pFiltTaps[ip + i * iI];
const int iCurSamplePos = in - 2 * i; const int iCurSamplePos = in - 2 * i;
dyL += dCurFiltTap * vecdIntBuff[iCurSamplePos]; dyL += dCurFiltTap * vecdIntBuffStereo[iCurSamplePos];
dyR += dCurFiltTap * vecdIntBuff[iCurSamplePos + 1]; dyR += dCurFiltTap * vecdIntBuffStereo[iCurSamplePos + 1];
} }
vecdOutput[2 * j] = dyL; vecdOutput[2 * j] = dyL;
@ -193,11 +95,61 @@ void CStereoAudioResample::Resample ( CVector<double>& vecdInput,
} }
} }
void CStereoAudioResample::ResampleMono ( CVector<double>& vecdInput,
CVector<double>& vecdOutput )
{
int j;
if ( dRation == 1.0 )
{
// if ratio is 1, no resampling is needed, just copy vector
vecdOutput = vecdInput;
}
else
{
/* move old data from the end to the history part of the buffer and
add new data (shift register) */
// shift old values
int iMovLen = iMonoInputBlockSize;
for ( j = 0; j < iNumTaps; j++ )
{
vecdIntBuffMono[j] = vecdIntBuffMono[iMovLen++];
}
// add new block of data
int iBlockEnd = iNumTaps;
for ( j = 0; j < iMonoInputBlockSize; j++ )
{
vecdIntBuffMono[iBlockEnd++] = vecdInput[j];
}
// main loop
for ( j = 0; j < iMonoOutputBlockSize; j++ )
{
// calculate filter phase
const int ip = (int) ( j * iI / dRation ) % iI;
// sample position in input vector
const int in = (int) ( j / dRation ) + iNumTaps - 1;
// convolution
double dy = 0.0;
for ( int i = 0; i < iNumTaps; i++ )
{
dy += pFiltTaps[ip + i * iI] * vecdIntBuffMono[in - i];
}
vecdOutput[j] = dy;
}
}
}
void CStereoAudioResample::Init ( const int iNewMonoInputBlockSize, 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;
iMonoInputBlockSize = iNewMonoInputBlockSize;
iStereoInputBlockSize = 2 * iNewMonoInputBlockSize; iStereoInputBlockSize = 2 * iNewMonoInputBlockSize;
iMonoOutputBlockSize = (int) ( iNewMonoInputBlockSize * dRation ); iMonoOutputBlockSize = (int) ( iNewMonoInputBlockSize * dRation );
@ -266,8 +218,9 @@ void CStereoAudioResample::Init ( const int iNewMonoInputBlockSize,
} }
} }
// allocate memory for internal buffer, clear sample history (we have // allocate memory for internal buffer, clear sample history (for
// to consider stereo data here -> two times the number of taps of // the stereo case we have to consider that two times the number of taps of
// additional memory is required) // additional memory is required)
vecdIntBuff.Init ( iStereoInputBlockSize + 2 * iNumTaps, 0.0 ); vecdIntBuffMono.Init ( iMonoInputBlockSize + iNumTaps, 0.0 );
vecdIntBuffStereo.Init ( iStereoInputBlockSize + 2 * iNumTaps, 0.0 );
} }

View file

@ -31,27 +31,6 @@
/* Classes ********************************************************************/ /* Classes ********************************************************************/
class CResample
{
public:
CResample() {}
virtual ~CResample() {}
void Init ( const int iNewInputBlockSize );
int Resample ( CVector<double>& vecdInput, CVector<double>& vecdOutput,
const double dRation );
protected:
double dTStep;
double dtOut;
double dBlockDuration;
CVector<double> vecdIntBuff;
int iHistorySize;
int iInputBlockSize;
};
class CStereoAudioResample class CStereoAudioResample
{ {
public: public:
@ -59,14 +38,16 @@ public:
virtual ~CStereoAudioResample() {} virtual ~CStereoAudioResample() {}
void Init ( const int iNewMonoInputBlockSize, 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 ResampleMono ( CVector<double>& vecdInput, CVector<double>& vecdOutput );
void ResampleStereo ( CVector<double>& vecdInput, CVector<double>& vecdOutput );
protected: protected:
double dRation; double dRation;
CVector<double> vecdIntBuff; CVector<double> vecdIntBuffMono;
int iHistorySize; CVector<double> vecdIntBuffStereo;
int iMonoInputBlockSize;
int iStereoInputBlockSize; int iStereoInputBlockSize;
int iMonoOutputBlockSize; int iMonoOutputBlockSize;
@ -75,5 +56,4 @@ protected:
int iI; int iI;
}; };
#endif // !defined ( RESAMPLE_H__3B0FEUFE7876F_FE8FE_CA63_4344_1912__INCLUDED_ ) #endif // !defined ( RESAMPLE_H__3B0FEUFE7876F_FE8FE_CA63_4344_1912__INCLUDED_ )