Chris@1: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1: Chris@9: #include "devuvuzelator-ladspa.h" Chris@9: Chris@1: #include Chris@1: #include Chris@1: #include Chris@1: Chris@9: #include "params.h" Chris@1: Chris@1: const char *const Chris@1: Devuvuzelator::portNames[PortCount] = Chris@1: { Chris@1: "Input", Chris@1: "Output", Chris@4: "latency", Chris@1: "Fundamental frequency (Hz)", Chris@1: "Bandwidth of fundamental (Hz)", Chris@1: "Number of partials", Chris@4: "Reduction (%)", Chris@1: }; Chris@1: Chris@1: const LADSPA_PortDescriptor Chris@1: Devuvuzelator::ports[PortCount] = Chris@1: { Chris@1: LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, Chris@1: LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, Chris@4: LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, Chris@1: LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, Chris@1: LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, Chris@1: LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, Chris@1: LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, Chris@1: }; Chris@1: Chris@1: const LADSPA_PortRangeHint Chris@1: Devuvuzelator::hints[PortCount] = Chris@1: { Chris@1: { 0, 0, 0 }, Chris@1: { 0, 0, 0 }, Chris@4: { 0, 0, 0 }, Chris@1: { LADSPA_HINT_DEFAULT_LOW | Chris@4: LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 50, 770 }, Chris@1: { LADSPA_HINT_DEFAULT_MIDDLE | Chris@1: LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 20, 100 }, Chris@1: { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER | Chris@1: LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 6 }, Chris@1: { LADSPA_HINT_DEFAULT_MIDDLE | Chris@4: LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 100 }, Chris@1: }; Chris@1: Chris@1: const LADSPA_Properties Chris@1: Devuvuzelator::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; Chris@1: Chris@1: const LADSPA_Descriptor Chris@1: Devuvuzelator::ladspaDescriptor = Chris@1: { Chris@16: 0xf0b374, // "Unique" ID Chris@1: "devuvuzelator", // Label Chris@1: properties, Chris@1: "Devuvuzelator", // Name Chris@1: "Queen Mary, University of London", // Maker Chris@11: "BSD", // Copyright Chris@1: PortCount, Chris@1: ports, Chris@1: portNames, Chris@1: hints, Chris@1: 0, // Implementation data Chris@1: instantiate, Chris@1: connectPort, Chris@1: activate, Chris@1: run, Chris@1: 0, // Run adding Chris@1: 0, // Set run adding gain Chris@1: deactivate, Chris@1: cleanup Chris@1: }; Chris@1: Chris@1: const LADSPA_Descriptor * Chris@1: Devuvuzelator::getDescriptor(unsigned long index) Chris@1: { Chris@1: if (index == 0) return &ladspaDescriptor; Chris@1: return 0; Chris@1: } Chris@1: Chris@1: Devuvuzelator::Devuvuzelator(int sampleRate) : Chris@1: m_sampleRate(sampleRate), Chris@1: m_input(0), Chris@1: m_output(0), Chris@4: m_platency(0), Chris@4: m_pfundamental(0), Chris@4: m_pbandwidth(0), Chris@4: m_pharmonics(0), Chris@4: m_preduction(0), Chris@1: m_fftsize(FFTSIZE), Chris@4: m_winsize(WINSIZE), Chris@4: m_increment(m_winsize/2), Chris@9: m_filtersecs(FILTERSECS), Chris@1: m_fill(0), Chris@1: m_read(0) Chris@1: { Chris@4: m_buffer = new float[m_winsize]; Chris@4: m_outacc = new float[m_winsize * 2]; Chris@4: m_window = new double[m_winsize]; Chris@1: m_real = new double[m_fftsize]; Chris@1: m_imag = new double[m_fftsize]; Chris@4: m_medians = new MedianFilter *[m_fftsize/2+1]; Chris@1: Chris@4: for (int i = 0; i < m_winsize; ++i) { Chris@4: m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize); Chris@1: } Chris@4: for (int i = 0; i < m_fftsize/2+1; ++i) { Chris@4: m_medians[i] = 0; Chris@4: } Chris@4: Chris@4: m_fundamental = 230; Chris@4: m_bandwidth = 60; Chris@4: m_harmonics = 3; Chris@4: m_reduction = 50; Chris@4: Chris@4: std::cerr << "note: latency = " << (float(m_winsize) / m_sampleRate)*1000 << " msec" << std::endl; Chris@1: Chris@1: reset(); Chris@1: } Chris@1: Chris@1: Devuvuzelator::~Devuvuzelator() Chris@1: { Chris@1: delete[] m_buffer; Chris@1: delete[] m_outacc; Chris@1: delete[] m_real; Chris@1: delete[] m_imag; Chris@1: delete[] m_window; Chris@4: for (int i = 0; i < m_fftsize/2+1; ++i) { Chris@4: delete m_medians[i]; Chris@4: } Chris@4: delete[] m_medians; Chris@1: } Chris@1: Chris@1: LADSPA_Handle Chris@1: Devuvuzelator::instantiate(const LADSPA_Descriptor *, unsigned long rate) Chris@1: { Chris@1: Devuvuzelator *devuvu = new Devuvuzelator(rate); Chris@1: return devuvu; Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::connectPort(LADSPA_Handle handle, Chris@1: unsigned long port, LADSPA_Data *location) Chris@1: { Chris@1: Devuvuzelator *devuvu = (Devuvuzelator *)handle; Chris@1: Chris@1: float **ports[PortCount] = { Chris@1: &devuvu->m_input, Chris@1: &devuvu->m_output, Chris@4: &devuvu->m_platency, Chris@4: &devuvu->m_pfundamental, Chris@4: &devuvu->m_pbandwidth, Chris@4: &devuvu->m_pharmonics, Chris@4: &devuvu->m_preduction, Chris@1: }; Chris@1: Chris@1: *ports[port] = (float *)location; Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::activate(LADSPA_Handle handle) Chris@1: { Chris@1: Devuvuzelator *devuvu = (Devuvuzelator *)handle; Chris@1: devuvu->reset(); Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::run(LADSPA_Handle handle, unsigned long samples) Chris@1: { Chris@1: Devuvuzelator *devuvu = (Devuvuzelator *)handle; Chris@1: devuvu->runImpl(samples); Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::deactivate(LADSPA_Handle handle) Chris@1: { Chris@1: activate(handle); // both functions just reset the plugin Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::cleanup(LADSPA_Handle handle) Chris@1: { Chris@1: delete (Devuvuzelator *)handle; Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::reset() Chris@1: { Chris@4: for (int i = 0; i < m_winsize; ++i) { Chris@1: m_buffer[i] = 0.f; Chris@1: } Chris@4: for (int i = 0; i < m_winsize*2; ++i) { Chris@1: m_outacc[i] = 0.f; Chris@1: } Chris@1: m_fill = 0; Chris@1: m_read = 0; Chris@4: for (int i = 0; i < m_fftsize/2+1; ++i) { Chris@4: if (m_medians[i]) m_medians[i]->reset(); Chris@4: } Chris@4: } Chris@4: Chris@4: void Chris@4: Devuvuzelator::updateParameters() Chris@4: { Chris@4: if (m_platency) *m_platency = m_winsize; Chris@4: if (m_pfundamental) m_fundamental = *m_pfundamental; Chris@4: if (m_pbandwidth) m_bandwidth = *m_pbandwidth; Chris@4: if (m_pharmonics) m_harmonics = *m_pharmonics; Chris@4: if (m_preduction) m_reduction = *m_preduction; Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::runImpl(unsigned long sampleCount) Chris@1: { Chris@1: if (!m_input || !m_output) return; Chris@4: updateParameters(); Chris@1: Chris@1: int ii = 0; Chris@1: int oi = 0; Chris@1: const int sc = sampleCount; Chris@1: Chris@14: float tmp_input; Chris@14: Chris@1: while (ii < sc) { Chris@1: Chris@14: tmp_input = m_input[ii++]; Chris@14: Chris@4: m_output[oi++] = m_outacc[m_read++]; Chris@1: Chris@4: if (m_fill == m_winsize) { Chris@1: Chris@1: processFrame(); Chris@1: Chris@4: for (int j = m_increment; j < m_winsize; ++j) { Chris@1: m_buffer[j - m_increment] = m_buffer[j]; Chris@1: } Chris@1: Chris@4: for (int j = m_increment; j < m_winsize*2; ++j) { Chris@1: m_outacc[j - m_increment] = m_outacc[j]; Chris@1: } Chris@1: Chris@4: for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) { Chris@1: m_outacc[j] = 0.f; Chris@1: } Chris@1: Chris@1: m_fill -= m_increment; Chris@1: m_read -= m_increment; Chris@1: } Chris@1: Chris@14: m_buffer[m_fill++] = tmp_input; Chris@1: } Chris@1: } Chris@1: Chris@1: void Chris@1: Devuvuzelator::processFrame() Chris@1: { Chris@1: double *frame = (double *)alloca(m_fftsize * sizeof(double)); Chris@1: for (int i = 0; i < m_fftsize; ++i) { Chris@4: frame[i] = 0.0; Chris@4: } Chris@4: Chris@4: int ix = m_fftsize - m_winsize/2; Chris@4: while (ix < 0) ix += m_fftsize; Chris@4: for (int i = 0; i < m_winsize; ++i) { Chris@4: frame[ix++] += m_buffer[i] * m_window[i]; Chris@1: if (ix == m_fftsize) ix = 0; Chris@1: } Chris@1: Chris@1: fft(m_fftsize, false, frame, 0, m_real, m_imag); Chris@1: Chris@1: processSpectralFrame(); Chris@1: Chris@1: for (int i = 0; i < m_fftsize/2-1; ++i) { Chris@3: m_real[m_fftsize-i-1] = m_real[i+1]; Chris@3: m_imag[m_fftsize-i-1] = -m_imag[i+1]; Chris@1: } Chris@1: Chris@1: double *spare = (double *)alloca(m_fftsize * sizeof(double)); Chris@1: fft(m_fftsize, true, m_real, m_imag, frame, spare); Chris@1: Chris@4: ix = m_fftsize - m_winsize/2; Chris@4: while (ix < 0) ix += m_fftsize; Chris@4: for (int i = 0; i < m_winsize; ++i) { Chris@4: m_outacc[m_winsize + i] += frame[ix++]; Chris@1: if (ix == m_fftsize) ix = 0; Chris@1: } Chris@1: } Chris@1: Chris@1: const LADSPA_Descriptor * Chris@1: ladspa_descriptor(unsigned long ix) Chris@1: { Chris@1: return Devuvuzelator::getDescriptor(ix); Chris@1: } Chris@1: