Skip to content

Commit 25725e2

Browse files
committed
feat: auto connect keyboard to running fluidsynth
1 parent 63455d7 commit 25725e2

2 files changed

Lines changed: 89 additions & 4 deletions

File tree

src/RtMidiInput.cpp

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "RtMidiInput.hpp"
22
#include "Logger.hpp"
33
#include <chrono>
4+
#include <cstdlib>
45
#include <map>
56
#include <rtmidi/RtMidi.h>
67
#include <thread>
@@ -72,24 +73,86 @@ bool RtMidiInput::initialize() {
7273
Logger::log("[RtMidiInput] Nombre de ports MIDI trouvés: {}",
7374
std::to_string(nPorts));
7475

76+
unsigned int hardwarePortIndex = 0;
7577
for (unsigned int i = 0; i < nPorts; i++) {
7678
std::string portName = midiIn->getPortName(i);
7779
Logger::log("[RtMidiInput] Port {}: {}", std::to_string(i),
7880
portName);
7981
// On cherche un clavier (ex: "reface CP", "USB MIDI", etc.)
80-
// On évite de se connecter à soi-même ou à "Midi Through"
82+
// On évite de se connecter à soi-même, "Midi Through", ou
83+
// "FluidSynth"
8184
if (portName.find("SmartPianoEngine") == std::string::npos &&
82-
portName.find("Through") == std::string::npos) {
85+
portName.find("Through") == std::string::npos &&
86+
portName.find("FluidSynth") == std::string::npos &&
87+
portName.find("fluidsynth") == std::string::npos &&
88+
portName.find("FLUID Synth") == std::string::npos) {
8389
Logger::log("[RtMidiInput] Tentative d'ouverture du port: {}",
8490
portName);
8591
midiIn->openPort(i);
8692
hardwareFound = true;
93+
hardwarePortIndex = i;
8794
Logger::log("[RtMidiInput] Connecté au port matériel: {}",
8895
portName);
8996
break;
9097
}
9198
}
9299

100+
if (hardwareFound) {
101+
// Check if there is a running instance of FluidSynth
102+
unsigned int nOutPorts = midiOut->getPortCount();
103+
bool fluidSynthFound = false;
104+
std::string fluidSynthPortName;
105+
for (unsigned int j = 0; j < nOutPorts; j++) {
106+
std::string outPortName = midiOut->getPortName(j);
107+
if (outPortName.find("FluidSynth") != std::string::npos ||
108+
outPortName.find("fluidsynth") != std::string::npos ||
109+
outPortName.find("FLUID Synth") != std::string::npos) {
110+
fluidSynthFound = true;
111+
fluidSynthPortName = outPortName;
112+
break;
113+
}
114+
}
115+
if (fluidSynthFound) {
116+
std::string keyboardPortName =
117+
midiIn->getPortName(hardwarePortIndex);
118+
Logger::log("[RtMidiInput] FluidSynth détecté sur le port: {}",
119+
fluidSynthPortName);
120+
121+
auto getClientPort = [](const std::string& name) {
122+
size_t lastSpace = name.find_last_of(' ');
123+
if (lastSpace != std::string::npos) {
124+
std::string lastToken = name.substr(lastSpace + 1);
125+
if (lastToken.find(':') != std::string::npos) {
126+
return lastToken;
127+
}
128+
}
129+
return name;
130+
};
131+
132+
std::string src = getClientPort(keyboardPortName);
133+
std::string dest = getClientPort(fluidSynthPortName);
134+
Logger::log("[RtMidiInput] Tentative de connexion via "
135+
"aconnect: {} -> {}",
136+
src, dest);
137+
138+
std::string command =
139+
"aconnect \"" + src + "\" \"" + dest + "\"";
140+
int status = std::system(command.c_str());
141+
if (status == 0) {
142+
Logger::log("[RtMidiInput] Connexion aconnect réussie de "
143+
"{} vers {}",
144+
src, dest);
145+
} else {
146+
Logger::err(
147+
"[RtMidiInput] Échec de la commande aconnect: {}",
148+
std::to_string(status));
149+
}
150+
} else {
151+
Logger::log(
152+
"[RtMidiInput] Aucun synthétiseur FluidSynth détecté");
153+
}
154+
}
155+
93156
if (!hardwareFound) {
94157
Logger::log("[RtMidiInput] Aucun clavier détecté, "
95158
"ouverture d'un port virtuel");

test/RtMidiInputTest.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class MockRtMidiOut : public IRtMidiOut {
7171
public:
7272
bool openPortCalled = false;
7373
bool openVirtualPortCalled = false;
74+
std::vector<std::string> mockPorts;
7475

7576
void openPort(unsigned int portNumber,
7677
const std::string& portName) override {
@@ -84,9 +85,9 @@ class MockRtMidiOut : public IRtMidiOut {
8485
openVirtualPortCalled = true;
8586
}
8687

87-
unsigned int getPortCount() override { return 0; }
88+
unsigned int getPortCount() override { return mockPorts.size(); }
8889
std::string getPortName(unsigned int portNumber) override {
89-
(void)portNumber;
90+
if (portNumber < mockPorts.size()) return mockPorts[portNumber];
9091
return "";
9192
}
9293
};
@@ -130,6 +131,27 @@ TEST_CASE("RtMidiInput initialization success (hardware detection)") {
130131
CHECK_FALSE(input.isReady());
131132
}
132133

134+
/// Vérifie initialisation avec détection de FluidSynth
135+
class FluidSynthRtMidiInput : public TestableRtMidiInput {
136+
protected:
137+
IRtMidiOut* createMidiOut() override {
138+
auto m = new MockRtMidiOut();
139+
m->mockPorts = {"Midi Through Port 14:0",
140+
"FluidSynth:FluidSynth 128:0"};
141+
mockOut = m;
142+
return m;
143+
}
144+
};
145+
146+
TEST_CASE("RtMidiInput initialization with FluidSynth detection") {
147+
FluidSynthRtMidiInput input;
148+
CHECK(input.initialize());
149+
CHECK(input.isReady());
150+
CHECK(input.mockIn->openPortCalled);
151+
CHECK(input.mockOut->openVirtualPortCalled);
152+
input.close();
153+
}
154+
133155
/// Vérifie repli sur port virtuel si aucun matériel détecté
134156
class FallbackRtMidiInput : public TestableRtMidiInput {
135157
protected:

0 commit comments

Comments
 (0)