speed optimizations
This commit is contained in:
parent
85d37b53b5
commit
55c680e6fd
7 changed files with 186 additions and 172 deletions
106
src/client.cpp
106
src/client.cpp
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
71
src/client.h
71
src/client.h
|
@ -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 );
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
38
src/util.cpp
38
src/util.cpp
|
@ -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 )
|
||||||
|
|
23
src/util.h
23
src/util.h
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue