From 23dc374917acd0d7100c6e9db7ae5333338cee28 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 10:19:38 +0300 Subject: WinMM: Added chan-alloc and audio output options --- utils/winmm_drv/CMakeLists.txt | 4 +-- utils/winmm_drv/config/regconfig.c | 46 +++++++++++++++++++++++-- utils/winmm_drv/config/regconfig.h | 3 ++ utils/winmm_drv/cpl/adlconfig.rc | 58 ++++++++++++++++--------------- utils/winmm_drv/cpl/config_dialog.c | 69 +++++++++++++++++++++++++++++++++++++ utils/winmm_drv/cpl/resource.h | 4 +++ utils/winmm_drv/src/MidiSynth.cpp | 22 +++++++++--- 7 files changed, 171 insertions(+), 35 deletions(-) diff --git a/utils/winmm_drv/CMakeLists.txt b/utils/winmm_drv/CMakeLists.txt index ae76a0c..79bf099 100644 --- a/utils/winmm_drv/CMakeLists.txt +++ b/utils/winmm_drv/CMakeLists.txt @@ -114,7 +114,7 @@ target_compile_definitions(adlmidiconfig PRIVATE -DADL_IS_CPL_APPLET ) -target_link_libraries(adlmidiconfig PRIVATE comctl32 gdi32 user32) +target_link_libraries(adlmidiconfig PRIVATE winmm comctl32 gdi32 user32) add_executable(adlmidiconfigtool ${ADLMIDI_DRIVER_SRC} cpl/adlconfig-tool.c cpl/res-tool.rc) @@ -128,7 +128,7 @@ target_compile_definitions(adlmidiconfigtool PRIVATE -DUNICODE ) -target_link_libraries(adlmidiconfigtool PRIVATE comctl32 gdi32 user32) +target_link_libraries(adlmidiconfigtool PRIVATE winmm comctl32 gdi32 user32) if(WIN32 AND CMAKE_COMPILER_IS_GNUCXX) target_compile_options(adlmidiconfig PRIVATE "-Wno-cast-function-type") diff --git a/utils/winmm_drv/config/regconfig.c b/utils/winmm_drv/config/regconfig.c index 353cea2..6e35df0 100644 --- a/utils/winmm_drv/config/regconfig.c +++ b/utils/winmm_drv/config/regconfig.c @@ -93,13 +93,15 @@ static BOOL readIntFromRegistry(HKEY hKeyParent, const PWCHAR subkey, const PWCH { WCHAR *buf = NULL; BOOL ret; + ret = readStringFromRegistry(hKeyParent, subkey, valueName, &buf); + if(ret && readData) - { *readData = _wtoi(buf); - } + if(buf) free(buf); + return ret; } @@ -115,6 +117,34 @@ static BOOL writeIntToRegistry(HKEY hKeyParent, const PWCHAR subkey, const PWCHA return ret; } +static BOOL readUIntFromRegistry(HKEY hKeyParent, const PWCHAR subkey, const PWCHAR valueName, UINT *readData) +{ + WCHAR *buf = NULL; + BOOL ret; + + ret = readStringFromRegistry(hKeyParent, subkey, valueName, &buf); + + if(ret && readData) + *readData = wcstoul(buf, NULL, 10); + + if(buf) + free(buf); + + return ret; +} + +static BOOL writeUIntToRegistry(HKEY hKeyParent, const PWCHAR subkey, const PWCHAR valueName, UINT intData) +{ + WCHAR buf[20]; + BOOL ret; + + ZeroMemory(buf, 20); + _snwprintf(buf, 20, L"%u", intData); + + ret = writeStringToRegistry(hKeyParent, subkey, valueName, buf); + return ret; +} + @@ -133,8 +163,11 @@ void setupDefault(DriverSettings *setup) setup->flagFullBrightness = BST_UNCHECKED; setup->volumeModel = 0; + setup->chanAlloc = 0; setup->numChips = 4; setup->num4ops = -1; + + setup->outputDevice = (UINT)-1; } @@ -144,6 +177,7 @@ static const PWCHAR s_regPath = L"SOFTWARE\\Wohlstand\\libADLMIDI"; void loadSetup(DriverSettings *setup) { int iVal; + UINT uVal; WCHAR *sVal = NULL; if(readIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"useExternalBank", &iVal)) @@ -179,11 +213,17 @@ void loadSetup(DriverSettings *setup) if(readIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"volumeModel", &iVal)) setup->volumeModel = iVal; + if(readIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"chanAlloc", &iVal)) + setup->chanAlloc = iVal; + if(readIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"numChips", &iVal)) setup->numChips = iVal; if(readIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"num4ops", &iVal)) setup->num4ops = iVal; + + if(readUIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"outputDevice", &uVal)) + setup->outputDevice = uVal; } void saveSetup(DriverSettings *setup) @@ -202,8 +242,10 @@ void saveSetup(DriverSettings *setup) writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"flagFullBrightness", setup->flagFullBrightness); writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"volumeModel", setup->volumeModel); + writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"chanAlloc", setup->chanAlloc); writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"numChips", setup->numChips); writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"num4ops", setup->num4ops); + writeUIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"outputDevice", setup->outputDevice); } diff --git a/utils/winmm_drv/config/regconfig.h b/utils/winmm_drv/config/regconfig.h index f854d1b..7c49bd6 100644 --- a/utils/winmm_drv/config/regconfig.h +++ b/utils/winmm_drv/config/regconfig.h @@ -25,8 +25,11 @@ typedef struct DriverSettings_t BOOL flagFullBrightness; int volumeModel; + int chanAlloc; int numChips; int num4ops; + + UINT outputDevice; } DriverSettings; extern const WCHAR g_adlSignalMemory[]; diff --git a/utils/winmm_drv/cpl/adlconfig.rc b/utils/winmm_drv/cpl/adlconfig.rc index 455c906..ff7fcf2 100644 --- a/utils/winmm_drv/cpl/adlconfig.rc +++ b/utils/winmm_drv/cpl/adlconfig.rc @@ -14,37 +14,41 @@ // Dialog resources // LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -IDD_CONFIG_BOX DIALOGEX 0, 0, 251, 244 +IDD_CONFIG_BOX DIALOGEX 0, 0, 247, 281 STYLE DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU CAPTION "libADLMIDI settings" FONT 8, "MS Shell Dlg", 400, 0, 1 BEGIN - GROUPBOX "Instruments bank", IDC_INS_BANK, 9, 4, 233, 51, 0, WS_EX_LEFT - AUTORADIOBUTTON "Internal bank", IDC_BANK_INTERNAL, 15, 17, 63, 8, WS_GROUP | WS_TABSTOP, WS_EX_LEFT - COMBOBOX IDC_BANK_ID, 83, 14, 155, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - AUTORADIOBUTTON "External bank", IDC_BANK_EXTERNAL, 15, 33, 63, 8, WS_TABSTOP, WS_EX_LEFT - EDITTEXT IDC_BANK_PATH, 83, 31, 107, 14, WS_DISABLED | ES_AUTOHSCROLL, WS_EX_LEFT - PUSHBUTTON "Browse...", IDC_BROWSE_BANK, 194, 30, 45, 14, 0, WS_EX_LEFT - LTEXT "Chip emulator type:", IDC_CHIPEMU_LABEL, 11, 60, 67, 10, SS_LEFT, WS_EX_LEFT - COMBOBOX IDC_EMULATOR, 83, 58, 159, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - LTEXT "Number of chips", IDC_CHIPNUM_LABEL, 11, 78, 67, 8, SS_LEFT, WS_EX_LEFT - COMBOBOX IDC_NUM_CHIPS, 83, 76, 34, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - LTEXT "Number of 4OP voices", IDC_4OPSNUM_LABEL, 128, 78, 72, 8, SS_LEFT, WS_EX_LEFT - COMBOBOX IDC_NUM_4OPVO, 202, 76, 40, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - LTEXT "Volume model:", IDC_VM_LABEL, 11, 95, 67, 13, SS_LEFT, WS_EX_LEFT - COMBOBOX IDC_VOLUMEMODEL, 83, 95, 159, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - AUTOCHECKBOX "Full-panning stereo", IDC_FLAG_SOFTPAN, 11, 115, 227, 10, 0, WS_EX_LEFT - AUTO3STATE "Deep tremolo (Auto/Enable/Disable)", IDC_FLAG_TREMOLO, 11, 130, 227, 10, NOT WS_TABSTOP, WS_EX_LEFT - AUTO3STATE "Deep vibrato (Auto/Enable/Disable)", IDC_FLAG_VIBRATO, 11, 145, 227, 10, NOT WS_TABSTOP, WS_EX_LEFT - AUTOCHECKBOX "Scalable modulation", IDC_FLAG_SCALE, 11, 160, 227, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "Full-range brightness (CC74)", IDC_FLAG_FULLBRIGHT, 11, 175, 227, 10, 0, WS_EX_LEFT - PUSHBUTTON "Reset synth now", IDC_RESET_SYNTH, 73, 195, 80, 14, 0, WS_EX_LEFT - PUSHBUTTON "Restore defaults", IDC_RESTORE_DEFAULTS, 155, 195, 88, 14, 0, WS_EX_LEFT - PUSHBUTTON "About...", IDC_ABOUT, 10, 212, 50, 14, 0, WS_EX_LEFT - DEFPUSHBUTTON "OK", IDOK, 88, 212, 50, 14, 0, WS_EX_LEFT - PUSHBUTTON "Cancel", IDCANCEL, 141, 212, 50, 14, 0, WS_EX_LEFT - PUSHBUTTON "Apply", IDC_APPLYBUTTON, 194, 212, 50, 14, 0, WS_EX_LEFT - RTEXT "Settings will be applied immediately", IDC_BOTTOMNOTE_LABEL, 7, 227, 235, 8, SS_RIGHT, WS_EX_LEFT + COMBOBOX IDC_AUDIOOUT, 81, 7, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + AUTORADIOBUTTON "Internal bank", IDC_BANK_INTERNAL, 13, 35, 63, 8, WS_GROUP | WS_TABSTOP, WS_EX_LEFT + COMBOBOX IDC_BANK_ID, 81, 32, 155, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + AUTORADIOBUTTON "External bank", IDC_BANK_EXTERNAL, 13, 51, 63, 8, WS_TABSTOP, WS_EX_LEFT + EDITTEXT IDC_BANK_PATH, 81, 49, 107, 14, WS_DISABLED | ES_AUTOHSCROLL, WS_EX_LEFT + PUSHBUTTON "Browse...", IDC_BROWSE_BANK, 192, 48, 45, 14, 0, WS_EX_LEFT + COMBOBOX IDC_EMULATOR, 81, 77, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_NUM_CHIPS, 81, 95, 34, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_NUM_4OPVO, 201, 95, 40, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_VOLUMEMODEL, 81, 114, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_CHANALLOC, 81, 133, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + AUTOCHECKBOX "Full-panning stereo", IDC_FLAG_SOFTPAN, 8, 154, 227, 10, 0, WS_EX_LEFT + AUTO3STATE "Deep tremolo (Auto/Enable/Disable)", IDC_FLAG_TREMOLO, 8, 169, 227, 10, 0, WS_EX_LEFT + AUTO3STATE "Deep vibrato (Auto/Enable/Disable)", IDC_FLAG_VIBRATO, 8, 184, 227, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Scalable modulation", IDC_FLAG_SCALE, 8, 199, 227, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Full-range brightness (CC74)", IDC_FLAG_FULLBRIGHT, 8, 214, 227, 10, 0, WS_EX_LEFT + PUSHBUTTON "About...", IDC_ABOUT, 6, 234, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Reset synth now", IDC_RESET_SYNTH, 71, 234, 80, 14, 0, WS_EX_LEFT + PUSHBUTTON "Restore defaults", IDC_RESTORE_DEFAULTS, 153, 234, 88, 14, 0, WS_EX_LEFT + DEFPUSHBUTTON "OK", IDOK, 85, 251, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Cancel", IDCANCEL, 138, 251, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Apply", IDC_APPLYBUTTON, 191, 251, 50, 14, 0, WS_EX_LEFT + GROUPBOX "Instruments bank", IDC_INS_BANK, 7, 22, 233, 51, 0, WS_EX_LEFT + LTEXT "Chip emulator type:", IDC_CHIPEMU_LABEL, 9, 79, 67, 10, SS_LEFT, WS_EX_LEFT + LTEXT "Number of chips", IDC_CHIPNUM_LABEL, 9, 97, 67, 8, SS_LEFT, WS_EX_LEFT + LTEXT "Number of 4OP voices", IDC_4OPSNUM_LABEL, 126, 97, 72, 8, SS_LEFT, WS_EX_LEFT + LTEXT "Volume model:", IDC_VM_LABEL, 9, 116, 67, 8, SS_LEFT, WS_EX_LEFT + RTEXT "Settings will be applied immediately", IDC_BOTTOMNOTE_LABEL, 4, 266, 235, 8, SS_RIGHT, WS_EX_LEFT + LTEXT "Channels allocation:", IDC_CA_LABEL, 9, 135, 64, 8, SS_LEFT, WS_EX_LEFT + LTEXT "Audio output:", IDC_AUDIOOUT_LABEL, 11, 9, 65, 8, SS_LEFT, WS_EX_LEFT END diff --git a/utils/winmm_drv/cpl/config_dialog.c b/utils/winmm_drv/cpl/config_dialog.c index 195524d..3f5c66d 100644 --- a/utils/winmm_drv/cpl/config_dialog.c +++ b/utils/winmm_drv/cpl/config_dialog.c @@ -1,5 +1,6 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include #include #include @@ -38,6 +39,15 @@ static const char *const volume_models_descriptions[] = NULL }; +static const char *const channel_allocation_descriptions[] = +{ + "Auto (defined by bank)", + "Sounding off delay based", + "Same instrument", + "Any first released", + NULL +}; + static const char * const emulator_type_descriptions[] = { "Nuked OPL3 1.8", @@ -50,6 +60,7 @@ static const char * const emulator_type_descriptions[] = static DriverSettings g_setup; static HINSTANCE s_hModule; +static UINT s_audioOutPrev = WAVE_MAPPER; static void syncBankType(HWND hwnd, int type); static void sync4ops(HWND hwnd); @@ -109,6 +120,12 @@ static void syncWidget(HWND hwnd) updateBankName(hwnd, g_setup.bankPath); SendDlgItemMessageA(hwnd, IDC_EMULATOR, CB_SETCURSEL, (WPARAM)g_setup.emulatorId, (LPARAM)0); SendDlgItemMessageA(hwnd, IDC_VOLUMEMODEL, CB_SETCURSEL, (WPARAM)g_setup.volumeModel, (LPARAM)0); + SendDlgItemMessageA(hwnd, IDC_CHANALLOC, CB_SETCURSEL, (WPARAM)g_setup.chanAlloc + 1, (LPARAM)0); + + if(g_setup.outputDevice == WAVE_MAPPER) + SendDlgItemMessageA(hwnd, IDC_AUDIOOUT, CB_SETCURSEL, (WPARAM)0, (LPARAM)0); + else + SendDlgItemMessageA(hwnd, IDC_AUDIOOUT, CB_SETCURSEL, (WPARAM)g_setup.outputDevice + 1, (LPARAM)0); sync4ops(hwnd); } @@ -116,6 +133,8 @@ static void syncWidget(HWND hwnd) static void buildLists(HWND hwnd) { int i, bMax; + UINT ai, aMax; + WAVEOUTCAPSW wavDev; HMODULE lib; const char *const* list; BankNamesCount adl_getBanksCount; @@ -152,11 +171,27 @@ static void buildLists(HWND hwnd) SendDlgItemMessageA(hwnd, IDC_VOLUMEMODEL, CB_ADDSTRING, (LPARAM)0, (LPARAM)volume_models_descriptions[i]); } + // Channel allocation mode + for(i = 0; channel_allocation_descriptions[i] != NULL; ++i) + { + SendDlgItemMessageA(hwnd, IDC_CHANALLOC, CB_ADDSTRING, (LPARAM)0, (LPARAM)channel_allocation_descriptions[i]); + } + // Emulators list for(i = 0; emulator_type_descriptions[i] != NULL; ++i) { SendDlgItemMessageA(hwnd, IDC_EMULATOR, CB_ADDSTRING, (LPARAM)0, (LPARAM)emulator_type_descriptions[i]); } + + // Audio devices + aMax = waveOutGetNumDevs(); + SendDlgItemMessageW(hwnd, IDC_AUDIOOUT, CB_ADDSTRING, (LPARAM)0, (WPARAM)L"[Default device]"); + for(ai = 0; ai < aMax; ++ai) + { + memset(&wavDev, 0, sizeof(wavDev)); + waveOutGetDevCapsW(ai, &wavDev, sizeof(wavDev)); + SendDlgItemMessageW(hwnd, IDC_AUDIOOUT, CB_ADDSTRING, (LPARAM)0, (WPARAM)wavDev.szPname); + } } static void syncBankType(HWND hwnd, int type) @@ -209,6 +244,18 @@ static void openCustomBank(HWND hwnd) } } +static void warnIfOutChanged(HWND hwnd) +{ + if(s_audioOutPrev != g_setup.outputDevice) + { + s_audioOutPrev = g_setup.outputDevice; + MessageBoxW(hwnd, + L"To apply the change of the audio output device, you should reload your applications.", + L"Audio output device changed", + MB_OK|MB_ICONINFORMATION); + } +} + INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) @@ -230,6 +277,17 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar MB_OK); break; + case IDC_AUDIOOUT: + if(HIWORD(wParam) == CBN_SELCHANGE) + { + g_setup.outputDevice = SendMessageW((HWND)lParam, (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0); + if(g_setup.outputDevice == 0) + g_setup.outputDevice = WAVE_MAPPER; + else + g_setup.outputDevice--; + } + break; + case IDC_NUM_CHIPS: if(HIWORD(wParam) == CBN_SELCHANGE) { @@ -260,6 +318,13 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar } break; + case IDC_CHANALLOC: + if(HIWORD(wParam) == CBN_SELCHANGE) + { + g_setup.chanAlloc = SendMessageW((HWND)lParam, (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0) - 1; + } + break; + case IDC_BANK_INTERNAL: g_setup.useExternalBank = 0; syncBankType(hwnd, FALSE); @@ -329,11 +394,13 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar case IDC_APPLYBUTTON: saveSetup(&g_setup); sendSignal(DRV_SIGNAL_RELOAD_SETUP); + warnIfOutChanged(hwnd); break; case IDOK: saveSetup(&g_setup); sendSignal(DRV_SIGNAL_RELOAD_SETUP); + warnIfOutChanged(hwnd); EndDialog(hwnd, IDOK); break; @@ -358,6 +425,8 @@ BOOL runAdlSetupBox(HINSTANCE hModule, HWND hwnd) s_hModule = hModule; loadSetup(&g_setup); + // Keep the last audio output setup for the future + s_audioOutPrev = g_setup.outputDevice; DialogBoxW(hModule, MAKEINTRESOURCEW(IDD_CONFIG_BOX), hwnd, ToolDlgProc); diff --git a/utils/winmm_drv/cpl/resource.h b/utils/winmm_drv/cpl/resource.h index 4d41e9f..27b17e5 100644 --- a/utils/winmm_drv/cpl/resource.h +++ b/utils/winmm_drv/cpl/resource.h @@ -28,5 +28,9 @@ #define IDC_4OPSNUM_LABEL 1025 #define IDC_RESET_SYNTH 1026 #define IDC_BOTTOMNOTE_LABEL 1027 +#define IDC_CHANALLOC 1028 +#define IDC_CA_LABEL 1029 +#define IDC_AUDIOOUT 1030 +#define IDC_AUDIOOUT_LABEL 1031 #define IDC_DRIVERNAME 40000 #define IDC_DRIVERDESC 40001 diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index 29cbb78..b1baa13 100644 --- a/utils/winmm_drv/src/MidiSynth.cpp +++ b/utils/winmm_drv/src/MidiSynth.cpp @@ -133,7 +133,7 @@ private: bool stopProcessing; public: - int Init(Bit16s *buffer, unsigned int bufferSize, unsigned int chunkSize, bool useRingBuffer, unsigned int sampleRate) + int Init(Bit16s *buffer, unsigned int bufferSize, unsigned int chunkSize, bool useRingBuffer, unsigned int sampleRate, UINT outDevice) { DWORD callbackType = CALLBACK_NULL; DWORD_PTR callback = (DWORD_PTR)NULL; @@ -148,7 +148,7 @@ public: PCMWAVEFORMAT wFormat = {WAVE_FORMAT_PCM, 2, sampleRate, sampleRate * 4, 4, 16}; // Open waveout device - int wResult = waveOutOpen(&hWaveOut, WAVE_MAPPER, (LPWAVEFORMATEX)&wFormat, callback, (DWORD_PTR)&midiSynth, callbackType); + int wResult = waveOutOpen(&hWaveOut, outDevice, (LPWAVEFORMATEX)&wFormat, callback, (DWORD_PTR)&midiSynth, callbackType); if(wResult != MMSYSERR_NOERROR) { MessageBoxW(NULL, L"Failed to open waveform output device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION); @@ -308,17 +308,21 @@ void WaveOutWin32::RenderingThread(void *) while(!s_waveOut.stopProcessing) { bool allBuffersRendered = true; + for(UINT i = 0; i < s_waveOut.chunks; i++) { if(s_waveOut.WaveHdr[i].dwFlags & WHDR_DONE) { allBuffersRendered = false; midiSynth.Render((Bit16s *)s_waveOut.WaveHdr[i].lpData, s_waveOut.WaveHdr[i].dwBufferLength / 4); + if(waveOutWrite(s_waveOut.hWaveOut, &s_waveOut.WaveHdr[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) MessageBoxW(NULL, L"Failed to write block to device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION); + midiSynth.CheckForSignals(); } } + if(allBuffersRendered) WaitForSingleObject(s_waveOut.hEvent, INFINITE); } @@ -518,8 +522,12 @@ int MidiSynth::Init() m_setupInit = false; LoadSynthSetup(); - UINT wResult = s_waveOut.Init(buffer, bufferSize, chunkSize, useRingBuffer, sampleRate); - if(wResult) return wResult; + UINT wResult = s_waveOut.Init(buffer, bufferSize, chunkSize, useRingBuffer, sampleRate, m_setup.outputDevice); + + if(wResult) + return wResult; + + m_setupCurrent.outputDevice = m_setup.outputDevice; // Start playing stream adl_generate(synth, bufferSize * 2, buffer); @@ -664,6 +672,12 @@ void MidiSynth::LoadSynthSetup() m_setupCurrent.volumeModel = m_setup.volumeModel; } + if(!m_setupInit || m_setupCurrent.chanAlloc != m_setup.chanAlloc) + { + adl_setChannelAllocMode(synth, m_setup.chanAlloc); + m_setupCurrent.chanAlloc = m_setup.chanAlloc; + } + if(!m_setupInit || m_setupCurrent.numChips != m_setup.numChips) { adl_setNumChips(synth, m_setup.numChips); -- cgit v1.2.3 From c68dc6970d5b4abab13e138ac977f7212ef32e4a Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 11:26:10 +0300 Subject: WinMM: Use the Float32 for WaveOut --- utils/winmm_drv/src/MidiSynth.cpp | 53 +++++++++++++++++++++++++++++---------- utils/winmm_drv/src/MidiSynth.h | 5 ++-- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index b1baa13..a03ee42 100644 --- a/utils/winmm_drv/src/MidiSynth.cpp +++ b/utils/winmm_drv/src/MidiSynth.cpp @@ -23,6 +23,8 @@ namespace OPL3Emu static MidiSynth &midiSynth = MidiSynth::getInstance(); +static const unsigned int s_audioChannels = 2; + static class MidiStream { private: @@ -133,10 +135,13 @@ private: bool stopProcessing; public: - int Init(Bit16s *buffer, unsigned int bufferSize, unsigned int chunkSize, bool useRingBuffer, unsigned int sampleRate, UINT outDevice) + int Init(float *buffer, unsigned int bufferSize, + unsigned int chunkSize, bool useRingBuffer, + unsigned int sampleRate, UINT outDevice) { DWORD callbackType = CALLBACK_NULL; DWORD_PTR callback = (DWORD_PTR)NULL; + hEvent = NULL; if(!useRingBuffer) { @@ -145,10 +150,18 @@ public: callbackType = CALLBACK_EVENT; } - PCMWAVEFORMAT wFormat = {WAVE_FORMAT_PCM, 2, sampleRate, sampleRate * 4, 4, 16}; + PCMWAVEFORMAT wFormat = + { + WAVE_FORMAT_IEEE_FLOAT, s_audioChannels, + sampleRate, + (DWORD)(sampleRate * sizeof(float) * s_audioChannels), + s_audioChannels * sizeof(float), + 8 * sizeof(float) + }; // Open waveout device - int wResult = waveOutOpen(&hWaveOut, outDevice, (LPWAVEFORMATEX)&wFormat, callback, (DWORD_PTR)&midiSynth, callbackType); + int wResult = waveOutOpen(&hWaveOut, outDevice, (LPWAVEFORMATEX)&wFormat, + callback, (DWORD_PTR)&midiSynth, callbackType); if(wResult != MMSYSERR_NOERROR) { MessageBoxW(NULL, L"Failed to open waveform output device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION); @@ -158,13 +171,15 @@ public: // Prepare headers chunks = useRingBuffer ? 1 : bufferSize / chunkSize; WaveHdr = new WAVEHDR[chunks]; + LPSTR chunkStart = (LPSTR)buffer; - DWORD chunkBytes = 4 * chunkSize; + DWORD chunkBytes = s_audioChannels * sizeof(float) * chunkSize; + for(UINT i = 0; i < chunks; i++) { if(useRingBuffer) { - WaveHdr[i].dwBufferLength = 4 * bufferSize; + WaveHdr[i].dwBufferLength = s_audioChannels * sizeof(float) * bufferSize; WaveHdr[i].lpData = chunkStart; WaveHdr[i].dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; WaveHdr[i].dwLoops = -1L; @@ -237,7 +252,7 @@ public: return 4; } } - _beginthread(RenderingThread, 16384, this); + _beginthread(RenderingThread, 16384 * 2, this); return 0; } @@ -288,6 +303,7 @@ public: std::cout << "OPL3: GetPos() wrap: " << delta << "\n"; ++getPosWraps; } + prevPlayPos = mmTime.u.sample; return mmTime.u.sample + getPosWraps * (1 << 27); } @@ -314,7 +330,8 @@ void WaveOutWin32::RenderingThread(void *) if(s_waveOut.WaveHdr[i].dwFlags & WHDR_DONE) { allBuffersRendered = false; - midiSynth.Render((Bit16s *)s_waveOut.WaveHdr[i].lpData, s_waveOut.WaveHdr[i].dwBufferLength / 4); + midiSynth.Render((float *)s_waveOut.WaveHdr[i].lpData, + s_waveOut.WaveHdr[i].dwBufferLength / (sizeof(float) * 2)); if(waveOutWrite(s_waveOut.hWaveOut, &s_waveOut.WaveHdr[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) MessageBoxW(NULL, L"Failed to write block to device", L"libADLMIDI", MB_OK | MB_ICONEXCLAMATION); @@ -373,12 +390,12 @@ void MidiSynth::RenderAvailableSpace() return; } } - midiSynth.Render(buffer + 2 * framesRendered, framesToRender); + midiSynth.Render(buffer + sizeof(float) * framesRendered, framesToRender); } // Renders totalFrames frames starting from bufpos // The number of frames rendered is added to the global counter framesRendered -void MidiSynth::Render(Bit16s *bufpos, DWORD totalFrames) +void MidiSynth::Render(float *bufpos, DWORD totalFrames) { while(totalFrames > 0) { @@ -444,10 +461,12 @@ void MidiSynth::Render(Bit16s *bufpos, DWORD totalFrames) } synthEvent.Wait(); - adl_generate(synth, framesToRender * 2, bufpos); + adl_generateFormat(synth, framesToRender * s_audioChannels, + (ADL_UInt8*)bufpos, (ADL_UInt8*)bufpos + synthAudioFormat.containerSize, + &synthAudioFormat); synthEvent.Release(); framesRendered += framesToRender; - bufpos += 2 * framesToRender; // each frame consists of two samples for both the Left and Right channels + bufpos += s_audioChannels * framesToRender; // each frame consists of two samples for both the Left and Right channels totalFrames -= framesToRender; } @@ -494,6 +513,7 @@ void MidiSynth::LoadSettings() chunkSize = MillisToFrames(10); midiLatency = MillisToFrames(0); useRingBuffer = false; + if(!useRingBuffer) { // Number of chunks should be ceil(bufferSize / chunkSize) @@ -506,7 +526,7 @@ void MidiSynth::LoadSettings() int MidiSynth::Init() { LoadSettings(); - buffer = new Bit16s[2 * bufferSize]; // each frame consists of two samples for both the Left and Right channels + buffer = new float[s_audioChannels * bufferSize]; // each frame consists of two samples for both the Left and Right channels // Init synth if(synthEvent.Init()) @@ -519,6 +539,10 @@ int MidiSynth::Init() return 1; } + synthAudioFormat.type = ADLMIDI_SampleType_F32; + synthAudioFormat.sampleOffset = s_audioChannels * sizeof(float); + synthAudioFormat.containerSize = sizeof(float); + m_setupInit = false; LoadSynthSetup(); @@ -530,7 +554,10 @@ int MidiSynth::Init() m_setupCurrent.outputDevice = m_setup.outputDevice; // Start playing stream - adl_generate(synth, bufferSize * 2, buffer); + adl_generateFormat(synth, bufferSize * s_audioChannels, + (ADL_UInt8*)buffer, + (ADL_UInt8*)buffer + synthAudioFormat.containerSize, + &synthAudioFormat); framesRendered = 0; wResult = s_waveOut.Start(); diff --git a/utils/winmm_drv/src/MidiSynth.h b/utils/winmm_drv/src/MidiSynth.h index bf2da02..a590a77 100644 --- a/utils/winmm_drv/src/MidiSynth.h +++ b/utils/winmm_drv/src/MidiSynth.h @@ -53,10 +53,11 @@ private: Bit8u reverbTime; Bit8u reverbLevel; - Bit16s *buffer; + float *buffer; DWORD framesRendered; ADL_MIDIPlayer *synth; + ADLMIDI_AudioFormat synthAudioFormat; bool m_setupInit; DriverSettings m_setup; @@ -76,7 +77,7 @@ public: void ResetSynth(); void PanicSynth(); void RenderAvailableSpace(); - void Render(Bit16s *bufpos, DWORD totalFrames); + void Render(float *bufpos, DWORD totalFrames); void CheckForSignals(); void PushMIDI(DWORD msg); void PlaySysex(Bit8u *bufpos, DWORD len); -- cgit v1.2.3 From b00d3f8d933fc7de26b954bedf841cb484139562 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 18:26:45 +0300 Subject: WinMM: Added gaining function --- utils/winmm_drv/config/regconfig.c | 19 +++++++++++- utils/winmm_drv/config/regconfig.h | 6 ++++ utils/winmm_drv/cpl/adlconfig.rc | 60 +++++++++++++++++++------------------ utils/winmm_drv/cpl/config_dialog.c | 15 ++++++++++ utils/winmm_drv/cpl/resource.h | 2 ++ utils/winmm_drv/src/MidiSynth.cpp | 39 ++++++++++++++++++++++-- utils/winmm_drv/src/MidiSynth.h | 7 +++++ utils/winmm_drv/src/winmm_drv.cpp | 21 +++++++++---- 8 files changed, 132 insertions(+), 37 deletions(-) diff --git a/utils/winmm_drv/config/regconfig.c b/utils/winmm_drv/config/regconfig.c index 6e35df0..a049a7d 100644 --- a/utils/winmm_drv/config/regconfig.c +++ b/utils/winmm_drv/config/regconfig.c @@ -163,11 +163,13 @@ void setupDefault(DriverSettings *setup) setup->flagFullBrightness = BST_UNCHECKED; setup->volumeModel = 0; - setup->chanAlloc = 0; + setup->chanAlloc = -1; setup->numChips = 4; setup->num4ops = -1; setup->outputDevice = (UINT)-1; + + setup->gain100 = 100; } @@ -224,6 +226,9 @@ void loadSetup(DriverSettings *setup) if(readUIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"outputDevice", &uVal)) setup->outputDevice = uVal; + + if(readUIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"gain100", &uVal)) + setup->gain100 = uVal; } void saveSetup(DriverSettings *setup) @@ -246,8 +251,20 @@ void saveSetup(DriverSettings *setup) writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"numChips", setup->numChips); writeIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"num4ops", setup->num4ops); writeUIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"outputDevice", setup->outputDevice); + writeUIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"gain100", setup->gain100); +} + +void getGain(DriverSettings *setup) +{ + UINT uVal; + if(readUIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"gain100", &uVal)) + setup->gain100 = uVal; } +void saveGain(DriverSettings *setup) +{ + writeUIntToRegistry(HKEY_CURRENT_USER, s_regPath, L"gain100", setup->gain100); +} static const PWCHAR s_regPathNotify = L"SOFTWARE\\Wohlstand\\libADLMIDI\\notify"; diff --git a/utils/winmm_drv/config/regconfig.h b/utils/winmm_drv/config/regconfig.h index 7c49bd6..2dac28a 100644 --- a/utils/winmm_drv/config/regconfig.h +++ b/utils/winmm_drv/config/regconfig.h @@ -30,6 +30,8 @@ typedef struct DriverSettings_t int num4ops; UINT outputDevice; + + UINT gain100; } DriverSettings; extern const WCHAR g_adlSignalMemory[]; @@ -38,9 +40,13 @@ extern void setupDefault(DriverSettings *setup); extern void loadSetup(DriverSettings *setup); extern void saveSetup(DriverSettings *setup); +extern void saveGain(DriverSettings *setup); +extern void getGain(DriverSettings *setup); + #define DRV_SIGNAL_RELOAD_SETUP 1 #define DRV_SIGNAL_RESET_SYNTH 2 +#define DRV_SIGNAL_UPDATE_GAIN 3 // Client /** diff --git a/utils/winmm_drv/cpl/adlconfig.rc b/utils/winmm_drv/cpl/adlconfig.rc index ff7fcf2..edc5048 100644 --- a/utils/winmm_drv/cpl/adlconfig.rc +++ b/utils/winmm_drv/cpl/adlconfig.rc @@ -14,41 +14,43 @@ // Dialog resources // LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -IDD_CONFIG_BOX DIALOGEX 0, 0, 247, 281 +IDD_CONFIG_BOX DIALOGEX 0, 0, 247, 307 STYLE DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU CAPTION "libADLMIDI settings" FONT 8, "MS Shell Dlg", 400, 0, 1 BEGIN COMBOBOX IDC_AUDIOOUT, 81, 7, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - AUTORADIOBUTTON "Internal bank", IDC_BANK_INTERNAL, 13, 35, 63, 8, WS_GROUP | WS_TABSTOP, WS_EX_LEFT - COMBOBOX IDC_BANK_ID, 81, 32, 155, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - AUTORADIOBUTTON "External bank", IDC_BANK_EXTERNAL, 13, 51, 63, 8, WS_TABSTOP, WS_EX_LEFT - EDITTEXT IDC_BANK_PATH, 81, 49, 107, 14, WS_DISABLED | ES_AUTOHSCROLL, WS_EX_LEFT - PUSHBUTTON "Browse...", IDC_BROWSE_BANK, 192, 48, 45, 14, 0, WS_EX_LEFT - COMBOBOX IDC_EMULATOR, 81, 77, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - COMBOBOX IDC_NUM_CHIPS, 81, 95, 34, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - COMBOBOX IDC_NUM_4OPVO, 201, 95, 40, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - COMBOBOX IDC_VOLUMEMODEL, 81, 114, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT - COMBOBOX IDC_CHANALLOC, 81, 133, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT - AUTOCHECKBOX "Full-panning stereo", IDC_FLAG_SOFTPAN, 8, 154, 227, 10, 0, WS_EX_LEFT - AUTO3STATE "Deep tremolo (Auto/Enable/Disable)", IDC_FLAG_TREMOLO, 8, 169, 227, 10, 0, WS_EX_LEFT - AUTO3STATE "Deep vibrato (Auto/Enable/Disable)", IDC_FLAG_VIBRATO, 8, 184, 227, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "Scalable modulation", IDC_FLAG_SCALE, 8, 199, 227, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "Full-range brightness (CC74)", IDC_FLAG_FULLBRIGHT, 8, 214, 227, 10, 0, WS_EX_LEFT - PUSHBUTTON "About...", IDC_ABOUT, 6, 234, 50, 14, 0, WS_EX_LEFT - PUSHBUTTON "Reset synth now", IDC_RESET_SYNTH, 71, 234, 80, 14, 0, WS_EX_LEFT - PUSHBUTTON "Restore defaults", IDC_RESTORE_DEFAULTS, 153, 234, 88, 14, 0, WS_EX_LEFT - DEFPUSHBUTTON "OK", IDOK, 85, 251, 50, 14, 0, WS_EX_LEFT - PUSHBUTTON "Cancel", IDCANCEL, 138, 251, 50, 14, 0, WS_EX_LEFT - PUSHBUTTON "Apply", IDC_APPLYBUTTON, 191, 251, 50, 14, 0, WS_EX_LEFT - GROUPBOX "Instruments bank", IDC_INS_BANK, 7, 22, 233, 51, 0, WS_EX_LEFT - LTEXT "Chip emulator type:", IDC_CHIPEMU_LABEL, 9, 79, 67, 10, SS_LEFT, WS_EX_LEFT - LTEXT "Number of chips", IDC_CHIPNUM_LABEL, 9, 97, 67, 8, SS_LEFT, WS_EX_LEFT - LTEXT "Number of 4OP voices", IDC_4OPSNUM_LABEL, 126, 97, 72, 8, SS_LEFT, WS_EX_LEFT - LTEXT "Volume model:", IDC_VM_LABEL, 9, 116, 67, 8, SS_LEFT, WS_EX_LEFT - RTEXT "Settings will be applied immediately", IDC_BOTTOMNOTE_LABEL, 4, 266, 235, 8, SS_RIGHT, WS_EX_LEFT - LTEXT "Channels allocation:", IDC_CA_LABEL, 9, 135, 64, 8, SS_LEFT, WS_EX_LEFT + CONTROL "", IDC_GAIN, TRACKBAR_CLASS, WS_TABSTOP | TBS_AUTOTICKS | TBS_BOTH, 84, 21, 155, 20, WS_EX_LEFT + AUTORADIOBUTTON "Internal bank", IDC_BANK_INTERNAL, 13, 61, 63, 8, WS_GROUP | WS_TABSTOP, WS_EX_LEFT + COMBOBOX IDC_BANK_ID, 81, 58, 155, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + AUTORADIOBUTTON "External bank", IDC_BANK_EXTERNAL, 13, 77, 63, 8, WS_TABSTOP, WS_EX_LEFT + EDITTEXT IDC_BANK_PATH, 81, 75, 107, 14, WS_DISABLED | ES_AUTOHSCROLL, WS_EX_LEFT + PUSHBUTTON "Browse...", IDC_BROWSE_BANK, 192, 74, 45, 14, 0, WS_EX_LEFT + COMBOBOX IDC_EMULATOR, 81, 103, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_NUM_CHIPS, 81, 121, 34, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_NUM_4OPVO, 201, 121, 40, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_VOLUMEMODEL, 81, 140, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT + COMBOBOX IDC_CHANALLOC, 81, 159, 160, 200, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT + AUTOCHECKBOX "Full-panning stereo", IDC_FLAG_SOFTPAN, 8, 180, 227, 10, 0, WS_EX_LEFT + AUTO3STATE "Deep tremolo (Auto/Enable/Disable)", IDC_FLAG_TREMOLO, 8, 195, 227, 10, 0, WS_EX_LEFT + AUTO3STATE "Deep vibrato (Auto/Enable/Disable)", IDC_FLAG_VIBRATO, 8, 210, 227, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Scalable modulation", IDC_FLAG_SCALE, 8, 225, 227, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Full-range brightness (CC74)", IDC_FLAG_FULLBRIGHT, 8, 240, 227, 10, 0, WS_EX_LEFT + PUSHBUTTON "About...", IDC_ABOUT, 6, 260, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Reset synth now", IDC_RESET_SYNTH, 71, 260, 80, 14, 0, WS_EX_LEFT + PUSHBUTTON "Restore defaults", IDC_RESTORE_DEFAULTS, 153, 260, 88, 14, 0, WS_EX_LEFT + DEFPUSHBUTTON "OK", IDOK, 85, 277, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Cancel", IDCANCEL, 138, 277, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Apply", IDC_APPLYBUTTON, 191, 277, 50, 14, 0, WS_EX_LEFT + GROUPBOX "Instruments bank", IDC_INS_BANK, 7, 48, 233, 51, 0, WS_EX_LEFT + LTEXT "Chip emulator type:", IDC_CHIPEMU_LABEL, 9, 105, 67, 10, SS_LEFT, WS_EX_LEFT + LTEXT "Number of chips", IDC_CHIPNUM_LABEL, 9, 123, 67, 8, SS_LEFT, WS_EX_LEFT + LTEXT "Number of 4OP voices", IDC_4OPSNUM_LABEL, 126, 123, 72, 8, SS_LEFT, WS_EX_LEFT + LTEXT "Volume model:", IDC_VM_LABEL, 9, 142, 67, 8, SS_LEFT, WS_EX_LEFT + RTEXT "Settings will be applied immediately", IDC_BOTTOMNOTE_LABEL, 4, 292, 235, 8, SS_RIGHT, WS_EX_LEFT + LTEXT "Channels allocation:", IDC_CA_LABEL, 9, 161, 64, 8, SS_LEFT, WS_EX_LEFT LTEXT "Audio output:", IDC_AUDIOOUT_LABEL, 11, 9, 65, 8, SS_LEFT, WS_EX_LEFT + LTEXT "Output gain:", IDC_GAIN_LABEL, 11, 29, 65, 8, SS_LEFT, WS_EX_LEFT END diff --git a/utils/winmm_drv/cpl/config_dialog.c b/utils/winmm_drv/cpl/config_dialog.c index 3f5c66d..cc2d553 100644 --- a/utils/winmm_drv/cpl/config_dialog.c +++ b/utils/winmm_drv/cpl/config_dialog.c @@ -99,6 +99,11 @@ static void syncWidget(HWND hwnd) else SendDlgItemMessage(hwnd, IDC_BANK_INTERNAL, BM_SETCHECK, 1, 0); + SendDlgItemMessage(hwnd, IDC_GAIN, TBM_SETRANGE, TRUE, MAKELPARAM(0, 1000)); + SendDlgItemMessage(hwnd, IDC_GAIN, TBM_SETPAGESIZE, 0, 10); + SendDlgItemMessage(hwnd, IDC_GAIN, TBM_SETTICFREQ, 100, 0); + SendDlgItemMessage(hwnd, IDC_GAIN, TBM_SETPOS, TRUE, g_setup.gain100); + syncBankType(hwnd, g_setup.useExternalBank); SendDlgItemMessage(hwnd, IDC_FLAG_TREMOLO, BM_SETCHECK, g_setup.flagDeepTremolo, 0); @@ -265,6 +270,16 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar syncWidget(hwnd); return TRUE; + case WM_HSCROLL: + if(lParam == GetDlgItem(hwnd, IDC_GAIN)) + { + g_setup.gain100 = SendMessageW((HWND)lParam, (UINT)TBM_GETPOS, (WPARAM)0, (LPARAM)0); + saveGain(&g_setup); + sendSignal(DRV_SIGNAL_UPDATE_GAIN); + break; + } + break; + case WM_COMMAND: switch(LOWORD(wParam)) { diff --git a/utils/winmm_drv/cpl/resource.h b/utils/winmm_drv/cpl/resource.h index 27b17e5..78461c5 100644 --- a/utils/winmm_drv/cpl/resource.h +++ b/utils/winmm_drv/cpl/resource.h @@ -32,5 +32,7 @@ #define IDC_CA_LABEL 1029 #define IDC_AUDIOOUT 1030 #define IDC_AUDIOOUT_LABEL 1031 +#define IDC_GAIN 1032 +#define IDC_GAIN_LABEL 1033 #define IDC_DRIVERNAME 40000 #define IDC_DRIVERDESC 40001 diff --git a/utils/winmm_drv/src/MidiSynth.cpp b/utils/winmm_drv/src/MidiSynth.cpp index a03ee42..e559a4f 100644 --- a/utils/winmm_drv/src/MidiSynth.cpp +++ b/utils/winmm_drv/src/MidiSynth.cpp @@ -464,6 +464,16 @@ void MidiSynth::Render(float *bufpos, DWORD totalFrames) adl_generateFormat(synth, framesToRender * s_audioChannels, (ADL_UInt8*)bufpos, (ADL_UInt8*)bufpos + synthAudioFormat.containerSize, &synthAudioFormat); + + // Apply the volume + float g_l = volumeFactorL * gain; + float g_r = volumeFactorR * gain; + for(size_t i = 0; i < framesToRender * s_audioChannels; i += s_audioChannels) + { + bufpos[i + 0] *= g_l; + bufpos[i + 1] *= g_r; + } + synthEvent.Release(); framesRendered += framesToRender; bufpos += s_audioChannels * framesToRender; // each frame consists of two samples for both the Left and Right channels @@ -484,15 +494,19 @@ void MidiSynth::CheckForSignals() switch(cmd) { - case 1: // Reload settings on the fly + case DRV_SIGNAL_RELOAD_SETUP: // Reload settings on the fly this->loadSetup(); LoadSynthSetup(); break; - case 2: + case DRV_SIGNAL_RESET_SYNTH: adl_reset(synth); break; + case DRV_SIGNAL_UPDATE_GAIN: + this->loadGain(); + break; + default: break; } @@ -513,6 +527,9 @@ void MidiSynth::LoadSettings() chunkSize = MillisToFrames(10); midiLatency = MillisToFrames(0); useRingBuffer = false; + volumeFactorL = 1.0f; + volumeFactorR = 1.0f; + gain = 1.0f; if(!useRingBuffer) { @@ -621,9 +638,27 @@ void MidiSynth::PlaySysex(Bit8u *bufpos, DWORD len) synthEvent.Release(); } +void MidiSynth::SetVolume(DWORD vol) +{ + volumeFactorR = (float)0xFFFF / HIWORD(vol); + volumeFactorL = (float)0xFFFF / LOWORD(vol); +} + +DWORD MidiSynth::GetVolume() +{ + return MAKELONG((DWORD)(0xFFFF * volumeFactorL), (DWORD)(0xFFFF * volumeFactorR)); +} + void MidiSynth::loadSetup() { ::loadSetup(&m_setup); + gain = (float)m_setup.gain100 / 100.f; +} + +void MidiSynth::loadGain() +{ + ::getGain(&m_setup); + gain = (float)m_setup.gain100 / 100.f; } void MidiSynth::LoadSynthSetup() diff --git a/utils/winmm_drv/src/MidiSynth.h b/utils/winmm_drv/src/MidiSynth.h index a590a77..0442f7b 100644 --- a/utils/winmm_drv/src/MidiSynth.h +++ b/utils/winmm_drv/src/MidiSynth.h @@ -52,6 +52,9 @@ private: Bit8u reverbMode; Bit8u reverbTime; Bit8u reverbLevel; + float volumeFactorL; + float volumeFactorR; + float gain; float *buffer; DWORD framesRendered; @@ -82,7 +85,11 @@ public: void PushMIDI(DWORD msg); void PlaySysex(Bit8u *bufpos, DWORD len); + void SetVolume(DWORD vol); + DWORD GetVolume(); + void loadSetup(); + void loadGain(); void LoadSynthSetup(); }; diff --git a/utils/winmm_drv/src/winmm_drv.cpp b/utils/winmm_drv/src/winmm_drv.cpp index 7f65dda..9baa56a 100644 --- a/utils/winmm_drv/src/winmm_drv.cpp +++ b/utils/winmm_drv/src/winmm_drv.cpp @@ -201,6 +201,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) CHAR synthName[] = "libADLMIDI synth\0"; WCHAR synthNameW[] = L"libADLMIDI synth\0"; + DWORD support = MIDICAPS_VOLUME | MIDICAPS_LRVOLUME; switch(capsSize) { @@ -214,7 +215,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCapsA->wVoices = 0; myCapsA->wNotes = 0; myCapsA->wChannelMask = 0xffff; - myCapsA->dwSupport = 0; + myCapsA->dwSupport = support; return MMSYSERR_NOERROR; case(sizeof(MIDIOUTCAPSW)): @@ -227,7 +228,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCapsW->wVoices = 0; myCapsW->wNotes = 0; myCapsW->wChannelMask = 0xffff; - myCapsW->dwSupport = 0; + myCapsW->dwSupport = support; return MMSYSERR_NOERROR; case(sizeof(MIDIOUTCAPS2A)): @@ -240,7 +241,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCaps2A->wVoices = 0; myCaps2A->wNotes = 0; myCaps2A->wChannelMask = 0xffff; - myCaps2A->dwSupport = 0; + myCaps2A->dwSupport = support; return MMSYSERR_NOERROR; case(sizeof(MIDIOUTCAPS2W)): @@ -253,7 +254,7 @@ EXTERN_C HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) myCaps2W->wVoices = 0; myCaps2W->wNotes = 0; myCaps2W->wChannelMask = 0xffff; - myCaps2W->dwSupport = 0; + myCaps2W->dwSupport = support; return MMSYSERR_NOERROR; default: @@ -316,7 +317,8 @@ LONG CloseDriver(Driver *driver, UINT uDeviceID, UINT uMsg, DWORD_PTR dwUser, DW return MMSYSERR_NOERROR; } -EXTERN_C DWORD __declspec(dllexport) __stdcall modMessage(DWORD uDeviceID, DWORD uMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +EXTERN_C DWORD __declspec(dllexport) __stdcall +modMessage(DWORD uDeviceID, DWORD uMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { MIDIHDR *midiHdr; Driver *driver = &drivers[uDeviceID]; @@ -377,6 +379,15 @@ EXTERN_C DWORD __declspec(dllexport) __stdcall modMessage(DWORD uDeviceID, DWORD DoCallback(uDeviceID, dwUser, MOM_DONE, dwParam1, (DWORD_PTR)NULL); return MMSYSERR_NOERROR; + case MODM_GETVOLUME: + if(dwParam1) + *(DWORD *)dwParam1 = midiSynth.GetVolume(); + return MMSYSERR_NOERROR; + + case MODM_SETVOLUME: + midiSynth.SetVolume(dwParam1); + return MMSYSERR_NOERROR; + case MODM_GETNUMDEVS: return 0x1; -- cgit v1.2.3 From 0a95f6178f4cf1e3f27ef215865455266d43483d Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 20:25:00 +0300 Subject: WinMM: Fixed the MinGW workaround --- utils/winmm_drv/src/winmm_drv.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/winmm_drv/src/winmm_drv.cpp b/utils/winmm_drv/src/winmm_drv.cpp index 9baa56a..09f38d2 100644 --- a/utils/winmm_drv/src/winmm_drv.cpp +++ b/utils/winmm_drv/src/winmm_drv.cpp @@ -266,8 +266,12 @@ void DoCallback(int driverNum, DWORD_PTR clientNum, DWORD msg, DWORD_PTR param1, { Driver::Client *client = &drivers[driverNum].clients[clientNum]; #ifdef __MINGW32__ - if(s_DriverCallback) + if(!s_DriverCallback) + { initWorkarounds(); + if(!s_DriverCallback) + return; // Ouch! + } #endif DriverCallback(client->callback, client->flags, drivers[driverNum].hdrvr, msg, client->instance, param1, param2); } -- cgit v1.2.3 From 572da4a9335a5a7f98baaedf1c982f7ac6c385d5 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 22 Aug 2024 20:52:32 +0300 Subject: WinMM: config_dialog.c: Fixed warning --- utils/winmm_drv/cpl/config_dialog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/winmm_drv/cpl/config_dialog.c b/utils/winmm_drv/cpl/config_dialog.c index cc2d553..1742ab1 100644 --- a/utils/winmm_drv/cpl/config_dialog.c +++ b/utils/winmm_drv/cpl/config_dialog.c @@ -271,7 +271,7 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar return TRUE; case WM_HSCROLL: - if(lParam == GetDlgItem(hwnd, IDC_GAIN)) + if(lParam == (LPARAM)GetDlgItem(hwnd, IDC_GAIN)) { g_setup.gain100 = SendMessageW((HWND)lParam, (UINT)TBM_GETPOS, (WPARAM)0, (LPARAM)0); saveGain(&g_setup); -- cgit v1.2.3