some more work for moving functions from the Windows sound interface to the sound base class
This commit is contained in:
parent
a8795c1bf3
commit
8720c40db6
8 changed files with 1200 additions and 1177 deletions
|
@ -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
|
||||
|
|
|
@ -59,7 +59,7 @@ 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(); }
|
||||
|
||||
|
@ -67,10 +67,6 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,9 +50,7 @@ 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 QString SetDev ( const int );
|
||||
virtual int GetDev() { return lCurDev; }
|
||||
|
||||
virtual int GetNumInputChannels() { return 2; }
|
||||
|
@ -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,7 +98,9 @@ protected:
|
|||
|
||||
void run();
|
||||
bool bRun;
|
||||
|
||||
bool bIsCallbackAudioInterface;
|
||||
QString strSystemDriverTechniqueName;
|
||||
|
||||
CVector<int16_t> vecsAudioSndCrdStereo;
|
||||
|
||||
|
|
|
@ -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,7 +397,7 @@ void CSound::Stop()
|
|||
}
|
||||
|
||||
CSound::CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ), void* arg ) :
|
||||
CSoundBase ( true, fpNewCallback, arg ),
|
||||
CSoundBase ( "ASIO", true, fpNewCallback, arg ),
|
||||
vSelectedInputChannels ( NUM_IN_OUT_CHANNELS ),
|
||||
vSelectedOutputChannels ( NUM_IN_OUT_CHANNELS ),
|
||||
lNumInChan ( 0 ),
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue