From 22cdfccb11679d6ae241653c9cb92c32f4fc1fde Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 3 Jan 2025 21:02:11 +0100 Subject: Integrate ClickStream into PCM --- ClickStream.cpp | 3 --- ClickStream.h | 57 ------------------------------------------------------ MIDI.h | 7 +++++++ Makefile | 1 - PCM.h | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-------- config.h | 2 ++ main.cpp | 8 ++++---- 7 files changed, 65 insertions(+), 73 deletions(-) delete mode 100644 ClickStream.cpp delete mode 100644 ClickStream.h diff --git a/ClickStream.cpp b/ClickStream.cpp deleted file mode 100644 index 0448af1..0000000 --- a/ClickStream.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "ClickStream.h" - - diff --git a/ClickStream.h b/ClickStream.h deleted file mode 100644 index c94f8de..0000000 --- a/ClickStream.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "config.h" - -#include - -#include -#include -#include - -class ClickStream -{ -public: - ClickStream(): m_phase(1000000) - { - std::string data_s = Reichwein::File::getFile("media/click.s16le"); - m_data.resize(data_s.size() / 2); // src is in bytes - memcpy(m_data.data(), data_s.data(), data_s.size()); - } - - // generate 1 buffer size - void generate() - { - int i; - size_t j = m_phase; - - for (i = 0; i < nframes; i++) { - if (j >= m_data.size()) - { - buffer[i] = 0; - } - else - { - buffer[i] = m_data[j]; - } - j++; - } - - m_phase = j; - } - - void click() - { - m_phase = 0; - } - - int16_t* get_buffer() - { - return buffer; - } - -private: - std::vector m_data; - size_t m_phase; - int16_t buffer[nframes]; -}; - diff --git a/MIDI.h b/MIDI.h index d71298d..23024c3 100644 --- a/MIDI.h +++ b/MIDI.h @@ -158,6 +158,13 @@ public: } } + void flush() + { + while (event_ready()) { + (void) read(); + } + } + void wait_for_event() { int result = poll(pfd, npfd, 10000); diff --git a/Makefile b/Makefile index 8667576..2cebb56 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,6 @@ SRCS= \ main.cpp \ MIDI.cpp \ PCM.cpp \ - ClickStream.cpp \ config.cpp \ UI.cpp \ Timer.cpp \ diff --git a/PCM.h b/PCM.h index bfa1e24..3e9b41d 100644 --- a/PCM.h +++ b/PCM.h @@ -1,22 +1,29 @@ #pragma once -#include "ClickStream.h" - #include "config.h" +#include "log.h" + +#include #include #include #include #include +#include using namespace std::string_literals; class PCM { public: - PCM(ClickStream& stream): m_stream(stream) + PCM(): m_phase(1000000) { + // prepare the sample + std::string data_s = Reichwein::File::getFile("media/click.s16le"); + m_data.resize(data_s.size() / 2); // src is in bytes + memcpy(m_data.data(), data_s.data(), data_s.size()); + // non-blocking if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { throw std::runtime_error(fmt::format("Playback open error: {}", snd_strerror(err))); @@ -27,11 +34,11 @@ public: 1, f_sample, 1, - 100000)) < 0) { // latency in us + pcm_latency_us)) < 0) { // latency in us throw std::runtime_error(fmt::format("Playback open error: {}", snd_strerror(err))); } - m_stream.generate(); + generate(); npfd = snd_pcm_poll_descriptors_count(handle); if (npfd < 0) { @@ -69,6 +76,33 @@ public: free(pfd); } + void click() + { + snd_pcm_sframes_t delay; + if (0 > snd_pcm_delay(handle, &delay)) { + } + + m_phase = 0; // - click_latency_frames + delay + } + + // generate 1 buffer size + void generate() + { + int i; + + for (i = 0; i < nframes; i++) { + if (m_phase < 0 || m_phase >= m_data.size()) + { + buffer[i] = 0; + } + else + { + buffer[i] = m_data[m_phase]; + } + m_phase++; + } + } + int fd() { return pfd->fd; @@ -77,7 +111,7 @@ public: // write from buffer to ALSA PCM void write() { - snd_pcm_sframes_t written = snd_pcm_writei(handle, m_stream.get_buffer(), nframes); + snd_pcm_sframes_t written = snd_pcm_writei(handle, buffer, nframes); if (written < 0) { if (written == -EPIPE) { std::cout << "Warning: PCM underrun" << std::endl; @@ -93,7 +127,15 @@ public: std::cout << "Warning: written " << std::to_string(written) << " frames instead of "<< std::to_string(nframes) << std::endl; } - m_stream.generate(); + snd_pcm_sframes_t avail; + snd_pcm_sframes_t delay; + if (0 > snd_pcm_avail_delay(handle, &avail, &delay)) { + log_cout << "Error detecting avail and delay" << std::endl; + } else { + log_cout << fmt::format("Delay: {}, avail. buffer; {} frames", delay, avail) << std::endl; + } + + generate(); } bool wait_for_event() @@ -130,6 +172,8 @@ private: int npfd; struct pollfd* pfd; - ClickStream& m_stream; + std::vector m_data; + int32_t m_phase; + int16_t buffer[nframes]; }; diff --git a/config.h b/config.h index b347113..f93e6a9 100644 --- a/config.h +++ b/config.h @@ -10,6 +10,8 @@ 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; +const int pcm_latency_us = 100000; +const int click_latency_frames = 10000; class Config { diff --git a/main.cpp b/main.cpp index ca8ec91..a58f7cd 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,4 @@ #include "Click.h" -#include "ClickStream.h" #include "MIDI.h" #include "PCM.h" #include "Timer.h" @@ -48,8 +47,7 @@ int main(void) std::shared_ptr click = note_click; MIDI midi; - ClickStream stream; - PCM pcm{stream}; + PCM pcm; UI ui; pcm.write(); @@ -62,10 +60,12 @@ int main(void) // Signal-Slot Connections: midi.signal_note.connect([&](int channel, int note){note_click->receive_note(channel, note);}); - note_click->signal_click.connect([&](){stream.click();}); + note_click->signal_click.connect([&](){pcm.click();}); timer_500ms.elapsed.connect([&](){ui.draw();}); signal_count_loops.connect([&](){ui.count_main_loops();}); + midi.flush(); + while (true) { debug_cout << "Main loop entered." << std::endl; signal_count_loops(); -- cgit v1.2.3