aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2024-08-29 16:21:02 +0300
committerWohlstand <admin@wohlnet.ru>2024-08-29 16:21:02 +0300
commitf97b1719771fda4670d903527cb14ec2979df03b (patch)
tree6b435735bf9144b415d4a5f4978bcb3262d08d37 /utils
parent68d04c38fe74e419283c9784eb0fdaf5cf18e086 (diff)
parent572da4a9335a5a7f98baaedf1c982f7ac6c385d5 (diff)
downloadlibADLMIDI-f97b1719771fda4670d903527cb14ec2979df03b.tar.gz
libADLMIDI-f97b1719771fda4670d903527cb14ec2979df03b.tar.bz2
libADLMIDI-f97b1719771fda4670d903527cb14ec2979df03b.zip
Merge branch 'master' of git@github.com:Wohlstand/libADLMIDI.git into wip-hw-serial
Diffstat (limited to 'utils')
-rw-r--r--utils/winmm_drv/CMakeLists.txt4
-rw-r--r--utils/winmm_drv/config/regconfig.c63
-rw-r--r--utils/winmm_drv/config/regconfig.h9
-rw-r--r--utils/winmm_drv/cpl/adlconfig.rc60
-rw-r--r--utils/winmm_drv/cpl/config_dialog.c84
-rw-r--r--utils/winmm_drv/cpl/resource.h6
-rw-r--r--utils/winmm_drv/src/MidiSynth.cpp110
-rw-r--r--utils/winmm_drv/src/MidiSynth.h12
-rw-r--r--utils/winmm_drv/src/winmm_drv.cpp27
9 files changed, 319 insertions, 56 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..a049a7d 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,13 @@ void setupDefault(DriverSettings *setup)
setup->flagFullBrightness = BST_UNCHECKED;
setup->volumeModel = 0;
+ setup->chanAlloc = -1;
setup->numChips = 4;
setup->num4ops = -1;
+
+ setup->outputDevice = (UINT)-1;
+
+ setup->gain100 = 100;
}
@@ -144,6 +179,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 +215,20 @@ 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;
+
+ if(readUIntFromRegistry(HKEY_CURRENT_USER, s_regPath, L"gain100", &uVal))
+ setup->gain100 = uVal;
}
void saveSetup(DriverSettings *setup)
@@ -202,10 +247,24 @@ 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);
+ 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 f854d1b..2dac28a 100644
--- a/utils/winmm_drv/config/regconfig.h
+++ b/utils/winmm_drv/config/regconfig.h
@@ -25,8 +25,13 @@ typedef struct DriverSettings_t
BOOL flagFullBrightness;
int volumeModel;
+ int chanAlloc;
int numChips;
int num4ops;
+
+ UINT outputDevice;
+
+ UINT gain100;
} DriverSettings;
extern const WCHAR g_adlSignalMemory[];
@@ -35,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 455c906..edc5048 100644
--- a/utils/winmm_drv/cpl/adlconfig.rc
+++ b/utils/winmm_drv/cpl/adlconfig.rc
@@ -14,37 +14,43 @@
// Dialog resources
//
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-IDD_CONFIG_BOX DIALOGEX 0, 0, 251, 244
+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
- 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
+ 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 195524d..1742ab1 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 <windows.h>
+#include <mmsystem.h>
#include <commctrl.h>
#include <commdlg.h>
#include <string.h>
@@ -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);
@@ -88,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);
@@ -109,6 +125,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 +138,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 +176,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 +249,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)
@@ -218,6 +270,16 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar
syncWidget(hwnd);
return TRUE;
+ case WM_HSCROLL:
+ if(lParam == (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))
{
@@ -230,6 +292,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 +333,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 +409,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 +440,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..78461c5 100644
--- a/utils/winmm_drv/cpl/resource.h
+++ b/utils/winmm_drv/cpl/resource.h
@@ -28,5 +28,11 @@
#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_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 29cbb78..e559a4f 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)
+ 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, 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);
@@ -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);
}
@@ -308,17 +324,22 @@ 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);
+ 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);
+
midiSynth.CheckForSignals();
}
}
+
if(allBuffersRendered)
WaitForSingleObject(s_waveOut.hEvent, INFINITE);
}
@@ -369,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)
{
@@ -440,10 +461,22 @@ 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);
+
+ // 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 += 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;
}
@@ -461,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;
}
@@ -490,6 +527,10 @@ void MidiSynth::LoadSettings()
chunkSize = MillisToFrames(10);
midiLatency = MillisToFrames(0);
useRingBuffer = false;
+ volumeFactorL = 1.0f;
+ volumeFactorR = 1.0f;
+ gain = 1.0f;
+
if(!useRingBuffer)
{
// Number of chunks should be ceil(bufferSize / chunkSize)
@@ -502,7 +543,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())
@@ -515,14 +556,25 @@ int MidiSynth::Init()
return 1;
}
+ synthAudioFormat.type = ADLMIDI_SampleType_F32;
+ synthAudioFormat.sampleOffset = s_audioChannels * sizeof(float);
+ synthAudioFormat.containerSize = sizeof(float);
+
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);
+ adl_generateFormat(synth, bufferSize * s_audioChannels,
+ (ADL_UInt8*)buffer,
+ (ADL_UInt8*)buffer + synthAudioFormat.containerSize,
+ &synthAudioFormat);
framesRendered = 0;
wResult = s_waveOut.Start();
@@ -586,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()
@@ -664,6 +734,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);
diff --git a/utils/winmm_drv/src/MidiSynth.h b/utils/winmm_drv/src/MidiSynth.h
index bf2da02..0442f7b 100644
--- a/utils/winmm_drv/src/MidiSynth.h
+++ b/utils/winmm_drv/src/MidiSynth.h
@@ -52,11 +52,15 @@ private:
Bit8u reverbMode;
Bit8u reverbTime;
Bit8u reverbLevel;
+ float volumeFactorL;
+ float volumeFactorR;
+ float gain;
- Bit16s *buffer;
+ float *buffer;
DWORD framesRendered;
ADL_MIDIPlayer *synth;
+ ADLMIDI_AudioFormat synthAudioFormat;
bool m_setupInit;
DriverSettings m_setup;
@@ -76,12 +80,16 @@ 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);
+ 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..09f38d2 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:
@@ -265,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);
}
@@ -316,7 +321,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 +383,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;