some cleanup and preperations for callback based audio interface

This commit is contained in:
Volker Fischer 2009-02-21 17:37:15 +00:00
parent 5917ead5e6
commit 71598931e2
3 changed files with 199 additions and 183 deletions

View file

@ -170,6 +170,101 @@ void CClient::OnProtocolStatus ( bool bOk )
} }
} }
void CClient::Start()
{
// init object
try
{
Init();
}
catch ( CGenErr generr )
{
// TODO better error management -> should be catched in main thread
// problem: how to catch errors in a different thread...?
// quick hack solution
QMessageBox::critical ( 0, APP_NAME, generr.GetErrorText(), "Quit", 0 );
exit ( 0 );
}
// enable channel
Channel.SetEnable ( true );
// start the audio working thread with hightest possible priority
start ( QThread::TimeCriticalPriority );
}
void CClient::Stop()
{
// set flag so that thread can leave the main loop
bRun = false;
// give thread some time to terminate
wait ( 5000 );
// disable channel
Channel.SetEnable ( false );
// disable sound interface
Sound.Close();
// reset current signal level and LEDs
SignalLevelMeter.Reset();
PostWinMessage ( MS_RESET_ALL, 0 );
}
void CClient::run()
{
// Set thread priority (The working thread should have a higher
// priority than the GUI)
#ifdef _WIN32
SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
#else
/*
// set the process to realtime privs, taken from
// "http://www.gardena.net/benno/linux/audio" but does not seem to work,
// maybe a problem with user rights
struct sched_param schp;
memset ( &schp, 0, sizeof ( schp ) );
schp.sched_priority = sched_get_priority_max ( SCHED_FIFO );
sched_setscheduler ( 0, SCHED_FIFO, &schp );
*/
#endif
// main loop of working thread
bRun = true;
while ( bRun )
{
// get audio from sound card (blocking function)
if ( Sound.Read ( vecsAudioSndCrdStereo ) )
{
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED );
}
else
{
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN );
}
// process audio data
ProcessAudioData ( vecsAudioSndCrdStereo );
// play the new block
if ( Sound.Write ( vecsAudioSndCrdStereo ) )
{
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED );
}
else
{
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN );
}
}
}
void CClient::Init() void CClient::Init()
{ {
// set block size (in samples) // set block size (in samples)
@ -205,65 +300,14 @@ void CClient::Init()
AudioReverb.Clear(); AudioReverb.Clear();
} }
void CClient::run() void CClient::ProcessAudioData ( CVector<short>& vecsStereoSndCrd )
{ {
int i, j; int i, j;
// Set thread priority (The working thread should have a higher
// priority than the GUI)
#ifdef _WIN32
SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
#else
/*
// set the process to realtime privs, taken from
// "http://www.gardena.net/benno/linux/audio" but does not seem to work,
// maybe a problem with user rights
struct sched_param schp;
memset ( &schp, 0, sizeof ( schp ) );
schp.sched_priority = sched_get_priority_max ( SCHED_FIFO );
sched_setscheduler ( 0, SCHED_FIFO, &schp );
*/
#endif
// init object
try
{
Init();
}
catch ( CGenErr generr )
{
// TODO better error management -> should be catched in main thread
// problem: how to catch errors in a different thread...?
// quick hack solution
QMessageBox::critical ( 0, APP_NAME, generr.GetErrorText(), "Quit", 0 );
exit ( 0 );
}
// runtime phase -----------------------------------------------------------
// enable channel
Channel.SetEnable ( true );
bRun = true;
// main loop of working thread
while ( bRun )
{
// get audio from sound card (blocking function)
if ( Sound.Read ( vecsAudioSndCrdStereo ) )
{
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED );
}
else
{
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN );
}
// convert data from short to double // convert data from short to double
for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ ) for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ )
{ {
vecdAudioSndCrdStereo[i] = (double) vecsAudioSndCrdStereo[i]; vecdAudioSndCrdStereo[i] = (double) vecsStereoSndCrd[i];
} }
// resample data for each channel seaparately // resample data for each channel seaparately
@ -356,8 +400,8 @@ static FILE* pFileDelay = fopen("v.dat", "wb");
short sData[2]; short sData[2];
for (i = 0; i < iMonoBlockSizeSam; 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);
} }
fflush(pFileDelay); fflush(pFileDelay);
*/ */
@ -372,49 +416,19 @@ fflush(pFileDelay);
// received data in both sound card channels // received data in both sound card channels
for ( i = 0, j = 0; i < iSndCrdMonoBlockSizeSam; i++, j += 2 ) for ( i = 0, j = 0; i < iSndCrdMonoBlockSizeSam; i++, j += 2 )
{ {
vecsAudioSndCrdStereo[j] = vecsAudioSndCrdStereo[j + 1] = vecsStereoSndCrd[j] = vecsStereoSndCrd[j + 1] =
Double2Short ( vecdAudioSndCrdMono[i] ); Double2Short ( vecdAudioSndCrdMono[i] );
} }
} }
else else
{ {
// if not connected, clear data // if not connected, clear data
vecsAudioSndCrdStereo.Reset ( 0 ); vecsStereoSndCrd.Reset ( 0 );
}
// play the new block
if ( Sound.Write ( vecsAudioSndCrdStereo ) )
{
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED );
}
else
{
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN );
} }
// update response time measurement and socket buffer size // update response time measurement and socket buffer size
UpdateTimeResponseMeasurement(); UpdateTimeResponseMeasurement();
UpdateSocketBufferSize(); UpdateSocketBufferSize();
}
// disable channel
Channel.SetEnable ( false );
// disable sound interface
Sound.Close();
// reset current signal level and LEDs
SignalLevelMeter.Reset();
PostWinMessage ( MS_RESET_ALL, 0 );
}
bool CClient::Stop()
{
// set flag so that thread can leave the main loop
bRun = false;
// give thread some time to terminate, return status
return wait ( 5000 );
} }
void CClient::UpdateTimeResponseMeasurement() void CClient::UpdateTimeResponseMeasurement()

View file

@ -66,8 +66,8 @@ public:
CClient ( const quint16 iPortNumber ); CClient ( const quint16 iPortNumber );
virtual ~CClient() {} virtual ~CClient() {}
void Init(); void Start();
bool Stop(); void Stop();
bool IsRunning() { return bRun; } bool IsRunning() { return bRun; }
bool SetServerAddr ( QString strNAddr ); bool SetServerAddr ( QString strNAddr );
double MicLevelL() { return SignalLevelMeter.MicLevelLeft(); } double MicLevelL() { return SignalLevelMeter.MicLevelLeft(); }
@ -149,7 +149,9 @@ public:
QString strName; QString strName;
protected: protected:
void Init();
virtual void run(); virtual void run();
void ProcessAudioData ( CVector<short>& vecsStereoSndCrd );
void UpdateTimeResponseMeasurement(); void UpdateTimeResponseMeasurement();
void UpdateSocketBufferSize(); void UpdateSocketBufferSize();

View file

@ -267,28 +267,12 @@ void CLlconClientDlg::OnSliderAudInFader ( int value )
void CLlconClientDlg::OnConnectDisconBut() void CLlconClientDlg::OnConnectDisconBut()
{ {
// start/stop client, set button text // start/stop client, set button text
if ( pClient->IsRunning() ) if ( !pClient->IsRunning() )
{
pClient->Stop();
PushButtonConnect->setText ( CON_BUT_CONNECTTEXT );
// stop timer for level meter bars and reset them
TimerSigMet.stop();
ProgressBarInputLevelL->setValue ( 0 );
ProgressBarInputLevelR->setValue ( 0 );
// immediately update status bar
OnTimerStatus();
// clear mixer board (remove all faders)
MainMixerBoard->HideAll();
}
else
{ {
// set address and check if address is valid // set address and check if address is valid
if ( pClient->SetServerAddr ( LineEditServerAddr->text() ) ) if ( pClient->SetServerAddr ( LineEditServerAddr->text() ) )
{ {
pClient->start ( QThread::TimeCriticalPriority ); pClient->Start();
PushButtonConnect->setText ( CON_BUT_DISCONNECTTEXT ); PushButtonConnect->setText ( CON_BUT_DISCONNECTTEXT );
@ -305,6 +289,22 @@ void CLlconClientDlg::OnConnectDisconBut()
TextLabelStatus->setText ( tr ( "invalid address" ) ); TextLabelStatus->setText ( tr ( "invalid address" ) );
} }
} }
else
{
pClient->Stop();
PushButtonConnect->setText ( CON_BUT_CONNECTTEXT );
// stop timer for level meter bars and reset them
TimerSigMet.stop();
ProgressBarInputLevelL->setValue ( 0 );
ProgressBarInputLevelR->setValue ( 0 );
// immediately update status bar
OnTimerStatus();
// clear mixer board (remove all faders)
MainMixerBoard->HideAll();
}
} }
void CLlconClientDlg::OnOpenGeneralSettings() void CLlconClientDlg::OnOpenGeneralSettings()