From 3fb2d9ca5eda4a469fd048a8eb5cacef8805ce15 Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Sun, 22 Feb 2009 23:13:59 +0000 Subject: [PATCH] added soundbase class --- linux/Makefile.am | 2 + linux/sound.h | 36 ++++++++-------- src/client.cpp | 88 ++++++--------------------------------- src/client.h | 11 ++--- src/soundbase.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/soundbase.h | 66 +++++++++++++++++++++++++++++ windows/llcon.vcproj | 10 ++++- windows/sound.cpp | 4 +- windows/sound.h | 30 +++++++------- 9 files changed, 233 insertions(+), 112 deletions(-) create mode 100755 src/soundbase.cpp create mode 100755 src/soundbase.h diff --git a/linux/Makefile.am b/linux/Makefile.am index 06f551e2..89a267a9 100755 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -18,6 +18,7 @@ llcon_SOURCES = ../src/buffer.cpp \ ../src/protocol.cpp \ ../src/multicolorled.cpp \ ../src/audiomixerboard.cpp \ + ../src/soundbase.cpp \ sound.cpp \ ../src/buffer.h \ ../src/global.h \ @@ -33,6 +34,7 @@ llcon_SOURCES = ../src/buffer.cpp \ ../src/protocol.h \ ../src/multicolorled.h \ ../src/audiomixerboard.h \ + ../src/soundbase.h \ ../src/llconserverdlg.h \ ../src/chatdlg.h \ ../src/llconclientdlg.h \ diff --git a/linux/sound.h b/linux/sound.h index de47cc97..1da1ae7d 100755 --- a/linux/sound.h +++ b/linux/sound.h @@ -18,9 +18,10 @@ #include #include #include - +#include #include #include "util.h" +#include "soundbase.h" #include "global.h" #if WITH_SOUND @@ -40,22 +41,25 @@ #define MAX_SND_BUF_IN 200 #define MAX_SND_BUF_OUT 200 + /* Classes ********************************************************************/ -class CSound +class CSound : public CSoundBase { public: - CSound ( const int iNewBufferSizeStereo ) + CSound ( const int iNewStereoBufferSize, + void (*fpNewCallback) ( CVector& psData, void* arg ), void* arg ) : #if WITH_SOUND - : rhandle ( NULL ), phandle ( NULL ), iCurPeriodSizeIn ( NUM_PERIOD_BLOCKS_IN ), + CSoundBase ( iNewStereoBufferSize, fpNewCallback, arg ), rhandle ( NULL ), + phandle ( NULL ), iCurPeriodSizeIn ( NUM_PERIOD_BLOCKS_IN ), iCurPeriodSizeOut ( NUM_PERIOD_BLOCKS_OUT ), bChangParamIn ( true ), bChangParamOut ( true ) { // set internal buffer size for read and write - iBufferSizeIn = iNewBufferSizeStereo / NUM_IN_OUT_CHANNELS; // mono size - iBufferSizeOut = iNewBufferSizeStereo / NUM_IN_OUT_CHANNELS; // mono size + iBufferSizeIn = iNewStereoBufferSize / NUM_IN_OUT_CHANNELS; // mono size + iBufferSizeOut = iNewStereoBufferSize / NUM_IN_OUT_CHANNELS; // mono size } #else - {} + CSoundBase ( iNewStereoBufferSize, fpNewCallback, arg ) {} #endif virtual ~CSound() { Close(); } @@ -70,10 +74,11 @@ public: int GetInNumBuf() { return iCurPeriodSizeIn; } void SetOutNumBuf ( int iNewNum ); int GetOutNumBuf() { return iCurPeriodSizeOut; } - void InitRecording ( const bool bNewBlocking = true ); - void InitPlayback ( const bool bNewBlocking = false ); - bool Read ( CVector& psData ); - bool Write ( CVector& psData ); + virtual void InitRecording ( const bool bNewBlocking = true ); + virtual void InitPlayback ( const bool bNewBlocking = false ); + + virtual bool Read ( CVector& psData ); + virtual bool Write ( CVector& psData ); void Close(); @@ -96,13 +101,12 @@ protected: int GetInNumBuf() { return 1; } void SetOutNumBuf ( int iNewNum ) {} int GetOutNumBuf() { return 1; } - void InitRecording ( const bool bNewBlocking = true ) { printf ( "no sound!" ); } - void InitPlayback ( const bool bNewBlocking = false ) { printf ( "no sound!" ); } - bool Read ( CVector& psData ) { printf ( "no sound!" ); return false; } - bool Write ( CVector& psData ) { printf ( "no sound!" ); return false; } + virtual void InitRecording ( const bool bNewBlocking = true ) { printf ( "no sound!" ); } + virtual void InitPlayback ( const bool bNewBlocking = false ) { printf ( "no sound!" ); } + virtual bool Read ( CVector& psData ) { printf ( "no sound!" ); return false; } + virtual bool Write ( CVector& psData ) { printf ( "no sound!" ); return false; } void Close() {} #endif }; - #endif // !defined(_SOUND_H__9518A621345F78_3634567_8C0D_EEBF182CF549__INCLUDED_) diff --git a/src/client.cpp b/src/client.cpp index 37567ab8..8f3cdc19 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -26,10 +26,10 @@ /* Implementation *************************************************************/ -CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ), +CClient::CClient ( const quint16 iPortNumber ) : 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 */, AudioCallback, this ), Socket ( &Channel, iPortNumber ), iAudioInFader ( AUD_FADER_IN_MIDDLE ), iReverbLevel ( 0 ), @@ -173,98 +173,37 @@ 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 ); - } + Init(); // enable channel Channel.SetEnable ( true ); - // start the audio working thread with hightest possible priority - start ( QThread::TimeCriticalPriority ); + // start audio interface + Sound.Start(); } 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(); + // stop audio interface + Sound.Stop(); // reset current signal level and LEDs SignalLevelMeter.Reset(); PostWinMessage ( MS_RESET_ALL, 0 ); } -void CClient::run() +void CClient::AudioCallback ( CVector& psData, void* arg ) { - // 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 + // get the pointer to the object + CClient* pMyClientObj = reinterpret_cast ( arg ); - // 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 ); - } - } + // process audio data + pMyClientObj->ProcessAudioData ( psData ); } - - - - - void CClient::Init() { // set block size (in samples) @@ -277,8 +216,7 @@ void CClient::Init() vecdAudioStereo.Init ( iStereoBlockSizeSam ); - Sound.InitRecording(); - Sound.InitPlayback(); + Sound.Init(); // resample objects are always initialized with the input block size // record diff --git a/src/client.h b/src/client.h index 1ccdad51..d5e25986 100755 --- a/src/client.h +++ b/src/client.h @@ -25,7 +25,7 @@ #if !defined ( CLIENT_HOIHGE76GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) #define CLIENT_HOIHGE76GEKJH98_3_43445KJIUHF1912__INCLUDED_ -#include +#include #include #include #include @@ -58,7 +58,7 @@ /* Classes ********************************************************************/ -class CClient : public QThread +class CClient : public QObject { Q_OBJECT @@ -68,7 +68,7 @@ public: void Start(); void Stop(); - bool IsRunning() { return bRun; } + bool IsRunning() { return Sound.IsRunning(); } bool SetServerAddr ( QString strNAddr ); double MicLevelL() { return SignalLevelMeter.MicLevelLeft(); } double MicLevelR() { return SignalLevelMeter.MicLevelRight(); } @@ -149,8 +149,10 @@ public: QString strName; protected: + // callback function must be static, otherwise it does not work + static void AudioCallback ( CVector& psData, void* arg ); + void Init(); - virtual void run(); void ProcessAudioData ( CVector& vecsStereoSndCrd ); void UpdateTimeResponseMeasurement(); void UpdateSocketBufferSize(); @@ -163,7 +165,6 @@ protected: CSound Sound; CStereoSignalLevelMeter SignalLevelMeter; - bool bRun; CVector vecdNetwData; int iAudioInFader; diff --git a/src/soundbase.cpp b/src/soundbase.cpp new file mode 100755 index 00000000..0c206f4c --- /dev/null +++ b/src/soundbase.cpp @@ -0,0 +1,98 @@ +/******************************************************************************\ + * Copyright (c) 2004-2009 + * + * 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 "soundbase.h" + + +/* Implementation *************************************************************/ +void CSoundBase::Init() +{ + InitRecording(); + InitPlayback(); +} + +void CSoundBase::Start() +{ + // start the audio thread + start(); +} + +void CSoundBase::Stop() +{ + // set flag so that thread can leave the main loop + bRun = false; + + // give thread some time to terminate + wait ( 5000 ); +} + +void CSoundBase::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 ) + { +// TEST +CVector vecsAudioSndCrdStereo ( iStereoBufferSize ); + + // get audio from sound card (blocking function) + if ( Read ( vecsAudioSndCrdStereo ) ) + { + PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED ); + } + else + { + PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN ); + } + + // process audio data + (*fpCallback) ( vecsAudioSndCrdStereo, pCallbackArg ); + + // play the new block + if ( Write ( vecsAudioSndCrdStereo ) ) + { + PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED ); + } + else + { + PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN ); + } + } +} diff --git a/src/soundbase.h b/src/soundbase.h new file mode 100755 index 00000000..656e2c58 --- /dev/null +++ b/src/soundbase.h @@ -0,0 +1,66 @@ +/******************************************************************************\ + * Copyright (c) 2004-2009 + * + * 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 + * +\******************************************************************************/ + +#if !defined ( SOUNDBASE_HOIHGEH8_3_4344456456345634565KJIUHF1912__INCLUDED_ ) +#define SOUNDBASE_HOIHGEH8_3_4344456456345634565KJIUHF1912__INCLUDED_ + +#include +#include "global.h" +#include "util.h" + + +/* Classes ********************************************************************/ +class CSoundBase : public QThread +{ +public: + CSoundBase ( const int iNewStereoBufferSize, + void (*fpNewCallback) ( CVector& psData, void* arg ), + void* arg ) : iStereoBufferSize ( iNewStereoBufferSize ), + fpCallback ( fpNewCallback ), pCallbackArg ( arg ), bRun ( false ) {} + virtual ~CSoundBase() {} + + virtual void Init(); + virtual void Start(); + virtual void Stop(); + bool IsRunning() const { return bRun; } + +protected: + // function pointer to callback function + void (*fpCallback) ( CVector& psData, void* arg ); + void* pCallbackArg; + + // these functions should be overwritten by derived class for + // non callback based audio interfaces + virtual bool Read ( CVector& psData ) { printf ( "no sound!" ); return false; } + virtual bool Write ( CVector& psData ) { printf ( "no sound!" ); return false; } + virtual void InitRecording ( const bool bNewBlocking = true ) = 0; + virtual void InitPlayback ( const bool bNewBlocking = false ) = 0; + + void run(); + bool bRun; + + int iStereoBufferSize; +}; + +#endif /* !defined ( SOUNDBASE_HOIHGEH8_3_4344456456345634565KJIUHF1912__INCLUDED_ ) */ diff --git a/windows/llcon.vcproj b/windows/llcon.vcproj index b8ded784..3d8de999 100755 --- a/windows/llcon.vcproj +++ b/windows/llcon.vcproj @@ -1,7 +1,7 @@ + + @@ -994,6 +998,10 @@ RelativePath="sound.h" > + + diff --git a/windows/sound.cpp b/windows/sound.cpp index 3d2e040f..f90236ac 100755 --- a/windows/sound.cpp +++ b/windows/sound.cpp @@ -681,7 +681,9 @@ void CSound::Close() bChangParamOut = true; } -CSound::CSound ( const int iNewBufferSizeStereo ) +CSound::CSound ( const int iNewBufferSizeStereo, + void (*fpNewCallback) ( CVector& psData, void* arg ), void* arg ) : + CSoundBase ( iNewBufferSizeStereo, fpNewCallback, arg ) { // set internal buffer size value and calculate mono buffer size iBufferSizeStereo = iNewBufferSizeStereo; diff --git a/windows/sound.h b/windows/sound.h index 10f1af8c..14242549 100755 --- a/windows/sound.h +++ b/windows/sound.h @@ -31,6 +31,7 @@ #include #include "../src/util.h" #include "../src/global.h" +#include "../src/soundbase.h" // copy the ASIO SDK in the llcon/windows directory: "llcon/windows/ASIOSDK2" to // get it work @@ -51,24 +52,25 @@ /* Classes ********************************************************************/ -class CSound +class CSound : public CSoundBase { public: - CSound ( const int iNewBufferSizeStereo ); + CSound ( const int iNewBufferSizeStereo, + void (*fpNewCallback) ( CVector& psData, void* arg ), void* arg ); virtual ~CSound(); - void InitRecording ( const bool bNewBlocking = true ) - { - bBlockingRec = bNewBlocking; - InitRecordingAndPlayback(); - } - void InitPlayback ( const bool bNewBlocking = false ) - { - bBlockingPlay = bNewBlocking; - InitRecordingAndPlayback(); - } - bool Read ( CVector& psData ); - bool Write ( CVector& psData ); + virtual void InitRecording ( const bool bNewBlocking = true ) + { + bBlockingRec = bNewBlocking; + InitRecordingAndPlayback(); + } + virtual void InitPlayback ( const bool bNewBlocking = false ) + { + bBlockingPlay = bNewBlocking; + InitRecordingAndPlayback(); + } + virtual bool Read ( CVector& psData ); + virtual bool Write ( CVector& psData ); int GetNumDev() { return lNumDevs; } std::string GetDeviceName ( const int iDiD ) { return cDriverNames[iDiD]; }