summaryrefslogtreecommitdiffhomepage
path: root/MainLoop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'MainLoop.cpp')
-rw-r--r--MainLoop.cpp160
1 files changed, 160 insertions, 0 deletions
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;
+}
+