From 1b4551a208cb2ebaecbd7ffbae4e91f597c8405a Mon Sep 17 00:00:00 2001 From: Steven Atkinson Date: Sat, 2 May 2026 20:07:00 -0700 Subject: [PATCH] Fix standalone app channel selection --- IPlug/APP/IPlugAPP_dialog.cpp | 69 ++++++++++++++++++++++++----------- IPlug/APP/IPlugAPP_host.cpp | 38 ++++++++++++++++--- IPlug/APP/IPlugAPP_host.h | 4 +- 3 files changed, 82 insertions(+), 29 deletions(-) diff --git a/IPlug/APP/IPlugAPP_dialog.cpp b/IPlug/APP/IPlugAPP_dialog.cpp index d3220e5dad..a6c0c0b14d 100644 --- a/IPlug/APP/IPlugAPP_dialog.cpp +++ b/IPlug/APP/IPlugAPP_dialog.cpp @@ -12,6 +12,8 @@ #include "config.h" #include "resource.h" +#include + #ifdef OS_WIN #include "asio.h" #define GET_MENU() GetMenu(gHWND) @@ -30,6 +32,17 @@ using namespace igraphics; extern int GetTitleBarOffset(); #endif +namespace +{ +int GetNumChannelStartOptions(int availableChannels, int streamChannels) +{ + if (availableChannels <= 0 || streamChannels <= 0) + return 0; + + return availableChannels > streamChannels ? availableChannels - streamChannels + 1 : 1; +} +} + // check the input and output devices, find matching srs void IPlugAPPHost::PopulateSampleRateList(HWND hwndDlg, RtAudio::DeviceInfo* inputDevInfo, RtAudio::DeviceInfo* outputDevInfo) { @@ -75,21 +88,28 @@ void IPlugAPPHost::PopulateAudioInputList(HWND hwndDlg, RtAudio::DeviceInfo* inf SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_L,CB_RESETCONTENT,0,0); SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_RESETCONTENT,0,0); - int i; + const int nInputChans = std::max(1, GetPlug()->MaxNChannels(ERoute::kInput)); + const int nInputStartOptions = GetNumChannelStartOptions(info->inputChannels, nInputChans); - for (i=0; iinputChannels -1; i++) + for (int i=0; iinputChannels; i++) + { + buf.SetFormatted(20, "%i", i+1); SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_ADDSTRING,0,(LPARAM)buf.Get()); } - // TEMP - buf.SetFormatted(20, "%i", i+1); - SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_ADDSTRING,0,(LPARAM)buf.Get()); + mState.mAudioInChanL = std::min(std::max(mState.mAudioInChanL, uint32_t(1)), uint32_t(nInputStartOptions)); + mState.mAudioInChanR = + nInputChans > 1 ? std::min(mState.mAudioInChanL + 1, uint32_t(info->inputChannels)) : mState.mAudioInChanL; SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_L,CB_SETCURSEL, mState.mAudioInChanL - 1, 0); SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_AUDIO_IN_R), nInputChans > 1); } void IPlugAPPHost::PopulateAudioOutputList(HWND hwndDlg, RtAudio::DeviceInfo* info) @@ -102,21 +122,28 @@ void IPlugAPPHost::PopulateAudioOutputList(HWND hwndDlg, RtAudio::DeviceInfo* in SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_L,CB_RESETCONTENT,0,0); SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_RESETCONTENT,0,0); - int i; + const int nOutputChans = std::max(1, GetPlug()->MaxNChannels(ERoute::kOutput)); + const int nOutputStartOptions = GetNumChannelStartOptions(info->outputChannels, nOutputChans); - for (i=0; ioutputChannels -1; i++) + for (int i=0; ioutputChannels; i++) + { + buf.SetFormatted(20, "%i", i+1); SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_ADDSTRING,0,(LPARAM)buf.Get()); } - // TEMP - buf.SetFormatted(20, "%i", i+1); - SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_ADDSTRING,0,(LPARAM)buf.Get()); + mState.mAudioOutChanL = std::min(std::max(mState.mAudioOutChanL, uint32_t(1)), uint32_t(nOutputStartOptions)); + mState.mAudioOutChanR = + nOutputChans > 1 ? std::min(mState.mAudioOutChanL + 1, uint32_t(info->outputChannels)) : mState.mAudioOutChanL; SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_L,CB_SETCURSEL, mState.mAudioOutChanL - 1, 0); SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_AUDIO_OUT_R), nOutputChans > 1); } // This has to get called after any change to audio driver/in dev/out dev @@ -408,36 +435,34 @@ WDL_DLGRET IPlugAPPHost::PreferencesDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wPar if (HIWORD(wParam) == CBN_SELCHANGE) { mState.mAudioInChanL = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_IN_L, CB_GETCURSEL, 0, 0) + 1; - - //TEMP - mState.mAudioInChanR = mState.mAudioInChanL + 1; + mState.mAudioInChanR = _this->GetPlug()->MaxNChannels(ERoute::kInput) > 1 ? mState.mAudioInChanL + 1 + : mState.mAudioInChanL; SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0); - // } break; case IDC_COMBO_AUDIO_IN_R: if (HIWORD(wParam) == CBN_SELCHANGE) - SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0); // TEMP - mState.mAudioInChanR = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_IN_R, CB_GETCURSEL, 0, 0); + { + SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0); + } break; case IDC_COMBO_AUDIO_OUT_L: if (HIWORD(wParam) == CBN_SELCHANGE) { mState.mAudioOutChanL = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_OUT_L, CB_GETCURSEL, 0, 0) + 1; - - //TEMP - mState.mAudioOutChanR = mState.mAudioOutChanL + 1; + mState.mAudioOutChanR = _this->GetPlug()->MaxNChannels(ERoute::kOutput) > 1 ? mState.mAudioOutChanL + 1 + : mState.mAudioOutChanL; SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0); - // } break; case IDC_COMBO_AUDIO_OUT_R: if (HIWORD(wParam) == CBN_SELCHANGE) - SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0); // TEMP - mState.mAudioOutChanR = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_OUT_R, CB_GETCURSEL, 0, 0); + { + SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0); + } break; // case IDC_CB_MONO_INPUT: diff --git a/IPlug/APP/IPlugAPP_host.cpp b/IPlug/APP/IPlugAPP_host.cpp index a3093498f2..2676cd0643 100644 --- a/IPlug/APP/IPlugAPP_host.cpp +++ b/IPlug/APP/IPlugAPP_host.cpp @@ -10,6 +10,8 @@ #include "IPlugAPP_host.h" +#include + #ifdef OS_WIN #include #endif @@ -24,6 +26,18 @@ using namespace iplug; #define STRBUFSZ 100 +namespace +{ +uint32_t ClampFirstChannel(uint32_t firstChannel, uint32_t availableChannels, uint32_t streamChannels) +{ + if (availableChannels == 0 || streamChannels == 0) + return 0; + + const uint32_t maxFirstChannel = availableChannels > streamChannels ? availableChannels - streamChannels + 1 : 1; + return std::min(std::max(firstChannel, uint32_t(1)), maxFirstChannel); +} +} + std::unique_ptr IPlugAPPHost::sInstance; UINT gSCROLLMSG; @@ -578,13 +592,28 @@ bool IPlugAPPHost::InitAudio(uint32_t inId, uint32_t outId, uint32_t sr, uint32_ CloseAudio(); RtAudio::StreamParameters iParams, oParams; + RtAudio::DeviceInfo inputInfo = mDAC->getDeviceInfo(inId); + RtAudio::DeviceInfo outputInfo = mDAC->getDeviceInfo(outId); + iParams.deviceId = inId; - iParams.nChannels = GetPlug()->MaxNChannels(ERoute::kInput); // TODO: flexible channel count - iParams.firstChannel = 0; // TODO: flexible channel count + iParams.nChannels = GetPlug()->MaxNChannels(ERoute::kInput); + if (iParams.nChannels > 0) + { + mState.mAudioInChanL = ClampFirstChannel(mState.mAudioInChanL, inputInfo.inputChannels, iParams.nChannels); + mState.mAudioInChanR = + iParams.nChannels > 1 ? std::min(mState.mAudioInChanL + 1, inputInfo.inputChannels) : mState.mAudioInChanL; + iParams.firstChannel = mState.mAudioInChanL - 1; + } oParams.deviceId = outId; - oParams.nChannels = GetPlug()->MaxNChannels(ERoute::kOutput); // TODO: flexible channel count - oParams.firstChannel = 0; // TODO: flexible channel count + oParams.nChannels = GetPlug()->MaxNChannels(ERoute::kOutput); + if (oParams.nChannels > 0) + { + mState.mAudioOutChanL = ClampFirstChannel(mState.mAudioOutChanL, outputInfo.outputChannels, oParams.nChannels); + mState.mAudioOutChanR = + oParams.nChannels > 1 ? std::min(mState.mAudioOutChanL + 1, outputInfo.outputChannels) : mState.mAudioOutChanL; + oParams.firstChannel = mState.mAudioOutChanL - 1; + } mBufferSize = iovs; // mBufferSize may get changed by stream @@ -783,4 +812,3 @@ void IPlugAPPHost::ErrorCallback(RtAudioError::Type type, const std::string &err { //TODO: } - diff --git a/IPlug/APP/IPlugAPP_host.h b/IPlug/APP/IPlugAPP_host.h index 046e1f2b99..974016fd7d 100644 --- a/IPlug/APP/IPlugAPP_host.h +++ b/IPlug/APP/IPlugAPP_host.h @@ -131,8 +131,8 @@ class IPlugAPPHost , mAudioInChanL(obj.mAudioInChanL) , mAudioInChanR(obj.mAudioInChanR) - , mAudioOutChanL(obj.mAudioInChanL) - , mAudioOutChanR(obj.mAudioInChanR) + , mAudioOutChanL(obj.mAudioOutChanL) + , mAudioOutChanR(obj.mAudioOutChanR) { }