ASIO backend, part 6

add support for handling device resets
this will be extended to the SDL and PortAudio backends soon
This commit is contained in:
tildearrow 2025-10-25 18:40:02 -05:00
parent 3edf62fc5c
commit db2f368813
7 changed files with 85 additions and 1 deletions

View file

@ -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() {
}
}

View file

@ -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) {

View file

@ -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);

View file

@ -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<String> 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),

View file

@ -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<String>& DivEngine::getAudioDevices() {
return audioDevs;
}

View file

@ -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);

View file

@ -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;