7#include "AudioTools/CoreAudio/AudioOutput.h"
8#include "AudioTools/CoreAudio/AudioTypes.h"
9#include "AudioToolsConfig.h"
23 float pitch_shift = 1.4f;
24 int buffer_size = 1000;
38 setIncrement(increment);
39 if (size > 0) resize(size);
42 void setIncrement(
float increment) { read_increment = increment; }
44 void resize(
int size) {
51 read_pos_float += read_increment;
53 if (read_pos_float > buffer_size) {
54 read_pos_float -= buffer_size;
60 if (buffer.size() == 0) {
61 LOGE(
"buffer has no memory");
64 result = buffer[(int)read_pos_float];
70 if (buffer.size() == 0) {
71 LOGE(
"buffer has no memory");
74 buffer[write_pos++] = sample;
76 if (write_pos >= buffer_size) {
86 memset(buffer.data(), 0,
sizeof(T) * buffer_size);
89 virtual bool isFull() {
return false; }
93 size_t size() {
return buffer_size; }
98 float read_pos_float = 0.0;
99 float read_increment = 1.0;
114 setIncrement(increment);
115 if (size > 0) resize(size);
118 void setIncrement(
float increment) { pitch_shift = increment; }
120 void resize(
int size) {
122 overlap = buffer_size / 10;
131 bool peek(T &result) {
return false; }
134 if (buffer.size() == 0) {
135 LOGE(
"buffer has no memory");
139 write_pointer = write_pos;
140 buffer[write_pos++] = sample;
142 if (write_pos >= buffer_size) {
153 overlap = buffer_size / 10;
154 memset(buffer.data(), 0,
sizeof(T) * buffer_size);
161 size_t size() {
return buffer_size; }
165 float read_pos_float = 0.0;
166 float cross_fade = 1.0;
168 int write_pointer = 0;
171 float pitch_shift = 0;
176 assert(pitch_shift > 0);
177 assert(buffer_size > 0);
181 int read_pointer_int = roundf(read_pos_float);
182 int read_pointer_int180 = 0;
183 if (read_pointer_int >= buffer_size / 2)
184 read_pointer_int180 = read_pointer_int - (buffer_size / 2);
186 read_pointer_int180 = read_pointer_int + (buffer_size / 2);
189 float read_sample = (float)buffer[read_pointer_int];
190 float read_sample_180 = (float)buffer[read_pointer_int180];
194 if (overlap >= (write_pointer - read_pointer_int) &&
195 (write_pointer - read_pointer_int) >= 0 && pitch_shift != 1.0f) {
196 int rel = write_pointer - read_pointer_int;
197 cross_fade = ((float)rel) / (float)overlap;
198 }
else if (write_pointer - read_pointer_int == 0)
203 if (overlap >= (write_pointer - read_pointer_int180) &&
204 (write_pointer - read_pointer_int180) >= 0 && pitch_shift != 1.0f) {
205 int rel = write_pointer - read_pointer_int180;
206 cross_fade = 1.0f - ((float)rel) / (float)overlap;
207 }
else if (write_pointer - read_pointer_int180 == 0)
211 T sum = (read_sample * cross_fade + read_sample_180 * (1.0f - cross_fade));
214 read_pos_float += pitch_shift;
215 if (roundf(read_pos_float) >= buffer_size) read_pos_float = 0.0f;
232 setIncrement(increment);
233 if (size > 0) resize(size);
236 void setIncrement(
float increment) { read_increment = increment; }
238 void resize(
int size) {
241 read_pos_float = size / 2;
246 assert(read_increment != 0.0f);
248 read_pos_float += read_increment;
250 if (read_pos_float > buffer_size) {
251 read_pos_float -= buffer_size;
257 if (buffer.size() == 0) {
266 if (buffer.size() == 0)
return false;
268 buffer[write_pos++] = sample;
270 if (write_pos >= buffer_size) {
280 memset(buffer.data(), 0,
sizeof(T) * buffer_size);
287 size_t size() {
return buffer_size; }
292 float read_pos_float = 0.0f;
293 float read_increment = 0.0f;
301 int read_pos_int = read_pos;
303 T value2 =
getValue(read_pos_int + 1);
304 incrementing = value2 - value1 >= 0;
307 if (value2 < value1) {
313 float offset_in = read_pos - read_pos_int;
314 LOGD(
"read_pos=%f read_pos_int=%d, offset_in=%f", read_pos, read_pos_int,
317 abs(value2 - value1);
318 float offset_result = offset_in * diff_result;
319 float result = offset_result + value1;
320 LOGD(
"interpolate %d %d -> %f -> %f", value1, value2, offset_result,
329 T
getValue(
int pos) {
return buffer[pos % buffer_size]; }
334 bool v_incrementing = v2 - v1 >= 0;
336 if (incrementing && v_incrementing && value1 >= v1 && value1 <= v2) {
340 if (!incrementing && !v_incrementing && value1 <= v1 && value1 >= v2) {
350 int read_pos_int = read_pos_float;
351 if (write_pos == read_pos_int ||
352 write_pos == (buffer_size % (read_pos_int + 1))) {
353 LOGD(
"handleReadWriteOverrun write_pos=%d read_pos_int=%d", write_pos,
358 for (
int j = read_increment * 2; j < buffer_size; j++) {
359 int pos = read_pos_int + j;
363 if (
isMatching(last_value, incrementing, v1, v2)) {
365 float diff_value = abs(v1 - v2);
366 float diff_last_value = abs(v1 - last_value);
368 if (diff_value > 0) {
369 fraction = diff_last_value / diff_value;
372 read_pos_float = fraction + pos;
374 read_pos_float += read_increment;
376 if (read_pos_float > buffer_size) {
377 read_pos_float -= buffer_size;
379 LOGD(
"handleReadWriteOverrun -> read_pos pos=%d pos_float=%f", pos,
386 LOGW(
"phase allign failed: maybe the buffer is too small")
402template <
typename T,
class BufferT>
417 buffer.resize(info.buffer_size);
419 buffer.setIncrement(info.pitch_shift);
424 size_t write(
const uint8_t *data,
size_t len)
override {
426 if (!active)
return 0;
431 int sample_count = len /
sizeof(T);
433 for (
int j = 0; j < sample_count; j += channels) {
435 for (
int ch = 0; ch < channels; ch++) {
436 value += p_in[j + ch];
442 T out_value = pitchShift(value);
443 LOGD(
"PitchShiftOutput %f -> %d", value, (
int)out_value);
444 T out_array[channels];
445 for (
int ch = 0; ch < channels; ch++) {
446 out_array[ch] = out_value;
448 result += p_out->write((uint8_t *)out_array,
sizeof(T) * channels);
453 void end() { active =
false; }
459 Print *p_out =
nullptr;
463 T pitchShift(T value) {
465 if (!active)
return 0;