ref: 88fe15083f4d55936c6d7708e35d65facd601a5c
parent: f8f21ffcc986ac8f79b81227321a0cd698f7cc6a
author: ceski <[email protected]>
date: Thu Sep 15 02:04:52 EDT 2022
Add selectable native MIDI devices to setup (#1506) * Add selectable native MIDI devices to setup * Fix formatting, free memory, remove extern from .c, change device to string * Add WinMM to CMake * Copy strings using M_StringDuplicate * Add MIDI_MAPPER device ID comment
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -229,6 +229,9 @@
if(ENABLE_SDL2_NET)
target_link_libraries("${PROGRAM_PREFIX}setup" SDL2::net)
endif()
+if(WIN32)
+ target_link_libraries("${PROGRAM_PREFIX}setup" winmm)
+endif()
if(MSVC)
set_target_properties("${PROGRAM_PREFIX}setup" PROPERTIES
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -518,6 +518,7 @@
M_BindStringVariable("gus_patch_path", &gus_patch_path);
M_BindIntVariable("gus_ram_kb", &gus_ram_kb);
#ifdef _WIN32
+ M_BindStringVariable("winmm_midi_device", &winmm_midi_device);
M_BindIntVariable("winmm_reverb_level", &winmm_reverb_level);
M_BindIntVariable("winmm_chorus_level", &winmm_chorus_level);
#endif
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -246,5 +246,9 @@
void I_SetOPLDriverVer(opl_driver_ver_t ver);
+#ifdef _WIN32
+extern char *winmm_midi_device;
+#endif
+
#endif
--- a/src/i_winmusic.c
+++ b/src/i_winmusic.c
@@ -33,6 +33,7 @@
#define CHORUS_MIN 0
#define CHORUS_MAX 127
+char *winmm_midi_device = NULL;
int winmm_reverb_level = 40;
int winmm_chorus_level = 0;
@@ -393,9 +394,48 @@
boolean I_WIN_InitMusic(void)
{
- UINT MidiDevice = MIDI_MAPPER;
+ UINT MidiDevice;
+ int all_devices;
+ int i;
MIDIHDR *hdr = &buffer.MidiStreamHdr;
+ MIDIOUTCAPS mcaps;
MMRESULT mmr;
+
+ // find the midi device that matches the saved one
+ if (winmm_midi_device != NULL)
+ {
+ all_devices = midiOutGetNumDevs() + 1; // include MIDI_MAPPER
+ for (i = 0; i < all_devices; ++i)
+ {
+ // start from device id -1 (MIDI_MAPPER)
+ mmr = midiOutGetDevCaps(i - 1, &mcaps, sizeof(mcaps));
+ if (mmr == MMSYSERR_NOERROR)
+ {
+ if (strstr(winmm_midi_device, mcaps.szPname))
+ {
+ MidiDevice = i - 1;
+ break;
+ }
+ }
+
+ if (i == all_devices - 1)
+ {
+ // give up and use MIDI_MAPPER
+ free(winmm_midi_device);
+ winmm_midi_device = NULL;
+ }
+ }
+ }
+
+ if (winmm_midi_device == NULL)
+ {
+ MidiDevice = MIDI_MAPPER;
+ mmr = midiOutGetDevCaps(MIDI_MAPPER, &mcaps, sizeof(mcaps));
+ if (mmr == MMSYSERR_NOERROR)
+ {
+ winmm_midi_device = M_StringDuplicate(mcaps.szPname);
+ }
+ }
mmr = midiStreamOpen(&hMidiStream, &MidiDevice, (DWORD)1,
(DWORD_PTR)MidiStreamProc, (DWORD_PTR)NULL,
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -967,6 +967,12 @@
#ifdef _WIN32
//!
+ // MIDI device for native Windows MIDI.
+ //
+
+ CONFIG_VARIABLE_STRING(winmm_midi_device),
+
+ //!
// Reverb level for native Windows MIDI, default 40, range 0-127.
//
--- a/src/setup/sound.c
+++ b/src/setup/sound.c
@@ -14,6 +14,12 @@
// Sound control menu
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+
#include <stdlib.h>
#include <string.h>
@@ -71,6 +77,11 @@
static char *gus_patch_path = NULL;
static int gus_ram_kb = 1024;
#ifdef _WIN32
+#define MAX_MIDI_DEVICES 20
+static char **midi_names;
+static int midi_num_devices;
+static int midi_index;
+char *winmm_midi_device = NULL;
static int winmm_reverb_level = 40;
static int winmm_chorus_level = 0;
#endif
@@ -129,10 +140,99 @@
}
}
+#ifdef _WIN32
+static void UpdateMidiDevice(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
+{
+ free(winmm_midi_device);
+ winmm_midi_device = M_StringDuplicate(midi_names[midi_index]);
+}
+
+static txt_dropdown_list_t *MidiDeviceSelector(void)
+{
+ txt_dropdown_list_t *result;
+ int all_devices;
+ int device_ids[MAX_MIDI_DEVICES];
+ MMRESULT mmr;
+ MIDIOUTCAPS mcaps;
+ int i;
+
+ if (midi_num_devices > 0)
+ {
+ for (i = 0; i < midi_num_devices; ++i)
+ {
+ free(midi_names[i]);
+ midi_names[i] = NULL;
+ }
+ free(midi_names);
+ midi_names = NULL;
+ }
+ midi_num_devices = 0;
+
+ // get the number of midi devices on this system
+ all_devices = midiOutGetNumDevs() + 1; // include MIDI_MAPPER
+ if (all_devices > MAX_MIDI_DEVICES)
+ {
+ all_devices = MAX_MIDI_DEVICES;
+ }
+
+ // get the valid device ids only, starting from -1 (MIDI_MAPPER)
+ for (i = 0; i < all_devices; ++i)
+ {
+ mmr = midiOutGetDevCaps(i - 1, &mcaps, sizeof(mcaps));
+ if (mmr == MMSYSERR_NOERROR)
+ {
+ device_ids[midi_num_devices] = i - 1;
+ midi_num_devices++;
+ }
+ }
+
+ // get the device names
+ midi_names = malloc(midi_num_devices * sizeof(char *));
+ for (i = 0; i < midi_num_devices; ++i)
+ {
+ mmr = midiOutGetDevCaps(device_ids[i], &mcaps, sizeof(mcaps));
+ if (mmr == MMSYSERR_NOERROR)
+ {
+ midi_names[i] = M_StringDuplicate(mcaps.szPname);
+ }
+ }
+
+ // set the dropdown list index to the previously selected device
+ for (i = 0; i < midi_num_devices; ++i)
+ {
+ if (winmm_midi_device != NULL &&
+ strstr(winmm_midi_device, midi_names[i]))
+ {
+ midi_index = i;
+ break;
+ }
+ else if (winmm_midi_device == NULL || i == midi_num_devices - 1)
+ {
+ // give up and use MIDI_MAPPER
+ midi_index = 0;
+ free(winmm_midi_device);
+ winmm_midi_device = M_StringDuplicate(midi_names[0]);
+ break;
+ }
+ }
+
+ result = TXT_NewDropdownList(&midi_index, (const char **)midi_names,
+ midi_num_devices);
+ TXT_SignalConnect(result, "changed", UpdateMidiDevice, NULL);
+
+ return result;
+}
+#endif
+
void ConfigSound(TXT_UNCAST_ARG(widget), void *user_data)
{
txt_window_t *window;
txt_window_action_t *music_action;
+#ifdef _WIN32
+ int window_ypos = 2;
+#else
+ int window_ypos = 3;
+#endif
// Build the window
@@ -141,7 +241,7 @@
TXT_SetColumnWidths(window, 40);
TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP,
- TXT_SCREEN_W / 2, 3);
+ TXT_SCREEN_W / 2, window_ypos);
music_action = TXT_NewWindowAction('m', "Music Packs");
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, music_action);
@@ -194,7 +294,15 @@
NULL)),
TXT_NewRadioButton("Native MIDI", &snd_musicdevice, SNDDEVICE_GENMIDI),
+#ifdef _WIN32
TXT_NewConditional(&snd_musicdevice, SNDDEVICE_GENMIDI,
+ TXT_NewHorizBox(
+ TXT_NewStrut(4, 0),
+ TXT_NewLabel("Device: "),
+ MidiDeviceSelector(),
+ NULL)),
+#endif
+ TXT_NewConditional(&snd_musicdevice, SNDDEVICE_GENMIDI,
TXT_MakeTable(2,
TXT_NewStrut(4, 0),
TXT_NewLabel("Timidity configuration file: "),
@@ -230,6 +338,7 @@
M_BindStringVariable("timidity_cfg_path", &timidity_cfg_path);
M_BindStringVariable("fluidsynth_sf_path", &fluidsynth_sf_path);
#ifdef _WIN32
+ M_BindStringVariable("winmm_midi_device", &winmm_midi_device);
M_BindIntVariable("winmm_reverb_level", &winmm_reverb_level);
M_BindIntVariable("winmm_chorus_level", &winmm_chorus_level);
#endif