From 9351c6d9812523b0b8027f2b2e0de54c27004bc2 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 4 Jan 2025 09:22:17 +0100 Subject: Fix config --- Click.h | 6 +++++- MIDI.h | 23 ++++++++++++++--------- PCM.h | 3 ++- UI.cpp | 2 +- UI.h | 8 ++++++++ config.cpp | 12 +++++++++++- config.h | 3 +++ main.cpp | 20 ++++++++++++++++++-- 8 files changed, 62 insertions(+), 15 deletions(-) diff --git a/Click.h b/Click.h index 0c2d0c7..7861d33 100644 --- a/Click.h +++ b/Click.h @@ -38,10 +38,14 @@ public: virtual ~NoteClick(){} + // signals boost::signals2::signal signal_click; - void receive_note(int channel, int note) + // slots + void receive_note(int channel, int note, uint64_t timestamp) { + (void) timestamp; + if (true || (channel == m_channel && note == m_note)) { signal_click(); } diff --git a/MIDI.h b/MIDI.h index 23024c3..96c9eb7 100644 --- a/MIDI.h +++ b/MIDI.h @@ -32,7 +32,7 @@ public: throw std::runtime_error("MIDI port couldn't be opened"); } - log_cout << "in_port: " << std::to_string(in_port) << std::endl; + debug_cout << "in_port: " << std::to_string(in_port) << std::endl; #if 1 snd_seq_addr_t sender, dest; @@ -80,7 +80,7 @@ public: free(pfd); } - boost::signals2::signal signal_note; + boost::signals2::signal signal_note; boost::signals2::signal signal_active_sensing; boost::signals2::signal signal_clock; @@ -121,40 +121,45 @@ public: return ev; } + uint64_t timestamp_from_event(const snd_seq_event_t *ev) + { + return ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick; + } + // returns if click starts void process(const snd_seq_event_t *ev) { if ((ev->type == SND_SEQ_EVENT_NOTEON) ||(ev->type == SND_SEQ_EVENT_NOTEOFF)) { + uint64_t timestamp = timestamp_from_event(ev); const char *type = (ev->type == SND_SEQ_EVENT_NOTEON) ? "on " : "off"; - debug_cout << fmt::format("[{}] Note {}: {:2x} vel({:2x}), ch {:2x}\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, + debug_cout << fmt::format("[{}] Note {}: {:2x} vel({:2x}), ch {:2x}\n", timestamp, type, ev->data.note.note, ev->data.note.velocity, ev->data.control.channel); if (ev->type == SND_SEQ_EVENT_NOTEON) { - signal_note(ev->data.control.channel, ev->data.note.note); + signal_note(ev->data.control.channel, ev->data.note.note, timestamp); } } else if (ev->type == SND_SEQ_EVENT_CONTROLLER) { - debug_cout << fmt::format("[{}] Control: {:2x} val({:2x})\n", - ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, + debug_cout << fmt::format("[{}] Control: {:2x} val({:2x})\n", timestamp_from_event(ev), ev->data.control.param, ev->data.control.value); } else if (ev->type == SND_SEQ_EVENT_SENSING) { signal_active_sensing(); - debug_cout << fmt::format("[{}] Active Sensing\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick) << std::endl; + debug_cout << fmt::format("[{}] Active Sensing\n", timestamp_from_event(ev)) << std::endl; } else if (ev->type == SND_SEQ_EVENT_CLOCK) { signal_clock(); - debug_cout << fmt::format("[{}] Clock\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick) << std::endl; + debug_cout << fmt::format("[{}] Clock\n", timestamp_from_event(ev)) << std::endl; } else { - log_cout << fmt::format("[{}] Unknown MIDI event: {}\n", ev->time.tick, ev->type) << std::endl; + log_cout << fmt::format("[{}] Unknown MIDI event: {}\n", timestamp_from_event(ev), ev->type) << std::endl; } } diff --git a/PCM.h b/PCM.h index a74b2ea..a9e251c 100644 --- a/PCM.h +++ b/PCM.h @@ -1,6 +1,7 @@ #pragma once #include "config.h" +#include "debug.h" #include "log.h" #include @@ -132,7 +133,7 @@ public: if (0 > snd_pcm_avail_delay(handle, &avail, &delay)) { log_cout << "Error detecting avail and delay" << std::endl; } else { - log_cout << fmt::format("Delay: {}, avail. buffer; {} frames", delay, avail) << std::endl; + debug_cout << fmt::format("Delay: {}, avail. buffer; {} frames", delay, avail) << std::endl; } generate(); diff --git a/UI.cpp b/UI.cpp index c083d53..c699aba 100644 --- a/UI.cpp +++ b/UI.cpp @@ -54,7 +54,7 @@ void UI::draw() std::cout << fmt::format(", max. {:2}%", max) << std::endl; std::cout << " Notes/Channels: -- -- -- ... (Choose)" << std::endl; - std::cout << " Timestamp: ------" << std::endl; + std::cout << " MIDI Timestamp: ------" << std::endl; std::cout << fmt::format(" Active sensing: {}", active_sensing_detected) << std::endl; std::cout << " Clock: ____ BPM" << std::endl; std::cout << " Click: ____ BPM" << std::endl; diff --git a/UI.h b/UI.h index 3041566..f507d2e 100644 --- a/UI.h +++ b/UI.h @@ -2,6 +2,8 @@ #include +#include + class UI { public: @@ -11,6 +13,12 @@ public: void draw(); + // signals + boost::signals2::signal bpm_plus; + boost::signals2::signal bpm_minus; + boost::signals2::signal note_set_from_midi; + boost::signals2::signal mode; + // slots void count_main_loops(); void slot_active_sensing(); diff --git a/config.cpp b/config.cpp index b6460f2..2cd061c 100644 --- a/config.cpp +++ b/config.cpp @@ -14,6 +14,16 @@ const char *device = "default"; // playback device std::string config_filename = "click.cfg"; Config::Config() +{ + recover(); +} + +Config::~Config() +{ + persist(); +} + +void Config::recover() { try { // presets / defaults @@ -41,7 +51,7 @@ Config::Config() } } -Config::~Config() +void Config::persist() { std::string config = fmt::format("midi_channel={}\n", m_midi_channel) + fmt::format("midi_note={}\n", m_midi_note) + diff --git a/config.h b/config.h index f93e6a9..07d3819 100644 --- a/config.h +++ b/config.h @@ -28,6 +28,9 @@ public: int get_bpm(); void set_bpm(int bpm); + void recover(); + void persist(); + private: int m_midi_channel; int m_midi_note; diff --git a/main.cpp b/main.cpp index 7d423f6..5e078d9 100644 --- a/main.cpp +++ b/main.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -30,8 +31,18 @@ double diff_timespec(const struct timespec *time1, const struct timespec *time0) + (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(); @@ -55,21 +66,25 @@ int main(void) 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){note_click->receive_note(channel, note);}); + 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();}); midi.signal_active_sensing.connect([&](){ui.slot_active_sensing();}); timer_500ms.elapsed.connect([&](){ui.draw();}); signal_count_loops.connect([&](){ui.count_main_loops();}); + timer_10min.elapsed.connect([&](){config.persist();}); midi.flush(); - while (true) { + while (run_flag) { debug_cout << "Main loop entered." << std::endl; signal_count_loops(); @@ -110,6 +125,7 @@ int main(void) // 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; -- cgit v1.2.3