lasp/src/lasp/dsp/lasp_timebuffer.cpp

92 lines
2.1 KiB
C++

/* #define DEBUGTRACE_ENABLED */
#include "lasp_timebuffer.h"
#include "debugtrace.hpp"
#include <algorithm>
#include <cassert>
#include <deque>
#include <memory>
#include <optional>
#include <stdexcept>
using rte = std::runtime_error;
class TimeBufferImp {
/**
* @brief Storage in a double-ended queue of armadillo row vectors.
*/
std::deque<arma::rowvec> _storage;
public:
void reset() {
DEBUGTRACE_ENTER;
_storage.clear();
}
void push(const dmat &mat) {
DEBUGTRACE_ENTER;
#if LASP_DEBUG == 1
if (!_storage.empty()) {
if (mat.n_cols != _storage.front().n_cols) {
throw rte("Invalid number of channels in mat");
}
}
#endif
for (us i = 0; i < mat.n_rows; i++) {
_storage.push_back(mat.row(i));
}
}
std::optional<dmat> pop(const us nframes, const us keep) {
DEBUGTRACE_ENTER;
if (keep >= nframes) {
throw rte("keep should be < nframes");
}
if (nframes <= n_frames()) {
assert(!_storage.empty());
dmat res(nframes, _storage.front().n_cols);
us j = 0;
for (us i = 0; i < nframes; i++) {
if (i + keep < nframes) {
// Just pop elements and copy over
res.row(i) = _storage.front();
_storage.pop_front();
} else {
// Suppose keep == 0, then we never arrive here
// Suppose keep == 1, then storage[0] is copyied over.
// Suppose keep == 2, then storage[0[ and storage[1] is copyied over.
// Etc.
res.row(i) = _storage[j];
j++;
}
}
return res;
}
// If nsamples is too much for what we have, we just return nothing.
return std::nullopt;
}
/**
* @brief Counts the number of available frames in the queue
*
* @return
*/
us n_frames() const { return _storage.size(); }
};
TimeBuffer::TimeBuffer() : _imp(std::make_unique<TimeBufferImp>()) {}
std::optional<dmat> TimeBuffer::pop(const us n_rows, const us keep) {
return _imp->pop(n_rows, keep);
}
TimeBuffer::~TimeBuffer() {}
void TimeBuffer::reset() { _imp->reset(); }
void TimeBuffer::push(const dmat &dat) { _imp->push(dat); }