jamulus/src/util.cpp

383 lines
12 KiB
C++
Raw Normal View History

/******************************************************************************\
* Copyright (c) 2004-2006
*
* Author(s):
* Volker Fischer
*
******************************************************************************
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
\******************************************************************************/
#include "util.h"
/* Implementation *************************************************************/
/* Input level meter implementation ------------------------------------------ */
void CSignalLevelMeter::Update ( CVector<double>& vecdAudio )
{
/* Do the update for entire vector */
const int iVecSize = vecdAudio.Size ();
for ( int i = 0; i < iVecSize; i++ )
{
/* norm of current audio sample */
const double dCurSig = fabs ( vecdAudio[i] );
/* search for maximum. Decrease this max with time */
/* decrease max with time */
if ( dCurLevel >= METER_FLY_BACK )
{
dCurLevel *= 0.9999;
}
else
{
dCurLevel = 0;
}
/* search for max */
if ( dCurSig > dCurLevel )
{
dCurLevel = dCurSig;
}
}
}
double CSignalLevelMeter::MicLevel ()
{
const double dNormMicLevel = dCurLevel / _MAXSHORT;
/* logarithmic measure */
if ( dNormMicLevel > 0 )
{
return 20.0 * log10 ( dNormMicLevel );
}
else
{
return -100000.0; /* large negative value */
}
}
/* CRC ---------------------------------------------------------------------- */
void CCRC::Reset ()
{
/* Init state shift-register with ones. Set all registers to "1" with
bit-wise not operation */
iStateShiftReg = ~uint32_t ( 0 );
}
void CCRC::AddByte ( const uint8_t byNewInput )
{
for ( int i = 0; i < 8; i++ )
{
/* Shift bits in shift-register for transistion */
iStateShiftReg <<= 1;
/* Take bit, which was shifted out of the register-size and place it
at the beginning (LSB)
(If condition is not satisfied, implicitely a "0" is added) */
if ( ( iStateShiftReg & iBitOutMask) > 0 )
{
iStateShiftReg |= 1;
}
/* Add new data bit to the LSB */
if ( ( byNewInput & ( 1 << ( 8 - i - 1 ) ) ) > 0 )
{
iStateShiftReg ^= 1;
}
/* Add mask to shift-register if first bit is true */
if ( iStateShiftReg & 1 )
{
iStateShiftReg ^= iPoly;
}
}
}
uint32_t CCRC::GetCRC()
{
/* Return inverted shift-register (1's complement) */
iStateShiftReg = ~iStateShiftReg;
/* Remove bit which where shifted out of the shift-register frame */
return iStateShiftReg & ( iBitOutMask - 1 );
}
2006-01-28 12:29:22 +01:00
/******************************************************************************\
* Audio Reverberation *
\******************************************************************************/
/*
The following code is based on "JCRev: John Chowning's reverberator class"
by Perry R. Cook and Gary P. Scavone, 1995 - 2004
which is in "The Synthesis ToolKit in C++ (STK)"
http://ccrma.stanford.edu/software/stk
Original description:
This class is derived from the CLM JCRev function, which is based on the use
of networks of simple allpass and comb delay filters. This class implements
three series allpass units, followed by four parallel comb filters, and two
decorrelation delay lines in parallel at the output.
2006-01-28 12:29:22 +01:00
*/
2006-12-06 22:10:24 +01:00
CAudioReverb::CAudioReverb ( const double rT60 )
2006-01-28 12:29:22 +01:00
{
2006-12-06 22:10:24 +01:00
int delay, i;
/* Delay lengths for 44100 Hz sample rate */
2006-12-06 22:10:24 +01:00
int lengths[9] = { 1777, 1847, 1993, 2137, 389, 127, 43, 211, 179 };
const double scaler = (double) SAMPLE_RATE / 44100.0;
2006-01-28 12:29:22 +01:00
2006-12-06 22:10:24 +01:00
if ( scaler != 1.0 )
{
2006-12-06 22:10:24 +01:00
for ( i = 0; i < 9; i++ )
{
2006-12-06 22:10:24 +01:00
delay = (int) floor ( scaler * lengths[i] );
2006-01-28 12:29:22 +01:00
2006-12-06 22:10:24 +01:00
if ( ( delay & 1 ) == 0 )
{
delay++;
2006-12-06 22:10:24 +01:00
}
2006-01-28 12:29:22 +01:00
2006-12-06 22:10:24 +01:00
while ( !isPrime ( delay ) )
{
delay += 2;
2006-12-06 22:10:24 +01:00
}
2006-01-28 12:29:22 +01:00
lengths[i] = delay;
}
}
2006-01-28 12:29:22 +01:00
2006-12-06 22:10:24 +01:00
for ( i = 0; i < 3; i++ )
{
allpassDelays_[i].Init ( lengths[i + 4] );
}
2006-01-28 12:29:22 +01:00
2006-12-06 22:10:24 +01:00
for ( i = 0; i < 4; i++ )
{
combDelays_[i].Init ( lengths[i] );
}
2006-01-28 12:29:22 +01:00
2006-12-06 22:10:24 +01:00
setT60 ( rT60 );
allpassCoefficient_ = (double) 0.7;
Clear();
2006-01-28 12:29:22 +01:00
}
2006-12-06 22:10:24 +01:00
bool CAudioReverb::isPrime ( const int number )
2006-01-28 12:29:22 +01:00
{
/*
Returns true if argument value is prime. Taken from "class Effect" in
"STK abstract effects parent class".
2006-01-28 12:29:22 +01:00
*/
2006-12-06 22:10:24 +01:00
if ( number == 2 )
{
return true;
2006-12-06 22:10:24 +01:00
}
2006-12-06 22:10:24 +01:00
if ( number & 1 )
{
2006-12-06 22:10:24 +01:00
for ( int i = 3; i < (int) sqrt ( (double) number ) + 1; i += 2 )
{
2006-12-06 22:10:24 +01:00
if ( ( number % i ) == 0 )
{
return false;
2006-12-06 22:10:24 +01:00
}
}
2006-12-06 22:10:24 +01:00
return true; // prime
}
else
2006-12-06 22:10:24 +01:00
{
return false; // even
}
2006-01-28 12:29:22 +01:00
}
void CAudioReverb::Clear()
{
2006-12-06 22:10:24 +01:00
// reset and clear all internal state
allpassDelays_[0].Reset ( 0 );
allpassDelays_[1].Reset ( 0 );
allpassDelays_[2].Reset ( 0 );
combDelays_[0].Reset ( 0 );
combDelays_[1].Reset ( 0 );
combDelays_[2].Reset ( 0 );
combDelays_[3].Reset ( 0 );
2006-01-28 12:29:22 +01:00
}
2006-12-06 22:10:24 +01:00
void CAudioReverb::setT60 ( const double rT60 )
2006-01-28 12:29:22 +01:00
{
2006-12-06 22:10:24 +01:00
// set the reverberation T60 decay time
for ( int i = 0; i < 4; i++ )
{
2006-12-06 22:10:24 +01:00
combCoefficient_[i] = pow ( (double) 10.0, (double) ( -3.0 *
combDelays_[i].Size() / ( rT60 * SAMPLE_RATE ) ) );
}
2006-01-28 12:29:22 +01:00
}
2006-12-06 22:10:24 +01:00
double CAudioReverb::ProcessSample ( const double input )
2006-01-28 12:29:22 +01:00
{
2006-12-06 22:10:24 +01:00
// compute one output sample
double temp, temp0, temp1, temp2;
temp = allpassDelays_[0].Get();
temp0 = allpassCoefficient_ * temp;
temp0 += input;
2006-12-06 22:10:24 +01:00
allpassDelays_[0].Add ( (int) temp0 );
temp0 = - ( allpassCoefficient_ * temp0 ) + temp;
temp = allpassDelays_[1].Get();
temp1 = allpassCoefficient_ * temp;
temp1 += temp0;
2006-12-06 22:10:24 +01:00
allpassDelays_[1].Add ( (int) temp1 );
temp1 = - ( allpassCoefficient_ * temp1 ) + temp;
temp = allpassDelays_[2].Get();
temp2 = allpassCoefficient_ * temp;
temp2 += temp1;
2006-12-06 22:10:24 +01:00
allpassDelays_[2].Add ( (int) temp2 );
temp2 = - ( allpassCoefficient_ * temp2 ) + temp;
2006-12-06 22:10:24 +01:00
const double temp3 = temp2 + ( combCoefficient_[0] * combDelays_[0].Get() );
const double temp4 = temp2 + ( combCoefficient_[1] * combDelays_[1].Get() );
const double temp5 = temp2 + ( combCoefficient_[2] * combDelays_[2].Get() );
const double temp6 = temp2 + ( combCoefficient_[3] * combDelays_[3].Get() );
2006-12-06 22:10:24 +01:00
combDelays_[0].Add ( (int) temp3 );
combDelays_[1].Add ( (int) temp4 );
combDelays_[2].Add ( (int) temp5 );
combDelays_[3].Add ( (int) temp6 );
2006-12-06 22:10:24 +01:00
return ( temp3 + temp4 + temp5 + temp6 ) * (double) 0.5;
2006-01-28 12:29:22 +01:00
}
/******************************************************************************\
* GUI utilities *
\******************************************************************************/
/* About dialog ------------------------------------------------------------- */
CAboutDlg::CAboutDlg(QWidget* parent, const char* name, bool modal, WFlags f)
: CAboutDlgBase(parent, name, modal, f)
2006-01-28 12:29:22 +01:00
{
/* Set the text for the about dialog html text control */
TextViewCredits->setText(
"<p>" /* General description of llcon software */
"<big><b>llcon</b> " + tr("Client/Server communication tool to enable "
"musician to play together through a conventional broadband internet "
"connection (like DSL).") + "</big>"
"</p><br>"
"<p><font face=\"courier\">" /* GPL header text */
"This program is free software; you can redistribute it and/or modify "
"it under the terms of the GNU General Public License as published by "
"the Free Software Foundation; either version 2 of the License, or "
"(at your option) any later version.<br>This program is distributed in "
"the hope that it will be useful, but WITHOUT ANY WARRANTY; without "
"even the implied warranty of MERCHANTABILITY or FITNESS FOR A "
"PARTICULAR PURPOSE. See the GNU General Public License for more "
"details.<br>You should have received a copy of the GNU General Public "
"License along with his program; if not, write to the Free Software "
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 "
"USA"
"</font></p><br>"
"<p>" /* Libraries used by this compilation of Dream */
"<b>" + tr("llcon uses the following libraries or code snippets:") +
"</b></p>"
"<ul>"
"<li>audio reverberation code: by Perry R. Cook and Gary P. Scavone, "
"1995 - 2004 (taken from \"The Synthesis ToolKit in C++ (STK)\")</li>"
"<li>IMA-ADPCM: by Erik de Castro Lopo</li>"
"<li>INI File Tools (STLINI): Robert Kesterson in 1999</li>"
"<li>Parts from Dream DRM Receiver by Volker Fischer and Alexander "
"Kurpiers</li>"
"</ul>"
"</center><br>");
/* Set version number in about dialog */
TextLabelVersion->setText(GetVersionAndNameStr());
2006-02-18 13:19:27 +01:00
}
QString CAboutDlg::GetVersionAndNameStr ( const bool bWithHtml )
2006-02-18 13:19:27 +01:00
{
QString strVersionText = "";
// name, short description and GPL hint
if ( bWithHtml )
{
strVersionText += "<center><b>";
}
strVersionText += tr("llcon, Version ") + VERSION;
if ( bWithHtml )
{
strVersionText += "</b><br>";
}
else
{
strVersionText += "\n";
}
strVersionText += tr("llcon, Low-Latency (internet) CONnection");
if ( bWithHtml )
{
strVersionText += "<br>";
}
else
{
strVersionText += "\n";
}
strVersionText += tr("Under the GNU General Public License (GPL)");
if ( bWithHtml )
{
strVersionText += "</center>";
}
return strVersionText;
2006-01-28 12:29:22 +01:00
}
/* Help menu ---------------------------------------------------------------- */
CLlconHelpMenu::CLlconHelpMenu ( QWidget* parent ) : QPopupMenu ( parent )
{
/* Standard help menu consists of about and what's this help */
insertItem ( tr ( "What's &This" ), this ,
SLOT ( OnHelpWhatsThis () ), SHIFT+Key_F1 );
insertSeparator();
insertItem ( tr ( "&About..." ), this, SLOT ( OnHelpAbout () ) );
2006-01-28 12:29:22 +01:00
}
/******************************************************************************\
* Global functions implementation *
\******************************************************************************/
void DebugError(const char* pchErDescr, const char* pchPar1Descr,
const double dPar1, const char* pchPar2Descr,
const double dPar2)
{
FILE* pFile = fopen("DebugError.dat", "a");
fprintf(pFile, pchErDescr); fprintf(pFile, " ### ");
fprintf(pFile, pchPar1Descr); fprintf(pFile, ": ");
fprintf(pFile, "%e ### ", dPar1);
fprintf(pFile, pchPar2Descr); fprintf(pFile, ": ");
fprintf(pFile, "%e\n", dPar2);
fclose(pFile);
printf("\nDebug error! For more information see test/DebugError.dat\n");
exit(1);
}