some more work for moving functions from the Windows sound interface to the sound base class

This commit is contained in:
Volker Fischer 2011-10-18 20:04:56 +00:00
parent a8795c1bf3
commit 8720c40db6
8 changed files with 1200 additions and 1177 deletions

View file

@ -1,3 +1,11 @@
3.2.1
TODO working on bug fix: Windows: driver is changed during connection results
sometimes in lowed noise
3.2.0
- new GUI style of the main window, added switch for selecting the GUI style

View file

@ -59,18 +59,14 @@ class CSound : public CSoundBase
{
public:
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ), void* arg ) :
CSoundBase ( true, fpNewProcessCallback, arg ), iJACKBufferSizeMono ( 0 ),
CSoundBase ( "Jack", true, fpNewProcessCallback, arg ), iJACKBufferSizeMono ( 0 ),
iJACKBufferSizeStero ( 0 ) { OpenJack(); }
virtual ~CSound() { CloseJack(); }
virtual int Init ( const int iNewPrefMonoBufferSize );
virtual int Init ( const int iNewPrefMonoBufferSize );
virtual void Start();
virtual void Stop();
// device cannot be set under Linux
virtual int GetNumDev() { return 1; }
virtual QString GetDeviceName ( const int ) { return "Jack"; }
// these variables should be protected but cannot since we want
// to access them from the callback function
CVector<short> vecsTmpAudioSndCrdStereo;

View file

@ -38,17 +38,13 @@ class CSound : public CSoundBase
{
public:
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ), void* arg ) :
CSoundBase ( true, fpNewProcessCallback, arg ) { OpenCoreAudio(); }
CSoundBase ( "CoreAudio", true, fpNewProcessCallback, arg ) { OpenCoreAudio(); }
virtual ~CSound() { CloseCoreAudio(); }
virtual int Init ( const int iNewPrefMonoBufferSize );
virtual void Start();
virtual void Stop();
// device cannot be set under MacOS
virtual int GetNumDev() { return 1; }
virtual QString GetDeviceName ( const int ) { return "Core Audio"; }
// these variables should be protected but cannot since we want
// to access them from the callback function
CVector<short> vecsTmpAudioSndCrdStereo;

View file

@ -455,6 +455,18 @@ void CClient::OnSndCrdReinitRequest()
// reinit the driver (we use the currently selected driver) and
// init client object, too
// TODO possible bug: In ASIO driver if set dev is called, the driver is
// unloaded. See ASIO manual: "Note: A host application has to defer
// processing of these notification to a later "secure" time as the
// driver has finish its processing of the notification. Especially on
// the kAsioResetRequest it is a bad idea to unload the driver during
// the asioMessage callback since the callback has to return back into
// the driver, which is no longer present."
// TODO write separate driver reset function in sound base instead
// of doing setdev with the old driver ID -> avoid unloading driver
Sound.SetDev ( Sound.GetDev() );
Init();

View file

@ -26,16 +26,18 @@
/* Implementation *************************************************************/
CSoundBase::CSoundBase ( const bool bNewIsCallbackAudioInterface,
CSoundBase::CSoundBase ( const QString& strNewSystemDriverTechniqueName,
const bool bNewIsCallbackAudioInterface,
void (*fpNewProcessCallback) ( CVector<int16_t>& psData, void* pParg ),
void* pParg ) :
fpProcessCallback ( fpNewProcessCallback ),
pProcessCallbackArg ( pParg ), bRun ( false ),
bIsCallbackAudioInterface ( bNewIsCallbackAudioInterface )
bIsCallbackAudioInterface ( bNewIsCallbackAudioInterface ),
strSystemDriverTechniqueName ( strNewSystemDriverTechniqueName )
{
// initializations for the sound card names (default)
lNumDevs = 1;
strDriverNames[0] = "Default";
strDriverNames[0] = strSystemDriverTechniqueName;
// set current device
lCurDev = 0; // default device
@ -123,3 +125,139 @@ void CSoundBase::run()
}
}
}
/******************************************************************************\
* Device handling *
\******************************************************************************/
QString CSoundBase::SetDev ( const int iNewDev )
{
QString strReturn = ""; // init with no error
bool bTryLoadAnyDriver = false;
// check if an ASIO driver was already initialized
if ( lCurDev >= 0 )
{
// a device was already been initialized and is used, first clean up
// driver
UnloadCurrentDriver();
const QString strErrorMessage = LoadAndInitializeDriver ( iNewDev );
if ( !strErrorMessage.isEmpty() )
{
if ( iNewDev != lCurDev )
{
// loading and initializing the new driver failed, go back to
// original driver and display error message
LoadAndInitializeDriver ( lCurDev );
}
else
{
// the same driver is used but the driver properties seems to
// have changed so that they are not compatible to our
// software anymore
QMessageBox::critical (
0, APP_NAME, QString ( tr ( "The audio driver properties "
"have changed to a state which is incompatible to this "
"software. The selected audio device could not be used "
"because of the following error: <b>" ) ) +
strErrorMessage +
QString ( tr ( "</b><br><br>Please restart the software." ) ),
"Close", 0 );
_exit ( 0 );
}
// store error return message
strReturn = strErrorMessage;
}
}
else
{
if ( iNewDev != INVALID_SNC_CARD_DEVICE )
{
// This is the first time a driver is to be initialized, we first
// try to load the selected driver, if this fails, we try to load
// the first available driver in the system. If this fails, too, we
// throw an error that no driver is available -> it does not make
// sense to start the llcon software if no audio hardware is
// available.
if ( !LoadAndInitializeDriver ( iNewDev ).isEmpty() )
{
// loading and initializing the new driver failed, try to find
// at least one usable driver
bTryLoadAnyDriver = true;
}
}
else
{
// try to find one usable driver (select the first valid driver)
bTryLoadAnyDriver = true;
}
}
if ( bTryLoadAnyDriver )
{
// try to load and initialize any valid driver
QVector<QString> vsErrorList =
LoadAndInitializeFirstValidDriver();
if ( !vsErrorList.isEmpty() )
{
// create error message with all details
QString sErrorMessage = tr ( "<b>No usable " ) +
strSystemDriverTechniqueName + tr ( " audio device "
"(driver) found.</b><br><br>"
"In the following there is a list of all available drivers "
"with the associated error message:<ul>" );
for ( int i = 0; i < lNumDevs; i++ )
{
sErrorMessage += "<li><b>" + GetDeviceName ( i ) + "</b>: " +
vsErrorList[i] + "</li>";
}
sErrorMessage += "</ul>";
throw CGenErr ( sErrorMessage );
}
}
return strReturn;
}
QVector<QString> CSoundBase::LoadAndInitializeFirstValidDriver()
{
QVector<QString> vsErrorList;
// load and initialize first valid ASIO driver
bool bValidDriverDetected = false;
int iCurDriverIdx = 0;
// try all available drivers in the system ("lNumDevs" devices)
while ( !bValidDriverDetected && ( iCurDriverIdx < lNumDevs ) )
{
// try to load and initialize current driver, store error message
const QString strCurError =
LoadAndInitializeDriver ( iCurDriverIdx );
vsErrorList.append ( strCurError );
if ( strCurError.isEmpty() )
{
// initialization was successful
bValidDriverDetected = true;
// store ID of selected driver
lCurDev = iCurDriverIdx;
// empty error list shows that init was successful
vsErrorList.clear();
}
// try next driver
iCurDriverIdx++;
}
return vsErrorList;
}

View file

@ -27,6 +27,7 @@
#include <qthread.h>
#include <qstring.h>
#include <qmessagebox.h>
#include "global.h"
#include "util.h"
@ -37,7 +38,8 @@ class CSoundBase : public QThread
Q_OBJECT
public:
CSoundBase ( const bool bNewIsCallbackAudioInterface,
CSoundBase ( const QString& strNewSystemDriverTechniqueName,
const bool bNewIsCallbackAudioInterface,
void (*fpNewProcessCallback) ( CVector<int16_t>& psData, void* pParg ),
void* pParg );
@ -48,10 +50,8 @@ public:
// device selection
virtual int GetNumDev() { return lNumDevs; }
virtual QString GetDeviceName ( const int iDiD ) { return strDriverNames[iDiD]; }
// dummy implementations in base class
virtual QString SetDev ( const int ) { return ""; }
virtual int GetDev() { return lCurDev; }
virtual QString SetDev ( const int );
virtual int GetDev() { return lCurDev; }
virtual int GetNumInputChannels() { return 2; }
virtual QString GetInputChannelName ( const int ) { return "Default"; }
@ -76,6 +76,11 @@ public:
void EmitReinitRequestSignal() { emit ReinitRequest(); }
protected:
// driver handling
virtual QString LoadAndInitializeDriver ( int ) { return ""; };
virtual void UnloadCurrentDriver() {}
QVector<QString> LoadAndInitializeFirstValidDriver();
// function pointer to callback function
void (*fpProcessCallback) ( CVector<int16_t>& psData, void* arg );
void* pProcessCallbackArg;
@ -93,13 +98,15 @@ protected:
void run();
bool bRun;
bool bIsCallbackAudioInterface;
bool bIsCallbackAudioInterface;
QString strSystemDriverTechniqueName;
CVector<int16_t> vecsAudioSndCrdStereo;
long lNumDevs;
long lCurDev;
QString strDriverNames[MAX_NUMBER_SOUND_CARDS];
long lNumDevs;
long lCurDev;
QString strDriverNames[MAX_NUMBER_SOUND_CARDS];
signals:
void ReinitRequest();

View file

@ -40,143 +40,6 @@ CSound* pSound;
/******************************************************************************\
* Common *
\******************************************************************************/
QString CSound::SetDev ( const int iNewDev )
{
QString strReturn = ""; // init with no error
bool bTryLoadAnyDriver = false;
// check if an ASIO driver was already initialized
if ( lCurDev >= 0 )
{
// a device was already been initialized and is used, first clean up
// dispose ASIO buffers
ASIODisposeBuffers();
// remove old driver
ASIOExit();
asioDrivers->removeCurrentDriver();
const QString strErrorMessage = LoadAndInitializeDriver ( iNewDev );
if ( !strErrorMessage.isEmpty() )
{
if ( iNewDev != lCurDev )
{
// loading and initializing the new driver failed, go back to
// original driver and display error message
LoadAndInitializeDriver ( lCurDev );
}
else
{
// the same driver is used but the driver properties seems to
// have changed so that they are not compatible to our
// software anymore
QMessageBox::critical (
0, APP_NAME, QString ( tr ( "The audio driver properties "
"have changed to a state which is incompatible to this "
"software. The selected audio device could not be used "
"because of the following error: <b>" ) ) +
strErrorMessage +
QString ( tr ( "</b><br><br>Please restart the software." ) ),
"Close", 0 );
_exit ( 0 );
}
// store error return message
strReturn = strErrorMessage;
}
Init ( iASIOBufferSizeStereo );
}
else
{
if ( iNewDev != INVALID_SNC_CARD_DEVICE )
{
// This is the first time a driver is to be initialized, we first
// try to load the selected driver, if this fails, we try to load
// the first available driver in the system. If this fails, too, we
// throw an error that no driver is available -> it does not make
// sense to start the llcon software if no audio hardware is
// available.
if ( !LoadAndInitializeDriver ( iNewDev ).isEmpty() )
{
// loading and initializing the new driver failed, try to find
// at least one usable driver
bTryLoadAnyDriver = true;
}
}
else
{
// try to find one usable driver (select the first valid driver)
bTryLoadAnyDriver = true;
}
}
if ( bTryLoadAnyDriver )
{
// try to load and initialize any valid driver
QVector<QString> vsErrorList =
LoadAndInitializeFirstValidDriver();
if ( !vsErrorList.isEmpty() )
{
// create error message with all details
QString sErrorMessage = tr ( "<b>No usable ASIO audio device "
"(driver) found.</b><br><br>"
"In the following there is a list of all available drivers "
"with the associated error message:<ul>" );
for ( int i = 0; i < lNumDevs; i++ )
{
sErrorMessage += "<li><b>" + GetDeviceName ( i ) + "</b>: " +
vsErrorList[i] + "</li>";
}
sErrorMessage += "</ul>";
throw CGenErr ( sErrorMessage );
}
}
return strReturn;
}
QVector<QString> CSound::LoadAndInitializeFirstValidDriver()
{
QVector<QString> vsErrorList;
// load and initialize first valid ASIO driver
bool bValidDriverDetected = false;
int iCurDriverIdx = 0;
// try all available drivers in the system ("lNumDevs" devices)
while ( !bValidDriverDetected && ( iCurDriverIdx < lNumDevs ) )
{
// try to load and initialize current driver, store error message
const QString strCurError =
LoadAndInitializeDriver ( iCurDriverIdx );
vsErrorList.append ( strCurError );
if ( strCurError.isEmpty() )
{
// initialization was successful
bValidDriverDetected = true;
// store ID of selected driver
lCurDev = iCurDriverIdx;
// empty error list shows that init was successful
vsErrorList.clear();
}
// try next driver
iCurDriverIdx++;
}
return vsErrorList;
}
QString CSound::LoadAndInitializeDriver ( int iDriverIdx )
{
// first check and correct input parameter
@ -212,6 +75,15 @@ QString CSound::LoadAndInitializeDriver ( int iDriverIdx )
return strStat;
}
void CSound::UnloadCurrentDriver()
{
// cleanup ASIO stuff
ASIOStop();
ASIODisposeBuffers();
ASIOExit();
asioDrivers->removeCurrentDriver();
}
QString CSound::CheckDeviceCapabilities()
{
// This function checks if our required input/output channel
@ -525,11 +397,11 @@ void CSound::Stop()
}
CSound::CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ), void* arg ) :
CSoundBase ( true, fpNewCallback, arg ),
vSelectedInputChannels ( NUM_IN_OUT_CHANNELS ),
CSoundBase ( "ASIO", true, fpNewCallback, arg ),
vSelectedInputChannels ( NUM_IN_OUT_CHANNELS ),
vSelectedOutputChannels ( NUM_IN_OUT_CHANNELS ),
lNumInChan ( 0 ),
lNumOutChan ( 0 )
lNumInChan ( 0 ),
lNumOutChan ( 0 )
{
int i;
@ -589,14 +461,6 @@ void CSound::ResetChannelMapping()
vSelectedOutputChannels[1] = 1;
}
CSound::~CSound()
{
// cleanup ASIO stuff
ASIOStop();
ASIODisposeBuffers();
ASIOExit();
asioDrivers->removeCurrentDriver();
}
// ASIO callbacks -------------------------------------------------------------
ASIOTime* CSound::bufferSwitchTimeInfo ( ASIOTime*,
@ -1104,6 +968,11 @@ long CSound::asioMessages ( long selector,
// both messages might be send if the buffer size changes
case kAsioBufferSizeChange:
case kAsioResetRequest:
// TODO implement separate ASIO reset function in base class!
pSound->EmitReinitRequestSignal();
ret = 1L; // 1L if request is accepted or 0 otherwise
break;

View file

@ -49,7 +49,7 @@ class CSound : public CSoundBase
{
public:
CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ), void* arg );
virtual ~CSound();
virtual ~CSound() { UnloadCurrentDriver(); }
virtual int Init ( const int iNewPrefMonoBufferSize );
virtual void Start();
@ -57,9 +57,6 @@ public:
virtual void OpenDriverSetup() { ASIOControlPanel(); }
// device selection
virtual QString SetDev ( const int iNewDev );
// channel selection
virtual int GetNumInputChannels() { return static_cast<int> ( lNumInChan ); }
virtual QString GetInputChannelName ( const int iDiD ) { return channelInfosInput[iDiD].name; }
@ -76,8 +73,8 @@ public:
virtual int GetRightOutputChannel() { return vSelectedOutputChannels[1]; }
protected:
QVector<QString> LoadAndInitializeFirstValidDriver();
QString LoadAndInitializeDriver ( int iIdx );
virtual QString LoadAndInitializeDriver ( int iIdx );
virtual void UnloadCurrentDriver();
int GetActualBufferSize ( const int iDesiredBufferSizeMono );
QString CheckDeviceCapabilities();
bool CheckSampleTypeSupported ( const ASIOSampleType SamType );