summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2025-01-04 11:28:20 +0100
committerRoland Reichwein <mail@reichwein.it>2025-01-04 11:28:20 +0100
commitb2c35cdf69a9084806ac7930cf4475980d596cf6 (patch)
treeb74b8f2ee2c66c59f7385407cfc34c2a0a16961f
parentaaafcea7e26791acbf5b9612e3fb396edcdfcc8f (diff)
Separate out implementation from headers
-rw-r--r--MIDI.cpp171
-rw-r--r--MIDI.h169
-rw-r--r--PCM.cpp149
-rw-r--r--PCM.h155
-rw-r--r--Timer.cpp37
-rw-r--r--Timer.h37
-rw-r--r--debug.cpp20
-rw-r--r--debug.h18
-rw-r--r--log.cpp53
-rw-r--r--log.h50
10 files changed, 469 insertions, 390 deletions
diff --git a/MIDI.cpp b/MIDI.cpp
index 1fe49fe..5e625bd 100644
--- a/MIDI.cpp
+++ b/MIDI.cpp
@@ -1,2 +1,173 @@
#include "MIDI.h"
+MIDI::MIDI()
+{
+ if (0 > snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK))
+ {
+ throw std::runtime_error("MIDI sequencer couldn't be opened");
+ }
+
+ if (0 > snd_seq_set_client_name(seq_handle, "Midi Listener"))
+ {
+ throw std::runtime_error("MIDI client name couldn't be set");
+ }
+
+ if (0 > ((in_port = snd_seq_create_simple_port(seq_handle, "24:0",
+ SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
+ SND_SEQ_PORT_TYPE_APPLICATION))))
+ {
+ throw std::runtime_error("MIDI port couldn't be opened");
+ }
+
+ debug_cout << "in_port: " << std::to_string(in_port) << std::endl;
+
+#if 1
+ snd_seq_addr_t sender, dest;
+ snd_seq_port_subscribe_t *subs;
+ sender.client = 24;
+ sender.port = 0;
+ dest.client = snd_seq_client_id(seq_handle);
+ dest.port = in_port;
+ snd_seq_port_subscribe_alloca(&subs);
+ snd_seq_port_subscribe_set_sender(subs, &sender);
+ snd_seq_port_subscribe_set_dest(subs, &dest);
+ snd_seq_port_subscribe_set_queue(subs, 1);
+ snd_seq_port_subscribe_set_time_update(subs, 1);
+ snd_seq_port_subscribe_set_time_real(subs, 1);
+ // TODO: fix timestamp (currently always 0)
+ if (0 > snd_seq_subscribe_port(seq_handle, subs))
+#endif
+ //if (0 > snd_seq_connect_from(seq_handle, in_port, 24, 0))
+ {
+ throw std::runtime_error("MIDI port couldn't be connected");
+ }
+
+ npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
+ if (npfd < 0) {
+ throw std::runtime_error("snd_seq_poll_descriptors_count() failed");
+ }
+ pfd = (struct pollfd *)malloc(npfd * sizeof(struct pollfd));
+ if (pfd == nullptr) {
+ throw std::runtime_error("alloca() error for MIDI");
+ }
+ if (0 > snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN))
+ {
+ throw std::runtime_error("snd_seq_poll_descriptors() failure");
+ }
+
+ if (npfd != 1) {
+ std::cout << "Warning: " << std::to_string(npfd) << " poll fds for MIDI" << std::endl;
+ } else if (fd() <= 2) {
+ std::cout << "Warning: Bad MIDI fd: " << std::to_string(fd()) << std::endl;
+ }
+}
+
+MIDI::~MIDI()
+{
+ free(pfd);
+}
+
+int MIDI::fd()
+{
+ return pfd->fd;
+}
+
+bool MIDI::event_ready()
+{
+ int result = snd_seq_event_input_pending(seq_handle, 1);
+ if (result < 0) {
+ throw std::runtime_error("snd_seq_event_input_pending() failed");
+ }
+
+ return result > 0;
+}
+
+snd_seq_event_t* MIDI::read(void)
+{
+ snd_seq_event_t *ev = NULL;
+ if (0 > snd_seq_event_input(seq_handle, &ev))
+ {
+ std::cerr << "snd_seq_event_input(): -EAGAIN" << std::endl;
+ }
+
+ return ev;
+}
+
+namespace {
+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 MIDI::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))
+ {
+ log_cout << "Error: timespec_get()" << std::endl;
+ }
+ else
+ {
+ ev->time.time.tv_sec = t.tv_sec;
+ ev->time.time.tv_nsec = t.tv_nsec;
+ }
+
+ 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 MIDI::flush()
+{
+ while (event_ready()) {
+ (void) read();
+ }
+}
+
+void MIDI::wait_for_event()
+{
+ int result = poll(pfd, npfd, 10000);
+ if (result > 0)
+ {
+ // event
+ }
+ else if (result == 0) {
+ // timeout
+ } else {
+ throw std::runtime_error("Poll unsuccessful");
+ }
+}
+
diff --git a/MIDI.h b/MIDI.h
index e24c18a..177fd59 100644
--- a/MIDI.h
+++ b/MIDI.h
@@ -13,178 +13,25 @@
class MIDI
{
public:
- MIDI()
- {
- if (0 > snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK))
- {
- throw std::runtime_error("MIDI sequencer couldn't be opened");
- }
-
- if (0 > snd_seq_set_client_name(seq_handle, "Midi Listener"))
- {
- throw std::runtime_error("MIDI client name couldn't be set");
- }
-
- if (0 > ((in_port = snd_seq_create_simple_port(seq_handle, "24:0",
- SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
- SND_SEQ_PORT_TYPE_APPLICATION))))
- {
- throw std::runtime_error("MIDI port couldn't be opened");
- }
-
- debug_cout << "in_port: " << std::to_string(in_port) << std::endl;
-
-#if 1
- snd_seq_addr_t sender, dest;
- snd_seq_port_subscribe_t *subs;
- sender.client = 24;
- sender.port = 0;
- dest.client = snd_seq_client_id(seq_handle);
- dest.port = in_port;
- snd_seq_port_subscribe_alloca(&subs);
- snd_seq_port_subscribe_set_sender(subs, &sender);
- snd_seq_port_subscribe_set_dest(subs, &dest);
- snd_seq_port_subscribe_set_queue(subs, 1);
- snd_seq_port_subscribe_set_time_update(subs, 1);
- snd_seq_port_subscribe_set_time_real(subs, 1);
- // TODO: fix timestamp (currently always 0)
- if (0 > snd_seq_subscribe_port(seq_handle, subs))
-#endif
- //if (0 > snd_seq_connect_from(seq_handle, in_port, 24, 0))
- {
- throw std::runtime_error("MIDI port couldn't be connected");
- }
-
- npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
- if (npfd < 0) {
- throw std::runtime_error("snd_seq_poll_descriptors_count() failed");
- }
- pfd = (struct pollfd *)malloc(npfd * sizeof(struct pollfd));
- if (pfd == nullptr) {
- throw std::runtime_error("alloca() error for MIDI");
- }
- if (0 > snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN))
- {
- throw std::runtime_error("snd_seq_poll_descriptors() failure");
- }
-
- if (npfd != 1) {
- std::cout << "Warning: " << std::to_string(npfd) << " poll fds for MIDI" << std::endl;
- } else if (fd() <= 2) {
- std::cout << "Warning: Bad MIDI fd: " << std::to_string(fd()) << std::endl;
- }
- }
-
- ~MIDI()
- {
- free(pfd);
- }
+ MIDI();
+ ~MIDI();
boost::signals2::signal<void(int, int, uint64_t)> signal_note;
boost::signals2::signal<void()> signal_active_sensing;
boost::signals2::signal<void()> signal_clock;
- int fd()
- {
- return pfd->fd;
- }
-
- bool event_ready()
- {
- int result = snd_seq_event_input_pending(seq_handle, 1);
- if (result < 0) {
- throw std::runtime_error("snd_seq_event_input_pending() failed");
- }
-
- return result > 0;
- }
+ int fd();
- snd_seq_event_t *read(void)
- {
- snd_seq_event_t *ev = NULL;
- if (0 > snd_seq_event_input(seq_handle, &ev))
- {
- std::cerr << "snd_seq_event_input(): -EAGAIN" << std::endl;
- }
+ bool event_ready();
- 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;
- }
+ snd_seq_event_t *read(void);
// 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))
- {
- log_cout << "Error: timespec_get()" << std::endl;
- }
- else
- {
- ev->time.time.tv_sec = t.tv_sec;
- ev->time.time.tv_nsec = t.tv_nsec;
- }
-
- 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 process(snd_seq_event_t *ev);
- void flush()
- {
- while (event_ready()) {
- (void) read();
- }
- }
+ void flush();
- void wait_for_event()
- {
- int result = poll(pfd, npfd, 10000);
- if (result > 0)
- {
- // event
- }
- else if (result == 0) {
- // timeout
- } else {
- throw std::runtime_error("Poll unsuccessful");
- }
- }
+ void wait_for_event();
private:
snd_seq_t *seq_handle;
diff --git a/PCM.cpp b/PCM.cpp
index b70652c..e6d915f 100644
--- a/PCM.cpp
+++ b/PCM.cpp
@@ -1 +1,150 @@
#include "PCM.h"
+
+PCM::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)));
+ }
+ if ((err = snd_pcm_set_params(handle,
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 1,
+ f_sample,
+ 1,
+ pcm_latency_us)) < 0) { // latency in us
+ throw std::runtime_error(fmt::format("Playback open error: {}", snd_strerror(err)));
+ }
+
+ generate();
+
+ npfd = snd_pcm_poll_descriptors_count(handle);
+ if (npfd < 0) {
+ throw std::runtime_error("snd_pcm_poll_descriptors_count() failed");
+ }
+ pfd = (struct pollfd *)malloc(npfd * sizeof(struct pollfd));
+ if (pfd == nullptr) {
+ throw std::runtime_error("alloca() error for PCM");
+ }
+ if (0 > snd_pcm_poll_descriptors(handle, pfd, npfd))
+ {
+ throw std::runtime_error("snd_pcm_poll_descriptors() failure");
+ }
+
+ if (0 > snd_pcm_start(handle))
+ {
+ throw std::runtime_error("PCM could not be started");
+ }
+
+ if (npfd != 1) {
+ std::cout << "Warning: " << std::to_string(npfd) << " poll fds for pcm" << std::endl;
+ } else if (fd() <= 2) {
+ std::cout << "Warning: Bad PCM fd: " << std::to_string(fd()) << std::endl;
+ }
+}
+
+PCM::~PCM()
+{
+ // pass the remaining samples, otherwise they're dropped in close
+ err = snd_pcm_drain(handle);
+ if (err < 0)
+ std::cerr << fmt::format("snd_pcm_drain failed: {}", snd_strerror(err)) << std::endl;
+ snd_pcm_close(handle);
+
+ free(pfd);
+}
+
+void PCM::click()
+{
+ snd_pcm_sframes_t delay;
+ if (0 > snd_pcm_delay(handle, &delay)) {
+ }
+
+ m_phase = - click_latency_frames + delay;
+}
+
+// generate 1 buffer size
+void PCM::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 PCM::fd()
+{
+ return pfd->fd;
+}
+
+// write from buffer to ALSA PCM
+void PCM::write()
+{
+ snd_pcm_sframes_t written = snd_pcm_writei(handle, buffer, nframes);
+ if (written < 0) {
+ if (written == -EPIPE) {
+ std::cout << "Warning: PCM underrun" << std::endl;
+ }
+ std::cout << "Recovering." << std::endl;
+ written = snd_pcm_recover(handle, written, 0);
+ }
+ if (written < 0) {
+ throw std::runtime_error("snd_pcm_writei failed: "s + snd_strerror(written));
+ }
+
+ if (written != nframes) {
+ std::cout << "Warning: written " << std::to_string(written) << " frames instead of "<< std::to_string(nframes) << std::endl;
+ }
+
+ 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 {
+ debug_cout << fmt::format("Delay: {}, avail. buffer; {} frames", delay, avail) << std::endl;
+ }
+
+ generate();
+}
+
+bool PCM::wait_for_event()
+{
+ int result = poll(pfd, npfd, 10000);
+ if (result > 0)
+ {
+ // event
+ return true;
+ }
+ else if (result == 0) {
+ // timeout
+ return false;
+ } else {
+ throw std::runtime_error("Poll unsuccessful");
+ }
+}
+
+bool PCM::write_available()
+{
+ snd_pcm_sframes_t result = snd_pcm_avail(handle);
+ if (0 > result) {
+ std::cerr << "Error: snd_pcm_avail()" << std::endl;
+ //throw std::runtime_error("snd_pcm_avail()");
+ }
+
+ return result >= nframes;
+}
+
diff --git a/PCM.h b/PCM.h
index a9e251c..73cdcc6 100644
--- a/PCM.h
+++ b/PCM.h
@@ -18,153 +18,22 @@ using namespace std::string_literals;
class PCM
{
public:
- 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)));
- }
- if ((err = snd_pcm_set_params(handle,
- SND_PCM_FORMAT_S16_LE,
- SND_PCM_ACCESS_RW_INTERLEAVED,
- 1,
- f_sample,
- 1,
- pcm_latency_us)) < 0) { // latency in us
- throw std::runtime_error(fmt::format("Playback open error: {}", snd_strerror(err)));
- }
-
- generate();
-
- npfd = snd_pcm_poll_descriptors_count(handle);
- if (npfd < 0) {
- throw std::runtime_error("snd_pcm_poll_descriptors_count() failed");
- }
- pfd = (struct pollfd *)malloc(npfd * sizeof(struct pollfd));
- if (pfd == nullptr) {
- throw std::runtime_error("alloca() error for PCM");
- }
- if (0 > snd_pcm_poll_descriptors(handle, pfd, npfd))
- {
- throw std::runtime_error("snd_pcm_poll_descriptors() failure");
- }
-
- if (0 > snd_pcm_start(handle))
- {
- throw std::runtime_error("PCM could not be started");
- }
-
- if (npfd != 1) {
- std::cout << "Warning: " << std::to_string(npfd) << " poll fds for pcm" << std::endl;
- } else if (fd() <= 2) {
- std::cout << "Warning: Bad PCM fd: " << std::to_string(fd()) << std::endl;
- }
- }
-
- ~PCM()
- {
- // pass the remaining samples, otherwise they're dropped in close
- err = snd_pcm_drain(handle);
- if (err < 0)
- std::cerr << fmt::format("snd_pcm_drain failed: {}", snd_strerror(err)) << std::endl;
- snd_pcm_close(handle);
-
- free(pfd);
- }
-
- void click()
- {
- snd_pcm_sframes_t delay;
- if (0 > snd_pcm_delay(handle, &delay)) {
- }
-
- m_phase = - click_latency_frames + delay;
- }
+ PCM();
+ ~PCM();
+
+ void click();
// 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;
- }
+ void generate();
+
+ int fd();
// write from buffer to ALSA PCM
- void write()
- {
- snd_pcm_sframes_t written = snd_pcm_writei(handle, buffer, nframes);
- if (written < 0) {
- if (written == -EPIPE) {
- std::cout << "Warning: PCM underrun" << std::endl;
- }
- std::cout << "Recovering." << std::endl;
- written = snd_pcm_recover(handle, written, 0);
- }
- if (written < 0) {
- throw std::runtime_error("snd_pcm_writei failed: "s + snd_strerror(written));
- }
-
- if (written != nframes) {
- std::cout << "Warning: written " << std::to_string(written) << " frames instead of "<< std::to_string(nframes) << std::endl;
- }
-
- 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 {
- debug_cout << fmt::format("Delay: {}, avail. buffer; {} frames", delay, avail) << std::endl;
- }
-
- generate();
- }
-
- bool wait_for_event()
- {
- int result = poll(pfd, npfd, 10000);
- if (result > 0)
- {
- // event
- return true;
- }
- else if (result == 0) {
- // timeout
- return false;
- } else {
- throw std::runtime_error("Poll unsuccessful");
- }
- }
-
- bool write_available()
- {
- snd_pcm_sframes_t result = snd_pcm_avail(handle);
- if (0 > result) {
- std::cerr << "Error: snd_pcm_avail()" << std::endl;
- //throw std::runtime_error("snd_pcm_avail()");
- }
-
- return result >= nframes;
- }
+ void write();
+
+ bool wait_for_event();
+
+ bool write_available();
private:
int err;
diff --git a/Timer.cpp b/Timer.cpp
index afe5d24..7885e73 100644
--- a/Timer.cpp
+++ b/Timer.cpp
@@ -1 +1,38 @@
#include "Timer.h"
+
+Timer::Timer(std::chrono::milliseconds interval, bool cyclic) :
+ m_start_time(clock_type::now()),
+ m_interval(interval),
+ m_running(false),
+ m_cyclic(cyclic)
+{
+}
+
+void Timer::start()
+{
+ m_running = true;
+ m_start_time = clock_type::now();
+}
+
+void Timer::stop()
+{
+ m_running = false;
+}
+
+bool Timer::is_elapsed() const
+{
+ return m_start_time + m_interval < clock_type::now();
+}
+
+void Timer::update()
+{
+ if (m_running && is_elapsed()) {
+ elapsed();
+ if (m_cyclic) {
+ start();
+ } else {
+ stop();
+ }
+ }
+}
+
diff --git a/Timer.h b/Timer.h
index 81192d6..c42db78 100644
--- a/Timer.h
+++ b/Timer.h
@@ -11,39 +11,18 @@ using clock_type = std::chrono::high_resolution_clock;
class Timer
{
public:
- Timer(std::chrono::milliseconds interval, bool cyclic) : m_start_time(clock_type::now()), m_interval(interval), m_running(false), m_cyclic(cyclic)
- {}
+ Timer(std::chrono::milliseconds interval, bool cyclic);
// connect to this signal
boost::signals2::signal<void()> elapsed;
- void start()
- {
- m_running = true;
- m_start_time = clock_type::now();
- }
-
- void stop()
- {
- m_running = false;
- }
-
- bool is_elapsed()
- {
- return m_start_time + m_interval < clock_type::now();
- }
-
- void update()
- {
- if (m_running && is_elapsed()) {
- elapsed();
- if (m_cyclic) {
- start();
- } else {
- stop();
- }
- }
- }
+ void start();
+
+ void stop();
+
+ bool is_elapsed() const;
+
+ void update();
private:
std::chrono::time_point<clock_type> m_start_time;
diff --git a/debug.cpp b/debug.cpp
index 09c9fcc..096c894 100644
--- a/debug.cpp
+++ b/debug.cpp
@@ -1,3 +1,23 @@
#include "debug.h"
debug_ostream debug_cout;
+
+debug_ostream::debug_ostream(): m_active(false) {}
+
+void debug_ostream::activate()
+{
+ m_active = true;
+}
+
+void debug_ostream::deactivate()
+{
+ m_active = false;
+}
+
+debug_ostream& debug_ostream::operator<<(
+ std::basic_ostream<char>& (*func)
+ (std::basic_ostream<char>&) ) {
+ if (m_active)
+ std::cout << *func;
+ return *this;
+}
diff --git a/debug.h b/debug.h
index 1965de0..335cd6e 100644
--- a/debug.h
+++ b/debug.h
@@ -6,17 +6,11 @@
class debug_ostream
{
public:
- debug_ostream(): m_active(false) {}
+ debug_ostream();
- void activate()
- {
- m_active = true;
- }
+ void activate();
- void deactivate()
- {
- m_active = false;
- }
+ void deactivate();
template<typename T>
debug_ostream& operator<<(const T& arg) {
@@ -27,11 +21,7 @@ public:
debug_ostream& operator<<(
std::basic_ostream<char>& (*func)
- (std::basic_ostream<char>&) ) {
- if (m_active)
- std::cout << *func;
- return *this;
- }
+ (std::basic_ostream<char>&) );
private:
bool m_active;
diff --git a/log.cpp b/log.cpp
index 7698e4f..dae56c7 100644
--- a/log.cpp
+++ b/log.cpp
@@ -2,3 +2,56 @@
log_stream log_cout;
+log_stream::log_stream(): m_active(false), m_buffer(), m_log_lines() {}
+
+void log_stream::log_lines(int n) {
+ m_log_lines = n;
+}
+
+std::string log_stream::get_log() {
+ return m_buffer.str();
+}
+
+// log to buffer
+void log_stream::activate()
+{
+ m_active = true;
+}
+
+// log to plain console
+void log_stream::deactivate()
+{
+ m_active = false;
+}
+
+log_stream& log_stream::operator<<(
+ std::basic_ostream<char>& (*func)
+ (std::basic_ostream<char>&) ) {
+ if (m_active) {
+ m_buffer << *func;
+ trim_buffer();
+ }
+ else
+ {
+ std::cout << *func;
+ }
+ return *this;
+}
+
+void log_stream::trim_buffer()
+{
+ std::string s = m_buffer.str();
+ size_t pos = s.npos;
+ for (int i = 0; i <= m_log_lines; ++i) {
+ pos = s.rfind("\n", pos);
+ if (pos == s.npos) {
+ // too few lines
+ return;
+ }
+ if (pos > 0) {
+ --pos;
+ }
+ }
+
+ m_buffer.str(s.substr((pos <= (s.size() - 2)) ? pos + 2 : pos));
+}
diff --git a/log.h b/log.h
index cfc4d4c..9aea958 100644
--- a/log.h
+++ b/log.h
@@ -8,27 +8,17 @@
class log_stream
{
public:
- log_stream(): m_active(false), m_buffer(), m_log_lines() {}
+ log_stream();
- void log_lines(int n) {
- m_log_lines = n;
- }
+ void log_lines(int n);
- std::string get_log() {
- return m_buffer.str();
- }
+ std::string get_log();
// log to buffer
- void activate()
- {
- m_active = true;
- }
+ void activate();
// log to plain console
- void deactivate()
- {
- m_active = false;
- }
+ void deactivate();
template<typename T>
log_stream& operator<<(const T& arg) {
@@ -45,36 +35,10 @@ public:
log_stream& operator<<(
std::basic_ostream<char>& (*func)
- (std::basic_ostream<char>&) ) {
- if (m_active) {
- m_buffer << *func;
- trim_buffer();
- }
- else
- {
- std::cout << *func;
- }
- return *this;
- }
+ (std::basic_ostream<char>&) );
private:
- void trim_buffer()
- {
- std::string s = m_buffer.str();
- size_t pos = s.npos;
- for (int i = 0; i <= m_log_lines; ++i) {
- pos = s.rfind("\n", pos);
- if (pos == s.npos) {
- // too few lines
- return;
- }
- if (pos > 0) {
- --pos;
- }
- }
-
- m_buffer.str(s.substr((pos <= (s.size() - 2)) ? pos + 2 : pos));
- }
+ void trim_buffer();
bool m_active;
std::stringstream m_buffer;