diff options
author | Roland Reichwein <mail@reichwein.it> | 2025-01-03 20:17:26 +0100 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2025-01-03 20:17:26 +0100 |
commit | 6bf4770e950299da92952f2965cccf86a903fc9f (patch) | |
tree | 9854c706f0fc8104f1f85fe0f6ff58b56661a5a6 | |
parent | 81ef3f08215a62d469c49762ccd492cb806150c4 (diff) |
Added config
-rw-r--r-- | Click.cpp | 2 | ||||
-rw-r--r-- | Click.h | 62 | ||||
-rw-r--r-- | MIDI.h | 39 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | config.cpp | 78 | ||||
-rw-r--r-- | config.h | 23 | ||||
-rw-r--r-- | main.cpp | 16 |
7 files changed, 203 insertions, 20 deletions
diff --git a/Click.cpp b/Click.cpp new file mode 100644 index 0000000..4083e0d --- /dev/null +++ b/Click.cpp @@ -0,0 +1,2 @@ +#include "Click.h" + @@ -0,0 +1,62 @@ +#pragma once + +#include <boost/signals2.hpp> + +#include "config.h" + +// Virtual base class +// Abstraction of BPM detection / setting +class Click +{ +public: + Click(){} + virtual ~Click(){} +}; + +// Internally generated +// Configured via: BPM +class InternalClick: public Click +{ +public: + InternalClick(Config& config): m_bpm(config.get_bpm()){} + virtual ~InternalClick(){} + +private: + int m_bpm; +}; + +// Generated from MIDI notes +// Configured via channel and note to listen to +class NoteClick: public Click +{ +public: + NoteClick(Config& config): + m_channel(config.get_midi_channel()), + m_note(config.get_midi_note()) + { + } + + virtual ~NoteClick(){} + + boost::signals2::signal<void()> signal_click; + + void receive_note(int channel, int note) + { + if (true || (channel == m_channel && note == m_note)) { + signal_click(); + } + } + +private: + int m_channel; + int m_note; +}; + +// Generated from MIDI Clock +class ClockClick: public Click +{ +public: + ClockClick(){} + virtual ~ClockClick(){} +}; + @@ -2,6 +2,7 @@ #include "config.h" #include "debug.h" +#include "log.h" #include <boost/signals2.hpp> @@ -31,7 +32,7 @@ public: throw std::runtime_error("MIDI port couldn't be opened"); } - std::cout << "in_port: " << std::to_string(in_port) << std::endl; + log_cout << "in_port: " << std::to_string(in_port) << std::endl; #if 1 snd_seq_addr_t sender, dest; @@ -79,7 +80,9 @@ public: free(pfd); } - boost::signals2::signal<void()> signal_click; + boost::signals2::signal<void(int, int)> signal_note; + boost::signals2::signal<void()> signal_active_sensing; + boost::signals2::signal<void()> signal_clock; int fd() { @@ -121,33 +124,37 @@ public: // 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)) { - 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, + if ((ev->type == SND_SEQ_EVENT_NOTEON) ||(ev->type == SND_SEQ_EVENT_NOTEOFF)) { + 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, type, ev->data.note.note, ev->data.note.velocity, ev->data.control.channel); - if (ev->type == SND_SEQ_EVENT_NOTEON) { - if (true || (ev->data.note.note == CLICK_NOTE && ev->data.control.channel == CLICK_CHANNEL)) { - signal_click(); - } - } + if (ev->type == SND_SEQ_EVENT_NOTEON) { + signal_note(ev->data.control.channel, ev->data.note.note); + } } - else if(ev->type == SND_SEQ_EVENT_CONTROLLER) + 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", + ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, ev->data.control.param, ev->data.control.value); } - else if(ev->type == SND_SEQ_EVENT_CLOCK) + else if (ev->type == SND_SEQ_EVENT_SENSING) { - 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;; + 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; + } + 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; } else { - debug_cout << fmt::format("[{}] Unknown: Unhandled Event Received\n", ev->time.tick) << std::endl;; + log_cout << fmt::format("[{}] Unknown MIDI event: {}\n", ev->time.tick, ev->type) << std::endl; } } @@ -12,7 +12,8 @@ SRCS= \ Timer.cpp \ debug.cpp \ cpuload.cpp \ - log.cpp + log.cpp \ + Click.cpp HEADERS=$(SRCS:.cpp=.h) @@ -1,4 +1,82 @@ #include "config.h" +#include "log.h" + +#include <libreichwein/file.h> +#include <libreichwein/stringhelper.h> + +#include <fmt/format.h> + +#include <string> + const char *device = "default"; // playback device +std::string config_filename = "click.cfg"; + +Config::Config() +{ + try { + // presets / defaults + m_midi_channel = CLICK_CHANNEL; + m_midi_note = CLICK_NOTE; + m_bpm = default_bpm; + + std::string config = Reichwein::File::getFile(config_filename); + + std::vector<std::string> lines = Reichwein::Stringhelper::split(config, "\n"); + + for (const auto& i: lines) { + if (i.starts_with("midi_channel=")) { + m_midi_channel = stoul(i.substr(13)); + } + if (i.starts_with("midi_note=")) { + m_midi_note = stoul(i.substr(10)); + } + if (i.starts_with("bpm=")) { + m_bpm = stoul(i.substr(4)); + } + } + } catch (const std::exception& ex) { + log_cout << "Config not found. Setting config to defaults." << std::endl; + } +} + +Config::~Config() +{ + std::string config = fmt::format("midi_channel={}\n", m_midi_channel) + + fmt::format("midi_note={}\n", m_midi_note) + + fmt::format("bpm={}\n", m_bpm); + + Reichwein::File::setFile(config_filename, config); +} + +int Config::get_midi_channel() +{ + return m_midi_channel; +} + +void Config::set_midi_channel(int channel) +{ + m_midi_channel = channel; +} + +int Config::get_midi_note() +{ + return m_midi_note; +} + +void Config::set_midi_note(int note) +{ + m_midi_note = note; +} + +int Config::get_bpm() +{ + return m_bpm; +} + +void Config::set_bpm(int bpm) +{ + m_bpm = bpm; +} + @@ -2,11 +2,32 @@ #include <alsa/asoundlib.h> -// Config +// Defaults static const int CLICK_NOTE = 37; static const int CLICK_CHANNEL = 4; extern const char *device; // playback device const snd_pcm_sframes_t nframes = 1024; // ~1/44th sec buffer size const unsigned int f_sample = 44100; const int log_lines = 10; +const int default_bpm = 120; +class Config +{ +public: + Config(); + ~Config(); + + int get_midi_channel(); + void set_midi_channel(int channel); + + int get_midi_note(); + void set_midi_note(int note); + + int get_bpm(); + void set_bpm(int bpm); + +private: + int m_midi_channel; + int m_midi_note; + int m_bpm; +}; @@ -1,3 +1,4 @@ +#include "Click.h" #include "ClickStream.h" #include "MIDI.h" #include "PCM.h" @@ -9,9 +10,10 @@ #include <chrono> #include <cmath> #include <cstdint> +#include <exception> #include <iostream> #include <limits> -#include <exception> +#include <memory> #include <stdexcept> #include <stdio.h> @@ -36,6 +38,15 @@ int main(void) log_cout.activate(); log_cout.log_lines(log_lines); + Config config; + + std::shared_ptr<ClockClick> clock_click = std::make_shared<ClockClick>(); + std::shared_ptr<NoteClick> note_click = std::make_shared<NoteClick>(config); + std::shared_ptr<InternalClick> internal_click = std::make_shared<InternalClick>(config); + + // Active Mode + std::shared_ptr<Click> click = note_click; + MIDI midi; ClickStream stream; PCM pcm{stream}; @@ -50,7 +61,8 @@ int main(void) boost::signals2::signal<void()> signal_count_loops; // Signal-Slot Connections: - midi.signal_click.connect([&](){stream.click();}); + midi.signal_note.connect([&](int channel, int note){note_click->receive_note(channel, note);}); + note_click->signal_click.connect([&](){stream.click();}); timer_500ms.elapsed.connect([&](){ui.draw();}); signal_count_loops.connect([&](){ui.count_main_loops();}); |