#include "Click.h" #include "MIDI.h" #include "PCM.h" #include "Timer.h" #include "UI.h" #include "config.h" #include "log.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; using namespace std::string_literals; double diff_timespec(const struct timespec *time1, const struct timespec *time0) { return (time1->tv_sec - time0->tv_sec) + (time1->tv_nsec - time0->tv_nsec) / 1000000000.0; } bool run_flag = true; void signal_handler(int) { run_flag = false; std::cout << "Signal received. Terminating." << std::endl; } int main(void) { signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); try { //debug_cout.activate(); log_cout.activate(); log_cout.log_lines(log_lines); Config config; std::shared_ptr clock_click = std::make_shared(); std::shared_ptr note_click = std::make_shared(config); std::shared_ptr internal_click = std::make_shared(config); MIDI midi; PCM pcm; UI ui(config); pcm.write(); Timer timer_500ms(500ms, true); timer_500ms.start(); Timer timer_10min(10min, true); timer_10min.start(); // Main signals boost::signals2::signal signal_count_loops; // // Signal-Slot Connections: // midi.signal_note.connect([&](int channel, int note, uint64_t timestamp){note_click->receive_note(channel, note, timestamp);}); note_click->signal_click.connect([&](){pcm.click();}); note_click->signal_bpm.connect([&](int bpm){ui.slot_note_bpm(bpm);}); clock_click->signal_bpm.connect([&](int bpm){ui.slot_clock_bpm(bpm);}); midi.signal_active_sensing.connect([&](){ui.slot_active_sensing();}); timer_500ms.elapsed.connect([&](){ui.draw();}); signal_count_loops.connect([&](){ui.count_main_loops();}); midi.signal_count_events.connect([&](){ui.count_midi_events();}); timer_10min.elapsed.connect([&](){config.persist();}); midi.signal_note.connect([&](int channel, int note, uint64_t timestamp){ui.slot_midi_note(channel, note, timestamp);}); midi.signal_clock.connect([&](){clock_click->receive_clock();}); midi.flush(); while (run_flag) { debug_cout << "Main loop entered." << std::endl; signal_count_loops(); fd_set read_set; FD_ZERO(&read_set); FD_SET(midi.fd(), &read_set); #if 0 // PCM fd almost always writeable: for single frames at high speed fd_set write_set; FD_ZERO(&write_set); FD_SET(pcm.fd(), &write_set); #endif struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 20000; int result = select(FD_SETSIZE, &read_set, nullptr/*&write_set*/, nullptr, &timeout); if (result < 0) { throw std::runtime_error("select() failed"); } else if (result == 0) { debug_cout << "select() timeout" << std::endl; } while (midi.event_ready()) { //std::cout << "read..." << std::endl; auto event = midi.read(); //std::cout << "process..." << std::endl; midi.process(event); } if (pcm.write_available()) { //std::cout << "DEBUG: WRITE" << std::endl; pcm.write(); } // handle timers, TODO: make updates more efficient at scale timer_500ms.update(); timer_10min.update(); } } catch (const std::exception& ex) { std::cerr << "Error: " << ex.what() << std::endl; } return 0; }