From 480548191fa6d6ed4324a67a0aebd4fcbf037ea3 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 17 Aug 2024 08:50:22 +0900 Subject: [PATCH] Add -mididevice option --- README.md | 7 ++++++- src/config.cpp | 18 ++++++++++++++++++ src/config.h | 1 + src/generic/mako.cpp | 2 +- src/sys/mako_midi.cpp | 17 ++++++++++++----- src/sys/mako_midi.h | 3 ++- src/win/mako.cpp | 2 +- system3.ini.example | 6 ++++-- 8 files changed, 45 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index bd44cad..f3bd4da 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,12 @@ The first line is not used because track 1 on a game CD is usually a data track. #### `-fm` -By default, system3-sdl2 uses MIDI sound if available. This option forces FM tone generator emulation. +By default, system3-sdl2 uses MIDI sound if available. This option forces FM +tone generator emulation. + +#### `-mididevice` _number_ +Specifies the MIDI device number to use. If not specified, the first available +device is used. #### `-game` _game_id_ As System1-3 have slight variations depending on the game, `system3` uses the diff --git a/src/config.cpp b/src/config.cpp index 6418963..a938a20 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #ifdef _WIN32 #include @@ -26,6 +27,19 @@ bool to_bool(const char *s, int lineno) return true; } +int to_int(const char *s, int lineno = -1) +{ + char *end; + int n = strtol(s, &end, 10); + if (*end) { + if (lineno == -1) + ERROR("Command line: Invalid integer value '%s'", s); + else + ERROR(INIFILENAME ":%d Invalid integer value '%s'", lineno, s); + } + return n; +} + std::string normalize_path(std::string s) { for (char& c : s) { @@ -96,6 +110,8 @@ Config::Config(int argc, char *argv[]) playlist = argv[++i]; else if (strcmp(argv[i], "-fm") == 0) use_fm = true; + else if (strcmp(argv[i], "-mididevice") == 0) + midi_device = to_int(argv[++i]); else if (strcmp(argv[i], "-game") == 0) game_id = argv[++i]; else if (strcmp(argv[i], "-encoding") == 0) @@ -152,6 +168,8 @@ void Config::load_ini() playlist = normalize_path(val); else if (!strcasecmp(key, "fm")) use_fm = to_bool(val, lineno); + else if (!strcasecmp(key, "mididevice")) + midi_device = to_int(val, lineno); else if (!strcasecmp(key, "game")) game_id = val; else if (!strcasecmp(key, "encoding")) diff --git a/src/config.h b/src/config.h index d571dd5..6f4851e 100644 --- a/src/config.h +++ b/src/config.h @@ -28,6 +28,7 @@ struct Config { std::string save_dir; std::string playlist; std::string title; + int midi_device = -1; bool use_fm = false; bool no_antialias = false; bool scanline = false; diff --git a/src/generic/mako.cpp b/src/generic/mako.cpp index ac9f4ce..175ab70 100644 --- a/src/generic/mako.cpp +++ b/src/generic/mako.cpp @@ -53,7 +53,7 @@ MAKO::MAKO(NACT* parent, const Config& config) : if (Mix_OpenAudio(SAMPLE_RATE, AUDIO_S16LSB, 2, 4096) < 0) WARNING("Mix_OpenAudio failed: %s", Mix_GetError()); - midi = std::make_unique(); + midi = std::make_unique(config.midi_device); if (!midi->is_available()) use_fm = true; } diff --git a/src/sys/mako_midi.cpp b/src/sys/mako_midi.cpp index 5420ae9..dc15ca5 100644 --- a/src/sys/mako_midi.cpp +++ b/src/sys/mako_midi.cpp @@ -21,7 +21,7 @@ namespace { std::unique_ptr midiout; -void initialize_midi() +void initialize_midi(int device) { try { midiout = std::make_unique(); @@ -34,8 +34,15 @@ void initialize_midi() for (int i = 0; i < n; i++) { NOTICE("MIDI #%d: %s", i, midiout->getPortName(i).c_str()); } - // Open first available port. - midiout->openPort(0); + if (device < 0) { + // not specified, use the first device + device = 0; + } else if (device >= n) { + WARNING("Invalid MIDI device number: %d", device); + midiout.reset(); + return; + } + midiout->openPort(device); } catch (RtMidiError &error) { WARNING("Cannot initialize MIDI: %s", error.getMessage().c_str()); midiout.reset(); @@ -627,9 +634,9 @@ struct MAKOMidi::Command { Command(Type t, std::unique_ptr p = {}) : type(t), playback(std::move(p)) {} }; -MAKOMidi::MAKOMidi() +MAKOMidi::MAKOMidi(int device) { - initialize_midi(); + initialize_midi(device); if (midiout) { thread = SDL_CreateThread(thread_main, "MAKOMidi", this); queue_mutex = SDL_CreateMutex(); diff --git a/src/sys/mako_midi.h b/src/sys/mako_midi.h index 79cc10e..87c6c82 100644 --- a/src/sys/mako_midi.h +++ b/src/sys/mako_midi.h @@ -12,7 +12,7 @@ class NACT; class MAKOMidi { public: - MAKOMidi(); + explicit MAKOMidi(int device); ~MAKOMidi(); bool is_available(); bool play(NACT* nact, char* amus, int page, int loop); @@ -38,6 +38,7 @@ private: class MAKOMidi { public: + explicit MAKOMidi(int device) {} bool is_available() { return false; } bool play(NACT* nact, char* amus, int page, int loop) { return false; } void stop() {} diff --git a/src/win/mako.cpp b/src/win/mako.cpp index 188486c..9880ca5 100644 --- a/src/win/mako.cpp +++ b/src/win/mako.cpp @@ -236,7 +236,7 @@ MAKO::MAKO(NACT* parent, const Config& config) : parent->fatal("SDL_GetWindowWMInfo failed: %s", SDL_GetError()); mci_thread = new MCIThread(parent, info.info.win.window); - midi = std::make_unique(); + midi = std::make_unique(config.midi_device); if (!midi->is_available()) use_fm = true; } diff --git a/system3.ini.example b/system3.ini.example index 8174cd5..6dfbf9e 100644 --- a/system3.ini.example +++ b/system3.ini.example @@ -18,10 +18,12 @@ fontfile = custom_font.ttf ; line. playlist = bgm/playlist.txt -; Enable FM tone generator emulation. If not specified, MIDI sound will be -; used. +; Force FM tone generator emulation even if MIDI is available. fm = true +; MIDI device number to use for music playback. +mididevice = 0 + ; Game ID. No need to specify if using AliceSoft's original game data. ; Refer to README.md for a list of possible values. game = rance41