summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Click.cpp2
-rw-r--r--Click.h75
-rw-r--r--ClockClick.cpp22
-rw-r--r--ClockClick.h27
-rw-r--r--InternalClick.cpp19
-rw-r--r--InternalClick.h28
-rw-r--r--MainLoop.cpp160
-rw-r--r--MainLoop.h33
-rw-r--r--Makefile7
-rw-r--r--NoteClick.cpp20
-rw-r--r--NoteClick.h27
-rw-r--r--PCM.cpp4
-rw-r--r--PCM.h2
-rw-r--r--UI.cpp87
-rw-r--r--UI.h13
-rw-r--r--main.cpp140
16 files changed, 435 insertions, 231 deletions
diff --git a/Click.cpp b/Click.cpp
deleted file mode 100644
index 4083e0d..0000000
--- a/Click.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "Click.h"
-
diff --git a/Click.h b/Click.h
deleted file mode 100644
index 6d3d871..0000000
--- a/Click.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#pragma once
-
-#include <boost/signals2.hpp>
-
-#include "config.h"
-#include "BPMDetect.h"
-
-// Internally generated
-// Configured via: BPM
-class InternalClick
-{
-public:
- InternalClick(Config& config): m_config(config){}
-
-private:
- Config& m_config;
-};
-
-// Generated from MIDI notes
-// Configured via channel and note to listen to
-class NoteClick
-{
-public:
- // signals
- boost::signals2::signal<void()> signal_click;
- boost::signals2::signal<void(int)> signal_bpm;
-
- NoteClick(Config& config):
- m_channel(config.get_midi_channel()),
- m_note(config.get_midi_note()),
- m_detect(1)
- {
- m_detect.signal_bpm.connect([&](int bpm){signal_bpm(bpm);});
- }
-
- // slots
- void receive_note(int channel, int note, uint64_t timestamp)
- {
- (void) timestamp;
-
- if (true || (channel == m_channel && note == m_note)) {
- signal_click();
- m_detect.receive_event();
- }
- }
-
-private:
- int m_channel;
- int m_note;
-
- BPMDetect m_detect;
-};
-
-// Generated from MIDI Clock
-class ClockClick
-{
-public:
- ClockClick(): m_detect(24)
- {
- m_detect.signal_bpm.connect([&](int bpm){signal_bpm(bpm);});
- }
-
- // signals
- boost::signals2::signal<void(int)> signal_bpm;
-
- // slots
- void receive_clock()
- {
- m_detect.receive_event();
- }
-
-private:
- BPMDetect m_detect;
-};
-
diff --git a/ClockClick.cpp b/ClockClick.cpp
new file mode 100644
index 0000000..c9f6938
--- /dev/null
+++ b/ClockClick.cpp
@@ -0,0 +1,22 @@
+#include "ClockClick.h"
+
+ClockClick::ClockClick(): m_divider(24), m_count{}, m_detect(24)
+{
+ m_detect.signal_bpm.connect([&](int bpm){signal_bpm(bpm);});
+}
+
+// slots
+void ClockClick::receive_clock()
+{
+ m_detect.receive_event();
+
+ // guard by divider
+ ++m_count;
+ if (m_count < m_divider) {
+ return;
+ } else {
+ m_count = 0;
+ }
+
+ signal_click();
+}
diff --git a/ClockClick.h b/ClockClick.h
new file mode 100644
index 0000000..2c0ef19
--- /dev/null
+++ b/ClockClick.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <boost/signals2.hpp>
+
+#include "config.h"
+#include "BPMDetect.h"
+
+// Generated from MIDI Clock
+class ClockClick
+{
+public:
+ ClockClick();
+
+ // signals
+ boost::signals2::signal<void()> signal_click;
+ boost::signals2::signal<void(int)> signal_bpm;
+
+ // slots
+ void receive_clock();
+
+private:
+ const int m_divider;
+ int m_count;
+
+ BPMDetect m_detect;
+};
+
diff --git a/InternalClick.cpp b/InternalClick.cpp
new file mode 100644
index 0000000..33654fd
--- /dev/null
+++ b/InternalClick.cpp
@@ -0,0 +1,19 @@
+#include "InternalClick.h"
+
+InternalClick::InternalClick(Config& config):
+ m_config{config},
+ m_timestamp{clock_type::now()}
+{
+}
+
+void InternalClick::run_cyclic_50ms()
+{
+ std::chrono::time_point<clock_type> now = clock_type::now();
+
+ std::chrono::duration<double> duration{60.0 / static_cast<double>(m_config.get_bpm())};
+ if (now - m_timestamp > duration) {
+ m_timestamp = now;
+ signal_click(0); // offset
+ }
+}
+
diff --git a/InternalClick.h b/InternalClick.h
new file mode 100644
index 0000000..1fffb6c
--- /dev/null
+++ b/InternalClick.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <boost/signals2.hpp>
+
+#include "config.h"
+#include "BPMDetect.h"
+
+using clock_type = std::chrono::high_resolution_clock;
+
+// Internally generated
+// Configured via: BPM
+class InternalClick
+{
+public:
+ InternalClick(Config& config);
+
+ // signals
+ boost::signals2::signal<void(int64_t)> signal_click;
+
+ // slots
+ void run_cyclic_50ms();
+
+private:
+ Config& m_config;
+
+ std::chrono::time_point<clock_type> m_timestamp;
+};
+
diff --git a/MainLoop.cpp b/MainLoop.cpp
new file mode 100644
index 0000000..1bd0e1d
--- /dev/null
+++ b/MainLoop.cpp
@@ -0,0 +1,160 @@
+#include "MainLoop.h"
+
+#include "Timer.h"
+#include "config.h"
+#include "log.h"
+
+#include <chrono>
+#include <cmath>
+#include <cstdint>
+#include <exception>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <stdexcept>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <signal.h>
+
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+MainLoop::MainLoop():
+ m_config{},
+ m_note_click{m_config},
+ m_clock_click{},
+ m_internal_click{m_config},
+ m_midi{},
+ m_pcm{},
+ m_ui{m_config}
+{
+}
+
+bool run_flag = true;
+
+void signal_handler(int) {
+ run_flag = false;
+ std::cout << "Signal received. Terminating." << std::endl;
+}
+
+void MainLoop::reconfigure_mode() {
+ debug_cout << "reconfiguring mode" << std::endl;
+
+ m_click_connection.disconnect();
+
+ int mode = m_config.get_mode();
+
+ if (mode == 0) {
+ m_click_connection = m_note_click.signal_click.connect([&](){m_pcm.click(0);});
+ } else if (mode == 1) {
+ m_click_connection = m_clock_click.signal_click.connect([&](){m_pcm.click(0);});
+ } else if (mode == 2) {
+ m_click_connection = m_internal_click.signal_click.connect([&](int64_t offset){m_pcm.click(offset);});
+ } else {
+ log_cout << fmt::format("Error: Unknown mode: {}", mode) << std::endl;
+ }
+}
+
+int MainLoop::run()
+{
+ signal(SIGTERM, signal_handler);
+ signal(SIGINT, signal_handler);
+
+ try {
+ //debug_cout.activate();
+ log_cout.activate();
+ log_cout.log_lines(log_lines);
+
+ m_pcm.write();
+
+ Timer timer_50ms(50ms, true);
+ timer_50ms.start();
+
+ Timer timer_500ms(500ms, true);
+ timer_500ms.start();
+
+ Timer timer_10min(10min, true);
+ timer_10min.start();
+
+ // Main signals
+ boost::signals2::signal<void()> signal_count_loops;
+
+ //
+ // Signal-Slot Connections:
+ //
+ m_midi.signal_note.connect([&](int channel, int note, uint64_t timestamp){m_note_click.receive_note(channel, note, timestamp);});
+ //m_click_connection = m_note_click.signal_click.connect([&](){m_pcm.click(0);});
+ reconfigure_mode();
+ m_note_click.signal_bpm.connect([&](int bpm){m_ui.slot_note_bpm(bpm);});
+ m_clock_click.signal_bpm.connect([&](int bpm){m_ui.slot_clock_bpm(bpm);});
+ m_midi.signal_active_sensing.connect([&](){m_ui.slot_active_sensing();});
+ timer_500ms.elapsed.connect([&](){m_ui.draw();});
+ signal_count_loops.connect([&](){m_ui.count_main_loops();});
+ m_midi.signal_count_events.connect([&](){m_ui.count_midi_events();});
+ timer_10min.elapsed.connect([&](){m_config.persist();});
+ m_midi.signal_note.connect([&](int channel, int note, uint64_t timestamp){m_ui.slot_midi_note(channel, note, timestamp);});
+ m_midi.signal_clock.connect([&](){m_clock_click.receive_clock();});
+ m_config.signal_mode.connect([&](int mode){reconfigure_mode();});
+ timer_50ms.elapsed.connect([&](){m_internal_click.run_cyclic_50ms();});
+
+ m_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(m_midi.fd(), &read_set);
+ FD_SET(0, &read_set);
+
+ if constexpr (0) {
+ // PCM fd almost always writeable: for single frames at high speed
+ fd_set write_set;
+ FD_ZERO(&write_set);
+ FD_SET(m_pcm.fd(), &write_set);
+ }
+
+ 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 (m_midi.event_ready())
+ {
+ //std::cout << "read..." << std::endl;
+ auto event = m_midi.read();
+ //std::cout << "process..." << std::endl;
+ m_midi.process(event);
+ }
+
+ if (m_pcm.write_available()) {
+ //std::cout << "DEBUG: WRITE" << std::endl;
+ m_pcm.write();
+ }
+
+ if (m_ui.key_available()) {
+ m_ui.handle_input();
+ }
+
+ // handle timers, TODO: make updates more efficient at scale
+ timer_50ms.update();
+ timer_500ms.update();
+ timer_10min.update();
+ }
+ } catch (const std::exception& ex) {
+ std::cerr << "Error: " << ex.what() << std::endl;
+ }
+
+ return 0;
+}
+
diff --git a/MainLoop.h b/MainLoop.h
new file mode 100644
index 0000000..0aac227
--- /dev/null
+++ b/MainLoop.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "NoteClick.h"
+#include "ClockClick.h"
+#include "InternalClick.h"
+#include "MIDI.h"
+#include "PCM.h"
+#include "UI.h"
+
+#include <boost/signals2.hpp>
+
+class MainLoop
+{
+public:
+ MainLoop();
+ int run();
+
+private:
+ void reconfigure_mode();
+
+ boost::signals2::connection m_click_connection;
+
+ Config m_config;
+
+ NoteClick m_note_click;
+ ClockClick m_clock_click;
+ InternalClick m_internal_click;
+
+ MIDI m_midi;
+ PCM m_pcm;
+ UI m_ui;
+};
+
diff --git a/Makefile b/Makefile
index faac1fe..93e322a 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ TARGET=click
default: $(TARGET)
SRCS= \
+ MainLoop.cpp \
main.cpp \
MIDI.cpp \
PCM.cpp \
@@ -12,8 +13,10 @@ SRCS= \
debug.cpp \
cpuload.cpp \
log.cpp \
- Click.cpp \
- BPMDetect.cpp
+ NoteClick.cpp \
+ ClockClick.cpp \
+ InternalClick.cpp \
+ BPMDetect.cpp \
HEADERS=$(SRCS:.cpp=.h)
diff --git a/NoteClick.cpp b/NoteClick.cpp
new file mode 100644
index 0000000..657a893
--- /dev/null
+++ b/NoteClick.cpp
@@ -0,0 +1,20 @@
+#include "NoteClick.h"
+
+NoteClick::NoteClick(Config& config):
+ m_config(config),
+ m_detect(1)
+{
+ m_detect.signal_bpm.connect([&](int bpm){signal_bpm(bpm);});
+}
+
+// slots
+void NoteClick::receive_note(int channel, int note, uint64_t timestamp)
+{
+ (void) timestamp;
+
+ if (channel == m_config.get_midi_channel() && note == m_config.get_midi_note()) {
+ signal_click();
+ m_detect.receive_event();
+ }
+}
+
diff --git a/NoteClick.h b/NoteClick.h
new file mode 100644
index 0000000..754329f
--- /dev/null
+++ b/NoteClick.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <boost/signals2.hpp>
+
+#include "config.h"
+#include "BPMDetect.h"
+
+// Generated from MIDI notes
+// Configured via channel and note to listen to
+class NoteClick
+{
+public:
+ NoteClick(Config& config);
+
+ // signals
+ boost::signals2::signal<void()> signal_click;
+ boost::signals2::signal<void(int)> signal_bpm;
+
+ // slots
+ void receive_note(int channel, int note, uint64_t timestamp);
+
+private:
+ Config& m_config;
+
+ BPMDetect m_detect;
+};
+
diff --git a/PCM.cpp b/PCM.cpp
index e6d915f..218ba59 100644
--- a/PCM.cpp
+++ b/PCM.cpp
@@ -59,13 +59,13 @@ PCM::~PCM()
free(pfd);
}
-void PCM::click()
+void PCM::click(int64_t offset_us)
{
snd_pcm_sframes_t delay;
if (0 > snd_pcm_delay(handle, &delay)) {
}
- m_phase = - click_latency_frames + delay;
+ m_phase = - click_latency_frames + delay + offset_us;
}
// generate 1 buffer size
diff --git a/PCM.h b/PCM.h
index 73cdcc6..90abc3d 100644
--- a/PCM.h
+++ b/PCM.h
@@ -21,7 +21,7 @@ public:
PCM();
~PCM();
- void click();
+ void click(int64_t offset_us);
// generate 1 buffer size
void generate();
diff --git a/UI.cpp b/UI.cpp
index 0adb48b..933f2de 100644
--- a/UI.cpp
+++ b/UI.cpp
@@ -11,6 +11,9 @@
#include <fmt/color.h>
#include <fmt/format.h>
+#include <stdio.h>
+#include <sys/poll.h>
+
const int midi_monitor_max_size = 3;
using namespace std::chrono_literals;
@@ -62,6 +65,31 @@ UI::UI(Config& config):
{
}
+bool UI::key_available() {
+ struct pollfd fds{};
+ int ret;
+ fds.fd = 0; // stdin
+ fds.events = POLLIN;
+ ret = poll(&fds, 1, 0);
+ if (ret == 0)
+ return false;
+ else if (ret == 1)
+ return true;
+ else
+ log_cout << "Error" << std::endl;
+ return false;
+}
+
+int read_key() {
+ char buf[1];
+ int got = read(0, buf, 1);
+ if (got != 1) {
+ log_cout << "Bad input size: " << std::to_string(got) << std::endl;
+ }
+
+ return buf[0];
+}
+
void UI::draw()
{
std::vector<int> cpuloads = get_cpu_loads();
@@ -71,28 +99,40 @@ void UI::draw()
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();
+ int internal_bpm = m_config.get_bpm();
+ int bpm;
+ if (mode == 0) {
+ bpm = m_note_bpm;
+ } else if (mode == 1) {
+ bpm = m_clock_bpm;
+ } else if (mode == 2) {
+ bpm = m_config.get_bpm();
+ }
+
int output = m_config.get_output();
int active_sensing_detected = (clock_type::now() - m_active_sensing_timestamp) < 2s ? 1 : 0;
+ fmt::text_style editable_color{fg(fmt::color::crimson) | fmt::emphasis::bold};
+ fmt::text_style value_color{fg(fmt::color::blue) | fmt::emphasis::bold};
+
// clear screen
std::cout << "\x1B[2J\x1B[H";
//std::cout << std::endl;
- std::cout << fmt::format("- {:3} BPM +", bpm) << std::endl;
+ std::cout << "- " << fmt::format(editable_color, "{: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]);
+ std::cout << fmt::format(editable_color, " {}", 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 << "MIDI Note: " << fmt::format(editable_color, "{}/{}", channel, note);
std::cout << std::endl;
- std::cout << "Audio Output: " << fmt::format(fg(fmt::color::crimson) | fmt::emphasis::bold, "{}", output_names[output]);
+ std::cout << "Audio Output: " << fmt::format(editable_color, "{}", output_names[output]);
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Status:" << std::endl;
@@ -111,7 +151,7 @@ void UI::draw()
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);
+ std::cout << fmt::format(editable_color, " {}/{}", i.first, i.second);
} else {
std::cout << fmt::format(" {}/{}", i.first, i.second);
}
@@ -123,11 +163,11 @@ void UI::draw()
}
std::cout << std::endl;
std::cout << fmt::format(" MIDI Timestamp: {}", m_midi_timestamp) << std::endl;
- std::cout << " MIDI Active Sensing: " << fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "{}", active_sensing_names[active_sensing_detected]) << std::endl;
+ std::cout << " MIDI Active Sensing: " << fmt::format(value_color, "{}", active_sensing_names[active_sensing_detected]) << std::endl;
std::cout << fmt::format(" MIDI Events/s: {}", midi_events_per_second) << std::endl;
std::cout << fmt::format(" MIDI Clock: {:3} BPM", m_clock_bpm) << std::endl;
std::cout << fmt::format(" MIDI Click: {:3} BPM", m_note_bpm) << std::endl;
- std::cout << fmt::format(" Internal: {:3} BPM", bpm) << std::endl;
+ std::cout << fmt::format(" Internal: {:3} BPM", internal_bpm) << std::endl;
std::cout << fmt::format(" Main loops/s: {}", main_loops_per_second) << std::endl;
@@ -135,6 +175,37 @@ void UI::draw()
std::cout << log_cout.get_log() << std::endl;
}
+void UI::handle_input()
+{
+ if (key_available()) {
+ char c;
+ std::cin >> c;
+
+ debug_cout << "Key: " << std::to_string(c) << std::endl;
+
+ if (c == '+') {
+ if (m_config.get_bpm() < 240) {
+ m_config.set_bpm(m_config.get_bpm() + 1);
+ }
+ } else if (c == '-') {
+ if (m_config.get_bpm() > 10) {
+ m_config.set_bpm(m_config.get_bpm() - 1);
+ }
+ } else if (c == 'm') {
+ m_config.set_mode((m_config.get_mode() + 1) % 3);
+ } else if (c == 'n') {
+ if (!m_midi_monitor.empty()) {
+ m_config.set_midi_channel(m_midi_monitor.front().first);
+ m_config.set_midi_note(m_midi_monitor.front().second);
+ }
+ } else if (c == 'o') {
+ m_config.set_output(1 - m_config.get_output());
+ } else {
+ log_cout << fmt::format("Unknown key: {}", c) << std::endl;
+ }
+ }
+}
+
void UI::count_main_loops()
{
m_main_loops.count();
diff --git a/UI.h b/UI.h
index db2f2cc..e8b1031 100644
--- a/UI.h
+++ b/UI.h
@@ -31,12 +31,15 @@ public:
void draw();
+ void handle_input();
+
+ bool key_available();
+
// signals, from user input
- boost::signals2::signal<void()> bpm_plus;
- boost::signals2::signal<void()> bpm_minus;
- boost::signals2::signal<void()> note_set_from_midi;
- boost::signals2::signal<void()> mode;
- boost::signals2::signal<void()> output;
+ boost::signals2::signal<void(int)> signal_bpm;
+ boost::signals2::signal<void(int, int)> signal_note_set_from_midi;
+ boost::signals2::signal<void(int)> signal_mode;
+ boost::signals2::signal<void(int)> signal_output;
// slots
void count_main_loops();
diff --git a/main.cpp b/main.cpp
index 4a5f698..548b8c5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,138 +1,6 @@
-#include "Click.h"
-#include "MIDI.h"
-#include "PCM.h"
-#include "Timer.h"
-#include "UI.h"
-#include "config.h"
-#include "log.h"
+#include "MainLoop.h"
-#include <chrono>
-#include <cmath>
-#include <cstdint>
-#include <exception>
-#include <iostream>
-#include <limits>
-#include <memory>
-#include <stdexcept>
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
-#include <signal.h>
-
-#include <boost/signals2.hpp>
-
-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;
-
- ClockClick clock_click;
- NoteClick note_click(config);
- InternalClick internal_click(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<void()> 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;
+int main() {
+ MainLoop main_loop;
+ return main_loop.run();
}
-