Chris@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@13: #define _USE_MATH_DEFINES Chris@13: #include Chris@13: Chris@9: #include "devuvuzelator-vst.h" Chris@9: Chris@0: #include Chris@2: #include Chris@0: Chris@9: #include "params.h" Chris@2: Chris@2: #define snprintf _snprintf Chris@2: #define alloca _alloca Chris@0: Chris@1: // VST params 0->1 Chris@1: Chris@0: void Chris@0: Devuvuzelator::setParameter(VstInt32 index, float value) Chris@0: { Chris@1: switch (index) { Chris@4: case 0: m_fundamental = 50 + 720 * value; break; Chris@4: case 1: m_bandwidth = 20 + 80 * value; break; Chris@4: case 2: m_harmonics = int(value * 6 + 0.5); break; Chris@4: case 3: m_reduction = 100 * value; break; Chris@1: } Chris@0: } Chris@0: Chris@0: float Chris@0: Devuvuzelator::getParameter(VstInt32 index) Chris@0: { Chris@1: switch (index) { Chris@4: case 0: return (m_fundamental - 50) / 720; Chris@4: case 1: return (m_bandwidth - 20) / 80; Chris@4: case 2: return (m_harmonics / 6.f); Chris@4: case 3: return m_reduction / 100; Chris@1: } Chris@4: return 0; Chris@0: } Chris@0: Chris@0: // NB! The max name length for VST parameter names, labels Chris@0: // (i.e. units) and display values (i.e. string renderings of current Chris@0: // value) is a rather amazing 8 bytes Chris@0: Chris@0: void Chris@0: Devuvuzelator::getParameterLabel(VstInt32 index, char *label) Chris@0: { Chris@0: const char *units[NumParams] = { Chris@0: "Hz", Chris@0: "Hz", Chris@0: "", Chris@4: "%", Chris@0: }; Chris@0: Chris@0: vst_strncpy(label, units[index], kVstMaxParamStrLen); Chris@0: } Chris@0: Chris@0: void Chris@0: Devuvuzelator::getParameterDisplay(VstInt32 index, char *label) Chris@0: { Chris@4: switch (index) { Chris@4: case 0: snprintf(label, kVstMaxParamStrLen, "%f", m_fundamental); break; Chris@4: case 1: snprintf(label, kVstMaxParamStrLen, "%f", m_bandwidth); break; Chris@4: case 2: snprintf(label, kVstMaxParamStrLen, "%d", m_harmonics); break; Chris@4: case 3: snprintf(label, kVstMaxParamStrLen, "%f", m_reduction); break; Chris@4: } Chris@0: } Chris@0: Chris@0: void Chris@0: Devuvuzelator::getParameterName(VstInt32 index, char *label) Chris@0: { Chris@0: const char *names[NumParams] = { Chris@0: "Pitch", Chris@0: "B/W", Chris@0: "Partials", Chris@0: "Reductn", Chris@0: }; Chris@0: Chris@0: vst_strncpy(label, names[index], kVstMaxParamStrLen); Chris@0: } Chris@0: Chris@0: Devuvuzelator::Devuvuzelator(audioMasterCallback cb) : Chris@0: AudioEffect(cb, 0, NumParams), Chris@0: m_sampleRate(0), Chris@0: m_input(0), Chris@0: m_output(0), Chris@0: m_fftsize(FFTSIZE), Chris@7: m_winsize(WINSIZE), Chris@5: m_increment(m_winsize/2), Chris@9: m_filtersecs(FILTERSECS), Chris@0: m_fill(0), Chris@0: m_read(0) Chris@0: { 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@9: m_frame = new double[m_fftsize]; Chris@9: m_spare = new double[m_fftsize]; Chris@0: m_real = new double[m_fftsize]; Chris@0: m_imag = new double[m_fftsize]; Chris@4: m_medians = new MedianFilter *[m_fftsize/2+1]; Chris@0: 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@4: } Chris@4: for (int i = 0; i < m_fftsize/2+1; ++i) { Chris@4: m_medians[i] = 0; Chris@0: } Chris@0: Chris@4: m_fundamental = 230; Chris@0: m_bandwidth = 60; Chris@0: m_harmonics = 3; Chris@4: m_reduction = 30; Chris@0: Chris@2: setUniqueID('qmvz'); Chris@0: setNumInputs(1); Chris@0: setNumOutputs(1); Chris@0: canProcessReplacing(true); Chris@0: canDoubleReplacing(false); Chris@0: Chris@0: reset(); Chris@0: } Chris@0: Chris@0: Devuvuzelator::~Devuvuzelator() Chris@0: { Chris@0: delete[] m_buffer; Chris@0: delete[] m_outacc; Chris@9: delete[] m_frame; Chris@9: delete[] m_spare; Chris@0: delete[] m_real; Chris@0: delete[] m_imag; Chris@0: 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@0: } Chris@0: Chris@0: void Chris@0: Devuvuzelator::reset() Chris@0: { Chris@4: for (int i = 0; i < m_winsize; ++i) { Chris@0: m_buffer[i] = 0.f; Chris@0: } Chris@4: for (int i = 0; i < m_winsize*2; ++i) { Chris@0: m_outacc[i] = 0.f; Chris@0: } Chris@0: m_fill = 0; Chris@0: 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@0: } Chris@0: Chris@0: void Chris@0: Devuvuzelator::runImpl(unsigned long sampleCount) Chris@0: { Chris@0: if (!m_input || !m_output) return; Chris@0: Chris@4: const int sc = sampleCount; Chris@0: Chris@9: float *output = m_output; Chris@9: if (m_input == m_output) { Chris@9: output = (float *)alloca(sampleCount * sizeof(float)); Chris@9: } Chris@0: Chris@9: int oi = 0; Chris@9: for (int ii = 0; ii < sc; ++ii) { Chris@0: Chris@9: output[oi++] = m_outacc[m_read++]; Chris@4: if (m_fill == m_winsize) { Chris@0: Chris@0: processFrame(); Chris@0: Chris@4: for (int j = m_increment; j < m_winsize; ++j) { Chris@0: m_buffer[j - m_increment] = m_buffer[j]; Chris@0: } Chris@0: Chris@4: for (int j = m_increment; j < m_winsize*2; ++j) { Chris@0: m_outacc[j - m_increment] = m_outacc[j]; Chris@0: } Chris@0: Chris@4: for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) { Chris@0: m_outacc[j] = 0.f; Chris@0: } Chris@0: Chris@8: m_fill = m_fill - m_increment; Chris@8: m_read = m_read - m_increment; Chris@0: } Chris@9: m_buffer[m_fill] = m_input[ii]; Chris@9: ++m_fill; Chris@8: } Chris@0: Chris@9: if (m_input == m_output) { Chris@9: for (int i = 0; i < sc; ++i) m_output[i] = output[i]; Chris@9: } Chris@0: } Chris@0: Chris@0: void Chris@0: Devuvuzelator::processFrame() Chris@0: { Chris@0: for (int i = 0; i < m_fftsize; ++i) { Chris@8: m_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@8: m_frame[ix++] += m_buffer[i] * m_window[i]; Chris@0: if (ix == m_fftsize) ix = 0; Chris@0: } Chris@0: Chris@8: fft(m_fftsize, false, m_frame, 0, m_real, m_imag); Chris@0: Chris@9: processSpectralFrame(); Chris@0: Chris@0: 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@0: } Chris@0: Chris@8: fft(m_fftsize, true, m_real, m_imag, m_frame, m_spare); Chris@0: 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@8: m_outacc[m_winsize + i] += m_frame[ix++]; Chris@0: if (ix == m_fftsize) ix = 0; Chris@0: } Chris@0: } Chris@0: Chris@0: AudioEffect *createEffectInstance(audioMasterCallback audioMaster) Chris@0: { Chris@0: return new Devuvuzelator(audioMaster); Chris@0: } Chris@0: Chris@1: