summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--MIDI.h88
-rw-r--r--UI.cpp67
-rw-r--r--UI.h12
-rw-r--r--config.cpp25
-rw-r--r--config.h12
-rw-r--r--main.cpp3
6 files changed, 155 insertions, 52 deletions
diff --git a/MIDI.h b/MIDI.h
index 96c9eb7..e24c18a 100644
--- a/MIDI.h
+++ b/MIDI.h
@@ -107,60 +107,62 @@ public:
std::cerr << "snd_seq_event_input(): -EAGAIN" << std::endl;
}
+ 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(snd_seq_event_t *ev)
+ {
+ uint64_t timestamp = timestamp_from_event(ev); // original timestamp
+
// TODO: fix timestamp to be set automatically
struct timespec t;
if (TIME_UTC != timespec_get(&t, TIME_UTC))
{
- std::cerr << "Error: timespec_get()" << std::endl;
+ log_cout << "Error: timespec_get()" << std::endl;
}
else
{
ev->time.time.tv_sec = t.tv_sec;
ev->time.time.tv_nsec = t.tv_nsec;
}
- 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", 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, timestamp);
- }
- }
- else if (ev->type == SND_SEQ_EVENT_CONTROLLER)
- {
- 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", timestamp_from_event(ev)) << std::endl;
- }
- else if (ev->type == SND_SEQ_EVENT_CLOCK)
- {
- signal_clock();
- debug_cout << fmt::format("[{}] Clock\n", timestamp_from_event(ev)) << std::endl;
- }
- else
- {
- log_cout << fmt::format("[{}] Unknown MIDI event: {}\n", timestamp_from_event(ev), ev->type) << std::endl;
- }
+ 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", 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, timestamp);
+ }
+ }
+ else if (ev->type == SND_SEQ_EVENT_CONTROLLER)
+ {
+ 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", timestamp_from_event(ev)) << std::endl;
+ }
+ else if (ev->type == SND_SEQ_EVENT_CLOCK)
+ {
+ signal_clock();
+ debug_cout << fmt::format("[{}] Clock\n", timestamp_from_event(ev)) << std::endl;
+ }
+ else
+ {
+ log_cout << fmt::format("[{}] Unknown MIDI event: {}\n", timestamp_from_event(ev), ev->type) << std::endl;
+ }
}
void flush()
diff --git a/UI.cpp b/UI.cpp
index c699aba..4e063d0 100644
--- a/UI.cpp
+++ b/UI.cpp
@@ -8,11 +8,24 @@
#include <iostream>
#include <string>
+#include <fmt/color.h>
#include <fmt/format.h>
+const int midi_monitor_max_size = 3;
+
using namespace std::chrono_literals;
-UI::UI(): m_main_loops{}, m_main_loops_checkpoint{}, m_main_loops_timestamp{}, m_active_sensing_timestamp{}
+static std::vector<std::string> mode_names{{
+ "NoteClick", "Clock", "Internal"
+}};
+
+UI::UI(Config& config):
+ m_config(config),
+ m_main_loops{},
+ m_main_loops_checkpoint{},
+ m_main_loops_timestamp{},
+ m_active_sensing_timestamp{},
+ m_midi_timestamp{}
{
}
@@ -34,6 +47,10 @@ void UI::draw()
{
std::vector<int> cpuloads = get_cpu_loads();
int main_loops_per_second = get_main_loops_per_second();
+ int mode = m_config.get_mode();
+ int channel = m_config.get_midi_channel();
+ int note = m_config.get_midi_note();
+ int bpm = m_config.get_bpm();
bool active_sensing_detected = (clock_type::now() - m_active_sensing_timestamp) < 2s;
@@ -41,8 +58,18 @@ void UI::draw()
std::cout << "\x1B[2J\x1B[H";
//std::cout << std::endl;
- std::cout << "- -- BPM +" << std::endl;
- std::cout << "Mode: Click __/__ (Clock Internal)" << std::endl;
+ std::cout << fmt::format("- {:3} BPM +", bpm) << std::endl;
+ std::cout << "Mode: ";
+ for (int i = 0; i < mode_names.size(); ++i) {
+ if (i == mode) {
+ std::cout << fmt::format(fg(fmt::color::crimson) | fmt::emphasis::bold, " {}", mode_names[i]);
+ } else {
+ std::cout << fmt::format(" {}", mode_names[i]);
+ }
+ }
+ std::cout << std::endl;
+ std::cout << fmt::format("MIDI Note: {}/{}", channel, note);
+ std::cout << std::endl;
std::cout << std::endl;
std::cout << "Status:" << std::endl;
@@ -53,12 +80,29 @@ void UI::draw()
int max = *std::max_element(cpuloads.begin(), cpuloads.end());
std::cout << fmt::format(", max. {:2}%", max) << std::endl;
- std::cout << " Notes/Channels: -- -- -- ... (Choose)" << std::endl;
- std::cout << " MIDI Timestamp: ------" << std::endl;
+ std::cout << " MIDI Activity: ";
+ if (m_midi_monitor.empty()) {
+ std::cout << "--";
+ } else {
+ int count{};
+ for (const auto& i: m_midi_monitor) {
+ if (count == 0) {
+ std::cout << fmt::format(fg(fmt::color::crimson) | fmt::emphasis::bold, " {}/{}", i.first, i.second);
+ } else {
+ std::cout << fmt::format(" {}/{}", i.first, i.second);
+ }
+ ++count;
+ }
+ if (count >= midi_monitor_max_size) {
+ std::cout << " ...";
+ }
+ }
+ std::cout << std::endl;
+ std::cout << fmt::format(" MIDI Timestamp: {}", m_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;
- std::cout << " Internal: ____ BPM" << std::endl;
+ std::cout << fmt::format(" Internal: {:3} BPM", bpm) << std::endl;
std::cout << fmt::format(" Main loops/s: {}", main_loops_per_second) << std::endl;
@@ -76,3 +120,14 @@ void UI::slot_active_sensing()
{
m_active_sensing_timestamp = clock_type::now();
}
+
+void UI::slot_midi_note(int channel, int note, uint64_t timestamp)
+{
+ m_midi_timestamp = timestamp;
+
+ m_midi_monitor.emplace_front(channel, note);
+
+ while (m_midi_monitor.size() > midi_monitor_max_size) {
+ m_midi_monitor.pop_back();
+ }
+}
diff --git a/UI.h b/UI.h
index f507d2e..a3c56e0 100644
--- a/UI.h
+++ b/UI.h
@@ -1,6 +1,10 @@
#pragma once
+#include "config.h"
+
#include <chrono>
+#include <deque>
+#include <utility>
#include <boost/signals2.hpp>
@@ -9,7 +13,7 @@ class UI
public:
using clock_type = std::chrono::high_resolution_clock;
- UI();
+ UI(Config& config);
void draw();
@@ -22,8 +26,10 @@ public:
// slots
void count_main_loops();
void slot_active_sensing();
+ void slot_midi_note(int channel, int note, uint64_t timestamp);
private:
+ Config& m_config;
int get_main_loops_per_second();
@@ -32,4 +38,8 @@ private:
std::chrono::time_point<clock_type> m_main_loops_timestamp;
std::chrono::time_point<clock_type> m_active_sensing_timestamp;
+
+ uint64_t m_midi_timestamp;
+ std::deque<std::pair<int,int>> m_midi_monitor;
};
+
diff --git a/config.cpp b/config.cpp
index 2cd061c..04736ea 100644
--- a/config.cpp
+++ b/config.cpp
@@ -30,6 +30,7 @@ void Config::recover()
m_midi_channel = CLICK_CHANNEL;
m_midi_note = CLICK_NOTE;
m_bpm = default_bpm;
+ m_mode = default_mode;
std::string config = Reichwein::File::getFile(config_filename);
@@ -38,12 +39,19 @@ void Config::recover()
for (const auto& i: lines) {
if (i.starts_with("midi_channel=")) {
m_midi_channel = stoul(i.substr(13));
+ signal_channel(m_midi_channel);
}
if (i.starts_with("midi_note=")) {
m_midi_note = stoul(i.substr(10));
+ signal_note(m_midi_note);
}
if (i.starts_with("bpm=")) {
m_bpm = stoul(i.substr(4));
+ signal_bpm(m_bpm);
+ }
+ if (i.starts_with("mode=")) {
+ m_mode = stoul(i.substr(5));
+ signal_mode(m_mode);
}
}
} catch (const std::exception& ex) {
@@ -55,7 +63,8 @@ void Config::persist()
{
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);
+ fmt::format("bpm={}\n", m_bpm) +
+ fmt::format("mode={}\n", m_mode);
Reichwein::File::setFile(config_filename, config);
}
@@ -68,6 +77,7 @@ int Config::get_midi_channel()
void Config::set_midi_channel(int channel)
{
m_midi_channel = channel;
+ signal_channel(channel);
}
int Config::get_midi_note()
@@ -78,6 +88,7 @@ int Config::get_midi_note()
void Config::set_midi_note(int note)
{
m_midi_note = note;
+ signal_note(note);
}
int Config::get_bpm()
@@ -88,5 +99,17 @@ int Config::get_bpm()
void Config::set_bpm(int bpm)
{
m_bpm = bpm;
+ signal_bpm(bpm);
+}
+
+int Config::get_mode()
+{
+ return m_mode;
+}
+
+void Config::set_mode(int mode)
+{
+ m_mode = mode;
+ signal_mode(mode);
}
diff --git a/config.h b/config.h
index 07d3819..5d2a1d0 100644
--- a/config.h
+++ b/config.h
@@ -1,5 +1,6 @@
#pragma once
+#include <boost/signals2.hpp>
#include <alsa/asoundlib.h>
// Defaults
@@ -12,6 +13,7 @@ const int log_lines = 10;
const int default_bpm = 120;
const int pcm_latency_us = 100000;
const int click_latency_frames = 10000;
+const int default_mode = 0; // 0 = note, 1 = clock, 2 = internal
class Config
{
@@ -19,6 +21,12 @@ public:
Config();
~Config();
+ // signals
+ boost::signals2::signal<void(int)> signal_mode;
+ boost::signals2::signal<void(int)> signal_channel;
+ boost::signals2::signal<void(int)> signal_note;
+ boost::signals2::signal<void(int)> signal_bpm;
+
int get_midi_channel();
void set_midi_channel(int channel);
@@ -28,6 +36,9 @@ public:
int get_bpm();
void set_bpm(int bpm);
+ int get_mode();
+ void set_mode(int mode);
+
void recover();
void persist();
@@ -35,4 +46,5 @@ private:
int m_midi_channel;
int m_midi_note;
int m_bpm;
+ int m_mode;
};
diff --git a/main.cpp b/main.cpp
index 5e078d9..337fa96 100644
--- a/main.cpp
+++ b/main.cpp
@@ -59,7 +59,7 @@ int main(void)
MIDI midi;
PCM pcm;
- UI ui;
+ UI ui(config);
pcm.write();
@@ -81,6 +81,7 @@ int main(void)
timer_500ms.elapsed.connect([&](){ui.draw();});
signal_count_loops.connect([&](){ui.count_main_loops();});
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.flush();