diff options
Diffstat (limited to 'MainLoop.cpp')
-rw-r--r-- | MainLoop.cpp | 160 |
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; +} + |