Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PATCH ENHANCEMENT] Control midi volume in game by keyboard keys #591

Open
cm8 opened this issue Dec 16, 2023 · 1 comment
Open

[PATCH ENHANCEMENT] Control midi volume in game by keyboard keys #591

cm8 opened this issue Dec 16, 2023 · 1 comment
Projects

Comments

@cm8
Copy link

cm8 commented Dec 16, 2023

Since it would be nice to alter the music volume in game, the following patch adds functionality to d2tm to do so. It adds

  • key M to turn off midi music while playing (actually toggle, since M turns on playing again as well)
  • key O to decrease midi volume in decrements of 10
  • key P to increase midi volume in increments of 10

Keyboard key M, as proposed by below patch, does not result in muting the music, but rather stops playing midi completely, freeing the resources used by allegro to generate the music. As a result, hitting M again, the last played midi restarts; just to point out that this is not a pause/resume function. The set_volume allegro range is 0..255 and allegro clamps the values given to this range itself.

Keyboard key P might not be the best choice. For future improvements it may be wise to reserve it as a hotkey for some 'pause' mnemonic, so please alter those defines to your likings. For the same reason KEY_PLUS_PAD or KEY_PLUS was not chosen, although it is currently unused.

diff --git a/cGame_logic.cpp b/cGame_logic.cpp
index b64a91d4..98c3458b 100644
--- a/cGame_logic.cpp
+++ b/cGame_logic.cpp
@@ -1919,11 +1919,34 @@ void cGame::onKeyDownGamePlaying(const cKeyboardEvent &event) {
 
 void cGame::onKeyPressedGamePlaying(const cKeyboardEvent &event) {
     cPlayer &humanPlayer = players[HUMAN];
+    int digivol;
+    int midivol;
 
     if (event.hasKey(KEY_F)) {
         m_drawFps = false;
     }
 
+    if (event.hasKey(KEY_M)) {
+        game.m_playMusic = !game.m_playMusic;
+        if (!game.m_playMusic) {
+            m_soundPlayer->stopMusic();
+        } else {
+            m_soundPlayer->playMusic(m_newMusicSample);
+        }
+    }
+
+    if (event.hasKey(KEY_O)) {
+        get_volume(&digivol, &midivol);
+        midivol -= 10;
+        set_volume(digivol, midivol);
+    }
+
+    if (event.hasKey(KEY_P)) {
+        get_volume(&digivol, &midivol);
+        midivol += 10;
+        set_volume(digivol, midivol);
+    }
+
     if (event.hasKey(KEY_H)) {
         mapCamera->centerAndJumpViewPortToCell(humanPlayer.getFocusCell());
     }

This bypasses m_musicVolume, but this has been / is an unused variable anyway. Even if the game is to initialize the midi volume on start, the variable is propaly not needed to steer midi volume levels as shown above. EDIT: The game does set midi volume on start in class cSoundPlayer, but does not reference m_musicVolume from there.

If midi does not play at all, it may be caused by reserve_voices() in cSoundPlayer. It hard-codes value 0 for midi voices to be reserved. While it may be irrelevant for hardware midi (?), this renders the DIGMID softsynth provided by allegro unusable. The following patch preserves the previous behavior, unless DIGMID is configured (as to not break drivers unknown to have the same issue).

diff --git a/utils/cSoundPlayer.cpp b/utils/cSoundPlayer.cpp
index 3ecb24d4..35d87361 100644
--- a/utils/cSoundPlayer.cpp
+++ b/utils/cSoundPlayer.cpp
@@ -3,6 +3,7 @@
 #include "definitions.h"
 #include "utils/cLog.h"
 
+#include <allegro/config.h>
 #include <allegro/datafile.h>
 #include <allegro/digi.h>
 #include <allegro/midi.h>
@@ -72,13 +73,25 @@ cSoundPlayer::cSoundPlayer(const cPlatformLayerInit&, int maxNrVoices)
     }
 
     int nr_voices = maxNrVoices;
+    int midi_voices = 0;
+
+    int card_id = get_config_id("sound", "midi_card", MIDI_AUTODETECT);
+
     while (true) {
         if (nr_voices < kMinNrVoices) {
             logger->log(LOG_WARN, COMP_SOUND, "Initialization", "Failed installing sound.", OUTC_FAILED);
             return;
         }
 
-        reserve_voices(nr_voices, 0); // Reserve nothing for MIDI, assume it will "steal" from the digi voices
+        nr_voices = maxNrVoices;
+        if (card_id == MIDI_DIGMID) {
+            midi_voices = nr_voices / 8;
+            nr_voices = CLAMP(kMinNrVoices, nr_voices - midi_voices, maxNrVoices);
+            midi_voices = maxNrVoices - nr_voices;
+        } else {
+            // Reserve nothing for MIDI, assume it will "steal" from the digi voices
+        }
+        reserve_voices(nr_voices, midi_voices);
 
         if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, nullptr) == 0)
         {
@@ -93,7 +106,7 @@ cSoundPlayer::cSoundPlayer(const cPlatformLayerInit&, int maxNrVoices)
         auto msg = fmt::format("Failed reserving {} voices. Will try {}.", nr_voices, (nr_voices / 2));
         logger->log(LOG_INFO, COMP_SOUND, "Initialization", msg, OUTC_FAILED);
 
-        nr_voices /= 2;
+        maxNrVoices = (nr_voices + midi_voices) / 2;
     }
 
     // Sound effects are loud, the music is queiter (its background music, so it should not be disturbing).

If alsa rawmidi does not work out of the box, the more basic DIGMID driver should work with these d2tm.cfg ini options:

[sound]
midi_card = DIGI
patches = /path/to/patches.dat

In this case allegro does wavetable synth on its own, but relies on a patches.dat. See allegro docs how to generate this, e. g. pat2dat patches.dat FluidR3_GM.sf2 -8 . However, as long as the game calls reserve_voices(nr_voices, 0) the allegro midi player probably stays mute, which may or may not be true for other midi drivers such as alsa rawmidi midi_card = AMID as well (untested).


Above inline patches as zip: control_ingame_midi_by_keyboard.patch.zip

@stefanhendriks
Copy link
Owner

thanks for the patch! I'll process this in a PR 👍

@stefanhendriks stefanhendriks added this to Backlog in D2TM via automation May 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Backlog
D2TM
  
Backlog
Development

No branches or pull requests

2 participants