zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit ef392d964724236d7c845ff0e5529eed077fbe98
parent 28ba182502484d6874f2c77c4175aa769729c129
Author: Johannes Lorenz <[email protected]>
Date:   Sun,  7 May 2023 00:47:05 +0200

Make PortChecker an in-process check

Diffstat:
Msrc/Tests/CMakeLists.txt | 6++++--
Asrc/Tests/PortChecker.cpp | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/check-ports.rb | 42------------------------------------------
3 files changed, 172 insertions(+), 44 deletions(-)

diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt @@ -64,8 +64,10 @@ if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")) target_link_libraries(ins-test ${test_lib} rt) if(LIBLO_FOUND) - cp_script(check-ports.rb) - add_test(PortChecker check-ports.rb) + quick_test(PortChecker zynaddsubfx_core zynaddsubfx_nio + zynaddsubfx_gui_bridge + ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES} + ${PLATFORM_LIBRARIES}) endif() add_executable(save-osc SaveOSC.cpp) target_link_libraries(save-osc diff --git a/src/Tests/PortChecker.cpp b/src/Tests/PortChecker.cpp @@ -0,0 +1,168 @@ +#include <cassert> +#include <thread> +#include <mutex> +#include <iostream> +#include <ctime> +#include <unistd.h> +#include <rtosc/thread-link.h> +#include <rtosc/rtosc-time.h> +#include <rtosc/port-checker.h> + +#include "../Misc/Master.h" +#include "../Misc/MiddleWare.h" +#include "../UI/NSM.H" + +// for linking purposes only: +NSM_Client *nsm = 0; +zyn::MiddleWare *middleware = 0; + +char *instance_name=(char*)""; + +class PortChecker +{ + void _masterChangedCallback(zyn::Master* m) + { + master = m; + master->setMasterChangedCallback(__masterChangedCallback, this); + } + + // TODO: eliminate static callbacks + static void __masterChangedCallback(void* ptr, zyn::Master* m) + { + ((PortChecker*)ptr)->_masterChangedCallback(m); + } + + void setUp() { + // this might be set to true in the future + // when saving will work better + config.cfg.SaveFullXml = false; + + synth = new zyn::SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + synth->alias(); + + mw = new zyn::MiddleWare(std::move(*synth), &config); + mw->setUiCallback(_uiCallback, this); + _masterChangedCallback(mw->spawnMaster()); + realtime = nullptr; + } + + void tearDown() { +#ifdef SAVE_OSC_DEBUG + printf("Master at the end: %p\n", master); +#endif + delete mw; + delete synth; + } + + void uiCallback(const char* msg) + { + (void)msg; + } + + bool exit_mw = false; + void run_mw() + { + while(!exit_mw) { + if(mw) + mw->tick(); + usleep(20000); + } + } + + public: + PortChecker() { setUp(); } + ~PortChecker() { tearDown(); } + + static void _uiCallback(void* ptr, const char* msg) + { + ((PortChecker*)ptr)->uiCallback(msg); + } + + int run() + { + assert(mw); + + std::thread mwthread(&PortChecker::run_mw, this); + + bool ok; + try { + rtosc::port_checker pc; + ok = pc(mw->getServerPort()); + + if(!pc.print_sanity_checks()) + ok = false; + pc.print_evaluation(); + if(pc.errors_found()) + ok = false; + pc.print_not_affected(); + pc.print_skipped(); + pc.print_statistics(); + + } catch(const std::exception& e) { + std::cerr << "**Error caught**: " << e.what() << std::endl; + ok = false; + } + + int res = ok ? EXIT_SUCCESS : EXIT_FAILURE; + exit_mw = true; + mwthread.join(); + return res; + } + + + void start_realtime(void) + { + do_exit = false; + + realtime = new std::thread([this](){ + while(!do_exit) + { + if(master->uToB->hasNext()) { + const char *msg = master->uToB->read(); +#ifdef ZYN_PORT_CHECKER_DEBUG + printf("Master %p: handling <%s>\n", master, msg); +#endif + master->applyOscEvent(msg, false); + } + else { + // RT has no incoming message? + if(do_exit) + break; + usleep(500); + } + master->last_ack = master->last_beat; + }}); + } + + void stop_realtime(void) + { + do_exit = true; + + realtime->join(); + delete realtime; + realtime = NULL; + } + + private: + zyn::Config config; + zyn::SYNTH_T* synth; + zyn::Master* master = NULL; + zyn::MiddleWare* mw; + std::thread* realtime; + bool do_exit; +}; + +int main() +{ + PortChecker test; + test.start_realtime(); + int res = test.run(); + test.stop_realtime(); + std::cerr << "Summary: " << ((res == EXIT_SUCCESS) ? "SUCCESS" : "FAILURE") + << std::endl; + return res; +} + + diff --git a/src/Tests/check-ports.rb b/src/Tests/check-ports.rb @@ -1,42 +0,0 @@ -#!/usr/bin/ruby - -require 'open3' - -rval=0 -my_path=File.dirname(__FILE__) - -# start zyn, grep the lo server port, and connect the port checker to it -# NOTE: If you add too much debug output to zyn, it will be blocked when writing into the pipe, -# leading to MiddleWare to not reply and to port-checker to fail. -# This script should be rewritten to keep reading (and printing) zyn's messages. -Open3.popen3(my_path + "/../zynaddsubfx -O null -I null --no-gui") do |stdin, stdout, stderr, wait_thr| - pid = wait_thr[:pid] - while line=stderr.gets do - # print "line: " + line; - if /^lo server running on (\d+)$/.match(line) then - sleep 3 # give zyn more time to setup - port_checker_rval = system(my_path + "/../../rtosc/port-checker 'osc.udp://localhost:" + $1 + "/'") - if port_checker_rval != true then - puts "Error: port-checker has returned #{$?.exitstatus}." - rval=1 - end - begin - # Check if zyn has not crashed yet - # Wait 1 second before detection - sleep 1 - Process.kill(0, pid) - # This is only executed if Process.kill did not raise an exception - Process.kill("KILL", pid) - rescue Errno::ESRCH - puts "Error: ZynAddSubFX (PID #{pid}) crashed!" - puts " Missing replies or port-checker crashes could be due to the crash." - rval=1 - rescue - puts "Error: Cannot kill ZynAddSubFX (PID #{pid})?" - rval=1 - end - end - end -end - -exit rval