summaryrefslogtreecommitdiff
path: root/src/drivers/pcm_buffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/pcm_buffer.cpp')
-rw-r--r--src/drivers/pcm_buffer.cpp40
1 files changed, 33 insertions, 7 deletions
diff --git a/src/drivers/pcm_buffer.cpp b/src/drivers/pcm_buffer.cpp
index 071f5cea..bc58d4b9 100644
--- a/src/drivers/pcm_buffer.cpp
+++ b/src/drivers/pcm_buffer.cpp
@@ -25,7 +25,8 @@ namespace drivers {
[[maybe_unused]] static const char kTag[] = "pcmbuf";
-PcmBuffer::PcmBuffer(size_t size_in_samples) : sent_(0), received_(0) {
+PcmBuffer::PcmBuffer(size_t size_in_samples)
+ : sent_(0), received_(0), suspended_(false) {
size_t size_in_bytes = size_in_samples * sizeof(int16_t);
ESP_LOGI(kTag, "allocating pcm buffer of size %u (%uKiB)", size_in_samples,
size_in_bytes / 1024);
@@ -49,18 +50,26 @@ auto PcmBuffer::send(std::span<const int16_t> data) -> size_t {
return data.size();
}
-IRAM_ATTR auto PcmBuffer::receive(std::span<int16_t> dest, bool isr)
+IRAM_ATTR auto PcmBuffer::receive(std::span<int16_t> dest, bool mix, bool isr)
-> BaseType_t {
+ if (suspended_) {
+ if (!mix) {
+ std::fill_n(dest.begin(), dest.size(), 0);
+ }
+ return false;
+ }
+
size_t first_read = 0, second_read = 0;
BaseType_t ret1 = false, ret2 = false;
- std::tie(first_read, ret1) = readSingle(dest, isr);
+ std::tie(first_read, ret1) = readSingle(dest, mix, isr);
if (first_read < dest.size()) {
- std::tie(second_read, ret2) = readSingle(dest.subspan(first_read), isr);
+ std::tie(second_read, ret2) =
+ readSingle(dest.subspan(first_read), mix, isr);
}
size_t total_read = first_read + second_read;
- if (total_read < dest.size()) {
+ if (total_read < dest.size() && !mix) {
std::fill_n(dest.begin() + total_read, dest.size() - total_read, 0);
}
@@ -85,6 +94,10 @@ auto PcmBuffer::isEmpty() -> bool {
xRingbufferGetCurFreeSize(ringbuf_);
}
+auto PcmBuffer::suspend(bool s) -> void {
+ suspended_ = s;
+}
+
auto PcmBuffer::totalSent() -> uint32_t {
return sent_;
}
@@ -93,7 +106,9 @@ auto PcmBuffer::totalReceived() -> uint32_t {
return received_;
}
-IRAM_ATTR auto PcmBuffer::readSingle(std::span<int16_t> dest, bool isr)
+IRAM_ATTR auto PcmBuffer::readSingle(std::span<int16_t> dest,
+ bool mix,
+ bool isr)
-> std::pair<size_t, BaseType_t> {
BaseType_t ret;
size_t read_bytes = 0;
@@ -111,7 +126,18 @@ IRAM_ATTR auto PcmBuffer::readSingle(std::span<int16_t> dest, bool isr)
return {read_samples, ret};
}
- std::memcpy(dest.data(), data, read_bytes);
+ if (mix) {
+ for (size_t i = 0; i < read_samples; i++) {
+ // Sum the two samples in a 32 bit field so that the addition is always
+ // safe.
+ int32_t sum = static_cast<int32_t>(dest[i]) +
+ static_cast<int32_t>(reinterpret_cast<int16_t*>(data)[i]);
+ // Clip back into the range of a single sample.
+ dest[i] = std::clamp<int32_t>(sum, INT16_MIN, INT16_MAX);
+ }
+ } else {
+ std::memcpy(dest.data(), data, read_bytes);
+ }
if (isr) {
vRingbufferReturnItem(ringbuf_, data);