2020-09-14 00:00:00 +00:00
|
|
|
#include "./delay.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include "util/math/algorithm.h"
|
|
|
|
#include "util/math/rational.h"
|
|
|
|
#include "util/memory/memory.h"
|
|
|
|
|
|
|
|
#include "./effect.h"
|
|
|
|
#include "./format.h"
|
|
|
|
|
|
|
|
struct jukebox_delay_t {
|
|
|
|
jukebox_effect_t super;
|
|
|
|
jukebox_format_t format;
|
|
|
|
|
|
|
|
float source;
|
|
|
|
float feedback;
|
|
|
|
|
|
|
|
size_t length;
|
|
|
|
size_t offset;
|
|
|
|
size_t cursor;
|
|
|
|
float buffer[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
static void jukebox_delay_affect_(
|
|
|
|
jukebox_effect_t* effect, const jukebox_effect_pcm_t* pcm) {
|
|
|
|
assert(effect != NULL);
|
|
|
|
assert(pcm != NULL);
|
|
|
|
|
|
|
|
jukebox_delay_t* d = (typeof(d)) effect;
|
|
|
|
|
|
|
|
const int32_t ch = d->format.channels;
|
2020-10-09 00:00:00 +00:00
|
|
|
const size_t pcmlen = (size_t) pcm->frames*ch;
|
2020-09-14 00:00:00 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < pcmlen; ++i) {
|
|
|
|
float* bufoff = &d->buffer[d->offset];
|
|
|
|
float* bufcur = &d->buffer[d->cursor];
|
|
|
|
float* pcmptr = &pcm->ptr[i];
|
|
|
|
|
|
|
|
*bufoff *= d->feedback;
|
|
|
|
*bufoff += *pcmptr * d->source;
|
|
|
|
|
|
|
|
*pcmptr += *bufcur;
|
|
|
|
if (MATH_ABS(*pcmptr) >= 1.0f) {
|
|
|
|
*pcmptr = MATH_SIGN(*pcmptr) * 0.99f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++d->offset >= d->length) d->offset = 0;
|
|
|
|
if (++d->cursor >= d->length) d->cursor = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
jukebox_delay_t* jukebox_delay_new(
|
|
|
|
const jukebox_format_t* format,
|
|
|
|
const rational_t* duration,
|
|
|
|
float source_attenuation,
|
|
|
|
float feedback_attenuation) {
|
|
|
|
assert(jukebox_format_valid(format));
|
|
|
|
assert(rational_valid(duration));
|
|
|
|
assert(MATH_FLOAT_VALID(source_attenuation));
|
|
|
|
assert(MATH_FLOAT_VALID(feedback_attenuation));
|
|
|
|
|
|
|
|
rational_t dur_r = rational(format->channels*duration->num, duration->den);
|
|
|
|
rational_normalize(&dur_r, format->sample_rate);
|
|
|
|
|
|
|
|
const size_t length = dur_r.num;
|
|
|
|
|
|
|
|
jukebox_delay_t* d =
|
|
|
|
memory_new(sizeof(*d) + (length-1)*sizeof(d->buffer[0]));
|
|
|
|
*d = (typeof(*d)) {
|
|
|
|
.super = {
|
|
|
|
.vtable = {
|
|
|
|
.affect = jukebox_delay_affect_,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.format = *format,
|
|
|
|
.source = source_attenuation,
|
|
|
|
.feedback = feedback_attenuation,
|
|
|
|
.length = length,
|
|
|
|
.offset = dur_r.num,
|
|
|
|
.cursor = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < d->length; ++i) d->buffer[i] = 0;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void jukebox_delay_delete(jukebox_delay_t* delay) {
|
|
|
|
if (delay == NULL) return;
|
|
|
|
|
|
|
|
memory_delete(delay);
|
|
|
|
}
|