/* -*- linux-c -*- Copyright (C) 2004 Tom Szilagyi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: tap_rotspeak.c,v 1.3 2004/02/21 17:33:36 tszilagyi Exp $ */ #include #include #include #include #include #include "tap_utils.h" /* The Unique ID of the plugin: */ #define ID_STEREO 2149 /* The port numbers for the plugin: */ #define BASSFREQ 0 #define HORNFREQ 1 #define STWIDTH 2 #define HRBAL 3 #define LATENCY 4 #define INPUT_L 5 #define INPUT_R 6 #define OUTPUT_L 7 #define OUTPUT_R 8 /* Total number of ports */ #define PORTCOUNT_STEREO 9 /* * This has to be bigger than 0.3f * sample_rate / (2*PI) for any sample rate. * At 192 kHz 9168 is needed so this should be enough. */ #define PM_DEPTH 9200 /* maximum phase mod freq */ #define PM_FREQ 30.0f /* splitting input signals into low and high freq components */ #define SPLIT_FREQ 1000.0f #define SPLIT_BW 1.0f /* approx. sound velocity in air [m/s] */ #define C_AIR 340.0f /* coefficient between rotating frequency and pitch mod depth (aka. Doppler effect) */ #define FREQ_PITCH 1.6f /* cosine table for fast computations */ LADSPA_Data cos_table[1024]; /* The structure used to hold port connection information and state */ typedef struct { LADSPA_Data * hornfreq; LADSPA_Data * bassfreq; LADSPA_Data * stwidth; LADSPA_Data * hrbal; LADSPA_Data * latency; LADSPA_Data * input_L; LADSPA_Data * input_R; LADSPA_Data * output_L; LADSPA_Data * output_R; LADSPA_Data * ringbuffer_h_L; unsigned long buflen_h_L; unsigned long pos_h_L; LADSPA_Data * ringbuffer_h_R; unsigned long buflen_h_R; unsigned long pos_h_R; LADSPA_Data * ringbuffer_b_L; unsigned long buflen_b_L; unsigned long pos_b_L; LADSPA_Data * ringbuffer_b_R; unsigned long buflen_b_R; unsigned long pos_b_R; biquad * eq_filter_L; biquad * lp_filter_L; biquad * hp_filter_L; biquad * eq_filter_R; biquad * lp_filter_R; biquad * hp_filter_R; unsigned long sample_rate; LADSPA_Data phase_h; LADSPA_Data phase_b; LADSPA_Data run_adding_gain; } RotSpkr; /* Construct a new plugin instance. */ LADSPA_Handle instantiate_RotSpkr(const LADSPA_Descriptor * Descriptor, unsigned long sample_rate) { LADSPA_Handle * ptr; if ((ptr = malloc(sizeof(RotSpkr))) != NULL) { ((RotSpkr *)ptr)->sample_rate = sample_rate; ((RotSpkr *)ptr)->run_adding_gain = 1.0; if ((((RotSpkr *)ptr)->ringbuffer_h_L = calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) return NULL; if ((((RotSpkr *)ptr)->ringbuffer_h_R = calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) return NULL; ((RotSpkr *)ptr)->buflen_h_L = ceil(0.3f * sample_rate / M_PI); ((RotSpkr *)ptr)->buflen_h_R = ceil(0.3f * sample_rate / M_PI); ((RotSpkr *)ptr)->pos_h_L = 0; ((RotSpkr *)ptr)->pos_h_R = 0; if ((((RotSpkr *)ptr)->ringbuffer_b_L = calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) return NULL; if ((((RotSpkr *)ptr)->ringbuffer_b_R = calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) return NULL; ((RotSpkr *)ptr)->buflen_b_L = ceil(0.3f * sample_rate / M_PI); ((RotSpkr *)ptr)->buflen_b_R = ceil(0.3f * sample_rate / M_PI); ((RotSpkr *)ptr)->pos_b_L = 0; ((RotSpkr *)ptr)->pos_b_R = 0; if ((((RotSpkr *)ptr)->eq_filter_L = calloc(1, sizeof(biquad))) == NULL) return NULL; if ((((RotSpkr *)ptr)->lp_filter_L = calloc(1, sizeof(biquad))) == NULL) return NULL; if ((((RotSpkr *)ptr)->hp_filter_L = calloc(1, sizeof(biquad))) == NULL) return NULL; if ((((RotSpkr *)ptr)->eq_filter_R = calloc(1, sizeof(biquad))) == NULL) return NULL; if ((((RotSpkr *)ptr)->lp_filter_R = calloc(1, sizeof(biquad))) == NULL) return NULL; if ((((RotSpkr *)ptr)->hp_filter_R = calloc(1, sizeof(biquad))) == NULL) return NULL; return ptr; } return NULL; } void activate_RotSpkr(LADSPA_Handle Instance) { int i; RotSpkr * ptr; ptr = (RotSpkr *)Instance; for (i = 0; i < 2 * PM_DEPTH; i++) { ptr->ringbuffer_h_L[i] = 0.0f; ptr->ringbuffer_h_R[i] = 0.0f; ptr->ringbuffer_b_L[i] = 0.0f; ptr->ringbuffer_b_R[i] = 0.0f; } ptr->phase_h = 0.0f; ptr->phase_b = 0.0f; biquad_init(ptr->eq_filter_L); biquad_init(ptr->lp_filter_L); biquad_init(ptr->hp_filter_L); biquad_init(ptr->eq_filter_R); biquad_init(ptr->lp_filter_R); biquad_init(ptr->hp_filter_R); eq_set_params(ptr->eq_filter_L, SPLIT_FREQ, +8.0f, SPLIT_BW, ptr->sample_rate); eq_set_params(ptr->eq_filter_R, SPLIT_FREQ, +8.0f, SPLIT_BW, ptr->sample_rate); lp_set_params(ptr->lp_filter_L, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); lp_set_params(ptr->lp_filter_R, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); hp_set_params(ptr->hp_filter_L, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); hp_set_params(ptr->hp_filter_R, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); } /* Connect a port to a data location. */ void connect_port_RotSpkr(LADSPA_Handle Instance, unsigned long Port, LADSPA_Data * DataLocation) { RotSpkr * ptr; ptr = (RotSpkr *)Instance; switch (Port) { case HORNFREQ: ptr->hornfreq = DataLocation; break; case BASSFREQ: ptr->bassfreq = DataLocation; break; case STWIDTH: ptr->stwidth = DataLocation; break; case HRBAL: ptr->hrbal = DataLocation; break; case LATENCY: ptr->latency = DataLocation; *(ptr->latency) = ptr->buflen_h_L / 2; /* IS THIS LEGAL? */ break; case INPUT_L: ptr->input_L = DataLocation; break; case INPUT_R: ptr->input_R = DataLocation; break; case OUTPUT_L: ptr->output_L = DataLocation; break; case OUTPUT_R: ptr->output_R = DataLocation; break; } } void run_RotSpkr(LADSPA_Handle Instance, unsigned long SampleCount) { RotSpkr * ptr = (RotSpkr *)Instance; LADSPA_Data * input_L = ptr->input_L; LADSPA_Data * input_R = ptr->input_R; LADSPA_Data * output_L = ptr->output_L; LADSPA_Data * output_R = ptr->output_R; LADSPA_Data freq_h = LIMIT(*(ptr->hornfreq),0.0f,PM_FREQ); LADSPA_Data freq_b = LIMIT(*(ptr->bassfreq),0.0f,PM_FREQ); LADSPA_Data stwidth = LIMIT(*(ptr->stwidth),0.0f,100.0f); LADSPA_Data hrbal = LIMIT(*(ptr->hrbal),0.0f,1.0f); LADSPA_Data pmdepth_h = LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_h/C_AIR) * ptr->sample_rate / 200.0f / M_PI / freq_h, 0, ptr->buflen_h_L / 2); LADSPA_Data pmdepth_b = LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_b/C_AIR) * ptr->sample_rate / 200.0f / M_PI / freq_b, 0, ptr->buflen_b_L / 2); unsigned long sample_index; LADSPA_Data in_L = 0.0f, in_R = 0.0f; LADSPA_Data lo_L = 0.0f, lo_R = 0.0f; LADSPA_Data hi_L = 0.0f, hi_R = 0.0f; LADSPA_Data phase_h_L = 0.0f, phase_b_L = 0.0f; LADSPA_Data phase_h_R = 0.0f, phase_b_R = 0.0f; LADSPA_Data phase_pm_h_L = 0.0f, phase_pm_b_L = 0.0f; LADSPA_Data phase_pm_h_R = 0.0f, phase_pm_b_R = 0.0f; LADSPA_Data pm_h_L = 0.0f, pm_b_L = 0.0f; LADSPA_Data pm_h_R = 0.0f, pm_b_R = 0.0f; LADSPA_Data fpos_h_L = 0.0f, fpos_b_L = 0.0f, fpos_h_R = 0.0f, fpos_b_R = 0.0f; LADSPA_Data n_h_L = 0.0f, n_b_L = 0.0f, n_h_R = 0.0f, n_b_R = 0.0f; LADSPA_Data rem_h_L = 0.0f, rem_b_L = 0.0f, rem_h_R = 0.0f, rem_b_R = 0.0f; LADSPA_Data sa_h_L = 0.0f, sa_b_L = 0.0f, sb_h_L = 0.0f, sb_b_L = 0.0f; LADSPA_Data sa_h_R = 0.0f, sa_b_R = 0.0f, sb_h_R = 0.0f, sb_b_R = 0.0f; for (sample_index = 0; sample_index < SampleCount; sample_index++) { in_L = *(input_L++); in_R = *(input_R++); in_L = biquad_run(ptr->eq_filter_L, in_L); in_R = biquad_run(ptr->eq_filter_R, in_R); lo_L = biquad_run(ptr->lp_filter_L, in_L); lo_R = biquad_run(ptr->lp_filter_R, in_R); hi_L = biquad_run(ptr->hp_filter_L, in_L); hi_R = biquad_run(ptr->hp_filter_R, in_R); phase_h_L = 1024.0f * freq_h * sample_index / ptr->sample_rate + ptr->phase_h; while (phase_h_L >= 1024.0f) phase_h_L -= 1024.0f; phase_pm_h_L = phase_h_L + 256.0f; while (phase_pm_h_L >= 1024.0f) phase_pm_h_L -= 1024.0f; phase_h_R = phase_h_L + 512.0f; while (phase_h_R >= 1024.0f) phase_h_R -= 1024.0f; phase_pm_h_R = phase_h_R + 256.0f; while (phase_pm_h_R >= 1024.0f) phase_pm_h_R -= 1024.0f; phase_b_L = 1024.0f * freq_b * sample_index / ptr->sample_rate + ptr->phase_b; while (phase_b_L >= 1024.0f) phase_b_L -= 1024.0f; phase_pm_b_L = phase_b_L + 256.0f; while (phase_pm_b_L >= 1024.0f) phase_pm_b_L -= 1024.0f; phase_b_R = phase_b_L + 512.0f; while (phase_b_R >= 1024.0f) phase_b_R -= 1024.0f; phase_pm_b_R = phase_b_R + 256.0f; while (phase_pm_b_R >= 1024.0f) phase_pm_b_R -= 1024.0f; push_buffer(hi_L, ptr->ringbuffer_h_L, ptr->buflen_h_L, &(ptr->pos_h_L)); push_buffer(hi_R, ptr->ringbuffer_h_R, ptr->buflen_h_R, &(ptr->pos_h_R)); push_buffer(lo_L, ptr->ringbuffer_b_L, ptr->buflen_b_L, &(ptr->pos_b_L)); push_buffer(lo_R, ptr->ringbuffer_b_R, ptr->buflen_b_R, &(ptr->pos_b_R)); fpos_h_L = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_L]); n_h_L = floorf(fpos_h_L); rem_h_L = fpos_h_L - n_h_L; sa_h_L = read_buffer(ptr->ringbuffer_h_L, ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L); sb_h_L = read_buffer(ptr->ringbuffer_h_L, ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L + 1); pm_h_L = (1 - rem_h_L) * sa_h_L + rem_h_L * sb_h_L; fpos_h_R = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_R]); n_h_R = floorf(fpos_h_R); rem_h_R = fpos_h_R - n_h_R; sa_h_R = read_buffer(ptr->ringbuffer_h_R, ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R); sb_h_R = read_buffer(ptr->ringbuffer_h_R, ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R + 1); pm_h_R = (1 - rem_h_R) * sa_h_R + rem_h_R * sb_h_R; fpos_b_L = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_L]); n_b_L = floorf(fpos_b_L); rem_b_L = fpos_b_L - n_b_L; sa_b_L = read_buffer(ptr->ringbuffer_b_L, ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L); sb_b_L = read_buffer(ptr->ringbuffer_b_L, ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L + 1); pm_b_L = (1 - rem_b_L) * sa_b_L + rem_b_L * sb_b_L; fpos_b_R = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_R]); n_b_R = floorf(fpos_b_R); rem_b_R = fpos_b_R - n_b_R; sa_b_R = read_buffer(ptr->ringbuffer_b_R, ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R); sb_b_R = read_buffer(ptr->ringbuffer_b_R, ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R + 1); pm_b_R = (1 - rem_b_R) * sa_b_R + rem_b_R * sb_b_R; *(output_L++) = hrbal * pm_h_L * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_h_L]) + (1.0f - hrbal) * pm_b_L * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_b_L]); *(output_R++) = hrbal * pm_h_R * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_h_R]) + (1.0f - hrbal) * pm_b_R * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_b_R]); } ptr->phase_h += 1024.0f * freq_h * sample_index / ptr->sample_rate; while (ptr->phase_h >= 1024.0f) ptr->phase_h -= 1024.0f; ptr->phase_b += 1024.0f * freq_b * sample_index / ptr->sample_rate; while (ptr->phase_b >= 1024.0f) ptr->phase_b -= 1024.0f; *(ptr->latency) = ptr->buflen_h_L / 2; } void set_run_adding_gain_RotSpkr(LADSPA_Handle Instance, LADSPA_Data gain) { RotSpkr * ptr = (RotSpkr *)Instance; ptr->run_adding_gain = gain; } void run_adding_RotSpkr(LADSPA_Handle Instance, unsigned long SampleCount) { RotSpkr * ptr = (RotSpkr *)Instance; LADSPA_Data * input_L = ptr->input_L; LADSPA_Data * input_R = ptr->input_R; LADSPA_Data * output_L = ptr->output_L; LADSPA_Data * output_R = ptr->output_R; LADSPA_Data freq_h = LIMIT(*(ptr->hornfreq),0.0f,PM_FREQ); LADSPA_Data freq_b = LIMIT(*(ptr->bassfreq),0.0f,PM_FREQ); LADSPA_Data stwidth = LIMIT(*(ptr->stwidth),0.0f,100.0f); LADSPA_Data hrbal = LIMIT(*(ptr->hrbal),0.0f,1.0f); LADSPA_Data pmdepth_h = LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_h/C_AIR) * ptr->sample_rate / 200.0f / M_PI / freq_h, 0, ptr->buflen_h_L / 2); LADSPA_Data pmdepth_b = LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_b/C_AIR) * ptr->sample_rate / 200.0f / M_PI / freq_b, 0, ptr->buflen_b_L / 2); unsigned long sample_index; LADSPA_Data in_L = 0.0f, in_R = 0.0f; LADSPA_Data lo_L = 0.0f, lo_R = 0.0f; LADSPA_Data hi_L = 0.0f, hi_R = 0.0f; LADSPA_Data phase_h_L = 0.0f, phase_b_L = 0.0f; LADSPA_Data phase_h_R = 0.0f, phase_b_R = 0.0f; LADSPA_Data phase_pm_h_L = 0.0f, phase_pm_b_L = 0.0f; LADSPA_Data phase_pm_h_R = 0.0f, phase_pm_b_R = 0.0f; LADSPA_Data pm_h_L = 0.0f, pm_b_L = 0.0f; LADSPA_Data pm_h_R = 0.0f, pm_b_R = 0.0f; LADSPA_Data fpos_h_L = 0.0f, fpos_b_L = 0.0f, fpos_h_R = 0.0f, fpos_b_R = 0.0f; LADSPA_Data n_h_L = 0.0f, n_b_L = 0.0f, n_h_R = 0.0f, n_b_R = 0.0f; LADSPA_Data rem_h_L = 0.0f, rem_b_L = 0.0f, rem_h_R = 0.0f, rem_b_R = 0.0f; LADSPA_Data sa_h_L = 0.0f, sa_b_L = 0.0f, sb_h_L = 0.0f, sb_b_L = 0.0f; LADSPA_Data sa_h_R = 0.0f, sa_b_R = 0.0f, sb_h_R = 0.0f, sb_b_R = 0.0f; for (sample_index = 0; sample_index < SampleCount; sample_index++) { in_L = *(input_L++); in_R = *(input_R++); in_L = biquad_run(ptr->eq_filter_L, in_L); in_R = biquad_run(ptr->eq_filter_R, in_R); lo_L = biquad_run(ptr->lp_filter_L, in_L); lo_R = biquad_run(ptr->lp_filter_R, in_R); hi_L = biquad_run(ptr->hp_filter_L, in_L); hi_R = biquad_run(ptr->hp_filter_R, in_R); phase_h_L = 1024.0f * freq_h * sample_index / ptr->sample_rate + ptr->phase_h; while (phase_h_L >= 1024.0f) phase_h_L -= 1024.0f; phase_pm_h_L = phase_h_L + 256.0f; while (phase_pm_h_L >= 1024.0f) phase_pm_h_L -= 1024.0f; phase_h_R = phase_h_L + 512.0f; while (phase_h_R >= 1024.0f) phase_h_R -= 1024.0f; phase_pm_h_R = phase_h_R + 256.0f; while (phase_pm_h_R >= 1024.0f) phase_pm_h_R -= 1024.0f; phase_b_L = 1024.0f * freq_b * sample_index / ptr->sample_rate + ptr->phase_b; while (phase_b_L >= 1024.0f) phase_b_L -= 1024.0f; phase_pm_b_L = phase_b_L + 256.0f; while (phase_pm_b_L >= 1024.0f) phase_pm_b_L -= 1024.0f; phase_b_R = phase_b_L + 512.0f; while (phase_b_R >= 1024.0f) phase_b_R -= 1024.0f; phase_pm_b_R = phase_b_R + 256.0f; while (phase_pm_b_R >= 1024.0f) phase_pm_b_R -= 1024.0f; push_buffer(hi_L, ptr->ringbuffer_h_L, ptr->buflen_h_L, &(ptr->pos_h_L)); push_buffer(hi_R, ptr->ringbuffer_h_R, ptr->buflen_h_R, &(ptr->pos_h_R)); push_buffer(lo_L, ptr->ringbuffer_b_L, ptr->buflen_b_L, &(ptr->pos_b_L)); push_buffer(lo_R, ptr->ringbuffer_b_R, ptr->buflen_b_R, &(ptr->pos_b_R)); fpos_h_L = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_L]); n_h_L = floorf(fpos_h_L); rem_h_L = fpos_h_L - n_h_L; sa_h_L = read_buffer(ptr->ringbuffer_h_L, ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L); sb_h_L = read_buffer(ptr->ringbuffer_h_L, ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L + 1); pm_h_L = (1 - rem_h_L) * sa_h_L + rem_h_L * sb_h_L; fpos_h_R = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_R]); n_h_R = floorf(fpos_h_R); rem_h_R = fpos_h_R - n_h_R; sa_h_R = read_buffer(ptr->ringbuffer_h_R, ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R); sb_h_R = read_buffer(ptr->ringbuffer_h_R, ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R + 1); pm_h_R = (1 - rem_h_R) * sa_h_R + rem_h_R * sb_h_R; fpos_b_L = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_L]); n_b_L = floorf(fpos_b_L); rem_b_L = fpos_b_L - n_b_L; sa_b_L = read_buffer(ptr->ringbuffer_b_L, ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L); sb_b_L = read_buffer(ptr->ringbuffer_b_L, ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L + 1); pm_b_L = (1 - rem_b_L) * sa_b_L + rem_b_L * sb_b_L; fpos_b_R = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_R]); n_b_R = floorf(fpos_b_R); rem_b_R = fpos_b_R - n_b_R; sa_b_R = read_buffer(ptr->ringbuffer_b_R, ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R); sb_b_R = read_buffer(ptr->ringbuffer_b_R, ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R + 1); pm_b_R = (1 - rem_b_R) * sa_b_R + rem_b_R * sb_b_R; *(output_L++) += ptr->run_adding_gain * hrbal * pm_h_L * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_h_L]) + (1.0f - hrbal) * pm_b_L * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_b_L]); *(output_R++) += ptr->run_adding_gain * hrbal * pm_h_R * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_h_R]) + (1.0f - hrbal) * pm_b_R * (1.0f + 0.5f * stwidth/100.0f * cos_table[(unsigned long) phase_b_R]); } ptr->phase_h += 1024.0f * freq_h * sample_index / ptr->sample_rate; while (ptr->phase_h >= 1024.0f) ptr->phase_h -= 1024.0f; ptr->phase_b += 1024.0f * freq_b * sample_index / ptr->sample_rate; while (ptr->phase_b >= 1024.0f) ptr->phase_b -= 1024.0f; *(ptr->latency) = ptr->buflen_h_L / 2; } /* Throw away an RotSpkr effect instance. */ void cleanup_RotSpkr(LADSPA_Handle Instance) { RotSpkr * ptr = (RotSpkr *)Instance; free(ptr->ringbuffer_h_L); free(ptr->ringbuffer_h_R); free(ptr->ringbuffer_b_L); free(ptr->ringbuffer_b_R); free(ptr->eq_filter_L); free(ptr->eq_filter_R); free(ptr->lp_filter_L); free(ptr->lp_filter_R); free(ptr->hp_filter_L); free(ptr->hp_filter_R); free(Instance); } LADSPA_Descriptor * stereo_descriptor = NULL; /* __attribute__((constructor)) _init() is called automatically when the plugin library is first loaded. */ void __attribute__((constructor)) _init() { int i; char ** port_names; LADSPA_PortDescriptor * port_descriptors; LADSPA_PortRangeHint * port_range_hints; if ((stereo_descriptor = (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) exit(1); for (i = 0; i < 1024; i++) cos_table[i] = cosf(i * M_PI / 512.0f); stereo_descriptor->UniqueID = ID_STEREO; stereo_descriptor->Label = strdup("tap_rotspeak"); stereo_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; stereo_descriptor->Name = strdup("TAP Rotary Speaker"); stereo_descriptor->Maker = strdup("Tom Szilagyi"); stereo_descriptor->Copyright = strdup("GPL"); stereo_descriptor->PortCount = PORTCOUNT_STEREO; if ((port_descriptors = (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) exit(1); stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; port_descriptors[HORNFREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; port_descriptors[BASSFREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; port_descriptors[STWIDTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; port_descriptors[HRBAL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; if ((port_names = (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) exit(1); stereo_descriptor->PortNames = (const char **)port_names; port_names[HORNFREQ] = strdup("Horn Frequency [Hz]"); port_names[BASSFREQ] = strdup("Rotor Frequency [Hz]"); port_names[STWIDTH] = strdup("Mic Distance [%]"); port_names[HRBAL] = strdup("Rotor/Horn Mix"); port_names[LATENCY] = strdup("latency"); port_names[INPUT_L] = strdup("Input L"); port_names[INPUT_R] = strdup("Input R"); port_names[OUTPUT_L] = strdup("Output L"); port_names[OUTPUT_R] = strdup("Output R"); if ((port_range_hints = ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) exit(1); stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; port_range_hints[HORNFREQ].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0); port_range_hints[BASSFREQ].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0); port_range_hints[STWIDTH].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW); port_range_hints[HRBAL].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE); port_range_hints[LATENCY].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MAXIMUM); port_range_hints[HORNFREQ].LowerBound = 0; port_range_hints[HORNFREQ].UpperBound = PM_FREQ; port_range_hints[BASSFREQ].LowerBound = 0; port_range_hints[BASSFREQ].UpperBound = PM_FREQ; port_range_hints[STWIDTH].LowerBound = 0; port_range_hints[STWIDTH].UpperBound = 100.0f; port_range_hints[HRBAL].LowerBound = 0; port_range_hints[HRBAL].UpperBound = 1.0f; port_range_hints[LATENCY].LowerBound = 0; port_range_hints[LATENCY].UpperBound = PM_DEPTH; port_range_hints[INPUT_L].HintDescriptor = 0; port_range_hints[INPUT_R].HintDescriptor = 0; port_range_hints[OUTPUT_L].HintDescriptor = 0; port_range_hints[OUTPUT_R].HintDescriptor = 0; stereo_descriptor->instantiate = instantiate_RotSpkr; stereo_descriptor->connect_port = connect_port_RotSpkr; stereo_descriptor->activate = activate_RotSpkr; stereo_descriptor->run = run_RotSpkr; stereo_descriptor->run_adding = run_adding_RotSpkr; stereo_descriptor->set_run_adding_gain = set_run_adding_gain_RotSpkr; stereo_descriptor->deactivate = NULL; stereo_descriptor->cleanup = cleanup_RotSpkr; } void delete_descriptor(LADSPA_Descriptor * descriptor) { unsigned long index; if (descriptor) { free((char *)descriptor->Label); free((char *)descriptor->Name); free((char *)descriptor->Maker); free((char *)descriptor->Copyright); free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); for (index = 0; index < descriptor->PortCount; index++) free((char *)(descriptor->PortNames[index])); free((char **)descriptor->PortNames); free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); free(descriptor); } } /* __attribute__((destructor)) _fini() is called automatically when the library is unloaded. */ void __attribute__((destructor)) _fini() { delete_descriptor(stereo_descriptor); } /* Return a descriptor of the requested plugin type. */ const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index) { switch (Index) { case 0: return stereo_descriptor; default: return NULL; } }