From 472cbf21e567c0c65c124f96cebe717cdef901fb Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 12 Jan 2025 23:08:08 +0100 Subject: Play MIDI --- MIDIPlayer.cpp | 55 ++++++++++++++++++++-- MIDIPlayer.h | 13 +++++- Makefile | 2 +- html/index.html | 140 ++++++++++++++++++++++++++++++++++++++++++-------------- midiplay.cpp | 138 +++++++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 275 insertions(+), 73 deletions(-) diff --git a/MIDIPlayer.cpp b/MIDIPlayer.cpp index 41f852e..c7945d6 100644 --- a/MIDIPlayer.cpp +++ b/MIDIPlayer.cpp @@ -1,27 +1,76 @@ #include "MIDIPlayer.h" -MIDIPlayer::MIDIPlayer() +#include + +#include + +namespace bp = boost::process; +namespace fs = std::filesystem; + +MIDIPlayer::MIDIPlayer(const std::filesystem::path& path): + m_child{}, + m_dir{path}, + m_file{} { -} + std::vector list = get_filelist(); + if (list.size() > 0) { + m_file = list[0]; + } +} void MIDIPlayer::start() { - "aplaymidi -p24 locked_out_of_heaven.midi" + if (m_child.valid() && m_child.running()) { + stop(); + } else { + m_child = bp::child("aplaymidi -p24 locked_out_of_heaven.midi");//, bp::std_out > bp::null); + } } void MIDIPlayer::stop() { + // note:: m_child.terminate() would kill via SIGKILL, preventing note offs + + if (m_child.valid()) { + int result = kill(m_child.native_handle(), SIGTERM); + if (result < 0) { + std::cerr << "Error in MIDIPlayer::stop(): kill() unsuccessful\n"; + } + } } bool MIDIPlayer::is_playing() { + if (!m_child.valid()) { + return false; + } + return m_child.running(); } void MIDIPlayer::set_file(const std::string& filename) { + m_file = filename; +} + +std::string MIDIPlayer::get_file() +{ + return m_file; } std::vector MIDIPlayer::get_filelist() { + std::vector result; + for (auto const& dir_entry: fs::directory_iterator{m_dir}) { + fs::path entry{dir_entry.path()}; + fs::path extension = entry.extension(); + if (extension == ".midi" || extension == ".mid") { + result.push_back(entry.filename()); + } + if (result.size() == 99) { + break; + } + } + return result; } + diff --git a/MIDIPlayer.h b/MIDIPlayer.h index e859bed..e104321 100644 --- a/MIDIPlayer.h +++ b/MIDIPlayer.h @@ -3,10 +3,14 @@ #include #include +#include + +#include + class MIDIPlayer { public: - MIDIPlayer(); + MIDIPlayer(const std::filesystem::path& path = "."); void start(); @@ -16,6 +20,13 @@ public: void set_file(const std::string& filename); + std::string get_file(); + std::vector get_filelist(); + +private: + boost::process::child m_child; + std::filesystem::path m_dir; + std::string m_file; }; diff --git a/Makefile b/Makefile index 7ceb738..7cb4c9d 100644 --- a/Makefile +++ b/Makefile @@ -25,4 +25,4 @@ $(TARGET): $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ $(CXXLIBS) clean: - -rm -rf $(TARGET) + -rm -rf $(OBJS) $(TARGET) diff --git a/html/index.html b/html/index.html index a27b654..ac85aa1 100644 --- a/html/index.html +++ b/html/index.html @@ -9,42 +9,108 @@ height: 150px; font-size: 20px; } + +.selected{ + color: #FF8080; +} + +.normal{ + color: #000000; +} @@ -54,10 +120,16 @@ MIDIPLAY

+(Loading Songlist...)


+
+
+ Status: ok +
+ diff --git a/midiplay.cpp b/midiplay.cpp index d5c0ef0..34879ee 100644 --- a/midiplay.cpp +++ b/midiplay.cpp @@ -1,63 +1,133 @@ #include "MIDIPlayer.h" +#include #include #include +#include +#include #include -std::string getPostData(FCGX_Request& request) +namespace pt = boost::property_tree; + +using namespace std::string_literals; + +namespace { + +class PostData { - std::string result; - std::string contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp)); - int contentLength = std::stoul(contentLengthString); +public: + PostData(FCGX_Request& request) { + std::string result; + std::string contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp)); + int contentLength = std::stoul(contentLengthString); - if (contentLength < 1) { - return "Bad content length"; - } else { result.resize(contentLength); unsigned int status = FCGX_GetStr(result.data(), result.size(), request.in); if (status != result.size()) { - return fmt::format("Read error: {}/{}", status, result.size()); + throw std::runtime_error(fmt::format("Read error: {}/{}", status, result.size())); } - return result; + m_data = result; + } + + std::string getData() + { + return m_data; + } + + // path: xml path, e.g. data.value + std::string getXMLElement(const std::string& path) + { + pt::ptree tree{}; + std::istringstream iss{m_data}; + pt::read_xml(iss, tree, pt::xml_parser::trim_whitespace); + + return tree.get(path); + } + +private: + std::string m_data; +}; + +std::string getCommand(FCGX_Request& request) +{ + std::string query = FCGX_GetParam("QUERY_STRING", request.envp); + size_t pos = query.find("command="); + if (pos != query.npos) { + return query.substr(pos + 8); + } else { + return {}; } } -int main(int argc, char* argv[]) { +std::string to_xml(const std::vector& filelist, const std::string& selected) +{ + std::string result{"ok"}; + + for (const auto& i: filelist) { + result += "" + i + ""; + } + + result += ""; + result += "" + selected + ""; + return result + ""; +} - int result = FCGX_Init(); - if (result != 0) { - return 1; // error on init - } +} // namespace - FCGX_Request request; +int main(int argc, char* argv[]) { + MIDIPlayer player; - if (FCGX_InitRequest(&request, 0, 0) != 0) { - return 1; // error on init - } + std::string ok_data{"okOK"}; + std::string error_data{"errorGeneral Error"}; - while (FCGX_Accept_r(&request) == 0) { - std::string query = FCGX_GetParam("QUERY_STRING", request.envp); - - std::string method = FCGX_GetParam("REQUEST_METHOD", request.envp); + int result = FCGX_Init(); + if (result != 0) { + return 1; // error on init + } - if (method == "POST") { - FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out); + FCGX_Request request; - std::string data = getPostData(request); - if (data == "3") { - FCGX_PutS("4", request.out); - } - } else { - FCGX_PutS("Content-Type: text/text\r\n\r\n", request.out); - FCGX_PutS("Bad request method: POST expected", request.out); - } + if (FCGX_InitRequest(&request, 0, 0) != 0) { + return 1; // error on init + } - } + 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 { + 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(("error"s + ex.what() + "").c_str(), request.out); + } + } - return 0; + return 0; } -- cgit v1.2.3