summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--MIDIPlayer.cpp80
-rw-r--r--MIDIPlayer.h10
-rw-r--r--Makefile2
-rw-r--r--debian/control2
-rw-r--r--midiplay.cpp81
5 files changed, 134 insertions, 41 deletions
diff --git a/MIDIPlayer.cpp b/MIDIPlayer.cpp
index f2bba8c..2c0bc6a 100644
--- a/MIDIPlayer.cpp
+++ b/MIDIPlayer.cpp
@@ -6,13 +6,19 @@
#include <algorithm>
#include <chrono>
#include <iostream>
+#include <string>
#include <thread>
+#include <unordered_set>
namespace bp = boost::process;
namespace fs = std::filesystem;
using namespace std::chrono_literals;
+namespace {
+ std::unordered_set<std::string> supported_devices{"AudioBox 22 VSL", "CH345"};
+}
+
MIDIPlayer::MIDIPlayer(const std::filesystem::path& path):
m_child{},
m_dir{path},
@@ -23,6 +29,10 @@ MIDIPlayer::MIDIPlayer(const std::filesystem::path& path):
if (list.size() > 0) {
m_file = list[0];
}
+
+ init_seq();
+ iterate_ports();
+ close_seq();
}
void MIDIPlayer::start()
@@ -30,7 +40,7 @@ void MIDIPlayer::start()
if (m_child.valid() && m_child.running()) {
stop();
} else {
- m_child = bp::child(fmt::format("aplaymidi -p24 \"{}\"", m_file).c_str());//, bp::std_out > bp::null);
+ m_child = bp::child(fmt::format("aplaymidi -p{} \"{}\"", m_client, m_file).c_str());//, bp::std_out > bp::null);
}
}
@@ -87,3 +97,71 @@ std::vector<std::string> MIDIPlayer::get_filelist()
return result;
}
+void MIDIPlayer::init_seq(void)
+{
+ /* open sequencer */
+ int err = snd_seq_open(&m_seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
+ if (err < 0)
+ {
+ throw std::runtime_error("snd_seq_open()");
+ }
+}
+
+void MIDIPlayer::close_seq(void)
+{
+ int err = snd_seq_close(m_seq);
+ if (err < 0)
+ {
+ throw std::runtime_error("snd_seq_close()");
+ }
+}
+
+void MIDIPlayer::iterate_ports(void)
+{
+ bool found{};
+
+ snd_seq_client_info_t *cinfo;
+ snd_seq_port_info_t *pinfo;
+
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_port_info_alloca(&pinfo);
+
+ snd_seq_client_info_set_client(cinfo, -1);
+ while (snd_seq_query_next_client(m_seq, cinfo) >= 0) {
+ int client = snd_seq_client_info_get_client(cinfo);
+
+ snd_seq_port_info_set_client(pinfo, client);
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (snd_seq_query_next_port(m_seq, pinfo) >= 0) {
+ /* port must understand MIDI messages */
+ if (!(snd_seq_port_info_get_type(pinfo)
+ & SND_SEQ_PORT_TYPE_MIDI_GENERIC))
+ continue;
+ /* we need both WRITE and SUBS_WRITE */
+ if ((snd_seq_port_info_get_capability(pinfo)
+ & (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE))
+ != (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE))
+ continue;
+ if (supported_devices.contains(std::string{snd_seq_client_info_get_name(cinfo)})) {
+ m_client = snd_seq_port_info_get_client(pinfo);
+ found = true;
+ }
+ //std::cout << fmt::format("DEBUG: {}", get_midi_port()) << std::endl;
+ //printf("%3d:%-3d %-32.32s %s\n",
+ // snd_seq_port_info_get_client(pinfo),
+ // snd_seq_port_info_get_port(pinfo),
+ // snd_seq_client_info_get_name(cinfo),
+ // snd_seq_port_info_get_name(pinfo));
+ }
+ }
+
+ if (!found) {
+ throw std::runtime_error("No MIDI device found");
+ }
+}
+
+int MIDIPlayer::get_midi_port()
+{
+ return m_client;
+}
+
diff --git a/MIDIPlayer.h b/MIDIPlayer.h
index e104321..811bea4 100644
--- a/MIDIPlayer.h
+++ b/MIDIPlayer.h
@@ -4,6 +4,7 @@
#include <vector>
#include <boost/process.hpp>
+#include <alsa/asoundlib.h>
#include <filesystem>
@@ -24,9 +25,18 @@ public:
std::vector<std::string> get_filelist();
+ int get_midi_port();
+
private:
+ void init_seq(void);
+ void close_seq(void);
+ void iterate_ports(void);
+
boost::process::child m_child;
std::filesystem::path m_dir;
std::string m_file;
+
+ snd_seq_t* m_seq;
+ int m_client;
};
diff --git a/Makefile b/Makefile
index 7cb4c9d..70a1928 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ OBJS=$(SRCS:.cpp=.o)
CXX=clang++
CXXFLAGS=-Wall -g -O2 -fPIC -std=c++20
-CXXLIBS=-lfcgi -lreichwein -lfmt
+CXXLIBS=-lfcgi -lreichwein -lfmt -lasound
all: $(TARGET)
diff --git a/debian/control b/debian/control
index 14ff375..7f46012 100644
--- a/debian/control
+++ b/debian/control
@@ -1,2 +1,2 @@
-Build-Depends: libfmt-dev, libboost-dev, libfcgi-dev, libreichwein-dev
+Build-Depends: libfmt-dev, libboost-dev, libfcgi-dev, libreichwein-dev, libasound2-dev
Depends: nginx, alsa-utils, spawn-fcgi
diff --git a/midiplay.cpp b/midiplay.cpp
index 34879ee..bc1ad08 100644
--- a/midiplay.cpp
+++ b/midiplay.cpp
@@ -2,6 +2,7 @@
#include <stdexcept>
#include <string>
+#include <iostream>
#include <fcgiapp.h>
@@ -79,53 +80,57 @@ std::string to_xml(const std::vector<std::string>& filelist, const std::string&
} // namespace
int main(int argc, char* argv[]) {
- MIDIPlayer player;
+ try {
+ MIDIPlayer player;
- std::string ok_data{"<data><status>ok</status><message>OK</message></data>"};
- std::string error_data{"<data><status>error</status><message>General Error</message></data>"};
+ std::string ok_data{"<data><status>ok</status><message>OK</message></data>"};
+ std::string error_data{"<data><status>error</status><message>General Error</message></data>"};
- int result = FCGX_Init();
- if (result != 0) {
- return 1; // error on init
- }
-
- FCGX_Request request;
-
- if (FCGX_InitRequest(&request, 0, 0) != 0) {
- return 1; // error on init
- }
+ int result = FCGX_Init();
+ if (result != 0) {
+ return 1; // error on init
+ }
- while (FCGX_Accept_r(&request) == 0) {
- std::string method = FCGX_GetParam("REQUEST_METHOD", request.envp);
+ FCGX_Request request;
- try {
- if (method == "POST") {
- FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out);
+ if (FCGX_InitRequest(&request, 0, 0) != 0) {
+ return 1; // error on init
+ }
- PostData data{request};
- std::string command {getCommand(request)};
- if (command == "start") {
- player.start();
- FCGX_PutS(ok_data.c_str(), request.out);
- } else if (command == "stop") {
- player.stop();
- FCGX_PutS(ok_data.c_str(), request.out);
- } else if (command == "getlist") {
- FCGX_PutS(to_xml(player.get_filelist(), player.get_file()).c_str(), request.out);
- } else if (command == "setfile") {
- std::string filename = data.getXMLElement("data.value");
- player.set_file(filename);
- FCGX_PutS(ok_data.c_str(), request.out);
+ while (FCGX_Accept_r(&request) == 0) {
+ std::string method = FCGX_GetParam("REQUEST_METHOD", request.envp);
+
+ try {
+ if (method == "POST") {
+ FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out);
+
+ PostData data{request};
+ std::string command {getCommand(request)};
+ if (command == "start") {
+ player.start();
+ FCGX_PutS(ok_data.c_str(), request.out);
+ } else if (command == "stop") {
+ player.stop();
+ FCGX_PutS(ok_data.c_str(), request.out);
+ } else if (command == "getlist") {
+ FCGX_PutS(to_xml(player.get_filelist(), player.get_file()).c_str(), request.out);
+ } else if (command == "setfile") {
+ std::string filename = data.getXMLElement("data.value");
+ player.set_file(filename);
+ FCGX_PutS(ok_data.c_str(), request.out);
+ } else {
+ FCGX_PutS(error_data.c_str(), request.out);
+ }
} else {
- FCGX_PutS(error_data.c_str(), request.out);
+ throw std::runtime_error(fmt::format("Bad request method: POST expected, got {}", method).c_str());
}
- } else {
- throw std::runtime_error(fmt::format("Bad request method: POST expected, got {}", method).c_str());
+ } catch (const std::exception& ex) {
+ FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out);
+ FCGX_PutS(("<data><status>error</status><message>"s + ex.what() + "</message></data>").c_str(), request.out);
}
- } catch (const std::exception& ex) {
- FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out);
- FCGX_PutS(("<data><status>error</status><message>"s + ex.what() + "</message></data>").c_str(), request.out);
}
+ } catch (const std::exception& ex) {
+ std::cerr << "Error: " << ex.what() << std::endl;
}
return 0;