//#include #include #include #include #include #include #define CHANNELS 2 #define TAPS 6 #define BUFFER_SECONDS 10 struct Tap { float *t_gain[TAPS]; float *l_gain; float *r_gain; float *gain; float *delay; }; static const int CONTROLS_PER_TAP = sizeof (Tap) / sizeof (float *); struct PTap { double sample_rate; size_t buffer_max; Tap tap[TAPS]; Tap l_out; Tap 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 */ PTap *ptap = new PTap(); ptap->sample_rate = sample_rate; ptap->buffer_max = ptap->sample_rate * BUFFER_SECONDS + 1; for (int i = 0; i < TAPS; i++) { ptap->buffers[i] = new float[ptap->buffer_max](); if (ptap->buffers[i] == NULL) { for (int j = 0; j < i; j++) { delete ptap->buffers[i]; } delete ptap; printf("Failed to allocate buffers\n"); return NULL; } 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) { PTap *ptap = (PTap *)lv2instance; Tap *tap; float *fdata = (float *)data; /* Audio ports */ if (port < 4) { switch (port) { case 0: ptap->in_l = fdata; break; case 1: ptap->in_r = fdata; break; case 2: ptap->out_l = fdata; break; case 3: ptap->out_r = fdata; 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] = fdata; } else if (tap_port - TAPS == 0) { tap->l_gain = fdata; } else if (tap_port - TAPS == 1) { tap->r_gain = fdata; } else if (tap_port - TAPS == 2) { tap->gain = fdata; } else if (tap_port - TAPS == 3) { tap->delay = fdata; } else { return; } } static void ptap_run(LV2_Handle lv2instance, uint32_t sample_count) { PTap *ptap = (PTap *)lv2instance; Tap *tap; float *wp; /* Position read pointers behind write pointers */ for (int 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 *in_l = ptap->in_l; float *in_r = ptap->in_r; float *out_l = ptap->out_l; float *out_r = ptap->out_r; while (sample_count--) { for (int i = 0; i < TAPS; i++) { wp = ptap->wp[i]; tap = &ptap->tap[i]; *wp = *in_l * *tap->l_gain; *wp += *in_r * *tap->r_gain; for (int j = 0; j < TAPS; j++) { *wp += *ptap->rp[j] * *tap->t_gain[j]; } *wp *= *tap->gain; } /* Write to left output */ tap = &ptap->l_out; *out_l = *in_l * *tap->l_gain; *out_l += *in_r * *tap->r_gain; for (int j = 0; j < TAPS; j++) { *out_l += *ptap->rp[j] * *tap->t_gain[j]; } *out_l *= *tap->gain; /* Write to right output */ tap = &ptap->r_out; *out_r = *in_l * *tap->l_gain; *out_r += *in_r * *tap->r_gain; for (int j = 0; j < TAPS; j++) { *out_r += *ptap->rp[j] * *tap->t_gain[j]; } *out_r *= *tap->gain; /* Progress read pointers */ for (int 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]; } } in_l++; in_r++; out_l++; out_r++; } } static void ptap_cleanup(LV2_Handle lv2instance) { PTap *ptap = (PTap *)lv2instance; for (int i = 0; i < TAPS; i++) { delete ptap->buffers[i]; } delete ptap; } static const LV2_Descriptor s_lv2descriptor = { "urn:fuzzle:ptap", &ptap_instantiate, &ptap_connect_port, NULL, &ptap_run, NULL, &ptap_cleanup, NULL, }; const LV2_Descriptor *lv2_descriptor(uint32_t index) { if (index == 0) { return &s_lv2descriptor; } return NULL; }