From 4bca25d7a388bbf69490340c860bc0c8241e9b2b Mon Sep 17 00:00:00 2001 From: jofemodo Date: Thu, 19 Aug 2021 14:31:47 +0200 Subject: [PATCH 1/8] Add "num_voices" option to CLI. --- clients/jack_client.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 806ddadb..7cecc9e7 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -151,7 +151,8 @@ static void done(int sig) ABSL_FLAG(std::string, client_name, "sfizz", "Jack client name"); ABSL_FLAG(std::string, oversampling, "1x", "Internal oversampling factor (value values are x1, x2, x4, x8)"); -ABSL_FLAG(uint32_t, preload_size, 8192, "Preloaded value"); +ABSL_FLAG(uint32_t, preload_size, 8192, "Preloaded size"); +ABSL_FLAG(uint32_t, num_voices, 32, "Num of voices"); ABSL_FLAG(bool, state, false, "Output the synth state in the jack loop"); int main(int argc, char** argv) @@ -167,12 +168,15 @@ int main(int argc, char** argv) const std::string clientName = absl::GetFlag(FLAGS_client_name); const std::string oversampling = absl::GetFlag(FLAGS_oversampling); const uint32_t preload_size = absl::GetFlag(FLAGS_preload_size); + const uint32_t num_voices = absl::GetFlag(FLAGS_num_voices); const bool verboseState = absl::GetFlag(FLAGS_state); std::cout << "Flags" << '\n'; std::cout << "- Client name: " << clientName << '\n'; std::cout << "- Oversampling: " << oversampling << '\n'; - std::cout << "- Preloaded Size: " << preload_size << '\n'; + std::cout << "- Preloaded size: " << preload_size << '\n'; + std::cout << "- Num of voices: " << num_voices << '\n'; + const auto factor = [&]() { if (oversampling == "x1") return 1; if (oversampling == "x2") return 2; @@ -189,6 +193,7 @@ int main(int argc, char** argv) sfz::Sfizz synth; synth.setOversamplingFactor(factor); synth.setPreloadSize(preload_size); + synth.setNumVoices(num_voices); const char *importFormat = nullptr; if (!sfizz_load_or_import_file(synth.handle(), filesToParse[0], &importFormat)) { From 29ff2b93f6b8a6457e9bbd3ccef0558b7f50c7cf Mon Sep 17 00:00:00 2001 From: jofemodo Date: Thu, 19 Aug 2021 20:06:37 +0200 Subject: [PATCH 2/8] Implement a basic CLI for loading soundfonts and setting engine parameters. --- clients/jack_client.cpp | 154 +++++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 49 deletions(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 7cecc9e7..0c2fa61b 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -43,6 +43,9 @@ #include #include + +sfz::Sfizz synth; + static jack_port_t* midiInputPort; static jack_port_t* outputPort1; static jack_port_t* outputPort2; @@ -149,26 +152,103 @@ static void done(int sig) // exit(0); } + +bool load_instrument(const char *fpath) { + const char *importFormat = nullptr; + if (!sfizz_load_or_import_file(synth.handle(), fpath, &importFormat)) { + std::cout << "Could not load the instrument file: " << fpath << '\n'; + return false; + } + + std::cout << "Instrument loaded: " << fpath << '\n'; + std::cout << "===========================" << '\n'; + std::cout << "Total:" << '\n'; + std::cout << "\tMasters: " << synth.getNumMasters() << '\n'; + std::cout << "\tGroups: " << synth.getNumGroups() << '\n'; + std::cout << "\tRegions: " << synth.getNumRegions() << '\n'; + std::cout << "\tCurves: " << synth.getNumCurves() << '\n'; + std::cout << "\tPreloadedSamples: " << synth.getNumPreloadedSamples() << '\n'; +#if 0 // not currently in public API + std::cout << "===========================" << '\n'; + std::cout << "Included files:" << '\n'; + for (auto& file : synth.getParser().getIncludedFiles()) + std::cout << '\t' << file << '\n'; + std::cout << "===========================" << '\n'; + std::cout << "Defines:" << '\n'; + for (auto& define : synth.getParser().getDefines()) + std::cout << '\t' << define.first << '=' << define.second << '\n'; +#endif + std::cout << "===========================" << '\n'; + std::cout << "Unknown opcodes:"; + for (auto& opcode : synth.getUnknownOpcodes()) + std::cout << opcode << ','; + std::cout << '\n'; + if (importFormat) { + std::cout << "===========================" << '\n'; + std::cout << "Import format: " << importFormat << '\n'; + } + // std::cout << std::flush; + + return true; +} + + +void cli_thread_proc() { + while (!shouldClose) { + std::cout << "\n> "; + + std::string command; + std::getline(std::cin, command); + std::size_t pos = command.find(" "); + std::string kw = command.substr(0, pos); + std::string args = command.substr(pos+1); + + if (kw=="load_instrument") { + load_instrument(args.c_str()); + } + else if (kw=="set_preload_size") { + try { + synth.setPreloadSize(stoi(args)); + } catch (...) { + std::cout << "ERROR: Can't set preload size!\n"; + } + } + else if (kw=="set_voices") { + try { + synth.setNumVoices(stoi(args)); + } catch (...) { + std::cout << "ERROR: Can't set num of voices!\n"; + } + } + else if (kw=="quit") { + shouldClose = true; + } + else if (kw.size()>0){ + std::cout << "ERROR: Unknown command '" << kw <<"'!\n"; + } + } +} + + ABSL_FLAG(std::string, client_name, "sfizz", "Jack client name"); ABSL_FLAG(std::string, oversampling, "1x", "Internal oversampling factor (value values are x1, x2, x4, x8)"); ABSL_FLAG(uint32_t, preload_size, 8192, "Preloaded size"); ABSL_FLAG(uint32_t, num_voices, 32, "Num of voices"); +ABSL_FLAG(bool, jack_autoconnect, false, "Autoconnect audio output"); ABSL_FLAG(bool, state, false, "Output the synth state in the jack loop"); int main(int argc, char** argv) { // std::ios::sync_with_stdio(false); auto arguments = absl::ParseCommandLine(argc, argv); - if (arguments.size() < 2) { - std::cout << "You need to specify an SFZ file to load." << '\n'; - return -1; - } + auto filesToParse = absl::MakeConstSpan(arguments).subspan(1); const std::string clientName = absl::GetFlag(FLAGS_client_name); const std::string oversampling = absl::GetFlag(FLAGS_oversampling); const uint32_t preload_size = absl::GetFlag(FLAGS_preload_size); const uint32_t num_voices = absl::GetFlag(FLAGS_num_voices); + const bool jack_autoconnect = absl::GetFlag(FLAGS_jack_autoconnect); const bool verboseState = absl::GetFlag(FLAGS_state); std::cout << "Flags" << '\n'; @@ -176,6 +256,8 @@ int main(int argc, char** argv) std::cout << "- Oversampling: " << oversampling << '\n'; std::cout << "- Preloaded size: " << preload_size << '\n'; std::cout << "- Num of voices: " << num_voices << '\n'; + std::cout << "- Audio Autoconnect: " << jack_autoconnect << '\n'; + std::cout << "- Verbose State: " << verboseState << '\n'; const auto factor = [&]() { if (oversampling == "x1") return 1; @@ -190,45 +272,10 @@ int main(int argc, char** argv) std::cout << " " << file << ','; std::cout << '\n'; - sfz::Sfizz synth; synth.setOversamplingFactor(factor); synth.setPreloadSize(preload_size); synth.setNumVoices(num_voices); - const char *importFormat = nullptr; - if (!sfizz_load_or_import_file(synth.handle(), filesToParse[0], &importFormat)) { - std::cout << "Could not load the instrument file: " << filesToParse[0] << '\n'; - return 1; - } - - std::cout << "==========" << '\n'; - std::cout << "Total:" << '\n'; - std::cout << "\tMasters: " << synth.getNumMasters() << '\n'; - std::cout << "\tGroups: " << synth.getNumGroups() << '\n'; - std::cout << "\tRegions: " << synth.getNumRegions() << '\n'; - std::cout << "\tCurves: " << synth.getNumCurves() << '\n'; - std::cout << "\tPreloadedSamples: " << synth.getNumPreloadedSamples() << '\n'; -#if 0 // not currently in public API - std::cout << "==========" << '\n'; - std::cout << "Included files:" << '\n'; - for (auto& file : synth.getParser().getIncludedFiles()) - std::cout << '\t' << file << '\n'; - std::cout << "==========" << '\n'; - std::cout << "Defines:" << '\n'; - for (auto& define : synth.getParser().getDefines()) - std::cout << '\t' << define.first << '=' << define.second << '\n'; -#endif - std::cout << "==========" << '\n'; - std::cout << "Unknown opcodes:"; - for (auto& opcode : synth.getUnknownOpcodes()) - std::cout << opcode << ','; - std::cout << '\n'; - if (importFormat) { - std::cout << "==========" << '\n'; - std::cout << "Import format: " << importFormat << '\n'; - } - // std::cout << std::flush; - jack_status_t status; client = jack_client_open(clientName.c_str(), JackNullOption, &status); if (client == nullptr) { @@ -270,26 +317,35 @@ int main(int argc, char** argv) return 1; } - auto systemPorts = jack_get_ports(client, nullptr, nullptr, JackPortIsPhysical | JackPortIsInput); - if (systemPorts == nullptr) { - std::cerr << "No physical output ports found" << '\n'; - return 1; + if (jack_autoconnect) { + auto systemPorts = jack_get_ports(client, nullptr, nullptr, JackPortIsPhysical | JackPortIsInput); + if (systemPorts == nullptr) { + std::cerr << "No physical output ports found" << '\n'; + return 1; + } + + if (jack_connect(client, jack_port_name(outputPort1), systemPorts[0])) { + std::cerr << "Cannot connect to physical output ports (0)" << '\n'; + } + + if (jack_connect(client, jack_port_name(outputPort2), systemPorts[1])) { + std::cerr << "Cannot connect to physical output ports (1)" << '\n'; + } + jack_free(systemPorts); } - if (jack_connect(client, jack_port_name(outputPort1), systemPorts[0])) { - std::cerr << "Cannot connect to physical output ports (0)" << '\n'; + if (filesToParse[0]) { + load_instrument(filesToParse[0]); } - if (jack_connect(client, jack_port_name(outputPort2), systemPorts[1])) { - std::cerr << "Cannot connect to physical output ports (1)" << '\n'; - } - jack_free(systemPorts); + std::thread cli_thread(cli_thread_proc); signal(SIGHUP, done); signal(SIGINT, done); signal(SIGTERM, done); signal(SIGQUIT, done); + while (!shouldClose){ if (verboseState) { std::cout << "Active voices: " << synth.getNumActiveVoices() << '\n'; From 48582af1194de26ceec4a47f94d1cd859b49c43c Mon Sep 17 00:00:00 2001 From: jofemodo Date: Fri, 20 Aug 2021 02:33:11 +0200 Subject: [PATCH 3/8] Add "set_oversampling" option to internal CLI. --- clients/jack_client.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 0c2fa61b..9095c881 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -206,6 +206,13 @@ void cli_thread_proc() { if (kw=="load_instrument") { load_instrument(args.c_str()); } + else if (kw=="set_oversampling") { + try { + synth.setOversamplingFactor(stoi(args)); + } catch (...) { + std::cout << "ERROR: Can't set oversampling!\n"; + } + } else if (kw=="set_preload_size") { try { synth.setPreloadSize(stoi(args)); From 07670686f924b1da289396a86dc03af6a3890058 Mon Sep 17 00:00:00 2001 From: jofemodo Date: Fri, 20 Aug 2021 03:31:31 +0200 Subject: [PATCH 4/8] Improve internal CLI: Implement tokenization algorithm for command arguments, including double quotes. --- clients/jack_client.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 9095c881..4de49455 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -42,6 +42,7 @@ #include #include #include +#include sfz::Sfizz synth; @@ -193,6 +194,30 @@ bool load_instrument(const char *fpath) { } +std::vector string_tokenize(std::string str) { + std::vector tokens; + std::string part = ""; + for (size_t i=0; i "; @@ -202,9 +227,11 @@ void cli_thread_proc() { std::size_t pos = command.find(" "); std::string kw = command.substr(0, pos); std::string args = command.substr(pos+1); + std::vector tokens = string_tokenize(args); if (kw=="load_instrument") { - load_instrument(args.c_str()); + //args.erase(std::remove(str.begin(), str.end(), '\"'), str.end()); + load_instrument(tokens[0].c_str()); } else if (kw=="set_oversampling") { try { From 16789b6a6e804a510694020a045d9db2d197e341 Mon Sep 17 00:00:00 2001 From: jofemodo Date: Thu, 26 Aug 2021 12:54:21 +0200 Subject: [PATCH 5/8] Add mutex lock on internal command line process. --- clients/jack_client.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 4de49455..799a6dbf 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -194,7 +194,7 @@ bool load_instrument(const char *fpath) { } -std::vector string_tokenize(std::string str) { +std::vector string_tokenize(const std::string str) { std::vector tokens; std::string part = ""; for (size_t i=0; i tokens = string_tokenize(args); if (kw=="load_instrument") { - //args.erase(std::remove(str.begin(), str.end(), '\"'), str.end()); - load_instrument(tokens[0].c_str()); + try { + std::lock_guard lock { processMutex }; + load_instrument(tokens[0].c_str()); + } catch (...) { + std::cout << "ERROR: Can't load instrument!\n"; + } } else if (kw=="set_oversampling") { try { + std::lock_guard lock { processMutex }; synth.setOversamplingFactor(stoi(args)); } catch (...) { std::cout << "ERROR: Can't set oversampling!\n"; @@ -242,6 +247,7 @@ void cli_thread_proc() { } else if (kw=="set_preload_size") { try { + std::lock_guard lock { processMutex }; synth.setPreloadSize(stoi(args)); } catch (...) { std::cout << "ERROR: Can't set preload size!\n"; @@ -249,6 +255,7 @@ void cli_thread_proc() { } else if (kw=="set_voices") { try { + std::lock_guard lock { processMutex }; synth.setNumVoices(stoi(args)); } catch (...) { std::cout << "ERROR: Can't set num of voices!\n"; From 8c1b5a11fe1d448cde205f8c4172b2993d9276a8 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 10 Sep 2021 13:59:20 +0200 Subject: [PATCH 6/8] Avoid a copy --- clients/jack_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 799a6dbf..7438e801 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -194,7 +194,7 @@ bool load_instrument(const char *fpath) { } -std::vector string_tokenize(const std::string str) { +std::vector string_tokenize(const std::string& str) { std::vector tokens; std::string part = ""; for (size_t i=0; i Date: Fri, 10 Sep 2021 14:04:24 +0200 Subject: [PATCH 7/8] Formatting --- clients/jack_client.cpp | 71 +++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 7438e801..63d0da66 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -44,7 +44,6 @@ #include #include - sfz::Sfizz synth; static jack_port_t* midiInputPort; @@ -153,9 +152,9 @@ static void done(int sig) // exit(0); } - -bool load_instrument(const char *fpath) { - const char *importFormat = nullptr; +bool loadInstrument(const char* fpath) +{ + const char* importFormat = nullptr; if (!sfizz_load_or_import_file(synth.handle(), fpath, &importFormat)) { std::cout << "Could not load the instrument file: " << fpath << '\n'; return false; @@ -193,32 +192,35 @@ bool load_instrument(const char *fpath) { return true; } - -std::vector string_tokenize(const std::string& str) { +std::vector stringTokenize(const std::string& str) +{ std::vector tokens; std::string part = ""; - for (size_t i=0; i "; @@ -226,51 +228,45 @@ void cli_thread_proc() { std::getline(std::cin, command); std::size_t pos = command.find(" "); std::string kw = command.substr(0, pos); - std::string args = command.substr(pos+1); - std::vector tokens = string_tokenize(args); + std::string args = command.substr(pos + 1); + std::vector tokens = stringTokenize(args); - if (kw=="load_instrument") { + if (kw == "loadInstrument") { try { std::lock_guard lock { processMutex }; - load_instrument(tokens[0].c_str()); + loadInstrument(tokens[0].c_str()); } catch (...) { std::cout << "ERROR: Can't load instrument!\n"; } - } - else if (kw=="set_oversampling") { + } else if (kw == "set_oversampling") { try { std::lock_guard lock { processMutex }; synth.setOversamplingFactor(stoi(args)); } catch (...) { std::cout << "ERROR: Can't set oversampling!\n"; } - } - else if (kw=="set_preload_size") { + } else if (kw == "set_preload_size") { try { std::lock_guard lock { processMutex }; synth.setPreloadSize(stoi(args)); } catch (...) { std::cout << "ERROR: Can't set preload size!\n"; } - } - else if (kw=="set_voices") { + } else if (kw == "set_voices") { try { std::lock_guard lock { processMutex }; synth.setNumVoices(stoi(args)); } catch (...) { std::cout << "ERROR: Can't set num of voices!\n"; } - } - else if (kw=="quit") { + } else if (kw == "quit") { shouldClose = true; - } - else if (kw.size()>0){ - std::cout << "ERROR: Unknown command '" << kw <<"'!\n"; + } else if (kw.size() > 0) { + std::cout << "ERROR: Unknown command '" << kw << "'!\n"; } } } - ABSL_FLAG(std::string, client_name, "sfizz", "Jack client name"); ABSL_FLAG(std::string, oversampling, "1x", "Internal oversampling factor (value values are x1, x2, x4, x8)"); ABSL_FLAG(uint32_t, preload_size, 8192, "Preloaded size"); @@ -280,10 +276,8 @@ ABSL_FLAG(bool, state, false, "Output the synth state in the jack loop"); int main(int argc, char** argv) { - // std::ios::sync_with_stdio(false); auto arguments = absl::ParseCommandLine(argc, argv); - auto filesToParse = absl::MakeConstSpan(arguments).subspan(1); const std::string clientName = absl::GetFlag(FLAGS_client_name); const std::string oversampling = absl::GetFlag(FLAGS_oversampling); @@ -376,23 +370,22 @@ int main(int argc, char** argv) } if (filesToParse[0]) { - load_instrument(filesToParse[0]); + loadInstrument(filesToParse[0]); } - std::thread cli_thread(cli_thread_proc); + std::thread cli_thread(cliThreadProc); signal(SIGHUP, done); signal(SIGINT, done); signal(SIGTERM, done); signal(SIGQUIT, done); - - while (!shouldClose){ + while (!shouldClose) { if (verboseState) { std::cout << "Active voices: " << synth.getNumActiveVoices() << '\n'; #ifndef NDEBUG - std::cout << "Allocated buffers: " << synth.getAllocatedBuffers() << '\n'; - std::cout << "Total size: " << synth.getAllocatedBytes() << '\n'; + std::cout << "Allocated buffers: " << synth.getAllocatedBuffers() << '\n'; + std::cout << "Total size: " << synth.getAllocatedBytes() << '\n'; #endif } std::this_thread::sleep_for(std::chrono::seconds(1)); From 6034c9f9a5647fd6f10e92cadb3668ca793e3ba6 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 21 Sep 2021 11:30:23 +0200 Subject: [PATCH 8/8] Fix overeager find/replace --- clients/jack_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 63d0da66..8f5f30d1 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -231,7 +231,7 @@ void cliThreadProc() std::string args = command.substr(pos + 1); std::vector tokens = stringTokenize(args); - if (kw == "loadInstrument") { + if (kw == "load_instrument") { try { std::lock_guard lock { processMutex }; loadInstrument(tokens[0].c_str());