shithub: choc

Download patch

ref: 2ca5c793d6bc52ba2fda3cfe41d7adfeae20499c
parent: fd11b0e02aa921865b60048b102409ea40080429
author: ceski <[email protected]>
date: Tue Sep 6 19:36:11 EDT 2022

Configurable reverb and chorus for native MIDI (#1504)


--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -85,6 +85,10 @@
 extern char *music_pack_path;
 extern char *fluidsynth_sf_path;
 extern char *timidity_cfg_path;
+#ifdef _WIN32
+extern int winmm_reverb_level;
+extern int winmm_chorus_level;
+#endif
 
 // DOS-specific options: These are unused but should be maintained
 // so that the config file can be shared between chocolate
@@ -513,6 +517,10 @@
     M_BindStringVariable("timidity_cfg_path",    &timidity_cfg_path);
     M_BindStringVariable("gus_patch_path",       &gus_patch_path);
     M_BindIntVariable("gus_ram_kb",              &gus_ram_kb);
+#ifdef _WIN32
+    M_BindIntVariable("winmm_reverb_level",      &winmm_reverb_level);
+    M_BindIntVariable("winmm_chorus_level",      &winmm_chorus_level);
+#endif
 
     M_BindIntVariable("use_libsamplerate",       &use_libsamplerate);
     M_BindFloatVariable("libsamplerate_scale",   &libsamplerate_scale);
--- a/src/i_winmusic.c
+++ b/src/i_winmusic.c
@@ -26,6 +26,16 @@
 #include "m_misc.h"
 #include "midifile.h"
 
+#define BETWEEN(l,u,x) (((l)>(x))?(l):((x)>(u))?(u):(x))
+
+#define REVERB_MIN 0
+#define REVERB_MAX 127
+#define CHORUS_MIN 0
+#define CHORUS_MAX 127
+
+int winmm_reverb_level = 40;
+int winmm_chorus_level = 0;
+
 static HMIDISTRM hMidiStream;
 static HANDLE hBufferReturnEvent;
 static HANDLE hExitEvent;
@@ -335,6 +345,52 @@
     }
 }
 
+void ResetDevice(void)
+{
+    for (int i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i)
+    {
+        DWORD msg = 0;
+
+        // RPN sequence to adjust pitch bend range (RPN value 0x0000)
+        msg = MIDI_EVENT_CONTROLLER | i | 0x65 << 8 | 0x00 << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x64 << 8 | 0x00 << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+
+        // reset pitch bend range to central tuning +/- 2 semitones and 0 cents
+        msg = MIDI_EVENT_CONTROLLER | i | 0x06 << 8 | 0x02 << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x26 << 8 | 0x00 << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+
+        // end of RPN sequence
+        msg = MIDI_EVENT_CONTROLLER | i | 0x64 << 8 | 0x7F << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x65 << 8 | 0x7F << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+
+        // reset all controllers
+        msg = MIDI_EVENT_CONTROLLER | i | 0x79 << 8 | 0x00 << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+
+        // reset pan to 64 (center)
+        msg = MIDI_EVENT_CONTROLLER | i | 0x0A << 8 | 0x40 << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+
+        // reset reverb and other effect controllers
+        msg = MIDI_EVENT_CONTROLLER | i | 0x5B << 8 | winmm_reverb_level << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x5C << 8 | 0x00 << 16; // tremolo
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x5D << 8 | winmm_chorus_level << 16;
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x5E << 8 | 0x00 << 16; // detune
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+        msg = MIDI_EVENT_CONTROLLER | i | 0x5F << 8 | 0x00 << 16; // phaser
+        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
+    }
+}
+
 boolean I_WIN_InitMusic(void)
 {
     UINT MidiDevice = MIDI_MAPPER;
@@ -366,6 +422,10 @@
     hBufferReturnEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
     hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 
+    winmm_reverb_level = BETWEEN(REVERB_MIN, REVERB_MAX, winmm_reverb_level);
+    winmm_chorus_level = BETWEEN(CHORUS_MIN, CHORUS_MAX, winmm_chorus_level);
+    ResetDevice();
+
     return true;
 }
 
@@ -378,7 +438,6 @@
 
 void I_WIN_StopSong(void)
 {
-    int i;
     MMRESULT mmr;
 
     if (hPlayerThread)
@@ -390,48 +449,7 @@
         hPlayerThread = NULL;
     }
 
-    for (i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i)
-    {
-        DWORD msg = 0;
-
-        // RPN sequence to adjust pitch bend range (RPN value 0x0000)
-        msg = MIDI_EVENT_CONTROLLER | i | 0x65 << 8 | 0x00 << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x64 << 8 | 0x00 << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-
-        // reset pitch bend range to central tuning +/- 2 semitones and 0 cents
-        msg = MIDI_EVENT_CONTROLLER | i | 0x06 << 8 | 0x02 << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x26 << 8 | 0x00 << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-
-        // end of RPN sequence
-        msg = MIDI_EVENT_CONTROLLER | i | 0x64 << 8 | 0x7F << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x65 << 8 | 0x7F << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-
-        // reset all controllers
-        msg = MIDI_EVENT_CONTROLLER | i | 0x79 << 8 | 0x00 << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-
-        // reset pan to 64 (center)
-        msg = MIDI_EVENT_CONTROLLER | i | 0x0A << 8 | 0x40 << 16;
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-
-        // reset reverb to 40 and other effect controllers to 0
-        msg = MIDI_EVENT_CONTROLLER | i | 0x5B << 8 | 0x28 << 16; // reverb
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x5C << 8 | 0x00 << 16; // tremolo
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x5D << 8 | 0x00 << 16; // chorus
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x5E << 8 | 0x00 << 16; // detune
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-        msg = MIDI_EVENT_CONTROLLER | i | 0x5F << 8 | 0x00 << 16; // phaser
-        midiOutShortMsg((HMIDIOUT)hMidiStream, msg);
-    }
+    ResetDevice();
 
     mmr = midiStreamStop(hMidiStream);
     if (mmr != MMSYSERR_NOERROR)
--- a/src/i_winmusic.h
+++ b/src/i_winmusic.h
@@ -31,6 +31,9 @@
 void I_WIN_UnRegisterSong(void);
 void I_WIN_ShutdownMusic(void);
 
+extern int winmm_reverb_level;
+extern int winmm_chorus_level;
+
 #endif
 
 #endif
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -965,6 +965,20 @@
 
     CONFIG_VARIABLE_INT(gus_ram_kb),
 
+#ifdef _WIN32
+    //!
+    // Reverb level for native Windows MIDI, default 40, range 0-127.
+    //
+
+    CONFIG_VARIABLE_INT(winmm_reverb_level),
+
+    //!
+    // Chorus level for native Windows MIDI, default 0, range 0-127.
+    //
+
+    CONFIG_VARIABLE_INT(winmm_chorus_level),
+#endif
+
     //!
     // @game doom strife
     //
--- a/src/setup/sound.c
+++ b/src/setup/sound.c
@@ -70,6 +70,10 @@
 static char *fluidsynth_sf_path = NULL;
 static char *gus_patch_path = NULL;
 static int gus_ram_kb = 1024;
+#ifdef _WIN32
+static int winmm_reverb_level = 40;
+static int winmm_chorus_level = 0;
+#endif
 
 // DOS specific variables: these are unused but should be maintained
 // so that the config file can be shared between chocolate
@@ -225,6 +229,10 @@
     M_BindStringVariable("music_pack_path",     &music_pack_path);
     M_BindStringVariable("timidity_cfg_path",     &timidity_cfg_path);
     M_BindStringVariable("fluidsynth_sf_path",    &fluidsynth_sf_path);
+#ifdef _WIN32
+    M_BindIntVariable("winmm_reverb_level",       &winmm_reverb_level);
+    M_BindIntVariable("winmm_chorus_level",       &winmm_chorus_level);
+#endif
 
     M_BindIntVariable("snd_sbport",               &snd_sbport);
     M_BindIntVariable("snd_sbirq",                &snd_sbirq);