diff --git a/src/audio/abstract.cpp b/src/audio/abstract.cpp index b579fc4a1..5687b76d9 100644 --- a/src/audio/abstract.cpp +++ b/src/audio/abstract.cpp @@ -37,6 +37,14 @@ void* TAAudio::getContext() { return NULL; } +TAAudioDeviceStatus TAAudio::getDeviceStatus() { + return deviceStatus; +} + +void TAAudio::acceptDeviceStatus() { + deviceStatus=TA_AUDIO_DEVICE_OK; +} + bool TAAudio::quit() { return true; } @@ -121,4 +129,4 @@ TAMidiIn::~TAMidiIn() { } TAMidiOut::~TAMidiOut() { -} \ No newline at end of file +} diff --git a/src/audio/asio.cpp b/src/audio/asio.cpp index 91991a980..0f9767dcf 100644 --- a/src/audio/asio.cpp +++ b/src/audio/asio.cpp @@ -36,6 +36,36 @@ static void _onSampleRate(ASIOSampleRate rate) { } static long _onMessage(long type, long value, void* msg, double* opt) { + if (callbackInstance==NULL) return; + switch (type) { + case kAsioSelectorSupported: + switch (value) { + case kAsioSelectorSupported: + case kAsioEngineVersion: + case kAsioResetRequest: + case kAsioBufferSizeChange: + case kAsioResyncRequest: + return 1; + default: + return 0; + } + break; + case kAsioEngineVersion: + return 2; + break; + case kAsioResetRequest: + callbackInstance->requestDeviceChange(); + return 1; + break; + case kAsioBufferSizeChange: + callbackInstance->onBufferSize(value); + return 1; + break; + case kAsioResyncRequest: + // ignore + return 1; + break; + } return 0; } @@ -343,6 +373,10 @@ bool TAAudioASIO::setRun(bool run) { return running; } +void TAAudioASIO::requestDeviceChange() { + deviceStatus=TA_AUDIO_DEVICE_RESET; +} + bool TAAudioASIO::init(TAAudioDesc& request, TAAudioDesc& response) { if (initialized) return false; if (callbackInstance) { diff --git a/src/audio/asio.h b/src/audio/asio.h index 348af3d2c..4118a370b 100644 --- a/src/audio/asio.h +++ b/src/audio/asio.h @@ -41,6 +41,7 @@ class TAAudioASIO: public TAAudio { void onSampleRate(double rate); void onBufferSize(int bufsize); void onProcess(int nframes); + void requestDeviceChange(); String getErrorStr(ASIOError which); String getFormatName(ASIOSampleType which); diff --git a/src/audio/taAudio.h b/src/audio/taAudio.h index 7752f9ffb..47dfa9e50 100644 --- a/src/audio/taAudio.h +++ b/src/audio/taAudio.h @@ -36,6 +36,15 @@ struct BufferSizeChangeEvent { bufsize(bs) {} }; +enum TAAudioDeviceStatus { + // device is working + TA_AUDIO_DEVICE_OK=0, + // device has reset - reload audio engine + TA_AUDIO_DEVICE_RESET, + // device has been removed - reload audio engine with another device + TA_AUDIO_DEVICE_REMOVED +}; + enum TAAudioFormat { TA_AUDIO_FORMAT_F32=0, TA_AUDIO_FORMAT_F64, @@ -157,6 +166,8 @@ class TAAudio { protected: TAAudioDesc desc; TAAudioFormat outFormat; + TAAudioDeviceStatus deviceStatus; + bool running, initialized; float** inBufs; float** outBufs; @@ -176,12 +187,15 @@ class TAAudio { virtual bool quit(); virtual bool setRun(bool run); virtual std::vector listAudioDevices(); + TAAudioDeviceStatus getDeviceStatus(); + void acceptDeviceStatus(); bool initMidi(bool jack); void quitMidi(); virtual bool init(TAAudioDesc& request, TAAudioDesc& response); TAAudio(): outFormat(TA_AUDIO_FORMAT_F32), + deviceStatus(TA_AUDIO_DEVICE_OK), running(false), initialized(false), inBufs(NULL), diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index d71a3e7cc..eb72ad152 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3798,6 +3798,16 @@ TAAudioDesc& DivEngine::getAudioDescGot() { return got; } +TAAudioDeviceStatus DivEngine::getAudioDeviceStatus() { + if (output==NULL) return TA_AUDIO_DEVICE_OK; + return output->getDeviceStatus(); +} + +void DivEngine::acceptAudioDeviceStatus() { + if (output==NULL) return; + output->acceptDeviceStatus(); +} + std::vector& DivEngine::getAudioDevices() { return audioDevs; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 08ba7a0b9..b1174b2b3 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -1403,6 +1403,12 @@ class DivEngine { // get audio desc TAAudioDesc& getAudioDescGot(); + // get audio device status + TAAudioDeviceStatus getAudioDeviceStatus(); + + // acknowledge an audio device status change + void acceptAudioDeviceStatus(); + // init dispatch void initDispatch(bool isRender=false); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a523bb3c8..6a726d4fe 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4333,6 +4333,17 @@ bool FurnaceGUI::loop() { }); } + // recover from audio resets + TAAudioDeviceStatus audioStatus=e->getAudioDeviceStatus(); + if (audioStatus!=TA_AUDIO_DEVICE_OK) { + logI("audio device reset!"); + e->acceptAudioDeviceStatus(); + + if (!e->switchMaster(false)) { + showError(_("audio device has reset or has been disconnected! check audio settings.")); + } + } + // recover from dead graphics if (rend->isDead() || killGraphics) { killGraphics=false;