From fa7405090e25b795c7eacdf2faaaa886a3635d26 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 31 Aug 2023 04:30:49 -0500 Subject: [PATCH] add WASAPI exclusive mode flag to PortAudio backen d --- src/audio/pa.cpp | 63 ++++++++++++++++++++++++++++++++++++++----- src/audio/taAudio.h | 5 +++- src/engine/engine.cpp | 1 + src/gui/gui.h | 2 ++ src/gui/settings.cpp | 16 +++++++++-- 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/src/audio/pa.cpp b/src/audio/pa.cpp index 722d29fd..ed809b22 100644 --- a/src/audio/pa.cpp +++ b/src/audio/pa.cpp @@ -21,6 +21,9 @@ #include #include "../ta-log.h" #include "pa.h" +#ifdef _WIN32 +#include +#endif int taPAProcess(const void* in, void* out, unsigned long nframes, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags flags, void* inst) { TAAudioPA* instance=(TAAudioPA*)inst; @@ -117,8 +120,18 @@ std::vector TAAudioPA::listAudioDevices() { if (devInfo==NULL) continue; if (devInfo->maxOutputChannels<1) continue; + String devName; + + const PaHostApiInfo* driverInfo=Pa_GetHostApiInfo(devInfo->hostApi); + if (driverInfo==NULL) { + devName+="[???] "; + } else { + devName+=fmt::sprintf("[%s] ",driverInfo->name); + } + if (devInfo->name!=NULL) { - ret.push_back(String(devInfo->name)); + devName+=devInfo->name; + ret.push_back(devName); } } @@ -146,11 +159,15 @@ bool TAAudioPA::init(TAAudioDesc& request, TAAudioDesc& response) { desc.outFormat=TA_AUDIO_FORMAT_F32; const PaDeviceInfo* devInfo=NULL; + const PaHostApiInfo* driverInfo=NULL; int outDeviceID=0; if (desc.deviceName.empty()) { outDeviceID=Pa_GetDefaultOutputDevice(); devInfo=Pa_GetDeviceInfo(outDeviceID); + if (devInfo!=NULL) { + driverInfo=Pa_GetHostApiInfo(devInfo->hostApi); + } } else { int count=Pa_GetDeviceCount(); bool found=false; @@ -164,12 +181,25 @@ bool TAAudioPA::init(TAAudioDesc& request, TAAudioDesc& response) { if (devInfo==NULL) continue; if (devInfo->maxOutputChannels<1) continue; + String devName; + + driverInfo=Pa_GetHostApiInfo(devInfo->hostApi); + if (driverInfo==NULL) { + devName+="[???] "; + } else { + devName+=fmt::sprintf("[%s] ",driverInfo->name); + } + if (devInfo->name!=NULL) { - if (strcmp(devInfo->name,desc.deviceName.c_str())==0) { - outDeviceID=i; - found=true; - break; - } + devName+=devInfo->name; + } else { + continue; + } + + if (devName==desc.deviceName) { + outDeviceID=i; + found=true; + break; } } if (!found) { @@ -190,6 +220,27 @@ bool TAAudioPA::init(TAAudioDesc& request, TAAudioDesc& response) { outParams.suggestedLatency=(double)(desc.bufsize*desc.fragments)/desc.rate; outParams.hostApiSpecificStreamInfo=NULL; + if (driverInfo!=NULL) { + if (driverInfo->type==paWASAPI) { + logV("setting WASAPI-specific flags"); + PaWasapiStreamInfo* wasapiInfo=new PaWasapiStreamInfo; + memset(wasapiInfo,0,sizeof(PaWasapiStreamInfo)); + wasapiInfo->size=sizeof(PaWasapiStreamInfo); + wasapiInfo->hostApiType=paWASAPI; + wasapiInfo->version=1; + wasapiInfo->flags=paWinWasapiThreadPriority; + wasapiInfo->threadPriority=eThreadPriorityProAudio; + wasapiInfo->streamCategory=eAudioCategoryMedia; + wasapiInfo->streamOption=eStreamOptionRaw; + + if (desc.wasapiEx) { + wasapiInfo->flags|=paWinWasapiExclusive; + } + + outParams.hostApiSpecificStreamInfo=wasapiInfo; + } + } + logV("opening audio device..."); status=Pa_OpenStream( &ac, diff --git a/src/audio/taAudio.h b/src/audio/taAudio.h index dd0d7674..20491dbb 100644 --- a/src/audio/taAudio.h +++ b/src/audio/taAudio.h @@ -58,13 +58,16 @@ struct TAAudioDesc { unsigned char inChans, outChans; TAAudioFormat outFormat; + bool wasapiEx; + TAAudioDesc(): rate(0.0), bufsize(0), fragments(0), inChans(0), outChans(0), - outFormat(TA_AUDIO_FORMAT_F32) {} + outFormat(TA_AUDIO_FORMAT_F32), + wasapiEx(false) {} }; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index f60bdf6a..8dbe1f26 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3370,6 +3370,7 @@ bool DivEngine::initAudioBackend() { want.inChans=0; want.outChans=getConfInt("audioChans",2); want.outFormat=TA_AUDIO_FORMAT_F32; + want.wasapiEx=getConfInt("wasapiEx",0); want.name="Furnace"; if (want.outChans<1) want.outChans=1; diff --git a/src/gui/gui.h b/src/gui/gui.h index 8c7837ca..4f90a7bd 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1571,6 +1571,7 @@ class FurnaceGUI { int centerPopup; int insIconsStyle; int classicChipOptions; + int wasapiEx; unsigned int maxUndoSteps; String mainFontPath; String headFontPath; @@ -1745,6 +1746,7 @@ class FurnaceGUI { centerPopup(1), insIconsStyle(1), classicChipOptions(0), + wasapiEx(0), maxUndoSteps(100), mainFontPath(""), headFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 9f5b01cf..18690514 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -872,11 +872,11 @@ void FurnaceGUI::drawSettings() { } bool lowLatencyB=settings.lowLatency; - if (ImGui::Checkbox("Low-latency mode (experimental!)",&lowLatencyB)) { + if (ImGui::Checkbox("Low-latency mode",&lowLatencyB)) { settings.lowLatency=lowLatencyB; } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("reduces latency by running the engine faster than the tick rate.\nuseful for live playback/jam mode.\n\nwarning: experimental! may produce glitches.\nonly enable if your buffer size is small (10ms or less)."); + ImGui::SetTooltip("reduces latency by running the engine faster than the tick rate.\nuseful for live playback/jam mode.\n\nwarning: nonly enable if your buffer size is small (10ms or less)."); } bool forceMonoB=settings.forceMono; @@ -884,6 +884,15 @@ void FurnaceGUI::drawSettings() { settings.forceMono=forceMonoB; } + if (settings.audioEngine==DIV_AUDIO_PORTAUDIO) { + if (settings.audioDevice.find("[Windows WASAPI] ")==0) { + bool wasapiExB=settings.wasapiEx; + if (ImGui::Checkbox("Exclusive mode",&wasapiExB)) { + settings.wasapiEx=wasapiExB; + } + } + } + TAAudioDesc& audioWant=e->getAudioDescWant(); TAAudioDesc& audioGot=e->getAudioDescGot(); @@ -3252,6 +3261,7 @@ void FurnaceGUI::syncSettings() { settings.centerPopup=e->getConfInt("centerPopup",1); settings.insIconsStyle=e->getConfInt("insIconsStyle",1); settings.classicChipOptions=e->getConfInt("classicChipOptions",0); + settings.wasapiEx=e->getConfInt("wasapiEx",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.headFontSize,2,96); @@ -3399,6 +3409,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.centerPopup,0,1); clampSetting(settings.insIconsStyle,0,2); clampSetting(settings.classicChipOptions,0,1); + clampSetting(settings.wasapiEx,0,1); if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; @@ -3653,6 +3664,7 @@ void FurnaceGUI::commitSettings() { e->setConf("centerPopup",settings.centerPopup); e->setConf("insIconsStyle",settings.insIconsStyle); e->setConf("classicChipOptions",settings.classicChipOptions); + e->setConf("wasapiEx",settings.wasapiEx); // colors for (int i=0; i