#include #include #include #include #include #include #define CHANNELS 2 #define TAPS 6 #define BUFFER_SECONDS 10 struct tap_t { float *t_gain[TAPS]; float *l_gain; float *r_gain; float *gain; float *delay; }; static const int CONTROLS_PER_TAP = sizeof (struct tap_t) / sizeof (float *); struct ptap_t { double sample_rate; size_t buffer_max; struct tap_t tap[TAPS]; struct tap_t l_out; struct tap_t r_out; float *buffers[TAPS]; ///< Tap audio buffers float *rp[TAPS]; ///< Read pointers float *wp[TAPS]; ///< Write pointers float *in_l; float *in_r; float *out_l; float *out_r; }; static LV2_Handle ptap_instantiate( const LV2_Descriptor *descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *host_features) { /* Allocate local data */ struct ptap_t *ptap = malloc(sizeof *ptap); if (ptap == NULL) { return NULL; } memset(ptap, 0, sizeof *ptap); ptap->sample_rate = sample_rate; ptap->buffer_max = ptap->sample_rate * BUFFER_SECONDS + 1; int i, j; for (i = 0; i < TAPS; i++) { ptap->buffers[i] = malloc(ptap->buffer_max * sizeof (float)); if (ptap->buffers[i] == NULL) { for (j = 0; j < i; j++) { free(ptap->buffers[i]); } free(ptap); printf("Failed to allocate buffers\n"); return NULL; } memset(ptap->buffers[i], 0, ptap->buffer_max * sizeof (float)); ptap->rp[i] = ptap->buffers[i]; ptap->wp[i] = ptap->buffers[i]; } return (LV2_Handle)ptap; } static void ptap_connect_port(LV2_Handle lv2instance, uint32_t port, void *data) { struct ptap_t *ptap = (struct ptap_t *)lv2instance; struct tap_t *tap; /* Audio ports */ if (port < 4) { switch (port) { case 0: ptap->in_l = data; break; case 1: ptap->in_r = data; break; case 2: ptap->out_l = data; break; case 3: ptap->out_r = data; break; } return; } port -= 4; int tap_index = port / CONTROLS_PER_TAP; if (tap_index < TAPS) { tap = &ptap->tap[tap_index]; } else if (tap_index - TAPS == 0) { tap = &ptap->l_out; } else if (tap_index - TAPS == 1) { tap = &ptap->r_out; } else { return; } int tap_port = port % CONTROLS_PER_TAP; if (tap_port < TAPS) { tap->t_gain[tap_port] = data; } else if (tap_port - TAPS == 0) { tap->l_gain = data; } else if (tap_port - TAPS == 1) { tap->r_gain = data; } else if (tap_port - TAPS == 2) { tap->gain = data; } else if (tap_port - TAPS == 3) { tap->delay = data; } else { return; } } static void ptap_run(LV2_Handle lv2instance, uint32_t sample_count) { struct ptap_t *ptap = (struct ptap_t *)lv2instance; const struct tap_t *tap; float *wp; int i, j; /* Position read pointers behind write pointers */ for (i = 0; i < TAPS; i++) { int delay = *ptap->tap[i].delay * ptap->sample_rate; ptap->rp[i] = ptap->wp[i] - delay; if (ptap->rp[i] < ptap->buffers[i]) { ptap->rp[i] += ptap->buffer_max; } } float *il = ptap->in_l; float *ir = ptap->in_r; float *ol = ptap->out_l; float *or = ptap->out_r; while (sample_count--) { for (i = 0; i < TAPS; i++) { wp = ptap->wp[i]; tap = &ptap->tap[i]; *wp = *il * *tap->l_gain; *wp += *ir * *tap->r_gain; for (j = 0; j < TAPS; j++) { *wp += *ptap->rp[j] * *tap->t_gain[j]; } *wp *= *tap->gain; } /* Write to left output */ tap = &ptap->l_out; *ol = *il * *tap->l_gain; *ol += *ir * *tap->r_gain; for (j = 0; j < TAPS; j++) { *ol += *ptap->rp[j] * *tap->t_gain[j]; } *ol *= *tap->gain; /* Write to right output */ tap = &ptap->r_out; *or = *il * *tap->l_gain; *or += *ir * *tap->r_gain; for (j = 0; j < TAPS; j++) { *or += *ptap->rp[j] * *tap->t_gain[j]; } *or *= *tap->gain; /* Progress read pointers */ for (i = 0; i < TAPS; i++) { ptap->wp[i]++; if (ptap->wp[i] >= ptap->buffers[i] + ptap->buffer_max) { ptap->wp[i] = ptap->buffers[i]; } ptap->rp[i]++; if (ptap->rp[i] >= ptap->buffers[i] + ptap->buffer_max) { ptap->rp[i] = ptap->buffers[i]; } } il++; ir++; ol++; or++; } } static void ptap_cleanup(LV2_Handle lv2instance) { struct ptap_t *ptap = (struct ptap_t *)lv2instance; int i; for (i = 0; i < TAPS; i++) { free(ptap->buffers[i]); } free(ptap); } static const LV2_Descriptor s_lv2descriptor = { .URI = "urn:fuzzle:ptap", .instantiate = &ptap_instantiate, .connect_port = &ptap_connect_port, .run = &ptap_run, .cleanup = &ptap_cleanup, }; const LV2_Descriptor *lv2_descriptor(uint32_t index) { if (index == 0) { return &s_lv2descriptor; } return NULL; }