| @@ -0,0 +1,40 @@ | |||
| /* (Auto-generated binary data file). */ | |||
| #ifndef BINARY_DISTRHOARTWORK3BANDEQ_HPP | |||
| #define BINARY_DISTRHOARTWORK3BANDEQ_HPP | |||
| namespace DistrhoArtwork3BandEQ | |||
| { | |||
| extern const char* aboutData; | |||
| const unsigned int aboutDataSize = 230280; | |||
| const unsigned int aboutWidth = 303; | |||
| const unsigned int aboutHeight = 190; | |||
| extern const char* aboutButtonHoverData; | |||
| const unsigned int aboutButtonHoverDataSize = 11600; | |||
| const unsigned int aboutButtonHoverWidth = 100; | |||
| const unsigned int aboutButtonHoverHeight = 29; | |||
| extern const char* aboutButtonNormalData; | |||
| const unsigned int aboutButtonNormalDataSize = 11600; | |||
| const unsigned int aboutButtonNormalWidth = 100; | |||
| const unsigned int aboutButtonNormalHeight = 29; | |||
| extern const char* backgroundData; | |||
| const unsigned int backgroundDataSize = 437472; | |||
| const unsigned int backgroundWidth = 392; | |||
| const unsigned int backgroundHeight = 372; | |||
| extern const char* knobData; | |||
| const unsigned int knobDataSize = 615040; | |||
| const unsigned int knobWidth = 62; | |||
| const unsigned int knobHeight = 2480; | |||
| extern const char* sliderData; | |||
| const unsigned int sliderDataSize = 6000; | |||
| const unsigned int sliderWidth = 50; | |||
| const unsigned int sliderHeight = 30; | |||
| } | |||
| #endif // BINARY_DISTRHOARTWORK3BANDEQ_HPP | |||
| @@ -0,0 +1,260 @@ | |||
| /* | |||
| * DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||
| * Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #include "DistrhoPlugin3BandEQ.hpp" | |||
| #include <cmath> | |||
| static const float cfAMP_DB = 8.656170245f; | |||
| static const float cfDC_ADD = 1e-30f; | |||
| static const float cfPI = 3.141592654f; | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| DistrhoPlugin3BandEQ::DistrhoPlugin3BandEQ() | |||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | |||
| { | |||
| // set default values | |||
| d_setProgram(0); | |||
| // reset | |||
| d_deactivate(); | |||
| } | |||
| DistrhoPlugin3BandEQ::~DistrhoPlugin3BandEQ() | |||
| { | |||
| } | |||
| // ------------------------------------------------- | |||
| // Init | |||
| void DistrhoPlugin3BandEQ::d_initParameter(uint32_t index, Parameter& parameter) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramLow: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Low"; | |||
| parameter.symbol = "low"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramMid: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Mid"; | |||
| parameter.symbol = "mid"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramHigh: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "High"; | |||
| parameter.symbol = "high"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramMaster: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Master"; | |||
| parameter.symbol = "master"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramLowMidFreq: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Low-Mid Freq"; | |||
| parameter.symbol = "low_mid"; | |||
| parameter.unit = "Hz"; | |||
| parameter.ranges.def = 440.0f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 1000.0f; | |||
| break; | |||
| case paramMidHighFreq: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Mid-High Freq"; | |||
| parameter.symbol = "mid_high"; | |||
| parameter.unit = "Hz"; | |||
| parameter.ranges.def = 1000.0f; | |||
| parameter.ranges.min = 1000.0f; | |||
| parameter.ranges.max = 20000.0f; | |||
| break; | |||
| } | |||
| } | |||
| void DistrhoPlugin3BandEQ::d_initProgramName(uint32_t index, d_string& programName) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| programName = "Default"; | |||
| } | |||
| // ------------------------------------------------- | |||
| // Internal data | |||
| float DistrhoPlugin3BandEQ::d_parameterValue(uint32_t index) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramLow: | |||
| return fLow; | |||
| case paramMid: | |||
| return fMid; | |||
| case paramHigh: | |||
| return fHigh; | |||
| case paramMaster: | |||
| return fMaster; | |||
| case paramLowMidFreq: | |||
| return fLowMidFreq; | |||
| case paramMidHighFreq: | |||
| return fMidHighFreq; | |||
| default: | |||
| return 0.0f; | |||
| } | |||
| } | |||
| void DistrhoPlugin3BandEQ::d_setParameterValue(uint32_t index, float value) | |||
| { | |||
| if (d_sampleRate() <= 0.0) | |||
| return; | |||
| switch (index) | |||
| { | |||
| case paramLow: | |||
| fLow = value; | |||
| lowVol = std::exp( (fLow/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramMid: | |||
| fMid = value; | |||
| midVol = std::exp( (fMid/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramHigh: | |||
| fHigh = value; | |||
| highVol = std::exp( (fHigh/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramMaster: | |||
| fMaster = value; | |||
| outVol = std::exp( (fMaster/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramLowMidFreq: | |||
| fLowMidFreq = std::min<float>(value, fMidHighFreq); | |||
| freqLP = fLowMidFreq; //fLowMidFreq * (fLowMidFreq / 24000.0f) * (fLowMidFreq / 24000.0f); | |||
| xLP = std::exp(-2.0 * cfPI * freqLP / d_sampleRate()); | |||
| a0LP = 1.0 - xLP; | |||
| b1LP = -xLP; | |||
| break; | |||
| case paramMidHighFreq: | |||
| fMidHighFreq = std::max<float>(value, fLowMidFreq); | |||
| freqHP = fMidHighFreq; //fMidHighFreq * (fMidHighFreq / 24000.0f) * (fMidHighFreq / 24000.0f); | |||
| xHP = std::exp(-2.0 * cfPI * freqHP / d_sampleRate()); | |||
| a0HP = 1.0 - xHP; | |||
| b1HP = -xHP; | |||
| break; | |||
| } | |||
| } | |||
| void DistrhoPlugin3BandEQ::d_setProgram(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| fLow = 0.0f; | |||
| fMid = 0.0f; | |||
| fHigh = 0.0f; | |||
| fMaster = 0.0f; | |||
| fLowMidFreq = 220.0f; | |||
| fMidHighFreq = 2000.0f; | |||
| // Internal stuff | |||
| lowVol = midVol = highVol = outVol = 1.0f; | |||
| freqLP = 200.0f; | |||
| freqHP = 2000.0f; | |||
| // reset filter values | |||
| d_activate(); | |||
| } | |||
| // ------------------------------------------------- | |||
| // Process | |||
| void DistrhoPlugin3BandEQ::d_activate() | |||
| { | |||
| xLP = exp(-2.0 * cfPI * freqLP / d_sampleRate()); | |||
| a0LP = 1.0f - xLP; | |||
| b1LP = -xLP; | |||
| xHP = exp(-2.0 * cfPI * freqHP / d_sampleRate()); | |||
| a0HP = 1.0f - xHP; | |||
| b1HP = -xHP; | |||
| } | |||
| void DistrhoPlugin3BandEQ::d_deactivate() | |||
| { | |||
| out1LP = out2LP = out1HP = out2HP = 0.0f; | |||
| tmp1LP = tmp2LP = tmp1HP = tmp2HP = 0.0f; | |||
| } | |||
| void DistrhoPlugin3BandEQ::d_run(float** inputs, float** outputs, uint32_t frames, uint32_t, const MidiEvent*) | |||
| { | |||
| const float* in1 = inputs[0]; | |||
| const float* in2 = inputs[1]; | |||
| float* out1 = outputs[0]; | |||
| float* out2 = outputs[1]; | |||
| for (uint32_t i=0; i < frames; i++) | |||
| { | |||
| tmp1LP = a0LP * in1[i] - b1LP * tmp1LP + cfDC_ADD; | |||
| tmp2LP = a0LP * in2[i] - b1LP * tmp2LP + cfDC_ADD; | |||
| out1LP = tmp1LP - cfDC_ADD; | |||
| out2LP = tmp2LP - cfDC_ADD; | |||
| tmp1HP = a0HP * in1[i] - b1HP * tmp1HP + cfDC_ADD; | |||
| tmp2HP = a0HP * in2[i] - b1HP * tmp2HP + cfDC_ADD; | |||
| out1HP = in1[i] - tmp1HP - cfDC_ADD; | |||
| out2HP = in2[i] - tmp2HP - cfDC_ADD; | |||
| out1[i] = (out1LP*lowVol + (in1[i] - out1LP - out1HP)*midVol + out1HP*highVol) * outVol; | |||
| out2[i] = (out2LP*lowVol + (in2[i] - out2LP - out2HP)*midVol + out2HP*highVol) * outVol; | |||
| } | |||
| } | |||
| // ------------------------------------------------- | |||
| Plugin* createPlugin() | |||
| { | |||
| return new DistrhoPlugin3BandEQ(); | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,107 @@ | |||
| /* | |||
| * DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||
| * Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_PLUGIN_3BANDEQ_HPP__ | |||
| #define __DISTRHO_PLUGIN_3BANDEQ_HPP__ | |||
| #include "DistrhoPlugin.h" | |||
| START_NAMESPACE_DISTRHO | |||
| class DistrhoPlugin3BandEQ : public Plugin | |||
| { | |||
| public: | |||
| enum Parameters | |||
| { | |||
| paramLow = 0, | |||
| paramMid, | |||
| paramHigh, | |||
| paramMaster, | |||
| paramLowMidFreq, | |||
| paramMidHighFreq, | |||
| paramCount | |||
| }; | |||
| DistrhoPlugin3BandEQ(); | |||
| ~DistrhoPlugin3BandEQ(); | |||
| // --------------------------------------------- | |||
| protected: | |||
| // Information | |||
| const char* d_label() const | |||
| { | |||
| return "3BandEQ"; | |||
| } | |||
| const char* d_maker() const | |||
| { | |||
| return "DISTRHO"; | |||
| } | |||
| const char* d_license() const | |||
| { | |||
| return "LGPL"; | |||
| } | |||
| uint32_t d_version() const | |||
| { | |||
| return 0x1000; | |||
| } | |||
| long d_uniqueId() const | |||
| { | |||
| return d_cconst('D', '3', 'E', 'Q'); | |||
| } | |||
| // Init | |||
| void d_initParameter(uint32_t index, Parameter& parameter); | |||
| void d_initProgramName(uint32_t index, d_string& programName); | |||
| // Internal data | |||
| float d_parameterValue(uint32_t index); | |||
| void d_setParameterValue(uint32_t index, float value); | |||
| void d_setProgram(uint32_t index); | |||
| // Process | |||
| void d_activate(); | |||
| void d_deactivate(); | |||
| void d_run(float** inputs, float** outputs, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents); | |||
| // --------------------------------------------- | |||
| #ifdef QTCREATOR_TEST | |||
| void d_initStateKey(uint32_t, d_string&) {} | |||
| void d_setState(const char*, const char*) {} | |||
| #endif | |||
| private: | |||
| float fLow, fMid, fHigh, fMaster, fLowMidFreq, fMidHighFreq; | |||
| float lowVol, midVol, highVol, outVol; | |||
| float freqLP, freqHP; | |||
| float xLP, a0LP, b1LP; | |||
| float xHP, a0HP, b1HP; | |||
| float out1LP, out2LP, out1HP, out2HP; | |||
| float tmp1LP, tmp2LP, tmp1HP, tmp2HP; | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // __DISTRHO_PLUGIN_3BANDEQ_HPP__ | |||
| @@ -0,0 +1,45 @@ | |||
| /* | |||
| * DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||
| * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_PLUGIN_INFO_H__ | |||
| #define __DISTRHO_PLUGIN_INFO_H__ | |||
| #define DISTRHO_PLUGIN_NAME "3 Band EQ" | |||
| #define DISTRHO_PLUGIN_HAS_UI 1 | |||
| #define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 0 | |||
| #define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandEQ" | |||
| #ifdef QTCREATOR_TEST | |||
| // TESTING | |||
| #include "3bandeq/DistrhoPluginInfo.h" | |||
| # undef DISTRHO_PLUGIN_IS_SYNTH | |||
| # undef DISTRHO_PLUGIN_WANT_LATENCY | |||
| # undef DISTRHO_PLUGIN_WANT_STATE | |||
| # define DISTRHO_PLUGIN_IS_SYNTH 1 | |||
| # define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
| # define DISTRHO_PLUGIN_WANT_STATE 1 | |||
| #endif | |||
| #endif // __DISTRHO_PLUGIN_INFO_H__ | |||
| @@ -0,0 +1,229 @@ | |||
| /* | |||
| * DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #include "DistrhoUI3BandEQ.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| DistrhoUI3BandEQ::DistrhoUI3BandEQ() | |||
| : OpenGLExtUI() | |||
| { | |||
| // background | |||
| Image bgImage(DistrhoArtwork3BandEQ::backgroundData, DistrhoArtwork3BandEQ::backgroundWidth, DistrhoArtwork3BandEQ::backgroundHeight, GL_BGR); | |||
| setBackgroundImage(bgImage); | |||
| // sliders | |||
| Image sliderImage(DistrhoArtwork3BandEQ::sliderData, DistrhoArtwork3BandEQ::sliderWidth, DistrhoArtwork3BandEQ::sliderHeight); | |||
| Point sliderPosStart(57, 43); | |||
| Point sliderPosEnd(57, 43 + 160); | |||
| // slider Low | |||
| sliderLow = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderLow->setRange(-24.0f, 24.0f); | |||
| sliderLow->setValue(0.0f); | |||
| addImageSlider(sliderLow); | |||
| // slider Mid | |||
| sliderPosStart.setX(120); | |||
| sliderPosEnd.setX(120); | |||
| sliderMid = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderMid->setRange(-24.0f, 24.0f); | |||
| sliderMid->setValue(0.0f); | |||
| addImageSlider(sliderMid); | |||
| // slider High | |||
| sliderPosStart.setX(183); | |||
| sliderPosEnd.setX(183); | |||
| sliderHigh = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderHigh->setRange(-24.0f, 24.0f); | |||
| sliderHigh->setValue(0.0f); | |||
| addImageSlider(sliderHigh); | |||
| // slider Master | |||
| sliderPosStart.setX(287); | |||
| sliderPosEnd.setX(287); | |||
| sliderMaster = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderMaster->setRange(-24.0f, 24.0f); | |||
| sliderMaster->setValue(0.0f); | |||
| addImageSlider(sliderMaster); | |||
| // knobs | |||
| Image knobImage(DistrhoArtwork3BandEQ::knobData, DistrhoArtwork3BandEQ::knobWidth, DistrhoArtwork3BandEQ::knobHeight); | |||
| Point knobPos(66, 270); | |||
| // knob Low-Mid | |||
| knobLowMid = new ImageKnob(knobImage, knobPos); | |||
| knobLowMid->setRange(0.0f, 1000.0f); | |||
| knobLowMid->setValue(220.0f); | |||
| addImageKnob(knobLowMid); | |||
| // knob Mid-High | |||
| knobPos.setX(160); | |||
| knobMidHigh = new ImageKnob(knobImage, knobPos); | |||
| knobMidHigh->setRange(1000.0f, 20000.0f); | |||
| knobMidHigh->setValue(2000.0f); | |||
| addImageKnob(knobMidHigh); | |||
| // about button | |||
| Image aboutImageNormal(DistrhoArtwork3BandEQ::aboutButtonNormalData, DistrhoArtwork3BandEQ::aboutButtonNormalWidth, DistrhoArtwork3BandEQ::aboutButtonNormalHeight); | |||
| Image aboutImageHover(DistrhoArtwork3BandEQ::aboutButtonHoverData, DistrhoArtwork3BandEQ::aboutButtonHoverWidth, DistrhoArtwork3BandEQ::aboutButtonHoverHeight); | |||
| Point aboutPos(264, 300); | |||
| buttonAbout = new ImageButton(aboutImageNormal, aboutImageHover, aboutImageHover, aboutPos); | |||
| addImageButton(buttonAbout); | |||
| } | |||
| DistrhoUI3BandEQ::~DistrhoUI3BandEQ() | |||
| { | |||
| delete sliderLow; | |||
| delete sliderMid; | |||
| delete sliderHigh; | |||
| delete sliderMaster; | |||
| delete knobLowMid; | |||
| delete knobMidHigh; | |||
| delete buttonAbout; | |||
| } | |||
| // ------------------------------------------------- | |||
| // DSP Callbacks | |||
| void DistrhoUI3BandEQ::d_parameterChanged(uint32_t index, float value) | |||
| { | |||
| switch (index) | |||
| { | |||
| case DistrhoPlugin3BandEQ::paramLow: | |||
| sliderLow->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandEQ::paramMid: | |||
| sliderMid->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandEQ::paramHigh: | |||
| sliderHigh->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandEQ::paramMaster: | |||
| sliderMaster->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandEQ::paramLowMidFreq: | |||
| knobLowMid->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandEQ::paramMidHighFreq: | |||
| knobMidHigh->setValue(value); | |||
| break; | |||
| } | |||
| d_uiRepaint(); | |||
| } | |||
| void DistrhoUI3BandEQ::d_programChanged(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| sliderLow->setValue(0.0f); | |||
| sliderMid->setValue(0.0f); | |||
| sliderHigh->setValue(0.0f); | |||
| sliderMaster->setValue(0.0f); | |||
| knobLowMid->setValue(220.0f); | |||
| knobMidHigh->setValue(2000.0f); | |||
| d_uiRepaint(); | |||
| } | |||
| // ------------------------------------------------- | |||
| // Extended Callbacks | |||
| void DistrhoUI3BandEQ::imageButtonClicked(ImageButton* button) | |||
| { | |||
| if (button != buttonAbout) | |||
| return; | |||
| Image imageAbout(DistrhoArtwork3BandEQ::aboutData, DistrhoArtwork3BandEQ::aboutWidth, DistrhoArtwork3BandEQ::aboutHeight, GL_BGRA); | |||
| showImageModalDialog(imageAbout, "About"); | |||
| } | |||
| void DistrhoUI3BandEQ::imageKnobDragStarted(ImageKnob* knob) | |||
| { | |||
| if (knob == knobLowMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramLowMidFreq, true); | |||
| else if (knob == knobMidHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramMidHighFreq, true); | |||
| } | |||
| void DistrhoUI3BandEQ::imageKnobDragFinished(ImageKnob* knob) | |||
| { | |||
| if (knob == knobLowMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramLowMidFreq, false); | |||
| else if (knob == knobMidHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramMidHighFreq, false); | |||
| } | |||
| void DistrhoUI3BandEQ::imageKnobValueChanged(ImageKnob* knob, float value) | |||
| { | |||
| if (knob == knobLowMid) | |||
| d_setParameterValue(DistrhoPlugin3BandEQ::paramLowMidFreq, value); | |||
| else if (knob == knobMidHigh) | |||
| d_setParameterValue(DistrhoPlugin3BandEQ::paramMidHighFreq, value); | |||
| } | |||
| void DistrhoUI3BandEQ::imageSliderDragStarted(ImageSlider* slider) | |||
| { | |||
| if (slider == sliderLow) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramLow, true); | |||
| else if (slider == sliderMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramMid, true); | |||
| else if (slider == sliderHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramHigh, true); | |||
| else if (slider == sliderMaster) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramMaster, true); | |||
| } | |||
| void DistrhoUI3BandEQ::imageSliderDragFinished(ImageSlider* slider) | |||
| { | |||
| if (slider == sliderLow) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramLow, false); | |||
| else if (slider == sliderMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramMid, false); | |||
| else if (slider == sliderHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramHigh, false); | |||
| else if (slider == sliderMaster) | |||
| d_uiEditParameter(DistrhoPlugin3BandEQ::paramMaster, false); | |||
| } | |||
| void DistrhoUI3BandEQ::imageSliderValueChanged(ImageSlider* slider, float value) | |||
| { | |||
| if (slider == sliderLow) | |||
| d_setParameterValue(DistrhoPlugin3BandEQ::paramLow, value); | |||
| else if (slider == sliderMid) | |||
| d_setParameterValue(DistrhoPlugin3BandEQ::paramMid, value); | |||
| else if (slider == sliderHigh) | |||
| d_setParameterValue(DistrhoPlugin3BandEQ::paramHigh, value); | |||
| else if (slider == sliderMaster) | |||
| d_setParameterValue(DistrhoPlugin3BandEQ::paramMaster, value); | |||
| } | |||
| // ------------------------------------------------- | |||
| UI* createUI() | |||
| { | |||
| return new DistrhoUI3BandEQ(); | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| * DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_UI_3BANDEQ_HPP__ | |||
| #define __DISTRHO_UI_3BANDEQ_HPP__ | |||
| #include "DistrhoUIOpenGLExt.h" | |||
| #include "DistrhoArtwork3BandEQ.hpp" | |||
| #include "DistrhoPlugin3BandEQ.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| class DistrhoUI3BandEQ : public OpenGLExtUI | |||
| { | |||
| public: | |||
| DistrhoUI3BandEQ(); | |||
| ~DistrhoUI3BandEQ(); | |||
| // --------------------------------------------- | |||
| protected: | |||
| // Information | |||
| unsigned int d_width() | |||
| { | |||
| return DistrhoArtwork3BandEQ::backgroundWidth; | |||
| } | |||
| unsigned int d_height() | |||
| { | |||
| return DistrhoArtwork3BandEQ::backgroundHeight; | |||
| } | |||
| // DSP Callbacks | |||
| void d_parameterChanged(uint32_t index, float value); | |||
| void d_programChanged(uint32_t index); | |||
| // Extended Callbacks | |||
| void imageButtonClicked(ImageButton* button); | |||
| void imageKnobDragStarted(ImageKnob* knob); | |||
| void imageKnobDragFinished(ImageKnob* knob); | |||
| void imageKnobValueChanged(ImageKnob* knob, float value); | |||
| void imageSliderDragStarted(ImageSlider* slider); | |||
| void imageSliderDragFinished(ImageSlider* slider); | |||
| void imageSliderValueChanged(ImageSlider* slider, float value); | |||
| #ifdef QTCREATOR_TEST | |||
| void d_stateChanged(const char*, const char*) {} | |||
| #endif | |||
| private: | |||
| ImageSlider* sliderLow; | |||
| ImageSlider* sliderMid; | |||
| ImageSlider* sliderHigh; | |||
| ImageSlider* sliderMaster; | |||
| ImageKnob* knobLowMid; | |||
| ImageKnob* knobMidHigh; | |||
| ImageButton* buttonAbout; | |||
| }; | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // __DISTRHO_UI_3BANDEQ_HPP__ | |||
| @@ -0,0 +1,40 @@ | |||
| /* (Auto-generated binary data file). */ | |||
| #ifndef BINARY_DISTRHOARTWORK3BANDSPLITTER_HPP | |||
| #define BINARY_DISTRHOARTWORK3BANDSPLITTER_HPP | |||
| namespace DistrhoArtwork3BandSplitter | |||
| { | |||
| extern const char* aboutData; | |||
| const unsigned int aboutDataSize = 230280; | |||
| const unsigned int aboutWidth = 303; | |||
| const unsigned int aboutHeight = 190; | |||
| extern const char* aboutButtonHoverData; | |||
| const unsigned int aboutButtonHoverDataSize = 11600; | |||
| const unsigned int aboutButtonHoverWidth = 100; | |||
| const unsigned int aboutButtonHoverHeight = 29; | |||
| extern const char* aboutButtonNormalData; | |||
| const unsigned int aboutButtonNormalDataSize = 11600; | |||
| const unsigned int aboutButtonNormalWidth = 100; | |||
| const unsigned int aboutButtonNormalHeight = 29; | |||
| extern const char* backgroundData; | |||
| const unsigned int backgroundDataSize = 437472; | |||
| const unsigned int backgroundWidth = 392; | |||
| const unsigned int backgroundHeight = 372; | |||
| extern const char* knobData; | |||
| const unsigned int knobDataSize = 615040; | |||
| const unsigned int knobWidth = 62; | |||
| const unsigned int knobHeight = 2480; | |||
| extern const char* sliderData; | |||
| const unsigned int sliderDataSize = 6000; | |||
| const unsigned int sliderWidth = 50; | |||
| const unsigned int sliderHeight = 30; | |||
| } | |||
| #endif // BINARY_DISTRHOARTWORK3BANDSPLITTER_HPP | |||
| @@ -0,0 +1,268 @@ | |||
| /* | |||
| * DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||
| * Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #include "DistrhoPlugin3BandSplitter.hpp" | |||
| #include <cmath> | |||
| static const float cfAMP_DB = 8.656170245f; | |||
| static const float cfDC_ADD = 1e-30f; | |||
| static const float cfPI = 3.141592654f; | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| DistrhoPlugin3BandSplitter::DistrhoPlugin3BandSplitter() | |||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | |||
| { | |||
| // set default values | |||
| d_setProgram(0); | |||
| // reset | |||
| d_deactivate(); | |||
| } | |||
| DistrhoPlugin3BandSplitter::~DistrhoPlugin3BandSplitter() | |||
| { | |||
| } | |||
| // ------------------------------------------------- | |||
| // Init | |||
| void DistrhoPlugin3BandSplitter::d_initParameter(uint32_t index, Parameter& parameter) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramLow: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Low"; | |||
| parameter.symbol = "low"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramMid: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Mid"; | |||
| parameter.symbol = "mid"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramHigh: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "High"; | |||
| parameter.symbol = "high"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramMaster: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Master"; | |||
| parameter.symbol = "master"; | |||
| parameter.unit = "dB"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -24.0f; | |||
| parameter.ranges.max = 24.0f; | |||
| break; | |||
| case paramLowMidFreq: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Low-Mid Freq"; | |||
| parameter.symbol = "low_mid"; | |||
| parameter.unit = "Hz"; | |||
| parameter.ranges.def = 440.0f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 1000.0f; | |||
| break; | |||
| case paramMidHighFreq: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Mid-High Freq"; | |||
| parameter.symbol = "mid_high"; | |||
| parameter.unit = "Hz"; | |||
| parameter.ranges.def = 1000.0f; | |||
| parameter.ranges.min = 1000.0f; | |||
| parameter.ranges.max = 20000.0f; | |||
| break; | |||
| } | |||
| } | |||
| void DistrhoPlugin3BandSplitter::d_initProgramName(uint32_t index, d_string& programName) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| programName = "Default"; | |||
| } | |||
| // ------------------------------------------------- | |||
| // Internal data | |||
| float DistrhoPlugin3BandSplitter::d_parameterValue(uint32_t index) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramLow: | |||
| return fLow; | |||
| case paramMid: | |||
| return fMid; | |||
| case paramHigh: | |||
| return fHigh; | |||
| case paramMaster: | |||
| return fMaster; | |||
| case paramLowMidFreq: | |||
| return fLowMidFreq; | |||
| case paramMidHighFreq: | |||
| return fMidHighFreq; | |||
| default: | |||
| return 0.0f; | |||
| } | |||
| } | |||
| void DistrhoPlugin3BandSplitter::d_setParameterValue(uint32_t index, float value) | |||
| { | |||
| if (d_sampleRate() <= 0.0) | |||
| return; | |||
| switch (index) | |||
| { | |||
| case paramLow: | |||
| fLow = value; | |||
| lowVol = std::exp( (fLow/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramMid: | |||
| fMid = value; | |||
| midVol = std::exp( (fMid/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramHigh: | |||
| fHigh = value; | |||
| highVol = std::exp( (fHigh/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramMaster: | |||
| fMaster = value; | |||
| outVol = std::exp( (fMaster/48.0f) * 48 / cfAMP_DB); | |||
| break; | |||
| case paramLowMidFreq: | |||
| fLowMidFreq = std::min<float>(value, fMidHighFreq); | |||
| freqLP = fLowMidFreq; //fLowMidFreq * (fLowMidFreq / 24000.0f) * (fLowMidFreq / 24000.0f); | |||
| xLP = std::exp(-2.0 * cfPI * freqLP / d_sampleRate()); | |||
| a0LP = 1.0 - xLP; | |||
| b1LP = -xLP; | |||
| break; | |||
| case paramMidHighFreq: | |||
| fMidHighFreq = std::max<float>(value, fLowMidFreq); | |||
| freqHP = fMidHighFreq; //fMidHighFreq * (fMidHighFreq / 24000.0f) * (fMidHighFreq / 24000.0f); | |||
| xHP = std::exp(-2.0 * cfPI * freqHP / d_sampleRate()); | |||
| a0HP = 1.0 - xHP; | |||
| b1HP = -xHP; | |||
| break; | |||
| } | |||
| } | |||
| void DistrhoPlugin3BandSplitter::d_setProgram(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| fLow = 0.0f; | |||
| fMid = 0.0f; | |||
| fHigh = 0.0f; | |||
| fMaster = 0.0f; | |||
| fLowMidFreq = 220.0f; | |||
| fMidHighFreq = 2000.0f; | |||
| // Internal stuff | |||
| lowVol = midVol = highVol = outVol = 1.0f; | |||
| freqLP = 200.0f; | |||
| freqHP = 2000.0f; | |||
| // reset filter values | |||
| d_activate(); | |||
| } | |||
| // ------------------------------------------------- | |||
| // Process | |||
| void DistrhoPlugin3BandSplitter::d_activate() | |||
| { | |||
| xLP = exp(-2.0 * cfPI * freqLP / d_sampleRate()); | |||
| a0LP = 1.0f - xLP; | |||
| b1LP = -xLP; | |||
| xHP = exp(-2.0 * cfPI * freqHP / d_sampleRate()); | |||
| a0HP = 1.0f - xHP; | |||
| b1HP = -xHP; | |||
| } | |||
| void DistrhoPlugin3BandSplitter::d_deactivate() | |||
| { | |||
| out1LP = out2LP = out1HP = out2HP = 0.0f; | |||
| tmp1LP = tmp2LP = tmp1HP = tmp2HP = 0.0f; | |||
| } | |||
| void DistrhoPlugin3BandSplitter::d_run(float** inputs, float** outputs, uint32_t frames, uint32_t, const MidiEvent*) | |||
| { | |||
| const float* in1 = inputs[0]; | |||
| const float* in2 = inputs[1]; | |||
| float* out1 = outputs[0]; | |||
| float* out2 = outputs[1]; | |||
| float* out3 = outputs[2]; | |||
| float* out4 = outputs[3]; | |||
| float* out5 = outputs[4]; | |||
| float* out6 = outputs[5]; | |||
| for (uint32_t i=0; i < frames; i++) | |||
| { | |||
| tmp1LP = a0LP * in1[i] - b1LP * tmp1LP + cfDC_ADD; | |||
| tmp2LP = a0LP * in2[i] - b1LP * tmp2LP + cfDC_ADD; | |||
| out1LP = tmp1LP - cfDC_ADD; | |||
| out2LP = tmp2LP - cfDC_ADD; | |||
| tmp1HP = a0HP * in1[i] - b1HP * tmp1HP + cfDC_ADD; | |||
| tmp2HP = a0HP * in2[i] - b1HP * tmp2HP + cfDC_ADD; | |||
| out1HP = in1[i] - tmp1HP - cfDC_ADD; | |||
| out2HP = in2[i] - tmp2HP - cfDC_ADD; | |||
| out1[i] = out1LP*lowVol * outVol; | |||
| out2[i] = out2LP*lowVol * outVol; | |||
| out3[i] = (in1[i] - out1LP - out1HP)*midVol * outVol; | |||
| out4[i] = (in2[i] - out2LP - out2HP)*midVol * outVol; | |||
| out5[i] = out1HP*highVol * outVol; | |||
| out6[i] = out2HP*highVol * outVol; | |||
| } | |||
| } | |||
| // ------------------------------------------------- | |||
| Plugin* createPlugin() | |||
| { | |||
| return new DistrhoPlugin3BandSplitter(); | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,102 @@ | |||
| /* | |||
| * DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||
| * Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_PLUGIN_3BANDSPLITTER_HPP__ | |||
| #define __DISTRHO_PLUGIN_3BANDSPLITTER_HPP__ | |||
| #include "DistrhoPlugin.h" | |||
| START_NAMESPACE_DISTRHO | |||
| class DistrhoPlugin3BandSplitter : public Plugin | |||
| { | |||
| public: | |||
| enum Parameters | |||
| { | |||
| paramLow = 0, | |||
| paramMid, | |||
| paramHigh, | |||
| paramMaster, | |||
| paramLowMidFreq, | |||
| paramMidHighFreq, | |||
| paramCount | |||
| }; | |||
| DistrhoPlugin3BandSplitter(); | |||
| ~DistrhoPlugin3BandSplitter(); | |||
| // --------------------------------------------- | |||
| protected: | |||
| // Information | |||
| const char* d_label() const | |||
| { | |||
| return "3BandSplitter"; | |||
| } | |||
| const char* d_maker() const | |||
| { | |||
| return "DISTRHO"; | |||
| } | |||
| const char* d_license() const | |||
| { | |||
| return "LGPL"; | |||
| } | |||
| uint32_t d_version() const | |||
| { | |||
| return 0x1000; | |||
| } | |||
| long d_uniqueId() const | |||
| { | |||
| return d_cconst('D', '3', 'E', 'S'); | |||
| } | |||
| // Init | |||
| void d_initParameter(uint32_t index, Parameter& parameter); | |||
| void d_initProgramName(uint32_t index, d_string& programName); | |||
| // Internal data | |||
| float d_parameterValue(uint32_t index); | |||
| void d_setParameterValue(uint32_t index, float value); | |||
| void d_setProgram(uint32_t index); | |||
| // Process | |||
| void d_activate(); | |||
| void d_deactivate(); | |||
| void d_run(float** inputs, float** outputs, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents); | |||
| // --------------------------------------------- | |||
| private: | |||
| float fLow, fMid, fHigh, fMaster, fLowMidFreq, fMidHighFreq; | |||
| float lowVol, midVol, highVol, outVol; | |||
| float freqLP, freqHP; | |||
| float xLP, a0LP, b1LP; | |||
| float xHP, a0HP, b1HP; | |||
| float out1LP, out2LP, out1HP, out2HP; | |||
| float tmp1LP, tmp2LP, tmp1HP, tmp2HP; | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // __DISTRHO_PLUGIN_3BANDSPLITTER_HPP__ | |||
| @@ -0,0 +1,34 @@ | |||
| /* | |||
| * DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_PLUGIN_INFO_H__ | |||
| #define __DISTRHO_PLUGIN_INFO_H__ | |||
| #define DISTRHO_PLUGIN_NAME "3 Band Splitter" | |||
| #define DISTRHO_PLUGIN_HAS_UI 1 | |||
| #define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 6 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 0 | |||
| #define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandSplitter" | |||
| #endif // __DISTRHO_PLUGIN_INFO_H__ | |||
| @@ -0,0 +1,229 @@ | |||
| /* | |||
| * DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #include "DistrhoUI3BandSplitter.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| DistrhoUI3BandSplitter::DistrhoUI3BandSplitter() | |||
| : OpenGLExtUI() | |||
| { | |||
| // background | |||
| Image bgImage(DistrhoArtwork3BandSplitter::backgroundData, DistrhoArtwork3BandSplitter::backgroundWidth, DistrhoArtwork3BandSplitter::backgroundHeight, GL_BGR); | |||
| setBackgroundImage(bgImage); | |||
| // sliders | |||
| Image sliderImage(DistrhoArtwork3BandSplitter::sliderData, DistrhoArtwork3BandSplitter::sliderWidth, DistrhoArtwork3BandSplitter::sliderHeight); | |||
| Point sliderPosStart(57, 43); | |||
| Point sliderPosEnd(57, 43 + 160); | |||
| // slider Low | |||
| sliderLow = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderLow->setRange(-24.0f, 24.0f); | |||
| sliderLow->setValue(0.0f); | |||
| addImageSlider(sliderLow); | |||
| // slider Mid | |||
| sliderPosStart.setX(120); | |||
| sliderPosEnd.setX(120); | |||
| sliderMid = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderMid->setRange(-24.0f, 24.0f); | |||
| sliderMid->setValue(0.0f); | |||
| addImageSlider(sliderMid); | |||
| // slider High | |||
| sliderPosStart.setX(183); | |||
| sliderPosEnd.setX(183); | |||
| sliderHigh = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderHigh->setRange(-24.0f, 24.0f); | |||
| sliderHigh->setValue(0.0f); | |||
| addImageSlider(sliderHigh); | |||
| // slider Master | |||
| sliderPosStart.setX(287); | |||
| sliderPosEnd.setX(287); | |||
| sliderMaster = new ImageSlider(sliderImage, sliderPosStart, sliderPosEnd); | |||
| sliderMaster->setRange(-24.0f, 24.0f); | |||
| sliderMaster->setValue(0.0f); | |||
| addImageSlider(sliderMaster); | |||
| // knobs | |||
| Image knobImage(DistrhoArtwork3BandSplitter::knobData, DistrhoArtwork3BandSplitter::knobWidth, DistrhoArtwork3BandSplitter::knobHeight); | |||
| Point knobPos(66, 270); | |||
| // knob Low-Mid | |||
| knobLowMid = new ImageKnob(knobImage, knobPos); | |||
| knobLowMid->setRange(0.0f, 1000.0f); | |||
| knobLowMid->setValue(220.0f); | |||
| addImageKnob(knobLowMid); | |||
| // knob Mid-High | |||
| knobPos.setX(160); | |||
| knobMidHigh = new ImageKnob(knobImage, knobPos); | |||
| knobMidHigh->setRange(1000.0f, 20000.0f); | |||
| knobMidHigh->setValue(2000.0f); | |||
| addImageKnob(knobMidHigh); | |||
| // about button | |||
| Image aboutImageNormal(DistrhoArtwork3BandSplitter::aboutButtonNormalData, DistrhoArtwork3BandSplitter::aboutButtonNormalWidth, DistrhoArtwork3BandSplitter::aboutButtonNormalHeight); | |||
| Image aboutImageHover(DistrhoArtwork3BandSplitter::aboutButtonHoverData, DistrhoArtwork3BandSplitter::aboutButtonHoverWidth, DistrhoArtwork3BandSplitter::aboutButtonHoverHeight); | |||
| Point aboutPos(264, 300); | |||
| buttonAbout = new ImageButton(aboutImageNormal, aboutImageHover, aboutImageHover, aboutPos); | |||
| addImageButton(buttonAbout); | |||
| } | |||
| DistrhoUI3BandSplitter::~DistrhoUI3BandSplitter() | |||
| { | |||
| delete sliderLow; | |||
| delete sliderMid; | |||
| delete sliderHigh; | |||
| delete sliderMaster; | |||
| delete knobLowMid; | |||
| delete knobMidHigh; | |||
| delete buttonAbout; | |||
| } | |||
| // ------------------------------------------------- | |||
| // DSP Callbacks | |||
| void DistrhoUI3BandSplitter::d_parameterChanged(uint32_t index, float value) | |||
| { | |||
| switch (index) | |||
| { | |||
| case DistrhoPlugin3BandSplitter::paramLow: | |||
| sliderLow->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandSplitter::paramMid: | |||
| sliderMid->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandSplitter::paramHigh: | |||
| sliderHigh->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandSplitter::paramMaster: | |||
| sliderMaster->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandSplitter::paramLowMidFreq: | |||
| knobLowMid->setValue(value); | |||
| break; | |||
| case DistrhoPlugin3BandSplitter::paramMidHighFreq: | |||
| knobMidHigh->setValue(value); | |||
| break; | |||
| } | |||
| d_uiRepaint(); | |||
| } | |||
| void DistrhoUI3BandSplitter::d_programChanged(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| sliderLow->setValue(0.0f); | |||
| sliderMid->setValue(0.0f); | |||
| sliderHigh->setValue(0.0f); | |||
| sliderMaster->setValue(0.0f); | |||
| knobLowMid->setValue(220.0f); | |||
| knobMidHigh->setValue(2000.0f); | |||
| d_uiRepaint(); | |||
| } | |||
| // ------------------------------------------------- | |||
| // Extended Callbacks | |||
| void DistrhoUI3BandSplitter::imageButtonClicked(ImageButton* button) | |||
| { | |||
| if (button != buttonAbout) | |||
| return; | |||
| Image imageAbout(DistrhoArtwork3BandSplitter::aboutData, DistrhoArtwork3BandSplitter::aboutWidth, DistrhoArtwork3BandSplitter::aboutHeight, GL_BGRA); | |||
| showImageModalDialog(imageAbout, "About"); | |||
| } | |||
| void DistrhoUI3BandSplitter::imageKnobDragStarted(ImageKnob* knob) | |||
| { | |||
| if (knob == knobLowMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramLowMidFreq, true); | |||
| else if (knob == knobMidHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramMidHighFreq, true); | |||
| } | |||
| void DistrhoUI3BandSplitter::imageKnobDragFinished(ImageKnob* knob) | |||
| { | |||
| if (knob == knobLowMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramLowMidFreq, false); | |||
| else if (knob == knobMidHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramMidHighFreq, false); | |||
| } | |||
| void DistrhoUI3BandSplitter::imageKnobValueChanged(ImageKnob* knob, float value) | |||
| { | |||
| if (knob == knobLowMid) | |||
| d_setParameterValue(DistrhoPlugin3BandSplitter::paramLowMidFreq, value); | |||
| else if (knob == knobMidHigh) | |||
| d_setParameterValue(DistrhoPlugin3BandSplitter::paramMidHighFreq, value); | |||
| } | |||
| void DistrhoUI3BandSplitter::imageSliderDragStarted(ImageSlider* slider) | |||
| { | |||
| if (slider == sliderLow) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramLow, true); | |||
| else if (slider == sliderMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramMid, true); | |||
| else if (slider == sliderHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramHigh, true); | |||
| else if (slider == sliderMaster) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramMaster, true); | |||
| } | |||
| void DistrhoUI3BandSplitter::imageSliderDragFinished(ImageSlider* slider) | |||
| { | |||
| if (slider == sliderLow) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramLow, false); | |||
| else if (slider == sliderMid) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramMid, false); | |||
| else if (slider == sliderHigh) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramHigh, false); | |||
| else if (slider == sliderMaster) | |||
| d_uiEditParameter(DistrhoPlugin3BandSplitter::paramMaster, false); | |||
| } | |||
| void DistrhoUI3BandSplitter::imageSliderValueChanged(ImageSlider* slider, float value) | |||
| { | |||
| if (slider == sliderLow) | |||
| d_setParameterValue(DistrhoPlugin3BandSplitter::paramLow, value); | |||
| else if (slider == sliderMid) | |||
| d_setParameterValue(DistrhoPlugin3BandSplitter::paramMid, value); | |||
| else if (slider == sliderHigh) | |||
| d_setParameterValue(DistrhoPlugin3BandSplitter::paramHigh, value); | |||
| else if (slider == sliderMaster) | |||
| d_setParameterValue(DistrhoPlugin3BandSplitter::paramMaster, value); | |||
| } | |||
| // ------------------------------------------------- | |||
| UI* createUI() | |||
| { | |||
| return new DistrhoUI3BandSplitter(); | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,76 @@ | |||
| /* | |||
| * DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_UI_3BANDSPLITTER_HPP__ | |||
| #define __DISTRHO_UI_3BANDSPLITTER_HPP__ | |||
| #include "DistrhoUIOpenGLExt.h" | |||
| #include "DistrhoArtwork3BandSplitter.hpp" | |||
| #include "DistrhoPlugin3BandSplitter.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| class DistrhoUI3BandSplitter : public OpenGLExtUI | |||
| { | |||
| public: | |||
| DistrhoUI3BandSplitter(); | |||
| ~DistrhoUI3BandSplitter(); | |||
| // --------------------------------------------- | |||
| protected: | |||
| // Information | |||
| unsigned int d_width() | |||
| { | |||
| return DistrhoArtwork3BandSplitter::backgroundWidth; | |||
| } | |||
| unsigned int d_height() | |||
| { | |||
| return DistrhoArtwork3BandSplitter::backgroundHeight; | |||
| } | |||
| // DSP Callbacks | |||
| void d_parameterChanged(uint32_t index, float value); | |||
| void d_programChanged(uint32_t index); | |||
| // Extended Callbacks | |||
| void imageButtonClicked(ImageButton* button); | |||
| void imageKnobDragStarted(ImageKnob* knob); | |||
| void imageKnobDragFinished(ImageKnob* knob); | |||
| void imageKnobValueChanged(ImageKnob* knob, float value); | |||
| void imageSliderDragStarted(ImageSlider* slider); | |||
| void imageSliderDragFinished(ImageSlider* slider); | |||
| void imageSliderValueChanged(ImageSlider* slider, float value); | |||
| private: | |||
| ImageSlider* sliderLow; | |||
| ImageSlider* sliderMid; | |||
| ImageSlider* sliderHigh; | |||
| ImageSlider* sliderMaster; | |||
| ImageKnob* knobLowMid; | |||
| ImageKnob* knobMidHigh; | |||
| ImageButton* buttonAbout; | |||
| }; | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // __DISTRHO_UI_3BANDSPLITTER_HPP__ | |||
| @@ -0,0 +1,96 @@ | |||
| /* | |||
| * Carla Native Plugins | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| * 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. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_native.h" | |||
| #include <string.h> // for memcpy | |||
| static PluginHandle bypass_instantiate(const PluginDescriptor* _this_, HostDescriptor* host) | |||
| { | |||
| // dummy, return non-NULL | |||
| return (PluginHandle)1; | |||
| // unused | |||
| (void)_this_; | |||
| (void)host; | |||
| } | |||
| static void bypass_process(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents) | |||
| { | |||
| float* in = inBuffer[0]; | |||
| float* out = outBuffer[0]; | |||
| memcpy(out, in, sizeof(float)*frames); | |||
| return; | |||
| // unused | |||
| (void)handle; | |||
| (void)midiEventCount; | |||
| (void)midiEvents; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| static const PluginDescriptor bypassDesc = { | |||
| .category = PLUGIN_CATEGORY_NONE, | |||
| .hints = 0x0, | |||
| .audioIns = 1, | |||
| .audioOuts = 1, | |||
| .midiIns = 0, | |||
| .midiOuts = 0, | |||
| .parameterIns = 0, | |||
| .parameterOuts = 0, | |||
| .name = "ByPass", | |||
| .label = "bypass", | |||
| .maker = "falkTX", | |||
| .copyright = "GNU GPL v2+", | |||
| .instantiate = bypass_instantiate, | |||
| .get_parameter_count = NULL, | |||
| .get_parameter_info = NULL, | |||
| .get_parameter_value = NULL, | |||
| .get_parameter_text = NULL, | |||
| .get_midi_program_count = NULL, | |||
| .get_midi_program_info = NULL, | |||
| .set_parameter_value = NULL, | |||
| .set_midi_program = NULL, | |||
| .set_custom_data = NULL, | |||
| .ui_show = NULL, | |||
| .ui_idle = NULL, | |||
| .ui_set_parameter_value = NULL, | |||
| .ui_set_midi_program = NULL, | |||
| .ui_set_custom_data = NULL, | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .cleanup = NULL, | |||
| .process = bypass_process | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| void carla_register_native_plugin_bypass() | |||
| { | |||
| carla_register_native_plugin(&bypassDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,58 @@ | |||
| /* | |||
| * Carla Native Plugins | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| * 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. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_native.hpp" | |||
| // Plugin Code | |||
| #include "3bandeq/DistrhoArtwork3BandEQ.cpp" | |||
| #include "3bandeq/DistrhoPlugin3BandEQ.cpp" | |||
| #include "3bandeq/DistrhoUI3BandEQ.cpp" | |||
| // Carla DISTRHO Plugin | |||
| #include "distrho/DistrhoPluginCarla.cpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| static PluginDescriptor tBandEqDesc = { | |||
| /* category */ ::PLUGIN_CATEGORY_EQ, | |||
| /* hints */ ::PLUGIN_IS_RTSAFE | ::PLUGIN_HAS_GUI, | |||
| /* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||
| /* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||
| /* midiIns */ 0, | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ DistrhoPlugin3BandEQ::paramCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ DISTRHO_PLUGIN_NAME, | |||
| /* label */ "3BandEQ", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "LGPL", | |||
| PluginDescriptorFILL(PluginCarla) | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| void carla_register_native_plugin_3BandEQ() | |||
| { | |||
| USE_NAMESPACE_DISTRHO | |||
| carla_register_native_plugin(&tBandEqDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,58 @@ | |||
| /* | |||
| * Carla Native Plugins | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| * 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. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_native.hpp" | |||
| // Plugin Code | |||
| #include "3bandsplitter/DistrhoArtwork3BandSplitter.cpp" | |||
| #include "3bandsplitter/DistrhoPlugin3BandSplitter.cpp" | |||
| #include "3bandsplitter/DistrhoUI3BandSplitter.cpp" | |||
| // Carla DISTRHO Plugin | |||
| #include "distrho/DistrhoPluginCarla.cpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| static PluginDescriptor tBandSplitterDesc = { | |||
| /* category */ ::PLUGIN_CATEGORY_EQ, | |||
| /* hints */ ::PLUGIN_HAS_GUI, | |||
| /* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||
| /* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||
| /* midiIns */ 0, | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ DistrhoPlugin3BandSplitter::paramCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ DISTRHO_PLUGIN_NAME, | |||
| /* label */ "3BandSplitter", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "LGPL", | |||
| PluginDescriptorFILL(PluginCarla) | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| void carla_register_native_plugin_3BandSplitter() | |||
| { | |||
| USE_NAMESPACE_DISTRHO | |||
| carla_register_native_plugin(&tBandSplitterDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,58 @@ | |||
| /* | |||
| * Carla Native Plugins | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| * 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. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_native.hpp" | |||
| // Plugin Code | |||
| #include "pingpongpan/DistrhoArtworkPingPongPan.cpp" | |||
| #include "pingpongpan/DistrhoPluginPingPongPan.cpp" | |||
| #include "pingpongpan/DistrhoUIPingPongPan.cpp" | |||
| // Carla DISTRHO Plugin | |||
| #include "distrho/DistrhoPluginCarla.cpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| static PluginDescriptor tBandEqDesc = { | |||
| /* category */ ::PLUGIN_CATEGORY_UTILITY, | |||
| /* hints */ ::PLUGIN_HAS_GUI, | |||
| /* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||
| /* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||
| /* midiIns */ 0, | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ DistrhoPluginPingPongPan::paramCount, | |||
| /* paramOuts */ 0, | |||
| /* name */ DISTRHO_PLUGIN_NAME, | |||
| /* label */ "PingPongPan", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "LGPL", | |||
| PluginDescriptorFILL(PluginCarla) | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| void carla_register_native_plugin_PingPongPan() | |||
| { | |||
| USE_NAMESPACE_DISTRHO | |||
| carla_register_native_plugin(&tBandEqDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,444 @@ | |||
| /* | |||
| * DISTHRO Plugin Toolkit (DPT) | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@gmail.com> | |||
| * | |||
| * 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 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. | |||
| * | |||
| * For a full copy of the license see the GPL.txt file | |||
| */ | |||
| #include "carla_native.hpp" | |||
| #include <QtGui/QDialog> | |||
| #include "DistrhoPluginMain.cpp" | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| # include "DistrhoUIMain.cpp" | |||
| #endif | |||
| // ------------------------------------------------- | |||
| START_NAMESPACE_DISTRHO | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| // ----------------------------------------------------------------------- | |||
| // Carla UI | |||
| class UICarla : public QDialog | |||
| { | |||
| public: | |||
| UICarla(const HostDescriptor* const host, PluginInternal* const plugin) | |||
| : QDialog(nullptr), | |||
| m_host(host), | |||
| m_plugin(plugin), | |||
| ui(this, realWinId(), setParameterCallback, setStateCallback, uiEditParameterCallback, uiSendNoteCallback, uiResizeCallback) | |||
| { | |||
| setFixedSize(ui.getWidth(), ui.getHeight()); | |||
| setWindowTitle("TEST GUI"); | |||
| } | |||
| ~UICarla() | |||
| { | |||
| } | |||
| intptr_t realWinId() const | |||
| { | |||
| WId wId = winId(); | |||
| #if DISTRHO_OS_WINDOWS | |||
| return (intptr_t)static_cast<HWND>(wId); | |||
| #else | |||
| return wId; | |||
| #endif | |||
| } | |||
| // --------------------------------------------- | |||
| void carla_show(const bool yesNo) | |||
| { | |||
| setVisible(yesNo); | |||
| } | |||
| void carla_idle() | |||
| { | |||
| ui.idle(); | |||
| } | |||
| void carla_setParameterValue(const uint32_t index, const float value) | |||
| { | |||
| ui.parameterChanged(index, value); | |||
| } | |||
| # if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| void carla_setMidiProgram(const uint32_t realProgram) | |||
| { | |||
| ui.programChanged(realProgram); | |||
| } | |||
| # endif | |||
| # if DISTRHO_PLUGIN_WANT_STATE | |||
| void carla_setCustomData(const char* const key, const char* const value) | |||
| { | |||
| ui.stateChanged(key, value); | |||
| } | |||
| # endif | |||
| // --------------------------------------------- | |||
| protected: | |||
| void setParameterValue(uint32_t index, float value) | |||
| { | |||
| m_host->ui_parameter_changed(m_host->handle, index, value); | |||
| } | |||
| # if DISTRHO_PLUGIN_WANT_STATE | |||
| void setState(const char* key, const char* value) | |||
| { | |||
| m_host->ui_custom_data_changed(m_host->handle, key, value); | |||
| } | |||
| # endif | |||
| void uiEditParameter(uint32_t, bool) | |||
| { | |||
| // TODO | |||
| } | |||
| # if DISTRHO_PLUGIN_IS_SYNTH | |||
| void uiSendNote(bool, uint8_t, uint8_t, uint8_t) | |||
| { | |||
| // TODO | |||
| } | |||
| # endif | |||
| void uiResize(unsigned int width, unsigned int height) | |||
| { | |||
| setFixedSize(width, height); | |||
| } | |||
| void closeEvent(QCloseEvent* event) | |||
| { | |||
| m_host->ui_closed(m_host->handle); | |||
| QDialog::closeEvent(event); | |||
| } | |||
| private: | |||
| // Plugin stuff | |||
| const HostDescriptor* const m_host; | |||
| PluginInternal* const m_plugin; | |||
| // UI | |||
| UIInternal ui; | |||
| // --------------------------------------------- | |||
| // Callbacks | |||
| static void setParameterCallback(void* ptr, uint32_t rindex, float value) | |||
| { | |||
| UICarla* _this_ = (UICarla*)ptr; | |||
| CARLA_ASSERT(_this_); | |||
| _this_->setParameterValue(rindex, value); | |||
| } | |||
| static void setStateCallback(void* ptr, const char* key, const char* value) | |||
| { | |||
| # if DISTRHO_PLUGIN_WANT_STATE | |||
| UICarla* _this_ = (UICarla*)ptr; | |||
| CARLA_ASSERT(_this_); | |||
| _this_->setState(key, value); | |||
| # else | |||
| Q_UNUSED(ptr); | |||
| Q_UNUSED(key); | |||
| Q_UNUSED(value); | |||
| # endif | |||
| } | |||
| static void uiEditParameterCallback(void* ptr, uint32_t index, bool started) | |||
| { | |||
| UICarla* _this_ = (UICarla*)ptr; | |||
| CARLA_ASSERT(_this_); | |||
| _this_->uiEditParameter(index, started); | |||
| } | |||
| static void uiSendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
| { | |||
| # if DISTRHO_PLUGIN_IS_SYNTH | |||
| UICarla* _this_ = (UICarla*)ptr; | |||
| CARLA_ASSERT(_this_); | |||
| _this_->uiSendNote(onOff, channel, note, velocity); | |||
| # else | |||
| Q_UNUSED(ptr); | |||
| Q_UNUSED(onOff); | |||
| Q_UNUSED(channel); | |||
| Q_UNUSED(note); | |||
| Q_UNUSED(velocity); | |||
| # endif | |||
| } | |||
| static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) | |||
| { | |||
| UICarla* _this_ = (UICarla*)ptr; | |||
| CARLA_ASSERT(_this_); | |||
| _this_->uiResize(width, height); | |||
| } | |||
| }; | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Plugin | |||
| class PluginCarla : public PluginDescriptorClass | |||
| { | |||
| public: | |||
| PluginCarla(const HostDescriptor* const host) | |||
| : PluginDescriptorClass(host) | |||
| { | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| uiPtr = nullptr; | |||
| #endif | |||
| } | |||
| ~PluginCarla() | |||
| { | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| if (uiPtr) | |||
| delete uiPtr; | |||
| #endif | |||
| } | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin parameter calls | |||
| uint32_t getParameterCount() | |||
| { | |||
| return plugin.parameterCount(); | |||
| } | |||
| const ::Parameter* getParameterInfo(const uint32_t index) | |||
| { | |||
| static ::Parameter param; | |||
| // reset | |||
| param.hints = ::PARAMETER_IS_ENABLED; | |||
| { | |||
| const uint32_t paramHints = plugin.parameterHints(index); | |||
| if (paramHints & PARAMETER_IS_AUTOMABLE) | |||
| param.hints |= ::PARAMETER_IS_AUTOMABLE; | |||
| if (paramHints & PARAMETER_IS_BOOLEAN) | |||
| param.hints |= ::PARAMETER_IS_BOOLEAN; | |||
| if (paramHints & PARAMETER_IS_INTEGER) | |||
| param.hints |= ::PARAMETER_IS_INTEGER; | |||
| if (paramHints & PARAMETER_IS_LOGARITHMIC) | |||
| param.hints |= ::PARAMETER_IS_LOGARITHMIC; | |||
| if (paramHints & PARAMETER_IS_OUTPUT) | |||
| param.hints |= ::PARAMETER_IS_OUTPUT; | |||
| } | |||
| param.name = plugin.parameterName(index); | |||
| param.unit = plugin.parameterUnit(index); | |||
| { | |||
| const ParameterRanges& ranges(plugin.parameterRanges(index)); | |||
| param.ranges.def = ranges.def; | |||
| param.ranges.min = ranges.min; | |||
| param.ranges.max = ranges.max; | |||
| param.ranges.step = ranges.step; | |||
| param.ranges.stepSmall = ranges.stepSmall; | |||
| param.ranges.stepLarge = ranges.stepLarge; | |||
| } | |||
| param.scalePointCount = 0; | |||
| param.scalePoints = nullptr; | |||
| return ¶m; | |||
| } | |||
| float getParameterValue(const uint32_t index) | |||
| { | |||
| return plugin.parameterValue(index); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin midi-program calls | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| virtual uint32_t getMidiProgramCount() | |||
| { | |||
| return plugin.programCount(); | |||
| } | |||
| virtual const ::MidiProgram* getMidiProgramInfo(const uint32_t index) | |||
| { | |||
| static ::MidiProgram midiProgram; | |||
| midiProgram.bank = index / 128; | |||
| midiProgram.program = index % 128; | |||
| midiProgram.name = plugin.programName(index); | |||
| return &midiProgram; | |||
| } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) | |||
| { | |||
| plugin.setParameterValue(index, value); | |||
| } | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| void setMidiProgram(const uint32_t bank, const uint32_t program) | |||
| { | |||
| const uint32_t realProgram = bank * 128 + program; | |||
| if (realProgram >= plugin.programCount()) | |||
| return; | |||
| plugin.setProgram(realProgram); | |||
| } | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| void setCustomData(const char* const key, const char* const value) | |||
| { | |||
| plugin.setState(key, value); | |||
| } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| // Plugin UI calls | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| void uiShow(const bool show) | |||
| { | |||
| if (show) | |||
| createUiIfNeeded(); | |||
| if (uiPtr) | |||
| uiPtr->carla_show(show); | |||
| } | |||
| void uiIdle() | |||
| { | |||
| if (uiPtr) | |||
| uiPtr->carla_idle(); | |||
| } | |||
| void uiSetParameterValue(const uint32_t index, const float value) | |||
| { | |||
| if (uiPtr) | |||
| uiPtr->carla_setParameterValue(index, value); | |||
| } | |||
| # if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| void uiSetMidiProgram(const uint32_t bank, const uint32_t program) | |||
| { | |||
| uint32_t realProgram = bank * 128 + program; | |||
| if (uiPtr) | |||
| uiPtr->carla_setMidiProgram(realProgram); | |||
| } | |||
| # endif | |||
| # if DISTRHO_PLUGIN_WANT_STATE | |||
| void uiSetCustomData(const char* const key, const char* const value) | |||
| { | |||
| if (uiPtr) | |||
| uiPtr->carla_setCustomData(key, value); | |||
| } | |||
| # endif | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void activate() | |||
| { | |||
| plugin.activate(); | |||
| } | |||
| void deactivate() | |||
| { | |||
| plugin.deactivate(); | |||
| } | |||
| #if DISTRHO_PLUGIN_IS_SYNTH | |||
| void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const ::MidiEvent* const midiEvents) | |||
| { | |||
| for (uint32_t i=0; i < midiEventCount && i < MAX_MIDI_EVENTS; i++) | |||
| { | |||
| const ::MidiEvent* midiEvent = &midiEvents[i]; | |||
| MidiEvent* realEvent = &realMidiEvents[i]; | |||
| realEvent->buffer[0] = midiEvent->data[0]; | |||
| realEvent->buffer[1] = midiEvent->data[1]; | |||
| realEvent->buffer[2] = midiEvent->data[2]; | |||
| realEvent->frame = midiEvent->time; | |||
| } | |||
| plugin.run(inBuffer, outBuffer, frames, midiEventCount, realMidiEvents); | |||
| } | |||
| #else | |||
| void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t, const ::MidiEvent* const) | |||
| { | |||
| plugin.run(inBuffer, outBuffer, frames, 0, nullptr); | |||
| } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| PluginInternal plugin; | |||
| #if DISTRHO_PLUGIN_IS_SYNTH | |||
| MidiEvent realMidiEvents[MAX_MIDI_EVENTS]; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| // UI | |||
| UICarla* uiPtr; | |||
| void createUiIfNeeded() | |||
| { | |||
| if (! uiPtr) | |||
| { | |||
| d_lastUiSampleRate = getSampleRate(); | |||
| uiPtr = new UICarla(getHostHandle(), &plugin); | |||
| } | |||
| } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| public: | |||
| static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host) | |||
| { | |||
| d_lastBufferSize = host->get_buffer_size(host->handle); | |||
| d_lastSampleRate = host->get_sample_rate(host->handle); | |||
| return new PluginCarla(host); | |||
| } | |||
| static void _cleanup(PluginHandle handle) | |||
| { | |||
| delete (PluginCarla*)handle; | |||
| } | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,94 @@ | |||
| /* | |||
| * Carla Native Plugins | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| * 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. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_native.hpp" | |||
| #include <cstring> | |||
| class MidiSplitPlugin : public PluginDescriptorClass | |||
| { | |||
| public: | |||
| MidiSplitPlugin(const HostDescriptor* const host) | |||
| : PluginDescriptorClass(host) | |||
| { | |||
| } | |||
| ~MidiSplitPlugin() | |||
| { | |||
| } | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void process(float**, float**, const uint32_t, const uint32_t midiEventCount, const MidiEvent* const midiEvents) | |||
| { | |||
| for (uint32_t i=0; i < midiEventCount; i++) | |||
| { | |||
| memcpy(&m_midiEvent, &midiEvents[i], sizeof(MidiEvent)); | |||
| const uint8_t status = m_midiEvent.data[0] & 0xF0; | |||
| const uint8_t channel = status & 0x0F; | |||
| CARLA_ASSERT(channel < 16); | |||
| if (channel >= 16) | |||
| continue; | |||
| m_midiEvent.port = channel; | |||
| m_midiEvent.data[0] = status; | |||
| writeMidiEvent(&m_midiEvent); | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| MidiEvent m_midiEvent; | |||
| PluginDescriptorClassEND(MidiSplitPlugin) | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSplitPlugin) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| static const PluginDescriptor midiSplitDesc = { | |||
| /* category */ PLUGIN_CATEGORY_UTILITY, | |||
| /* hints */ PLUGIN_IS_RTSAFE, | |||
| /* audioIns */ 0, | |||
| /* audioOuts */ 0, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 16, | |||
| /* paramIns */ 0, | |||
| /* paramOuts */ 0, | |||
| /* name */ "MIDI Split", | |||
| /* label */ "midiSplit", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| PluginDescriptorFILL(MidiSplitPlugin) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| void carla_register_native_plugin_midiSplit() | |||
| { | |||
| carla_register_native_plugin(&midiSplitDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,35 @@ | |||
| /* (Auto-generated binary data file). */ | |||
| #ifndef BINARY_DISTRHOARTWORKPINGPONGPAN_HPP | |||
| #define BINARY_DISTRHOARTWORKPINGPONGPAN_HPP | |||
| namespace DistrhoArtworkPingPongPan | |||
| { | |||
| extern const char* aboutData; | |||
| const unsigned int aboutDataSize = 230280; | |||
| const unsigned int aboutWidth = 303; | |||
| const unsigned int aboutHeight = 190; | |||
| extern const char* aboutButtonHoverData; | |||
| const unsigned int aboutButtonHoverDataSize = 9600; | |||
| const unsigned int aboutButtonHoverWidth = 96; | |||
| const unsigned int aboutButtonHoverHeight = 25; | |||
| extern const char* aboutButtonNormalData; | |||
| const unsigned int aboutButtonNormalDataSize = 9600; | |||
| const unsigned int aboutButtonNormalWidth = 96; | |||
| const unsigned int aboutButtonNormalHeight = 25; | |||
| extern const char* backgroundData; | |||
| const unsigned int backgroundDataSize = 200736; | |||
| const unsigned int backgroundWidth = 369; | |||
| const unsigned int backgroundHeight = 136; | |||
| extern const char* knobData; | |||
| const unsigned int knobDataSize = 742716; | |||
| const unsigned int knobWidth = 69; | |||
| const unsigned int knobHeight = 2691; | |||
| } | |||
| #endif // BINARY_DISTRHOARTWORKPINGPONGPAN_HPP | |||
| @@ -0,0 +1,34 @@ | |||
| /* | |||
| * DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_PLUGIN_INFO_H__ | |||
| #define __DISTRHO_PLUGIN_INFO_H__ | |||
| #define DISTRHO_PLUGIN_NAME "Ping Pong Pan" | |||
| #define DISTRHO_PLUGIN_HAS_UI 1 | |||
| #define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 0 | |||
| #define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/PingPongPan" | |||
| #endif // __DISTRHO_PLUGIN_INFO_H__ | |||
| @@ -0,0 +1,165 @@ | |||
| /* | |||
| * DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||
| * Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #include "DistrhoPluginPingPongPan.hpp" | |||
| #include <cmath> | |||
| static const float cf2PI = 6.283185307f; | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| DistrhoPluginPingPongPan::DistrhoPluginPingPongPan() | |||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | |||
| { | |||
| // set default values | |||
| d_setProgram(0); | |||
| // reset | |||
| d_deactivate(); | |||
| } | |||
| DistrhoPluginPingPongPan::~DistrhoPluginPingPongPan() | |||
| { | |||
| } | |||
| // ------------------------------------------------- | |||
| // Init | |||
| void DistrhoPluginPingPongPan::d_initParameter(uint32_t index, Parameter& parameter) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramFreq: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Frequency"; | |||
| parameter.symbol = "freq"; | |||
| parameter.ranges.def = 50.0f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 100.0f; | |||
| break; | |||
| case paramWidth: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Width"; | |||
| parameter.symbol = "with"; | |||
| parameter.unit = "%"; | |||
| parameter.ranges.def = 75.0f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 100.0f; | |||
| break; | |||
| } | |||
| } | |||
| void DistrhoPluginPingPongPan::d_initProgramName(uint32_t index, d_string& programName) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| programName = "Default"; | |||
| } | |||
| // ------------------------------------------------- | |||
| // Internal data | |||
| float DistrhoPluginPingPongPan::d_parameterValue(uint32_t index) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramFreq: | |||
| return fFreq; | |||
| case paramWidth: | |||
| return fWidth; | |||
| default: | |||
| return 0.0f; | |||
| } | |||
| } | |||
| void DistrhoPluginPingPongPan::d_setParameterValue(uint32_t index, float value) | |||
| { | |||
| if (d_sampleRate() <= 0.0) | |||
| return; | |||
| switch (index) | |||
| { | |||
| case paramFreq: | |||
| fFreq = value; | |||
| waveSpeed = (cf2PI * fFreq / 100.0f)/d_sampleRate(); | |||
| break; | |||
| case paramWidth: | |||
| fWidth = value; | |||
| break; | |||
| } | |||
| } | |||
| void DistrhoPluginPingPongPan::d_setProgram(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| fFreq = 50.0f; | |||
| fWidth = 75.0f; | |||
| // reset filter values | |||
| d_activate(); | |||
| } | |||
| // ------------------------------------------------- | |||
| // Process | |||
| void DistrhoPluginPingPongPan::d_activate() | |||
| { | |||
| waveSpeed = (cf2PI * fFreq / 100.0f)/d_sampleRate(); | |||
| } | |||
| void DistrhoPluginPingPongPan::d_deactivate() | |||
| { | |||
| wavePos = 0.0f; | |||
| } | |||
| void DistrhoPluginPingPongPan::d_run(float** inputs, float** outputs, uint32_t frames, uint32_t, const MidiEvent*) | |||
| { | |||
| const float* in1 = inputs[0]; | |||
| const float* in2 = inputs[1]; | |||
| float* out1 = outputs[0]; | |||
| float* out2 = outputs[1]; | |||
| for (uint32_t i=0; i < frames; i++) | |||
| { | |||
| pan = std::min<float>(std::max<float>(sin(wavePos) * (fWidth/100.0f), -1.0f), 1.0f); | |||
| if ((wavePos += waveSpeed) >= cf2PI) | |||
| wavePos -= cf2PI; | |||
| out1[i] = in1[i] * (pan > 0.0f ? 1.0f-pan : 1.0f); | |||
| out2[i] = in2[i] * (pan < 0.0f ? 1.0f+pan : 1.0f); | |||
| } | |||
| } | |||
| // ------------------------------------------------- | |||
| Plugin* createPlugin() | |||
| { | |||
| return new DistrhoPluginPingPongPan(); | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,93 @@ | |||
| /* | |||
| * DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||
| * Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_PLUGIN_PINGPONGPAN_HPP__ | |||
| #define __DISTRHO_PLUGIN_PINGPONGPAN_HPP__ | |||
| #include "DistrhoPlugin.h" | |||
| START_NAMESPACE_DISTRHO | |||
| class DistrhoPluginPingPongPan : public Plugin | |||
| { | |||
| public: | |||
| enum Parameters | |||
| { | |||
| paramFreq = 0, | |||
| paramWidth, | |||
| paramCount | |||
| }; | |||
| DistrhoPluginPingPongPan(); | |||
| ~DistrhoPluginPingPongPan(); | |||
| // --------------------------------------------- | |||
| protected: | |||
| // Information | |||
| const char* d_label() const | |||
| { | |||
| return "PingPongPan"; | |||
| } | |||
| const char* d_maker() const | |||
| { | |||
| return "DISTRHO"; | |||
| } | |||
| const char* d_license() const | |||
| { | |||
| return "LGPL"; | |||
| } | |||
| uint32_t d_version() const | |||
| { | |||
| return 0x1000; | |||
| } | |||
| long d_uniqueId() const | |||
| { | |||
| return d_cconst('D', 'P', 'P', 'P'); | |||
| } | |||
| // Init | |||
| void d_initParameter(uint32_t index, Parameter& parameter); | |||
| void d_initProgramName(uint32_t index, d_string& programName); | |||
| // Internal data | |||
| float d_parameterValue(uint32_t index); | |||
| void d_setParameterValue(uint32_t index, float value); | |||
| void d_setProgram(uint32_t index); | |||
| // Process | |||
| void d_activate(); | |||
| void d_deactivate(); | |||
| void d_run(float** inputs, float** outputs, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents); | |||
| // --------------------------------------------- | |||
| private: | |||
| float fFreq; | |||
| float fWidth; | |||
| float waveSpeed; | |||
| float pan, wavePos; | |||
| }; | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // __DISTRHO_PLUGIN_PINGPONGPAN_HPP__ | |||
| @@ -0,0 +1,138 @@ | |||
| /* | |||
| * DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #include "DistrhoUIPingPongPan.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| DistrhoUIPingPongPan::DistrhoUIPingPongPan() | |||
| : OpenGLExtUI() | |||
| { | |||
| // background | |||
| Image bgImage(DistrhoArtworkPingPongPan::backgroundData, DistrhoArtworkPingPongPan::backgroundWidth, DistrhoArtworkPingPongPan::backgroundHeight, GL_BGRA); | |||
| setBackgroundImage(bgImage); | |||
| // knobs | |||
| Image knobImage(DistrhoArtworkPingPongPan::knobData, DistrhoArtworkPingPongPan::knobWidth, DistrhoArtworkPingPongPan::knobHeight); | |||
| Point knobPos(136, 30); | |||
| // knob Low-Mid | |||
| knobFreq = new ImageKnob(knobImage, knobPos); | |||
| knobFreq->setRange(0.0f, 100.0f); | |||
| knobFreq->setValue(50.0f); | |||
| addImageKnob(knobFreq); | |||
| // knob Mid-High | |||
| knobPos.setX(258); | |||
| knobWidth = new ImageKnob(knobImage, knobPos); | |||
| knobWidth->setRange(0.0f, 100.0f); | |||
| knobWidth->setValue(75.0f); | |||
| addImageKnob(knobWidth); | |||
| // about button | |||
| Image aboutImageNormal(DistrhoArtworkPingPongPan::aboutButtonNormalData, DistrhoArtworkPingPongPan::aboutButtonNormalWidth, DistrhoArtworkPingPongPan::aboutButtonNormalHeight); | |||
| Image aboutImageHover(DistrhoArtworkPingPongPan::aboutButtonHoverData, DistrhoArtworkPingPongPan::aboutButtonHoverWidth, DistrhoArtworkPingPongPan::aboutButtonHoverHeight); | |||
| Point aboutPos(25, 23); | |||
| buttonAbout = new ImageButton(aboutImageNormal, aboutImageHover, aboutImageHover, aboutPos); | |||
| addImageButton(buttonAbout); | |||
| } | |||
| DistrhoUIPingPongPan::~DistrhoUIPingPongPan() | |||
| { | |||
| delete knobFreq; | |||
| delete knobWidth; | |||
| delete buttonAbout; | |||
| } | |||
| // ------------------------------------------------- | |||
| // DSP Callbacks | |||
| void DistrhoUIPingPongPan::d_parameterChanged(uint32_t index, float value) | |||
| { | |||
| switch (index) | |||
| { | |||
| case DistrhoPluginPingPongPan::paramFreq: | |||
| knobFreq->setValue(value); | |||
| break; | |||
| case DistrhoPluginPingPongPan::paramWidth: | |||
| knobWidth->setValue(value); | |||
| break; | |||
| } | |||
| d_uiRepaint(); | |||
| } | |||
| void DistrhoUIPingPongPan::d_programChanged(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| knobFreq->setValue(50.0f); | |||
| knobWidth->setValue(75.0f); | |||
| d_uiRepaint(); | |||
| } | |||
| // ------------------------------------------------- | |||
| // Extended Callbacks | |||
| void DistrhoUIPingPongPan::imageButtonClicked(ImageButton* button) | |||
| { | |||
| if (button != buttonAbout) | |||
| return; | |||
| Image imageAbout(DistrhoArtworkPingPongPan::aboutData, DistrhoArtworkPingPongPan::aboutWidth, DistrhoArtworkPingPongPan::aboutHeight, GL_BGRA); | |||
| showImageModalDialog(imageAbout, "About"); | |||
| } | |||
| void DistrhoUIPingPongPan::imageKnobDragStarted(ImageKnob* knob) | |||
| { | |||
| if (knob == knobFreq) | |||
| d_uiEditParameter(DistrhoPluginPingPongPan::paramFreq, true); | |||
| else if (knob == knobWidth) | |||
| d_uiEditParameter(DistrhoPluginPingPongPan::paramWidth, true); | |||
| } | |||
| void DistrhoUIPingPongPan::imageKnobDragFinished(ImageKnob* knob) | |||
| { | |||
| if (knob == knobFreq) | |||
| d_uiEditParameter(DistrhoPluginPingPongPan::paramFreq, false); | |||
| else if (knob == knobWidth) | |||
| d_uiEditParameter(DistrhoPluginPingPongPan::paramWidth, false); | |||
| } | |||
| void DistrhoUIPingPongPan::imageKnobValueChanged(ImageKnob* knob, float value) | |||
| { | |||
| if (knob == knobFreq) | |||
| d_setParameterValue(DistrhoPluginPingPongPan::paramFreq, value); | |||
| else if (knob == knobWidth) | |||
| d_setParameterValue(DistrhoPluginPingPongPan::paramWidth, value); | |||
| } | |||
| // ------------------------------------------------- | |||
| UI* createUI() | |||
| { | |||
| return new DistrhoUIPingPongPan; | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,69 @@ | |||
| /* | |||
| * DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation. | |||
| * | |||
| * 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 Lesser General Public License for more details. | |||
| * | |||
| * For a full copy of the license see the LGPL.txt file | |||
| */ | |||
| #ifndef __DISTRHO_UI_PINGPONGPAN_HPP__ | |||
| #define __DISTRHO_UI_PINGPONGPAN_HPP__ | |||
| #include "DistrhoUIOpenGLExt.h" | |||
| #include "DistrhoArtworkPingPongPan.hpp" | |||
| #include "DistrhoPluginPingPongPan.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ------------------------------------------------- | |||
| class DistrhoUIPingPongPan : public OpenGLExtUI | |||
| { | |||
| public: | |||
| DistrhoUIPingPongPan(); | |||
| ~DistrhoUIPingPongPan(); | |||
| // --------------------------------------------- | |||
| protected: | |||
| // Information | |||
| unsigned int d_width() | |||
| { | |||
| return DistrhoArtworkPingPongPan::backgroundWidth; | |||
| } | |||
| unsigned int d_height() | |||
| { | |||
| return DistrhoArtworkPingPongPan::backgroundHeight; | |||
| } | |||
| // DSP Callbacks | |||
| void d_parameterChanged(uint32_t index, float value); | |||
| void d_programChanged(uint32_t index); | |||
| // Extended Callbacks | |||
| void imageButtonClicked(ImageButton* button); | |||
| void imageKnobDragStarted(ImageKnob* knob); | |||
| void imageKnobDragFinished(ImageKnob* knob); | |||
| void imageKnobValueChanged(ImageKnob* knob, float value); | |||
| private: | |||
| ImageKnob* knobFreq; | |||
| ImageKnob* knobWidth; | |||
| ImageButton* buttonAbout; | |||
| }; | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // __DISTRHO_UI_PINGPONGPAN_HPP__ | |||
| @@ -0,0 +1,51 @@ | |||
| // TODO - merge this into zynaddsubfx.cpp once the native plugin is finished | |||
| // zynaddsubfx includes | |||
| #include "zynaddsubfx/DSP/AnalogFilter.cpp" | |||
| #include "zynaddsubfx/DSP/FFTwrapper.cpp" | |||
| #include "zynaddsubfx/DSP/Filter.cpp" | |||
| #include "zynaddsubfx/DSP/FormantFilter.cpp" | |||
| #include "zynaddsubfx/DSP/SVFilter.cpp" | |||
| #include "zynaddsubfx/DSP/Unison.cpp" | |||
| #include "zynaddsubfx/Effects/Alienwah.cpp" | |||
| #include "zynaddsubfx/Effects/Chorus.cpp" | |||
| #include "zynaddsubfx/Effects/Distorsion.cpp" | |||
| #include "zynaddsubfx/Effects/DynamicFilter.cpp" | |||
| #include "zynaddsubfx/Effects/Echo.cpp" | |||
| #include "zynaddsubfx/Effects/Effect.cpp" | |||
| #include "zynaddsubfx/Effects/EffectLFO.cpp" | |||
| #include "zynaddsubfx/Effects/EffectMgr.cpp" | |||
| #include "zynaddsubfx/Effects/EQ.cpp" | |||
| #include "zynaddsubfx/Effects/Phaser.cpp" | |||
| #include "zynaddsubfx/Effects/Reverb.cpp" | |||
| #include "zynaddsubfx/Misc/Bank.cpp" | |||
| #include "zynaddsubfx/Misc/Config.cpp" | |||
| #include "zynaddsubfx/Misc/Dump.cpp" | |||
| #include "zynaddsubfx/Misc/Master.cpp" | |||
| #include "zynaddsubfx/Misc/Microtonal.cpp" | |||
| #include "zynaddsubfx/Misc/Part.cpp" | |||
| #include "zynaddsubfx/Misc/Recorder.cpp" | |||
| //#include "zynaddsubfx/Misc/Stereo.cpp" | |||
| #include "zynaddsubfx/Misc/Util.cpp" | |||
| #include "zynaddsubfx/Misc/WavFile.cpp" | |||
| #include "zynaddsubfx/Misc/WaveShapeSmps.cpp" | |||
| #include "zynaddsubfx/Misc/XMLwrapper.cpp" | |||
| #include "zynaddsubfx/Params/ADnoteParameters.cpp" | |||
| #include "zynaddsubfx/Params/Controller.cpp" | |||
| #include "zynaddsubfx/Params/EnvelopeParams.cpp" | |||
| #include "zynaddsubfx/Params/FilterParams.cpp" | |||
| #include "zynaddsubfx/Params/LFOParams.cpp" | |||
| #include "zynaddsubfx/Params/PADnoteParameters.cpp" | |||
| #include "zynaddsubfx/Params/Presets.cpp" | |||
| #include "zynaddsubfx/Params/PresetsArray.cpp" | |||
| #include "zynaddsubfx/Params/PresetsStore.cpp" | |||
| #include "zynaddsubfx/Params/SUBnoteParameters.cpp" | |||
| #include "zynaddsubfx/Synth/ADnote.cpp" | |||
| #include "zynaddsubfx/Synth/Envelope.cpp" | |||
| #include "zynaddsubfx/Synth/LFO.cpp" | |||
| #include "zynaddsubfx/Synth/OscilGen.cpp" | |||
| #include "zynaddsubfx/Synth/PADnote.cpp" | |||
| #include "zynaddsubfx/Synth/Resonance.cpp" | |||
| #include "zynaddsubfx/Synth/SUBnote.cpp" | |||
| #include "zynaddsubfx/Synth/SynthNote.cpp" | |||
| @@ -0,0 +1,353 @@ | |||
| /* | |||
| * Carla Native Plugins | |||
| * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| * 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. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| // for UINT32_MAX | |||
| #define __STDC_LIMIT_MACROS | |||
| #include <cstdint> | |||
| #include "carla_midi.h" | |||
| #include "carla_native.hpp" | |||
| #include "zynaddsubfx/Misc/Master.h" | |||
| #include "zynaddsubfx/Misc/Util.h" | |||
| //Dummy variables and functions for linking purposes | |||
| class WavFile; | |||
| namespace Nio { | |||
| bool start(void){return 1;} | |||
| void stop(void){} | |||
| void waveNew(WavFile*){} | |||
| void waveStart(void){} | |||
| void waveStop(void){} | |||
| void waveEnd(void){} | |||
| } | |||
| SYNTH_T* synth = nullptr; | |||
| class ZynAddSubFxPlugin : public PluginDescriptorClass | |||
| { | |||
| public: | |||
| enum Parameters { | |||
| PARAMETER_COUNT = 0 | |||
| }; | |||
| ZynAddSubFxPlugin(const HostDescriptor* const host) | |||
| : PluginDescriptorClass(host) | |||
| { | |||
| m_master = new Master; | |||
| // refresh banks | |||
| m_master->bank.rescanforbanks(); | |||
| for (uint32_t i=0, size = m_master->bank.banks.size(); i < size; i++) | |||
| { | |||
| if (m_master->bank.banks[i].dir.empty()) | |||
| continue; | |||
| m_master->bank.loadbank(m_master->bank.banks[i].dir); | |||
| for (unsigned int instrument = 0; instrument < BANK_SIZE; instrument++) | |||
| { | |||
| const std::string insName(m_master->bank.getname(instrument)); | |||
| if (insName.empty() || insName[0] == '\0' || insName[0] == ' ') | |||
| continue; | |||
| ProgramInfo pInfo = { i, instrument, CarlaString(insName.c_str()) }; | |||
| m_programs.push_back(pInfo); | |||
| } | |||
| } | |||
| } | |||
| ~ZynAddSubFxPlugin() | |||
| { | |||
| //ensure that everything has stopped with the mutex wait | |||
| pthread_mutex_lock(&m_master->mutex); | |||
| pthread_mutex_unlock(&m_master->mutex); | |||
| m_programs.clear(); | |||
| delete m_master; | |||
| } | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin parameter calls | |||
| uint32_t getParameterCount() | |||
| { | |||
| return PARAMETER_COUNT; | |||
| } | |||
| const Parameter* getParameterInfo(const uint32_t index) | |||
| { | |||
| CARLA_ASSERT(index < getParameterCount()); | |||
| //if (index >= PARAMETER_COUNT) | |||
| return nullptr; | |||
| static Parameter param; | |||
| param.ranges.step = PARAMETER_RANGES_DEFAULT_STEP; | |||
| param.ranges.stepSmall = PARAMETER_RANGES_DEFAULT_STEP_SMALL; | |||
| param.ranges.stepLarge = PARAMETER_RANGES_DEFAULT_STEP_LARGE; | |||
| param.scalePointCount = 0; | |||
| param.scalePoints = nullptr; | |||
| switch (index) | |||
| { | |||
| #if 0 | |||
| case PARAMETER_MASTER: | |||
| param.hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; | |||
| param.name = "Master Volume"; | |||
| param.unit = nullptr; | |||
| param.ranges.min = 0.0f; | |||
| param.ranges.max = 100.0f; | |||
| param.ranges.def = 100.0f; | |||
| break; | |||
| #endif | |||
| } | |||
| return ¶m; | |||
| } | |||
| float getParameterValue(const uint32_t index) | |||
| { | |||
| switch (index) | |||
| { | |||
| #if 0 | |||
| case PARAMETER_MASTER: | |||
| return m_master->Pvolume; | |||
| #endif | |||
| default: | |||
| return 0.0f; | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin midi-program calls | |||
| uint32_t getMidiProgramCount() | |||
| { | |||
| return m_programs.size(); | |||
| } | |||
| const MidiProgram* getMidiProgramInfo(const uint32_t index) | |||
| { | |||
| CARLA_ASSERT(index < getMidiProgramCount()); | |||
| if (index >= m_programs.size()) | |||
| return nullptr; | |||
| const ProgramInfo& pInfo(m_programs[index]); | |||
| static MidiProgram midiProgram; | |||
| midiProgram.bank = pInfo.bank; | |||
| midiProgram.program = pInfo.prog; | |||
| midiProgram.name = pInfo.name; | |||
| return &midiProgram; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin state calls | |||
| void setParameterValue(const uint32_t index, const float value) | |||
| { | |||
| switch (index) | |||
| { | |||
| } | |||
| Q_UNUSED(value); | |||
| } | |||
| void setMidiProgram(const uint32_t bank, const uint32_t program) | |||
| { | |||
| if (bank >= m_master->bank.banks.size()) | |||
| return; | |||
| if (program >= BANK_SIZE) | |||
| return; | |||
| const std::string bankdir = m_master->bank.banks[bank].dir; | |||
| if (! bankdir.empty()) | |||
| { | |||
| pthread_mutex_lock(&m_master->mutex); | |||
| m_master->bank.loadbank(bankdir); | |||
| m_master->bank.loadfromslot(program, m_master->part[0]); | |||
| pthread_mutex_unlock(&m_master->mutex); | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin process calls | |||
| void activate() | |||
| { | |||
| m_master->setController(0, MIDI_CONTROL_ALL_SOUND_OFF, 0); | |||
| } | |||
| void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents) | |||
| { | |||
| uint32_t fromFrame = 0; | |||
| uint32_t eventIndex = 0; | |||
| uint32_t nextEventFrame = 0; | |||
| uint32_t toFrame = 0; | |||
| pthread_mutex_lock(&m_master->mutex); | |||
| do { | |||
| // Find the time of the next event, if any | |||
| if (eventIndex >= midiEventCount) | |||
| nextEventFrame = UINT32_MAX; | |||
| else | |||
| nextEventFrame = midiEvents[eventIndex].time; | |||
| // find the end of the sub-sample to be processed this time round... | |||
| // if the next event falls within the desired sample interval... | |||
| if ((nextEventFrame < frames) && (nextEventFrame >= toFrame)) | |||
| // set the end to be at that event | |||
| toFrame = nextEventFrame; | |||
| else | |||
| // ...else go for the whole remaining sample | |||
| toFrame = frames; | |||
| if (fromFrame < toFrame) | |||
| { | |||
| // call master to fill from `fromFrame` to `toFrame`: | |||
| m_master->GetAudioOutSamples(toFrame - fromFrame, (unsigned)getSampleRate(), &outBuffer[0][fromFrame], &outBuffer[1][fromFrame]); | |||
| // next sub-sample please... | |||
| fromFrame = toFrame; | |||
| } | |||
| // Now process any event(s) at the current timing point | |||
| while (eventIndex < midiEventCount && midiEvents[eventIndex].time == toFrame) | |||
| { | |||
| uint8_t status = midiEvents[eventIndex].data[0]; | |||
| uint8_t channel = status & 0x0F; | |||
| if (MIDI_IS_STATUS_NOTE_OFF(status)) | |||
| { | |||
| uint8_t note = midiEvents[eventIndex].data[1]; | |||
| m_master->noteOff(channel, note); | |||
| } | |||
| else if (MIDI_IS_STATUS_NOTE_ON(status)) | |||
| { | |||
| uint8_t note = midiEvents[eventIndex].data[1]; | |||
| uint8_t velo = midiEvents[eventIndex].data[2]; | |||
| m_master->noteOn(channel, note, velo); | |||
| } | |||
| else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status)) | |||
| { | |||
| uint8_t note = midiEvents[eventIndex].data[1]; | |||
| uint8_t pressure = midiEvents[eventIndex].data[2]; | |||
| m_master->polyphonicAftertouch(channel, note, pressure); | |||
| } | |||
| eventIndex++; | |||
| } | |||
| // Keep going until we have the desired total length of sample... | |||
| } while (toFrame < frames); | |||
| pthread_mutex_unlock(&m_master->mutex); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| struct ProgramInfo { | |||
| uint32_t bank; | |||
| uint32_t prog; | |||
| CarlaString name; | |||
| }; | |||
| std::vector<ProgramInfo> m_programs; | |||
| Master* m_master; | |||
| public: | |||
| static int s_instanceCount; | |||
| static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host) | |||
| { | |||
| if (s_instanceCount++ == 0) | |||
| { | |||
| synth = new SYNTH_T; | |||
| synth->buffersize = host->get_buffer_size(host->handle); | |||
| synth->samplerate = host->get_sample_rate(host->handle); | |||
| synth->alias(); | |||
| config.init(); | |||
| config.cfg.SoundBufferSize = synth->buffersize; | |||
| config.cfg.SampleRate = synth->samplerate; | |||
| config.cfg.GzipCompression = 0; | |||
| sprng(time(NULL)); | |||
| denormalkillbuf = new float [synth->buffersize]; | |||
| for (int i=0; i < synth->buffersize; i++) | |||
| denormalkillbuf[i] = (RND - 0.5f) * 1e-16; | |||
| } | |||
| return new ZynAddSubFxPlugin(host); | |||
| } | |||
| static void _cleanup(PluginHandle handle) | |||
| { | |||
| delete (ZynAddSubFxPlugin*)handle; | |||
| if (--s_instanceCount == 0) | |||
| { | |||
| delete[] denormalkillbuf; | |||
| denormalkillbuf = nullptr; | |||
| delete synth; | |||
| synth = nullptr; | |||
| } | |||
| } | |||
| }; | |||
| int ZynAddSubFxPlugin::s_instanceCount = 0; | |||
| // ----------------------------------------------------------------------- | |||
| static const PluginDescriptor zynAddSubFxDesc = { | |||
| /* category */ PLUGIN_CATEGORY_SYNTH, | |||
| /* hints */ PLUGIN_IS_SYNTH, | |||
| /* audioIns */ 2, | |||
| /* audioOuts */ 2, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 0, | |||
| /* paramIns */ ZynAddSubFxPlugin::PARAMETER_COUNT, | |||
| /* paramOuts */ 0, | |||
| /* name */ "ZynAddSubFX", | |||
| /* label */ "zynaddsubfx", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| PluginDescriptorFILL(ZynAddSubFxPlugin) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| void carla_register_native_plugin_zynaddsubfx() | |||
| { | |||
| carla_register_native_plugin(&zynAddSubFxDesc); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,366 @@ | |||
| #checking include/library paths | |||
| message(STATUS "Checking Include Path" $ENV{CMAKE_INCLUDE_PATH} ${CMAKE_INCLUDE_PATH}) | |||
| message(STATUS "Checking Library Path" $ENV{CMAKE_LIBRARY_PATH} ${CMAKE_LIBRARY_PATH}) | |||
| #Dependency check | |||
| find_package(PkgConfig REQUIRED) | |||
| find_package(zlib REQUIRED) | |||
| pkg_check_modules(FFTW REQUIRED fftw3) | |||
| pkg_check_modules(MXML REQUIRED mxml) | |||
| find_package(Threads REQUIRED) | |||
| find_package(OSS) | |||
| find_package(Alsa) | |||
| pkg_check_modules(JACK jack) | |||
| pkg_check_modules(PORTAUDIO portaudio-2.0>=19) | |||
| set(FLTK_SKIP_OPENGL true) | |||
| pkg_check_modules(NTK ntk) | |||
| pkg_check_modules(NTK_IMAGES ntk_images) | |||
| find_package(FLTK) | |||
| find_package(OpenGL) #for FLTK | |||
| find_package(CxxTest) | |||
| if(CXXTEST_FOUND) | |||
| set(CXXTEST_USE_PYTHON TRUE) | |||
| endif() | |||
| # lash | |||
| pkg_search_module(LASH lash-1.0) | |||
| mark_as_advanced(LASH_LIBRARIES) | |||
| pkg_search_module(DSSI dssi>=0.9.0) | |||
| mark_as_advanced(DSSI_LIBRARIES) | |||
| pkg_search_module(LIBLO liblo>=0.26) | |||
| mark_as_advanced(LIBLO_LIBRARIES) | |||
| ######### Settings ########### | |||
| # NOTE: These cache variables should normally not be changed in this | |||
| # file, but either in in CMakeCache.txt before compile, or by passing | |||
| # parameters directly into cmake using the -D flag. | |||
| SET (GuiModule fltk CACHE STRING "GUI module, either fltk, ntk or off") | |||
| SET (CompileTests ${CXXTEST_FOUND} CACHE BOOL "whether tests should be compiled in or not") | |||
| SET (AlsaEnable ${ALSA_FOUND} CACHE BOOL | |||
| "Enable support for Advanced Linux Sound Architecture") | |||
| SET (JackEnable ${JACK_FOUND} CACHE BOOL | |||
| "Enable support for JACK Audio Connection toolKit") | |||
| SET (OssEnable ${OSS_FOUND} CACHE BOOL | |||
| "Enable support for Open Sound System") | |||
| SET (PaEnable ${PORTAUDIO_FOUND} CACHE BOOL | |||
| "Enable support for Port Audio System") | |||
| SET (LashEnable ${LASH_FOUND} CACHE BOOL | |||
| "Enable LASH Audio Session Handler") | |||
| SET (DssiEnable ${DSSI_FOUND} CACHE BOOL | |||
| "Enable DSSI Plugin compilation") | |||
| SET (LibloEnable ${LIBLO_FOUND} CACHE BOOL | |||
| "Enable Liblo") | |||
| # Now, handle the incoming settings and set define flags/variables based | |||
| # on this | |||
| # Add version information | |||
| add_definitions(-DVERSION="${VERSION}") | |||
| # Give a good guess on the best Input/Output default backends | |||
| if (JackEnable) | |||
| SET (DefaultOutput jack CACHE STRING | |||
| "Default Output module: [null, alsa, oss, jack, portaudio]") | |||
| # Override with perhaps more helpful midi backends | |||
| if (AlsaEnable) | |||
| SET (DefaultInput alsa CACHE STRING | |||
| "Default Input module: [null, alsa, oss, jack]") | |||
| elseif (OssEnable) | |||
| SET (DefaultInput oss CACHE STRING | |||
| "Default Input module: [null, alsa, oss, jack]") | |||
| else () | |||
| SET (DefaultInput jack CACHE STRING | |||
| "Default Input module: [null, alsa, oss, jack]") | |||
| endif () | |||
| elseif (AlsaEnable) | |||
| SET (DefaultOutput alsa CACHE STRING | |||
| "Default Output module: [null, alsa, oss, jack, portaudio]") | |||
| SET (DefaultInput alsa CACHE STRING | |||
| "Default Input module: [null, alsa, oss, jack]") | |||
| elseif (OssEnable) | |||
| SET (DefaultOutput oss CACHE STRING | |||
| "Default Output module: [null, alsa, oss, jack, portaudio]") | |||
| SET (DefaultInput oss CACHE STRING | |||
| "Default Input module: [null, alsa, oss, jack]") | |||
| else() | |||
| SET (DefaultOutput null CACHE STRING | |||
| "Default Output module: [null, alsa, oss, jack, portaudio]") | |||
| SET (DefaultInput null CACHE STRING | |||
| "Default Input module: [null, alsa, oss, jack]") | |||
| endif() | |||
| if (GuiModule STREQUAL qt AND QT_FOUND) | |||
| set (QtGui TRUE) | |||
| elseif(GuiModule STREQUAL ntk AND NTK_FOUND) | |||
| set (NtkGui TRUE) | |||
| elseif(GuiModule STREQUAL fltk AND FLTK_FOUND) | |||
| set (FltkGui TRUE) | |||
| elseif(GuiModule STREQUAL off) | |||
| add_definitions(-DDISABLE_GUI) | |||
| else () | |||
| set (GuiModule off CACHE STRING "GUI module, either fltk, qt or off") | |||
| add_definitions(-DDISABLE_GUI) | |||
| message(STATUS "GUI module defaulting to off") | |||
| endif() | |||
| #Build Flags | |||
| option (BuildForAMD_X86_64 "Build for AMD x86_64 system" OFF) | |||
| option (BuildForCore2_X86_64 "Build for Intel Core2 x86_64 system" OFF) | |||
| option (BuildForDebug "Include gdb debugging support" OFF) | |||
| set(CMAKE_BUILD_TYPE "Release") | |||
| set (BuildOptions_x86_64AMD | |||
| "-O3 -march=athlon64 -m64 -Wall -ffast-math -fno-finite-math-only -fomit-frame-pointer" | |||
| CACHE STRING "X86_64 compiler options" | |||
| ) | |||
| set (BuildOptions_X86_64Core2 | |||
| "-O3 -march=core2 -m64 -Wall -ffast-math -fno-finite-math-only -fomit-frame-pointer" | |||
| CACHE STRING "X86_64 compiler options" | |||
| ) | |||
| set (BuildOptionsBasic | |||
| "-O3 -msse -msse2 -mfpmath=sse -ffast-math -fomit-frame-pointer" | |||
| CACHE STRING "basic X86 complier options" | |||
| ) | |||
| set (BuildOptionsDebug | |||
| "-O0 -g3 -ggdb -Wall -Wpointer-arith" CACHE STRING "Debug build flags") | |||
| ########### Settings dependant code ########### | |||
| # From here on, the setting variables have been prepared so concentrate | |||
| # on the actual compiling. | |||
| if(AlsaEnable) | |||
| list(APPEND AUDIO_LIBRARIES ${ASOUND_LIBRARY}) | |||
| list(APPEND AUDIO_LIBRARY_DIRS ${ASOUND_LIBRARY_DIRS}) | |||
| add_definitions(-DALSA=1) | |||
| endif(AlsaEnable) | |||
| if(JackEnable) | |||
| list(APPEND AUDIO_LIBRARIES ${JACK_LIBRARIES}) | |||
| list(APPEND AUDIO_LIBRARY_DIRS ${JACK_LIBRARY_DIRS}) | |||
| add_definitions(-DJACK=1) | |||
| endif(JackEnable) | |||
| if(OssEnable) | |||
| add_definitions(-DOSS=1) | |||
| endif(OssEnable) | |||
| if(PaEnable) | |||
| include_directories(${PORTAUDIO_INCLUDE_DIR}) | |||
| add_definitions(-DPORTAUDIO=1) | |||
| list(APPEND AUDIO_LIBRARIES ${PORTAUDIO_LIBRARIES}) | |||
| list(APPEND AUDIO_LIBRARY_DIRS ${PORTAUDIO_LIBRARY_DIRS}) | |||
| endif() | |||
| if (CompileTests) | |||
| ENABLE_TESTING() | |||
| endif() | |||
| if(LashEnable) | |||
| include_directories(${LASH_INCLUDE_DIRS}) | |||
| add_definitions(-DLASH=1) | |||
| list(APPEND AUDIO_LIBRARIES ${LASH_LIBRARIES}) | |||
| list(APPEND AUDIO_LIBRARY_DIRS ${LASH_LIBRARY_DIRS}) | |||
| message(STATUS "Compiling with lash") | |||
| endif() | |||
| if(LibloEnable) | |||
| include_directories(${LIBLO_INCLUDE_DIRS}) | |||
| add_definitions(-DUSE_NSM=1) | |||
| list(APPEND AUDIO_LIBRARIES ${LIBLO_LIBRARIES}) | |||
| list(APPEND AUDIO_LIBRARY_DIRS ${LIBLO_LIBRARY_DIRS}) | |||
| message(STATUS "Compiling with liblo") | |||
| endif() | |||
| # other include directories | |||
| include_directories(${ZLIB_INCLUDE_DIRS} ${MXML_INCLUDE_DIRS}) | |||
| add_definitions( | |||
| -DASM_F2I_YES | |||
| -g #TODO #todo put in a better location | |||
| -Wall | |||
| -Wextra | |||
| ) | |||
| if (BuildForDebug) | |||
| set (CMAKE_BUILD_TYPE "Debug") | |||
| set (CMAKE_CXX_FLAGS_DEBUG ${BuildOptionsDebug}) | |||
| message (STATUS "Building for ${CMAKE_BUILD_TYPE}, flags: ${CMAKE_CXX_FLAGS_DEBUG}") | |||
| else (BuildForDebug) | |||
| set (CMAKE_BUILD_TYPE "Release") | |||
| if (BuildForAMD_X86_64) | |||
| set (CMAKE_CXX_FLAGS_RELEASE ${BuildOptions_x86_64AMD}) | |||
| else (BuildForAMD_X86_64) | |||
| if (BuildForCore2_X86_64) | |||
| set (CMAKE_CXX_FLAGS_RELEASE ${BuildOptions_X86_64Core2}) | |||
| else (BuildForCore2_X86_64) | |||
| set (CMAKE_CXX_FLAGS_RELEASE ${BuildOptionsBasic}) | |||
| endif (BuildForCore2_X86_64) | |||
| endif (BuildForAMD_X86_64) | |||
| message (STATUS "Building for ${CMAKE_BUILD_TYPE}, flags: ${CMAKE_CXX_FLAGS_RELEASE}") | |||
| endif (BuildForDebug) | |||
| add_definitions(-fPIC) | |||
| if(FLTK_FOUND) | |||
| mark_as_advanced(FORCE FLTK_BASE_LIBRARY) | |||
| mark_as_advanced(FORCE FLTK_CONFIG_SCRIPT) | |||
| mark_as_advanced(FORCE FLTK_DIR) | |||
| mark_as_advanced(FORCE FLTK_FLUID_EXECUTABLE) | |||
| mark_as_advanced(FORCE FLTK_FORMS_LIBRARY) | |||
| mark_as_advanced(FORCE FLTK_GL_LIBRARY) | |||
| mark_as_advanced(FORCE FLTK_IMAGES_LIBRARY) | |||
| mark_as_advanced(FORCE FLTK_INCLUDE_DIR) | |||
| mark_as_advanced(FORCE FLTK_MATH_LIBRARY) | |||
| endif(FLTK_FOUND) | |||
| if(NTK_FOUND) | |||
| mark_as_advanced(FORCE NTK_BASE_LIBRARY) | |||
| mark_as_advanced(FORCE NTK_CONFIG_SCRIPT) | |||
| mark_as_advanced(FORCE NTK_DIR) | |||
| mark_as_advanced(FORCE FLTK_FLUID_EXECUTABLE) | |||
| mark_as_advanced(FORCE NTK_FORMS_LIBRARY) | |||
| mark_as_advanced(FORCE NTK_GL_LIBRARY) | |||
| mark_as_advanced(FORCE NTK_IMAGES_LIBRARY) | |||
| mark_as_advanced(FORCE NTK_INCLUDE_DIR) | |||
| mark_as_advanced(FORCE NTK_MATH_LIBRARY) | |||
| endif(NTK_FOUND) | |||
| if(FltkGui) | |||
| #UGLY WORKAROUND | |||
| find_program (FLTK_CONFIG fltk-config) | |||
| if (FLTK_CONFIG) | |||
| execute_process (COMMAND ${FLTK_CONFIG} --use-images --ldflags OUTPUT_VARIABLE FLTK_LDFLAGS) | |||
| string(STRIP ${FLTK_LDFLAGS} FLTK_LIBRARIES) | |||
| endif() | |||
| message(STATUS ${FLTK_LDFLAGS}) | |||
| set(GUI_LIBRARIES ${FLTK_LIBRARIES} ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES} zynaddsubfx_gui) | |||
| add_definitions(-DFLTK_GUI) | |||
| message(STATUS "Will build FLTK gui") | |||
| include_directories( | |||
| ${FLTK_INCLUDE_DIR} | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/UI" | |||
| "${CMAKE_CURRENT_BINARY_DIR}/UI" | |||
| ) | |||
| add_subdirectory(UI) | |||
| endif() | |||
| if(NtkGui) | |||
| find_program( FLTK_FLUID_EXECUTABLE ntk-fluid) | |||
| message(STATUS ${NTK_LDFLAGS} ${NTK_IMAGES_LDFLAGS}) | |||
| set(GUI_LIBRARIES ${NTK_LIBRARIES} ${NTK_IMAGES_LIBRARIES} ${OPENGL_LIBRARIES} zynaddsubfx_gui) | |||
| add_definitions(-DNTK_GUI) | |||
| message(STATUS "Will build NTK gui") | |||
| include_directories( | |||
| ${NTK_INCLUDE_DIRS} | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/UI" | |||
| "${CMAKE_CURRENT_BINARY_DIR}/UI" | |||
| ) | |||
| add_subdirectory(UI) | |||
| endif() | |||
| ########### General section ############## | |||
| # Following this should be only general compilation code, and no mention | |||
| # of module-specific variables | |||
| link_directories(${AUDIO_LIBRARY_DIRS} ${ZLIB_LIBRARY_DIRS} ${FFTW_LIBRARY_DIRS} ${MXML_LIBRARY_DIRS} ${FLTK_LIBRARY_DIRS} ${NTK_LIBRARY_DIRS}) | |||
| include_directories( | |||
| ${CMAKE_CURRENT_SOURCE_DIR} | |||
| ${CMAKE_CURRENT_BINARY_DIR} | |||
| ) | |||
| set(NONGUI_LIBRARIES | |||
| zynaddsubfx_misc | |||
| zynaddsubfx_synth | |||
| zynaddsubfx_effect | |||
| zynaddsubfx_params | |||
| zynaddsubfx_dsp | |||
| zynaddsubfx_nio | |||
| ) | |||
| add_subdirectory(Misc) | |||
| add_subdirectory(Synth) | |||
| add_subdirectory(Effects) | |||
| add_subdirectory(Params) | |||
| add_subdirectory(DSP) | |||
| if(CompileTests) | |||
| add_subdirectory(Tests) | |||
| endif(CompileTests) | |||
| add_subdirectory(Nio) | |||
| add_library(zynaddsubfx_core STATIC | |||
| ${zynaddsubfx_dsp_SRCS} | |||
| ${zynaddsubfx_effect_SRCS} | |||
| ${zynaddsubfx_misc_SRCS} | |||
| ${zynaddsubfx_params_SRCS} | |||
| ${zynaddsubfx_synth_SRCS} | |||
| ) | |||
| target_link_libraries(zynaddsubfx_core | |||
| ${ZLIB_LIBRARIES} | |||
| ${FFTW_LIBRARIES} | |||
| ${MXML_LIBRARIES} | |||
| ${OS_LIBRARIES} | |||
| pthread) | |||
| message(STATUS "using link directories: ${AUDIO_LIBRARY_DIRS} ${ZLIB_LIBRARY_DIRS} ${FFTW_LIBRARY_DIRS} ${MXML_LIBRARY_DIRS} ${FLTK_LIBRARY_DIRS}") | |||
| add_executable(zynaddsubfx main.cpp) | |||
| target_link_libraries(zynaddsubfx | |||
| zynaddsubfx_core | |||
| zynaddsubfx_nio | |||
| ${GUI_LIBRARIES} | |||
| ${NIO_LIBRARIES} | |||
| ${AUDIO_LIBRARIES} | |||
| ) | |||
| if (DssiEnable) | |||
| add_library(zynaddsubfx_dssi SHARED | |||
| Output/DSSIaudiooutput.cpp | |||
| ) | |||
| target_link_libraries(zynaddsubfx_dssi | |||
| zynaddsubfx_core | |||
| ${OS_LIBRARIES} | |||
| ) | |||
| if (${CMAKE_SIZEOF_VOID_P} EQUAL "8") | |||
| install(TARGETS zynaddsubfx_dssi LIBRARY DESTINATION lib64/dssi/) | |||
| else () | |||
| install(TARGETS zynaddsubfx_dssi LIBRARY DESTINATION lib/dssi/) | |||
| endif () | |||
| endif() | |||
| message(STATUS "Link libraries: ${ZLIB_LIBRARY} ${FFTW_LIBRARY} ${MXML_LIBRARIES} ${AUDIO_LIBRARIES} ${OS_LIBRARIES}") | |||
| install(TARGETS zynaddsubfx | |||
| RUNTIME DESTINATION bin | |||
| ) | |||
| if(NtkGui) | |||
| install(DIRECTORY ../pixmaps DESTINATION share/zynaddsubfx) | |||
| add_definitions(-DPIXMAP_PATH="${CMAKE_INSTALL_PREFIX}/share/zynaddsubfx/pixmaps/") | |||
| add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") | |||
| endif(NtkGui) | |||
| include(CTest) | |||
| @@ -0,0 +1,396 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| AnalogFilter.cpp - Several analog filters (lowpass, highpass...) | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright (C) 2010-2010 Mark McCurry | |||
| Author: Nasca Octavian Paul | |||
| Mark McCurry | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cstring> //memcpy | |||
| #include <cmath> | |||
| #include "../Misc/Util.h" | |||
| #include "AnalogFilter.h" | |||
| AnalogFilter::AnalogFilter(unsigned char Ftype, | |||
| float Ffreq, | |||
| float Fq, | |||
| unsigned char Fstages) | |||
| :type(Ftype), | |||
| stages(Fstages), | |||
| freq(Ffreq), | |||
| q(Fq), | |||
| gain(1.0), | |||
| abovenq(false), | |||
| oldabovenq(false) | |||
| { | |||
| for(int i = 0; i < 3; ++i) | |||
| coeff.c[i] = coeff.d[i] = oldCoeff.c[i] = oldCoeff.d[i] = 0.0f; | |||
| if(stages >= MAX_FILTER_STAGES) | |||
| stages = MAX_FILTER_STAGES; | |||
| cleanup(); | |||
| firsttime = false; | |||
| setfreq_and_q(Ffreq, Fq); | |||
| firsttime = true; | |||
| coeff.d[0] = 0; //this is not used | |||
| outgain = 1.0f; | |||
| } | |||
| AnalogFilter::~AnalogFilter() | |||
| {} | |||
| void AnalogFilter::cleanup() | |||
| { | |||
| for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) { | |||
| history[i].x1 = 0.0f; | |||
| history[i].x2 = 0.0f; | |||
| history[i].y1 = 0.0f; | |||
| history[i].y2 = 0.0f; | |||
| oldHistory[i] = history[i]; | |||
| } | |||
| needsinterpolation = false; | |||
| } | |||
| void AnalogFilter::computefiltercoefs(void) | |||
| { | |||
| float tmp; | |||
| bool zerocoefs = false; //this is used if the freq is too high | |||
| //do not allow frequencies bigger than samplerate/2 | |||
| float freq = this->freq; | |||
| if(freq > (synth->halfsamplerate_f - 500.0f)) { | |||
| freq = synth->halfsamplerate_f - 500.0f; | |||
| zerocoefs = true; | |||
| } | |||
| if(freq < 0.1f) | |||
| freq = 0.1f; | |||
| //do not allow bogus Q | |||
| if(q < 0.0f) | |||
| q = 0.0f; | |||
| float tmpq, tmpgain; | |||
| if(stages == 0) { | |||
| tmpq = q; | |||
| tmpgain = gain; | |||
| } | |||
| else { | |||
| tmpq = (q > 1.0f) ? powf(q, 1.0f / (stages + 1)) : q; | |||
| tmpgain = powf(gain, 1.0f / (stages + 1)); | |||
| } | |||
| //Alias Terms | |||
| float *c = coeff.c; | |||
| float *d = coeff.d; | |||
| //General Constants | |||
| const float omega = 2 * PI * freq / synth->samplerate_f; | |||
| const float sn = sinf(omega), cs = cosf(omega); | |||
| float alpha, beta; | |||
| //most of theese are implementations of | |||
| //the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson | |||
| //The original location of the Cookbook is: | |||
| //http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt | |||
| switch(type) { | |||
| case 0: //LPF 1 pole | |||
| if(!zerocoefs) | |||
| tmp = expf(-2.0f * PI * freq / synth->samplerate_f); | |||
| else | |||
| tmp = 0.0f; | |||
| c[0] = 1.0f - tmp; | |||
| c[1] = 0.0f; | |||
| c[2] = 0.0f; | |||
| d[1] = tmp; | |||
| d[2] = 0.0f; | |||
| order = 1; | |||
| break; | |||
| case 1: //HPF 1 pole | |||
| if(!zerocoefs) | |||
| tmp = expf(-2.0f * PI * freq / synth->samplerate_f); | |||
| else | |||
| tmp = 0.0f; | |||
| c[0] = (1.0f + tmp) / 2.0f; | |||
| c[1] = -(1.0f + tmp) / 2.0f; | |||
| c[2] = 0.0f; | |||
| d[1] = tmp; | |||
| d[2] = 0.0f; | |||
| order = 1; | |||
| break; | |||
| case 2: //LPF 2 poles | |||
| if(!zerocoefs) { | |||
| alpha = sn / (2.0f * tmpq); | |||
| tmp = 1 + alpha; | |||
| c[1] = (1.0f - cs) / tmp; | |||
| c[0] = c[2] = c[1] / 2.0f; | |||
| d[1] = -2.0f * cs / tmp * -1.0f; | |||
| d[2] = (1.0f - alpha) / tmp * -1.0f; | |||
| } | |||
| else { | |||
| c[0] = 1.0f; | |||
| c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| } | |||
| order = 2; | |||
| break; | |||
| case 3: //HPF 2 poles | |||
| if(!zerocoefs) { | |||
| alpha = sn / (2.0f * tmpq); | |||
| tmp = 1 + alpha; | |||
| c[0] = (1.0f + cs) / 2.0f / tmp; | |||
| c[1] = -(1.0f + cs) / tmp; | |||
| c[2] = (1.0f + cs) / 2.0f / tmp; | |||
| d[1] = -2.0f * cs / tmp * -1.0f; | |||
| d[2] = (1.0f - alpha) / tmp * -1.0f; | |||
| } | |||
| else | |||
| c[0] = c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| order = 2; | |||
| break; | |||
| case 4: //BPF 2 poles | |||
| if(!zerocoefs) { | |||
| alpha = sn / (2.0f * tmpq); | |||
| tmp = 1.0f + alpha; | |||
| c[0] = alpha / tmp *sqrtf(tmpq + 1.0f); | |||
| c[1] = 0.0f; | |||
| c[2] = -alpha / tmp *sqrtf(tmpq + 1.0f); | |||
| d[1] = -2.0f * cs / tmp * -1.0f; | |||
| d[2] = (1.0f - alpha) / tmp * -1.0f; | |||
| } | |||
| else | |||
| c[0] = c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| order = 2; | |||
| break; | |||
| case 5: //NOTCH 2 poles | |||
| if(!zerocoefs) { | |||
| alpha = sn / (2.0f * sqrtf(tmpq)); | |||
| tmp = 1.0f + alpha; | |||
| c[0] = 1.0f / tmp; | |||
| c[1] = -2.0f * cs / tmp; | |||
| c[2] = 1.0f / tmp; | |||
| d[1] = -2.0f * cs / tmp * -1.0f; | |||
| d[2] = (1.0f - alpha) / tmp * -1.0f; | |||
| } | |||
| else { | |||
| c[0] = 1.0f; | |||
| c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| } | |||
| order = 2; | |||
| break; | |||
| case 6: //PEAK (2 poles) | |||
| if(!zerocoefs) { | |||
| tmpq *= 3.0f; | |||
| alpha = sn / (2.0f * tmpq); | |||
| tmp = 1.0f + alpha / tmpgain; | |||
| c[0] = (1.0f + alpha * tmpgain) / tmp; | |||
| c[1] = (-2.0f * cs) / tmp; | |||
| c[2] = (1.0f - alpha * tmpgain) / tmp; | |||
| d[1] = -2.0f * cs / tmp * -1.0f; | |||
| d[2] = (1.0f - alpha / tmpgain) / tmp * -1.0f; | |||
| } | |||
| else { | |||
| c[0] = 1.0f; | |||
| c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| } | |||
| order = 2; | |||
| break; | |||
| case 7: //Low Shelf - 2 poles | |||
| if(!zerocoefs) { | |||
| tmpq = sqrtf(tmpq); | |||
| alpha = sn / (2.0f * tmpq); | |||
| beta = sqrtf(tmpgain) / tmpq; | |||
| tmp = (tmpgain + 1.0f) + (tmpgain - 1.0f) * cs + beta * sn; | |||
| c[0] = tmpgain | |||
| * ((tmpgain | |||
| + 1.0f) - (tmpgain - 1.0f) * cs + beta * sn) / tmp; | |||
| c[1] = 2.0f * tmpgain | |||
| * ((tmpgain - 1.0f) - (tmpgain + 1.0f) * cs) / tmp; | |||
| c[2] = tmpgain | |||
| * ((tmpgain | |||
| + 1.0f) - (tmpgain - 1.0f) * cs - beta * sn) / tmp; | |||
| d[1] = -2.0f * ((tmpgain - 1.0f) + (tmpgain + 1.0f) * cs) | |||
| / tmp * -1.0f; | |||
| d[2] = ((tmpgain + 1.0f) + (tmpgain - 1.0f) * cs - beta * sn) | |||
| / tmp * -1.0f; | |||
| } | |||
| else { | |||
| c[0] = tmpgain; | |||
| c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| } | |||
| order = 2; | |||
| break; | |||
| case 8: //High Shelf - 2 poles | |||
| if(!zerocoefs) { | |||
| tmpq = sqrtf(tmpq); | |||
| alpha = sn / (2.0f * tmpq); | |||
| beta = sqrtf(tmpgain) / tmpq; | |||
| tmp = (tmpgain + 1.0f) - (tmpgain - 1.0f) * cs + beta * sn; | |||
| c[0] = tmpgain | |||
| * ((tmpgain | |||
| + 1.0f) + (tmpgain - 1.0f) * cs + beta * sn) / tmp; | |||
| c[1] = -2.0f * tmpgain | |||
| * ((tmpgain - 1.0f) + (tmpgain + 1.0f) * cs) / tmp; | |||
| c[2] = tmpgain | |||
| * ((tmpgain | |||
| + 1.0f) + (tmpgain - 1.0f) * cs - beta * sn) / tmp; | |||
| d[1] = 2.0f * ((tmpgain - 1.0f) - (tmpgain + 1.0f) * cs) | |||
| / tmp * -1.0f; | |||
| d[2] = ((tmpgain + 1.0f) - (tmpgain - 1.0f) * cs - beta * sn) | |||
| / tmp * -1.0f; | |||
| } | |||
| else { | |||
| c[0] = 1.0f; | |||
| c[1] = c[2] = d[1] = d[2] = 0.0f; | |||
| } | |||
| order = 2; | |||
| break; | |||
| default: //wrong type | |||
| type = 0; | |||
| computefiltercoefs(); | |||
| break; | |||
| } | |||
| } | |||
| void AnalogFilter::setfreq(float frequency) | |||
| { | |||
| if(frequency < 0.1f) | |||
| frequency = 0.1f; | |||
| float rap = freq / frequency; | |||
| if(rap < 1.0f) | |||
| rap = 1.0f / rap; | |||
| oldabovenq = abovenq; | |||
| abovenq = frequency > (synth->halfsamplerate_f - 500.0f); | |||
| bool nyquistthresh = (abovenq ^ oldabovenq); | |||
| //if the frequency is changed fast, it needs interpolation | |||
| if((rap > 3.0f) || nyquistthresh) { //(now, filter and coeficients backup) | |||
| oldCoeff = coeff; | |||
| for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) | |||
| oldHistory[i] = history[i]; | |||
| if(!firsttime) | |||
| needsinterpolation = true; | |||
| } | |||
| freq = frequency; | |||
| computefiltercoefs(); | |||
| firsttime = false; | |||
| } | |||
| void AnalogFilter::setfreq_and_q(float frequency, float q_) | |||
| { | |||
| q = q_; | |||
| setfreq(frequency); | |||
| } | |||
| void AnalogFilter::setq(float q_) | |||
| { | |||
| q = q_; | |||
| computefiltercoefs(); | |||
| } | |||
| void AnalogFilter::settype(int type_) | |||
| { | |||
| type = type_; | |||
| computefiltercoefs(); | |||
| } | |||
| void AnalogFilter::setgain(float dBgain) | |||
| { | |||
| gain = dB2rap(dBgain); | |||
| computefiltercoefs(); | |||
| } | |||
| void AnalogFilter::setstages(int stages_) | |||
| { | |||
| if(stages_ >= MAX_FILTER_STAGES) | |||
| stages_ = MAX_FILTER_STAGES - 1; | |||
| stages = stages_; | |||
| cleanup(); | |||
| computefiltercoefs(); | |||
| } | |||
| void AnalogFilter::singlefilterout(float *smp, fstage &hist, | |||
| const Coeff &coeff) | |||
| { | |||
| if(order == 1) //First order filter | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float y0 = smp[i] * coeff.c[0] + hist.x1 * coeff.c[1] | |||
| + hist.y1 * coeff.d[1]; | |||
| hist.y1 = y0; | |||
| hist.x1 = smp[i]; | |||
| smp[i] = y0; | |||
| } | |||
| if(order == 2) //Second order filter | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float y0 = smp[i] * coeff.c[0] + hist.x1 * coeff.c[1] | |||
| + hist.x2 * coeff.c[2] + hist.y1 * coeff.d[1] | |||
| + hist.y2 * coeff.d[2]; | |||
| hist.y2 = hist.y1; | |||
| hist.y1 = y0; | |||
| hist.x2 = hist.x1; | |||
| hist.x1 = smp[i]; | |||
| smp[i] = y0; | |||
| } | |||
| } | |||
| void AnalogFilter::filterout(float *smp) | |||
| { | |||
| for(int i = 0; i < stages + 1; ++i) | |||
| singlefilterout(smp, history[i], coeff); | |||
| if(needsinterpolation) { | |||
| //Merge Filter at old coeff with new coeff | |||
| float *ismp = getTmpBuffer(); | |||
| memcpy(ismp, smp, synth->bufferbytes); | |||
| for(int i = 0; i < stages + 1; ++i) | |||
| singlefilterout(ismp, oldHistory[i], oldCoeff); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float x = (float)i / synth->buffersize_f; | |||
| smp[i] = ismp[i] * (1.0f - x) + smp[i] * x; | |||
| } | |||
| returnTmpBuffer(ismp); | |||
| needsinterpolation = false; | |||
| } | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| smp[i] *= outgain; | |||
| } | |||
| float AnalogFilter::H(float freq) | |||
| { | |||
| float fr = freq / synth->samplerate_f * PI * 2.0f; | |||
| float x = coeff.c[0], y = 0.0f; | |||
| for(int n = 1; n < 3; ++n) { | |||
| x += cosf(n * fr) * coeff.c[n]; | |||
| y -= sinf(n * fr) * coeff.c[n]; | |||
| } | |||
| float h = x * x + y * y; | |||
| x = 1.0f; | |||
| y = 0.0f; | |||
| for(int n = 1; n < 3; ++n) { | |||
| x -= cosf(n * fr) * coeff.d[n]; | |||
| y += sinf(n * fr) * coeff.d[n]; | |||
| } | |||
| h = h / (x * x + y * y); | |||
| return powf(h, (stages + 1.0f) / 2.0f); | |||
| } | |||
| @@ -0,0 +1,85 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Analog Filter.h - Several analog filters (lowpass, highpass...) | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright (C) 2010-2010 Mark McCurry | |||
| Author: Nasca Octavian Paul | |||
| Mark McCurry | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef ANALOG_FILTER_H | |||
| #define ANALOG_FILTER_H | |||
| #include "../globals.h" | |||
| #include "Filter.h" | |||
| /**Implementation of Several analog filters (lowpass, highpass...) | |||
| * Implemented with IIR filters | |||
| * Coefficients generated with "Cookbook formulae for audio EQ"*/ | |||
| class AnalogFilter:public Filter | |||
| { | |||
| public: | |||
| AnalogFilter(unsigned char Ftype, float Ffreq, float Fq, | |||
| unsigned char Fstages); | |||
| ~AnalogFilter(); | |||
| void filterout(float *smp); | |||
| void setfreq(float frequency); | |||
| void setfreq_and_q(float frequency, float q_); | |||
| void setq(float q_); | |||
| void settype(int type_); | |||
| void setgain(float dBgain); | |||
| void setstages(int stages_); | |||
| void cleanup(); | |||
| float H(float freq); //Obtains the response for a given frequency | |||
| private: | |||
| struct fstage { | |||
| float x1, x2; //Input History | |||
| float y1, y2; //Output History | |||
| } history[MAX_FILTER_STAGES + 1], oldHistory[MAX_FILTER_STAGES + 1]; | |||
| struct Coeff { | |||
| float c[3], //Feed Forward | |||
| d[3]; //Feed Back | |||
| } coeff, oldCoeff; | |||
| //old coeffs are used for interpolation when paremeters change quickly | |||
| //Apply IIR filter to Samples, with coefficients, and past history | |||
| void singlefilterout(float *smp, fstage &hist, const Coeff &coeff); | |||
| //Update coeff and order | |||
| void computefiltercoefs(void); | |||
| int type; //The type of the filter (LPF1,HPF1,LPF2,HPF2...) | |||
| int stages; //how many times the filter is applied (0->1,1->2,etc.) | |||
| float freq; //Frequency given in Hz | |||
| float q; //Q factor (resonance or Q factor) | |||
| float gain; //the gain of the filter (if are shelf/peak) filters | |||
| int order; //the order of the filter (number of poles) | |||
| bool needsinterpolation, //Interpolation between coeff changes | |||
| firsttime; //First Iteration of filter | |||
| bool abovenq, //if the frequency is above the nyquist | |||
| oldabovenq; //if the last time was above nyquist | |||
| //(used to see if it needs interpolation) | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,9 @@ | |||
| set(zynaddsubfx_dsp_SRCS | |||
| DSP/AnalogFilter.cpp | |||
| DSP/FFTwrapper.cpp | |||
| DSP/Filter.cpp | |||
| DSP/FormantFilter.cpp | |||
| DSP/SVFilter.cpp | |||
| DSP/Unison.cpp | |||
| PARENT_SCOPE | |||
| ) | |||
| @@ -0,0 +1,85 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| FFTwrapper.c - A wrapper for Fast Fourier Transforms | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include <cassert> | |||
| #include <cstring> | |||
| #include "FFTwrapper.h" | |||
| FFTwrapper::FFTwrapper(int fftsize_) | |||
| { | |||
| fftsize = fftsize_; | |||
| time = new fftw_real[fftsize]; | |||
| fft = new fftw_complex[fftsize + 1]; | |||
| planfftw = fftw_plan_dft_r2c_1d(fftsize, | |||
| time, | |||
| fft, | |||
| FFTW_ESTIMATE); | |||
| planfftw_inv = fftw_plan_dft_c2r_1d(fftsize, | |||
| fft, | |||
| time, | |||
| FFTW_ESTIMATE); | |||
| } | |||
| FFTwrapper::~FFTwrapper() | |||
| { | |||
| fftw_destroy_plan(planfftw); | |||
| fftw_destroy_plan(planfftw_inv); | |||
| delete [] time; | |||
| delete [] fft; | |||
| } | |||
| void FFTwrapper::smps2freqs(const float *smps, fft_t *freqs) | |||
| { | |||
| //Load data | |||
| for(int i = 0; i < fftsize; ++i) | |||
| time[i] = static_cast<double>(smps[i]); | |||
| //DFT | |||
| fftw_execute(planfftw); | |||
| //Grab data | |||
| memcpy((void *)freqs, (const void *)fft, fftsize * sizeof(double)); | |||
| } | |||
| void FFTwrapper::freqs2smps(const fft_t *freqs, float *smps) | |||
| { | |||
| //Load data | |||
| memcpy((void *)fft, (const void *)freqs, fftsize * sizeof(double)); | |||
| //clear unused freq channel | |||
| fft[fftsize / 2][0] = 0.0f; | |||
| fft[fftsize / 2][1] = 0.0f; | |||
| //IDFT | |||
| fftw_execute(planfftw_inv); | |||
| //Grab data | |||
| for(int i = 0; i < fftsize; ++i) | |||
| smps[i] = static_cast<float>(time[i]); | |||
| } | |||
| void FFT_cleanup() | |||
| { | |||
| fftw_cleanup(); | |||
| } | |||
| @@ -0,0 +1,52 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| FFTwrapper.h - A wrapper for Fast Fourier Transforms | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef FFT_WRAPPER_H | |||
| #define FFT_WRAPPER_H | |||
| #include <fftw3.h> | |||
| #include <complex> | |||
| typedef double fftw_real; | |||
| typedef std::complex<fftw_real> fft_t; | |||
| /**A wrapper for the FFTW library (Fast Fourier Transforms)*/ | |||
| class FFTwrapper | |||
| { | |||
| public: | |||
| /**Constructor | |||
| * @param fftsize The size of samples to be fed to fftw*/ | |||
| FFTwrapper(int fftsize_); | |||
| /**Destructor*/ | |||
| ~FFTwrapper(); | |||
| /**Convert Samples to Frequencies using Fourier Transform | |||
| * @param smps Pointer to Samples to be converted; has length fftsize_ | |||
| * @param freqs Structure FFTFREQS which stores the frequencies*/ | |||
| void smps2freqs(const float *smps, fft_t *freqs); | |||
| void freqs2smps(const fft_t *freqs, float *smps); | |||
| private: | |||
| int fftsize; | |||
| fftw_real *time; | |||
| fftw_complex *fft; | |||
| fftw_plan planfftw, planfftw_inv; | |||
| }; | |||
| void FFT_cleanup(); | |||
| #endif | |||
| @@ -0,0 +1,62 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Filter.cpp - Filters, uses analog,formant,etc. filters | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <math.h> | |||
| #include <stdio.h> | |||
| #include "Filter.h" | |||
| #include "AnalogFilter.h" | |||
| #include "FormantFilter.h" | |||
| #include "SVFilter.h" | |||
| #include "../Params/FilterParams.h" | |||
| Filter *Filter::generate(FilterParams *pars) | |||
| { | |||
| unsigned char Ftype = pars->Ptype; | |||
| unsigned char Fstages = pars->Pstages; | |||
| Filter *filter; | |||
| switch(pars->Pcategory) { | |||
| case 1: | |||
| filter = new FormantFilter(pars); | |||
| break; | |||
| case 2: | |||
| filter = new SVFilter(Ftype, 1000.0f, pars->getq(), Fstages); | |||
| filter->outgain = dB2rap(pars->getgain()); | |||
| if(filter->outgain > 1.0f) | |||
| filter->outgain = sqrt(filter->outgain); | |||
| break; | |||
| default: | |||
| filter = new AnalogFilter(Ftype, 1000.0f, pars->getq(), Fstages); | |||
| if((Ftype >= 6) && (Ftype <= 8)) | |||
| filter->setgain(pars->getgain()); | |||
| else | |||
| filter->outgain = dB2rap(pars->getgain()); | |||
| break; | |||
| } | |||
| return filter; | |||
| } | |||
| float Filter::getrealfreq(float freqpitch) | |||
| { | |||
| return powf(2.0f, freqpitch + 9.96578428f); //log2(1000)=9.95748f | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Filter.h - Filters, uses analog,formant,etc. filters | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef FILTER_H | |||
| #define FILTER_H | |||
| #include "../globals.h" | |||
| class Filter | |||
| { | |||
| public: | |||
| static float getrealfreq(float freqpitch); | |||
| static Filter *generate(class FilterParams * pars); | |||
| virtual ~Filter() {} | |||
| virtual void filterout(float *smp) = 0; | |||
| virtual void setfreq(float frequency) = 0; | |||
| virtual void setfreq_and_q(float frequency, float q_) = 0; | |||
| virtual void setq(float q_) = 0; | |||
| virtual void setgain(float dBgain) = 0; | |||
| protected: | |||
| float outgain; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,231 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| FormantFilter.cpp - formant filters | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include <cstdio> | |||
| #include "../Misc/Util.h" | |||
| #include "FormantFilter.h" | |||
| #include "AnalogFilter.h" | |||
| #include "../Params/FilterParams.h" | |||
| FormantFilter::FormantFilter(FilterParams *pars) | |||
| { | |||
| numformants = pars->Pnumformants; | |||
| for(int i = 0; i < numformants; ++i) | |||
| formant[i] = new AnalogFilter(4 /*BPF*/, 1000.0f, 10.0f, pars->Pstages); | |||
| cleanup(); | |||
| for(int j = 0; j < FF_MAX_VOWELS; ++j) | |||
| for(int i = 0; i < numformants; ++i) { | |||
| formantpar[j][i].freq = pars->getformantfreq( | |||
| pars->Pvowels[j].formants[i].freq); | |||
| formantpar[j][i].amp = pars->getformantamp( | |||
| pars->Pvowels[j].formants[i].amp); | |||
| formantpar[j][i].q = pars->getformantq( | |||
| pars->Pvowels[j].formants[i].q); | |||
| } | |||
| for(int i = 0; i < FF_MAX_FORMANTS; ++i) | |||
| oldformantamp[i] = 1.0f; | |||
| for(int i = 0; i < numformants; ++i) { | |||
| currentformants[i].freq = 1000.0f; | |||
| currentformants[i].amp = 1.0f; | |||
| currentformants[i].q = 2.0f; | |||
| } | |||
| formantslowness = powf(1.0f - (pars->Pformantslowness / 128.0f), 3.0f); | |||
| sequencesize = pars->Psequencesize; | |||
| if(sequencesize == 0) | |||
| sequencesize = 1; | |||
| for(int k = 0; k < sequencesize; ++k) | |||
| sequence[k].nvowel = pars->Psequence[k].nvowel; | |||
| vowelclearness = powf(10.0f, (pars->Pvowelclearness - 32.0f) / 48.0f); | |||
| sequencestretch = powf(0.1f, (pars->Psequencestretch - 32.0f) / 48.0f); | |||
| if(pars->Psequencereversed) | |||
| sequencestretch *= -1.0f; | |||
| outgain = dB2rap(pars->getgain()); | |||
| oldinput = -1.0f; | |||
| Qfactor = 1.0f; | |||
| oldQfactor = Qfactor; | |||
| firsttime = 1; | |||
| } | |||
| FormantFilter::~FormantFilter() | |||
| { | |||
| for(int i = 0; i < numformants; ++i) | |||
| delete (formant[i]); | |||
| } | |||
| void FormantFilter::cleanup() | |||
| { | |||
| for(int i = 0; i < numformants; ++i) | |||
| formant[i]->cleanup(); | |||
| } | |||
| void FormantFilter::setpos(float input) | |||
| { | |||
| int p1, p2; | |||
| if(firsttime != 0) | |||
| slowinput = input; | |||
| else | |||
| slowinput = slowinput | |||
| * (1.0f - formantslowness) + input * formantslowness; | |||
| if((fabsf(oldinput - input) < 0.001f) && (fabsf(slowinput - input) < 0.001f) | |||
| && (fabsf(Qfactor - oldQfactor) < 0.001f)) { | |||
| // oldinput=input; daca setez asta, o sa faca probleme la schimbari foarte lente | |||
| firsttime = 0; | |||
| return; | |||
| } | |||
| else | |||
| oldinput = input; | |||
| float pos = fmodf(input * sequencestretch, 1.0f); | |||
| if(pos < 0.0f) | |||
| pos += 1.0f; | |||
| F2I(pos * sequencesize, p2); | |||
| p1 = p2 - 1; | |||
| if(p1 < 0) | |||
| p1 += sequencesize; | |||
| pos = fmodf(pos * sequencesize, 1.0f); | |||
| if(pos < 0.0f) | |||
| pos = 0.0f; | |||
| else | |||
| if(pos > 1.0f) | |||
| pos = 1.0f; | |||
| pos = | |||
| (atanf((pos * 2.0f | |||
| - 1.0f) | |||
| * vowelclearness) / atanf(vowelclearness) + 1.0f) * 0.5f; | |||
| p1 = sequence[p1].nvowel; | |||
| p2 = sequence[p2].nvowel; | |||
| if(firsttime != 0) { | |||
| for(int i = 0; i < numformants; ++i) { | |||
| currentformants[i].freq = | |||
| formantpar[p1][i].freq | |||
| * (1.0f - pos) + formantpar[p2][i].freq * pos; | |||
| currentformants[i].amp = | |||
| formantpar[p1][i].amp | |||
| * (1.0f - pos) + formantpar[p2][i].amp * pos; | |||
| currentformants[i].q = | |||
| formantpar[p1][i].q * (1.0f - pos) + formantpar[p2][i].q * pos; | |||
| formant[i]->setfreq_and_q(currentformants[i].freq, | |||
| currentformants[i].q * Qfactor); | |||
| oldformantamp[i] = currentformants[i].amp; | |||
| } | |||
| firsttime = 0; | |||
| } | |||
| else | |||
| for(int i = 0; i < numformants; ++i) { | |||
| currentformants[i].freq = | |||
| currentformants[i].freq * (1.0f - formantslowness) | |||
| + (formantpar[p1][i].freq | |||
| * (1.0f - pos) + formantpar[p2][i].freq * pos) | |||
| * formantslowness; | |||
| currentformants[i].amp = | |||
| currentformants[i].amp * (1.0f - formantslowness) | |||
| + (formantpar[p1][i].amp * (1.0f - pos) | |||
| + formantpar[p2][i].amp * pos) * formantslowness; | |||
| currentformants[i].q = currentformants[i].q | |||
| * (1.0f - formantslowness) | |||
| + (formantpar[p1][i].q * (1.0f - pos) | |||
| + formantpar[p2][i].q | |||
| * pos) * formantslowness; | |||
| formant[i]->setfreq_and_q(currentformants[i].freq, | |||
| currentformants[i].q * Qfactor); | |||
| } | |||
| oldQfactor = Qfactor; | |||
| } | |||
| void FormantFilter::setfreq(float frequency) | |||
| { | |||
| setpos(frequency); | |||
| } | |||
| void FormantFilter::setq(float q_) | |||
| { | |||
| Qfactor = q_; | |||
| for(int i = 0; i < numformants; ++i) | |||
| formant[i]->setq(Qfactor * currentformants[i].q); | |||
| } | |||
| void FormantFilter::setgain(float /*dBgain*/) | |||
| {} | |||
| inline float log_2(float x) | |||
| { | |||
| return logf(x) / logf(2.0f); | |||
| } | |||
| void FormantFilter::setfreq_and_q(float frequency, float q_) | |||
| { | |||
| //Convert form real freq[Hz] | |||
| const float freq = log_2(frequency) - 9.96578428f; //log2(1000)=9.95748f. | |||
| Qfactor = q_; | |||
| setpos(freq); | |||
| } | |||
| void FormantFilter::filterout(float *smp) | |||
| { | |||
| float *inbuffer = getTmpBuffer(); | |||
| memcpy(inbuffer, smp, synth->bufferbytes); | |||
| memset(smp, 0, synth->bufferbytes); | |||
| for(int j = 0; j < numformants; ++j) { | |||
| float *tmpbuf = getTmpBuffer(); | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| tmpbuf[i] = inbuffer[i] * outgain; | |||
| formant[j]->filterout(tmpbuf); | |||
| if(ABOVE_AMPLITUDE_THRESHOLD(oldformantamp[j], currentformants[j].amp)) | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| smp[i] += tmpbuf[i] | |||
| * INTERPOLATE_AMPLITUDE(oldformantamp[j], | |||
| currentformants[j].amp, | |||
| i, | |||
| synth->buffersize); | |||
| else | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| smp[i] += tmpbuf[i] * currentformants[j].amp; | |||
| returnTmpBuffer(tmpbuf); | |||
| oldformantamp[j] = currentformants[j].amp; | |||
| } | |||
| returnTmpBuffer(inbuffer); | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| FormantFilter.h - formant filter | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef FORMANT_FILTER_H | |||
| #define FORMANT_FILTER_H | |||
| #include "../globals.h" | |||
| #include "Filter.h" | |||
| class FormantFilter:public Filter | |||
| { | |||
| public: | |||
| FormantFilter(class FilterParams *pars); | |||
| ~FormantFilter(); | |||
| void filterout(float *smp); | |||
| void setfreq(float frequency); | |||
| void setfreq_and_q(float frequency, float q_); | |||
| void setq(float q_); | |||
| void setgain(float dBgain); | |||
| void cleanup(void); | |||
| private: | |||
| void setpos(float input); | |||
| class AnalogFilter * formant[FF_MAX_FORMANTS]; | |||
| struct { | |||
| float freq, amp, q; //frequency,amplitude,Q | |||
| } formantpar[FF_MAX_VOWELS][FF_MAX_FORMANTS], | |||
| currentformants[FF_MAX_FORMANTS]; | |||
| struct { | |||
| unsigned char nvowel; | |||
| } sequence [FF_MAX_SEQUENCE]; | |||
| float oldformantamp[FF_MAX_FORMANTS]; | |||
| int sequencesize, numformants, firsttime; | |||
| float oldinput, slowinput; | |||
| float Qfactor, formantslowness, oldQfactor; | |||
| float vowelclearness, sequencestretch; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,178 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| SVFilter.cpp - Several state-variable filters | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include <cstdio> | |||
| #include <cstring> | |||
| #include <cassert> | |||
| #include <err.h> | |||
| #include "../Misc/Util.h" | |||
| #include "SVFilter.h" | |||
| SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq, | |||
| unsigned char Fstages) | |||
| :type(Ftype), | |||
| stages(Fstages), | |||
| freq(Ffreq), | |||
| q(Fq), | |||
| gain(1.0f), | |||
| needsinterpolation(false), | |||
| firsttime(true) | |||
| { | |||
| if(stages >= MAX_FILTER_STAGES) | |||
| stages = MAX_FILTER_STAGES; | |||
| outgain = 1.0f; | |||
| cleanup(); | |||
| setfreq_and_q(Ffreq, Fq); | |||
| } | |||
| SVFilter::~SVFilter() | |||
| {} | |||
| void SVFilter::cleanup() | |||
| { | |||
| for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) | |||
| st[i].low = st[i].high = st[i].band = st[i].notch = 0.0f; | |||
| oldabovenq = false; | |||
| abovenq = false; | |||
| } | |||
| void SVFilter::computefiltercoefs(void) | |||
| { | |||
| par.f = freq / synth->samplerate_f * 4.0f; | |||
| if(par.f > 0.99999f) | |||
| par.f = 0.99999f; | |||
| par.q = 1.0f - atanf(sqrtf(q)) * 2.0f / PI; | |||
| par.q = powf(par.q, 1.0f / (stages + 1)); | |||
| par.q_sqrt = sqrtf(par.q); | |||
| } | |||
| void SVFilter::setfreq(float frequency) | |||
| { | |||
| if(frequency < 0.1f) | |||
| frequency = 0.1f; | |||
| float rap = freq / frequency; | |||
| if(rap < 1.0f) | |||
| rap = 1.0f / rap; | |||
| oldabovenq = abovenq; | |||
| abovenq = frequency > (synth->samplerate_f / 2 - 500.0f); | |||
| bool nyquistthresh = (abovenq ^ oldabovenq); | |||
| //if the frequency is changed fast, it needs interpolation | |||
| if((rap > 3.0f) || nyquistthresh) { //(now, filter and coeficients backup) | |||
| if(!firsttime) | |||
| needsinterpolation = true; | |||
| ipar = par; | |||
| } | |||
| freq = frequency; | |||
| computefiltercoefs(); | |||
| firsttime = false; | |||
| } | |||
| void SVFilter::setfreq_and_q(float frequency, float q_) | |||
| { | |||
| q = q_; | |||
| setfreq(frequency); | |||
| } | |||
| void SVFilter::setq(float q_) | |||
| { | |||
| q = q_; | |||
| computefiltercoefs(); | |||
| } | |||
| void SVFilter::settype(int type_) | |||
| { | |||
| type = type_; | |||
| computefiltercoefs(); | |||
| } | |||
| void SVFilter::setgain(float dBgain) | |||
| { | |||
| gain = dB2rap(dBgain); | |||
| computefiltercoefs(); | |||
| } | |||
| void SVFilter::setstages(int stages_) | |||
| { | |||
| if(stages_ >= MAX_FILTER_STAGES) | |||
| stages_ = MAX_FILTER_STAGES - 1; | |||
| stages = stages_; | |||
| cleanup(); | |||
| computefiltercoefs(); | |||
| } | |||
| void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par) | |||
| { | |||
| float *out = NULL; | |||
| switch(type) { | |||
| case 0: | |||
| out = &x.low; | |||
| break; | |||
| case 1: | |||
| out = &x.high; | |||
| break; | |||
| case 2: | |||
| out = &x.band; | |||
| break; | |||
| case 3: | |||
| out = &x.notch; | |||
| break; | |||
| default: | |||
| errx(1, "Impossible SVFilter type encountered [%d]", type); | |||
| } | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| x.low = x.low + par.f * x.band; | |||
| x.high = par.q_sqrt * smp[i] - x.low - par.q * x.band; | |||
| x.band = par.f * x.high + x.band; | |||
| x.notch = x.high + x.low; | |||
| smp[i] = *out; | |||
| } | |||
| } | |||
| void SVFilter::filterout(float *smp) | |||
| { | |||
| for(int i = 0; i < stages + 1; ++i) | |||
| singlefilterout(smp, st[i], par); | |||
| if(needsinterpolation) { | |||
| float *ismp = getTmpBuffer(); | |||
| memcpy(ismp, smp, synth->bufferbytes); | |||
| for(int i = 0; i < stages + 1; ++i) | |||
| singlefilterout(ismp, st[i], ipar); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float x = i / synth->buffersize_f; | |||
| smp[i] = ismp[i] * (1.0f - x) + smp[i] * x; | |||
| } | |||
| returnTmpBuffer(ismp); | |||
| needsinterpolation = false; | |||
| } | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| smp[i] *= outgain; | |||
| } | |||
| @@ -0,0 +1,69 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| SV Filter.h - Several state-variable filters | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef SV_FILTER_H | |||
| #define SV_FILTER_H | |||
| #include "../globals.h" | |||
| #include "Filter.h" | |||
| class SVFilter:public Filter | |||
| { | |||
| public: | |||
| SVFilter(unsigned char Ftype, | |||
| float Ffreq, | |||
| float Fq, | |||
| unsigned char Fstages); | |||
| ~SVFilter(); | |||
| void filterout(float *smp); | |||
| void setfreq(float frequency); | |||
| void setfreq_and_q(float frequency, float q_); | |||
| void setq(float q_); | |||
| void settype(int type_); | |||
| void setgain(float dBgain); | |||
| void setstages(int stages_); | |||
| void cleanup(); | |||
| private: | |||
| struct fstage { | |||
| float low, high, band, notch; | |||
| } st[MAX_FILTER_STAGES + 1]; | |||
| struct parameters { | |||
| float f, q, q_sqrt; | |||
| } par, ipar; | |||
| void singlefilterout(float *smp, fstage &x, parameters &par); | |||
| void computefiltercoefs(void); | |||
| int type; // The type of the filter (LPF1,HPF1,LPF2,HPF2...) | |||
| int stages; // how many times the filter is applied (0->1,1->2,etc.) | |||
| float freq; // Frequency given in Hz | |||
| float q; // Q factor (resonance or Q factor) | |||
| float gain; // the gain of the filter (if are shelf/peak) filters | |||
| bool abovenq, //if the frequency is above the nyquist | |||
| oldabovenq; | |||
| bool needsinterpolation, firsttime; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,198 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Unison.cpp - Unison effect (multivoice chorus) | |||
| Copyright (C) 2002-2009 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include <cstring> | |||
| #include <err.h> | |||
| #include "Unison.h" | |||
| Unison::Unison(int update_period_samples_, float max_delay_sec_) | |||
| :unison_size(0), | |||
| base_freq(1.0f), | |||
| uv(NULL), | |||
| update_period_samples(update_period_samples_), | |||
| update_period_sample_k(0), | |||
| max_delay((int)(synth->samplerate_f * max_delay_sec_) + 1), | |||
| delay_k(0), | |||
| first_time(false), | |||
| delay_buffer(NULL), | |||
| unison_amplitude_samples(0.0f), | |||
| unison_bandwidth_cents(10.0f) | |||
| { | |||
| if(max_delay < 10) | |||
| max_delay = 10; | |||
| delay_buffer = new float[max_delay]; | |||
| memset(delay_buffer, 0, max_delay * sizeof(float)); | |||
| setSize(1); | |||
| } | |||
| Unison::~Unison() { | |||
| delete [] delay_buffer; | |||
| delete [] uv; | |||
| } | |||
| void Unison::setSize(int new_size) | |||
| { | |||
| if(new_size < 1) | |||
| new_size = 1; | |||
| unison_size = new_size; | |||
| if(uv) | |||
| delete [] uv; | |||
| uv = new UnisonVoice[unison_size]; | |||
| first_time = true; | |||
| updateParameters(); | |||
| } | |||
| void Unison::setBaseFrequency(float freq) | |||
| { | |||
| base_freq = freq; | |||
| updateParameters(); | |||
| } | |||
| void Unison::setBandwidth(float bandwidth) | |||
| { | |||
| if(bandwidth < 0) | |||
| bandwidth = 0.0f; | |||
| if(bandwidth > 1200.0f) | |||
| bandwidth = 1200.0f; | |||
| /* If the bandwidth is too small, the audio may cancel itself out | |||
| * (due to the sign change of the outputs) | |||
| * TODO figure out the acceptable lower bound and codify it | |||
| */ | |||
| unison_bandwidth_cents = bandwidth; | |||
| updateParameters(); | |||
| } | |||
| void Unison::updateParameters(void) | |||
| { | |||
| if(!uv) | |||
| return; | |||
| float increments_per_second = synth->samplerate_f | |||
| / (float) update_period_samples; | |||
| // printf("#%g, %g\n",increments_per_second,base_freq); | |||
| for(int i = 0; i < unison_size; ++i) { | |||
| float base = powf(UNISON_FREQ_SPAN, synth->numRandom() * 2.0f - 1.0f); | |||
| uv[i].relative_amplitude = base; | |||
| float period = base / base_freq; | |||
| float m = 4.0f / (period * increments_per_second); | |||
| if(synth->numRandom() < 0.5f) | |||
| m = -m; | |||
| uv[i].step = m; | |||
| // printf("%g %g\n",uv[i].relative_amplitude,period); | |||
| } | |||
| float max_speed = powf(2.0f, unison_bandwidth_cents / 1200.0f); | |||
| unison_amplitude_samples = 0.125f * (max_speed - 1.0f) | |||
| * synth->samplerate_f / base_freq; | |||
| //If functions exceed this limit, they should have requested a bigguer delay | |||
| //and thus are buggy | |||
| if(unison_amplitude_samples >= max_delay - 1) { | |||
| warnx("BUG: Unison amplitude samples too big"); | |||
| warnx("Unision max_delay should be larger"); | |||
| unison_amplitude_samples = max_delay - 2; | |||
| } | |||
| updateUnisonData(); | |||
| } | |||
| void Unison::process(int bufsize, float *inbuf, float *outbuf) | |||
| { | |||
| if(!uv) | |||
| return; | |||
| if(!outbuf) | |||
| outbuf = inbuf; | |||
| float volume = 1.0f / sqrtf(unison_size); | |||
| float xpos_step = 1.0f / (float) update_period_samples; | |||
| float xpos = (float) update_period_sample_k * xpos_step; | |||
| for(int i = 0; i < bufsize; ++i) { | |||
| if(update_period_sample_k++ >= update_period_samples) { | |||
| updateUnisonData(); | |||
| update_period_sample_k = 0; | |||
| xpos = 0.0f; | |||
| } | |||
| xpos += xpos_step; | |||
| float in = inbuf[i], out = 0.0f; | |||
| float sign = 1.0f; | |||
| for(int k = 0; k < unison_size; ++k) { | |||
| float vpos = uv[k].realpos1 * (1.0f - xpos) + uv[k].realpos2 * xpos; //optimize | |||
| float pos = (float)(delay_k + max_delay) - vpos - 1.0f; | |||
| int posi; | |||
| F2I(pos, posi); //optimize! | |||
| int posi_next = posi + 1; | |||
| if(posi >= max_delay) | |||
| posi -= max_delay; | |||
| if(posi_next >= max_delay) | |||
| posi_next -= max_delay; | |||
| float posf = pos - floorf(pos); | |||
| out += ((1.0f - posf) * delay_buffer[posi] + posf | |||
| * delay_buffer[posi_next]) * sign; | |||
| sign = -sign; | |||
| } | |||
| outbuf[i] = out * volume; | |||
| // printf("%d %g\n",i,outbuf[i]); | |||
| delay_buffer[delay_k] = in; | |||
| delay_k = (++delay_k < max_delay) ? delay_k : 0; | |||
| } | |||
| } | |||
| void Unison::updateUnisonData() | |||
| { | |||
| if(!uv) | |||
| return; | |||
| for(int k = 0; k < unison_size; ++k) { | |||
| float pos = uv[k].position; | |||
| float step = uv[k].step; | |||
| pos += step; | |||
| if(pos <= -1.0f) { | |||
| pos = -1.0f; | |||
| step = -step; | |||
| } | |||
| else | |||
| if(pos >= 1.0f) { | |||
| pos = 1.0f; | |||
| step = -step; | |||
| } | |||
| float vibratto_val = (pos - 0.333333333f * pos * pos * pos) * 1.5f; //make the vibratto lfo smoother | |||
| //Relative amplitude is utilized, so the delay may be larger than the | |||
| //whole buffer, if the buffer is too small, this indicates a buggy call | |||
| //to Unison() | |||
| float newval = 1.0f + 0.5f | |||
| * (vibratto_val + 1.0f) * unison_amplitude_samples | |||
| * uv[k].relative_amplitude; | |||
| if(first_time) | |||
| uv[k].realpos1 = uv[k].realpos2 = newval; | |||
| else { | |||
| uv[k].realpos1 = uv[k].realpos2; | |||
| uv[k].realpos2 = newval; | |||
| } | |||
| uv[k].position = pos; | |||
| uv[k].step = step; | |||
| } | |||
| first_time = false; | |||
| } | |||
| @@ -0,0 +1,73 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Unison.h - Unison effect (multivoice chorus) | |||
| Copyright (C) 2002-2009 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef UNISON_H | |||
| #define UNISON_H | |||
| #include "../Misc/Util.h" | |||
| //how much the unison frequencies varies (always >= 1.0) | |||
| #define UNISON_FREQ_SPAN 2.0f | |||
| class Unison | |||
| { | |||
| public: | |||
| Unison(int update_period_samples_, float max_delay_sec_); | |||
| ~Unison(); | |||
| void setSize(int new_size); | |||
| void setBaseFrequency(float freq); | |||
| void setBandwidth(float bandwidth_cents); | |||
| void process(int bufsize, float *inbuf, float *outbuf = NULL); | |||
| private: | |||
| void updateParameters(void); | |||
| void updateUnisonData(void); | |||
| int unison_size; | |||
| float base_freq; | |||
| struct UnisonVoice { | |||
| float step; //base LFO | |||
| float position; | |||
| float realpos1; //the position regarding samples | |||
| float realpos2; | |||
| float relative_amplitude; | |||
| float lin_fpos; | |||
| float lin_ffreq; | |||
| UnisonVoice() { | |||
| position = RND * 1.8f - 0.9f; | |||
| realpos1 = 0.0f; | |||
| realpos2 = 0.0f; | |||
| step = 0.0f; | |||
| relative_amplitude = 1.0f; | |||
| } | |||
| } *uv; | |||
| int update_period_samples; | |||
| int update_period_sample_k; | |||
| int max_delay, delay_k; | |||
| bool first_time; | |||
| float *delay_buffer; | |||
| float unison_amplitude_samples; | |||
| float unison_bandwidth_cents; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,235 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Alienwah.cpp - "AlienWah" effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include "Alienwah.h" | |||
| Alienwah::Alienwah(bool insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), | |||
| oldl(NULL), | |||
| oldr(NULL) | |||
| { | |||
| setpreset(Ppreset); | |||
| cleanup(); | |||
| oldclfol = complex<float>(fb, 0.0f); | |||
| oldclfor = complex<float>(fb, 0.0f); | |||
| } | |||
| Alienwah::~Alienwah() | |||
| { | |||
| if(oldl != NULL) | |||
| delete [] oldl; | |||
| if(oldr != NULL) | |||
| delete [] oldr; | |||
| } | |||
| //Apply the effect | |||
| void Alienwah::out(const Stereo<float *> &smp) | |||
| { | |||
| float lfol, lfor; //Left/Right LFOs | |||
| complex<float> clfol, clfor; | |||
| /**\todo Rework, as optimization can be used when the new complex type is | |||
| * utilized. | |||
| * Before all calculations needed to be done with individual float, | |||
| * but now they can be done together*/ | |||
| lfo.effectlfoout(&lfol, &lfor); | |||
| lfol *= depth * PI * 2.0f; | |||
| lfor *= depth * PI * 2.0f; | |||
| clfol = complex<float>(cosf(lfol + phase) * fb, sinf(lfol + phase) * fb); //rework | |||
| clfor = complex<float>(cosf(lfor + phase) * fb, sinf(lfor + phase) * fb); //rework | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float x = ((float) i) / synth->buffersize_f; | |||
| float x1 = 1.0f - x; | |||
| //left | |||
| complex<float> tmp = clfol * x + oldclfol * x1; | |||
| complex<float> out = tmp * oldl[oldk]; | |||
| out += (1 - fabs(fb)) * smp.l[i] * pangainL; | |||
| oldl[oldk] = out; | |||
| float l = out.real() * 10.0f * (fb + 0.1f); | |||
| //right | |||
| tmp = clfor * x + oldclfor * x1; | |||
| out = tmp * oldr[oldk]; | |||
| out += (1 - fabs(fb)) * smp.r[i] * pangainR; | |||
| oldr[oldk] = out; | |||
| float r = out.real() * 10.0f * (fb + 0.1f); | |||
| if(++oldk >= Pdelay) | |||
| oldk = 0; | |||
| //LRcross | |||
| efxoutl[i] = l * (1.0f - lrcross) + r * lrcross; | |||
| efxoutr[i] = r * (1.0f - lrcross) + l * lrcross; | |||
| } | |||
| oldclfol = clfol; | |||
| oldclfor = clfor; | |||
| } | |||
| //Cleanup the effect | |||
| void Alienwah::cleanup(void) | |||
| { | |||
| for(int i = 0; i < Pdelay; ++i) { | |||
| oldl[i] = complex<float>(0.0f, 0.0f); | |||
| oldr[i] = complex<float>(0.0f, 0.0f); | |||
| } | |||
| oldk = 0; | |||
| } | |||
| //Parameter control | |||
| void Alienwah::setdepth(unsigned char _Pdepth) | |||
| { | |||
| Pdepth = _Pdepth; | |||
| depth = Pdepth / 127.0f; | |||
| } | |||
| void Alienwah::setfb(unsigned char _Pfb) | |||
| { | |||
| Pfb = _Pfb; | |||
| fb = fabs((Pfb - 64.0f) / 64.1f); | |||
| fb = sqrtf(fb); | |||
| if(fb < 0.4f) | |||
| fb = 0.4f; | |||
| if(Pfb < 64) | |||
| fb = -fb; | |||
| } | |||
| void Alienwah::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| outvolume = Pvolume / 127.0f; | |||
| if(insertion == 0) | |||
| volume = 1.0f; | |||
| else | |||
| volume = outvolume; | |||
| } | |||
| void Alienwah::setphase(unsigned char _Pphase) | |||
| { | |||
| Pphase = _Pphase; | |||
| phase = (Pphase - 64.0f) / 64.0f * PI; | |||
| } | |||
| void Alienwah::setdelay(unsigned char _Pdelay) | |||
| { | |||
| if(oldl != NULL) | |||
| delete [] oldl; | |||
| if(oldr != NULL) | |||
| delete [] oldr; | |||
| Pdelay = (_Pdelay >= MAX_ALIENWAH_DELAY) ? MAX_ALIENWAH_DELAY : _Pdelay; | |||
| oldl = new complex<float>[Pdelay]; | |||
| oldr = new complex<float>[Pdelay]; | |||
| cleanup(); | |||
| } | |||
| void Alienwah::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 11; | |||
| const int NUM_PRESETS = 4; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| //AlienWah1 | |||
| {127, 64, 70, 0, 0, 62, 60, 105, 25, 0, 64}, | |||
| //AlienWah2 | |||
| {127, 64, 73, 106, 0, 101, 60, 105, 17, 0, 64}, | |||
| //AlienWah3 | |||
| {127, 64, 63, 0, 1, 100, 112, 105, 31, 0, 42}, | |||
| //AlienWah4 | |||
| {93, 64, 25, 0, 1, 66, 101, 11, 47, 0, 86} | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| if(insertion == 0) | |||
| changepar(0, presets[npreset][0] / 2); //lower the volume if this is system effect | |||
| Ppreset = npreset; | |||
| } | |||
| void Alienwah::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| lfo.Pfreq = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 3: | |||
| lfo.Prandomness = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 4: | |||
| lfo.PLFOtype = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 5: | |||
| lfo.Pstereo = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 6: | |||
| setdepth(value); | |||
| break; | |||
| case 7: | |||
| setfb(value); | |||
| break; | |||
| case 8: | |||
| setdelay(value); | |||
| break; | |||
| case 9: | |||
| setlrcross(value); | |||
| break; | |||
| case 10: | |||
| setphase(value); | |||
| break; | |||
| } | |||
| } | |||
| unsigned char Alienwah::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return lfo.Pfreq; | |||
| case 3: return lfo.Prandomness; | |||
| case 4: return lfo.PLFOtype; | |||
| case 5: return lfo.Pstereo; | |||
| case 6: return Pdepth; | |||
| case 7: return Pfb; | |||
| case 8: return Pdelay; | |||
| case 9: return Plrcross; | |||
| case 10: return Pphase; | |||
| default: return 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Alienwah.h - "AlienWah" effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef ALIENWAH_H | |||
| #define ALIENWAH_H | |||
| #include <complex> | |||
| #include "Effect.h" | |||
| #include "EffectLFO.h" | |||
| using namespace std; | |||
| #define MAX_ALIENWAH_DELAY 100 | |||
| /**"AlienWah" Effect*/ | |||
| class Alienwah:public Effect | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor | |||
| * @param insertion_ true for insertion Effect | |||
| * @param efxoutl_ Pointer to Alienwah's left channel output buffer | |||
| * @param efxoutr_ Pointer to Alienwah's left channel output buffer | |||
| * @return Initialized Alienwah | |||
| */ | |||
| Alienwah(bool insertion_, | |||
| float *const efxoutl_, | |||
| float *const efxoutr_); | |||
| ~Alienwah(); | |||
| void out(const Stereo<float *> &smp); | |||
| void setpreset(unsigned char npreset); | |||
| void changepar(int npar, unsigned char value); | |||
| unsigned char getpar(int npar) const; | |||
| void cleanup(void); | |||
| private: | |||
| //Alienwah Parameters | |||
| EffectLFO lfo; //lfo-ul Alienwah | |||
| unsigned char Pvolume; | |||
| unsigned char Pdepth; //the depth of the Alienwah | |||
| unsigned char Pfb; //feedback | |||
| unsigned char Pdelay; | |||
| unsigned char Pphase; | |||
| //Control Parameters | |||
| void setvolume(unsigned char _Pvolume); | |||
| void setdepth(unsigned char _Pdepth); | |||
| void setfb(unsigned char _Pfb); | |||
| void setdelay(unsigned char _Pdelay); | |||
| void setphase(unsigned char _Pphase); | |||
| //Internal Values | |||
| float fb, depth, phase; | |||
| complex<float> *oldl, *oldr; | |||
| complex<float> oldclfol, oldclfor; | |||
| int oldk; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,14 @@ | |||
| set(zynaddsubfx_effect_SRCS | |||
| Effects/Alienwah.cpp | |||
| Effects/Chorus.cpp | |||
| Effects/Distorsion.cpp | |||
| Effects/DynamicFilter.cpp | |||
| Effects/Echo.cpp | |||
| Effects/Effect.cpp | |||
| Effects/EffectLFO.cpp | |||
| Effects/EffectMgr.cpp | |||
| Effects/EQ.cpp | |||
| Effects/Phaser.cpp | |||
| Effects/Reverb.cpp | |||
| PARENT_SCOPE | |||
| ) | |||
| @@ -0,0 +1,268 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Chorus.cpp - Chorus and Flange effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include "Chorus.h" | |||
| #include <iostream> | |||
| using namespace std; | |||
| Chorus::Chorus(bool insertion_, float *const efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), | |||
| maxdelay((int)(MAX_CHORUS_DELAY / 1000.0f * synth->samplerate_f)), | |||
| delaySample(new float[maxdelay], new float[maxdelay]) | |||
| { | |||
| dlk = 0; | |||
| drk = 0; | |||
| setpreset(Ppreset); | |||
| changepar(1, 64); | |||
| lfo.effectlfoout(&lfol, &lfor); | |||
| dl2 = getdelay(lfol); | |||
| dr2 = getdelay(lfor); | |||
| cleanup(); | |||
| } | |||
| Chorus::~Chorus() | |||
| { | |||
| delete [] delaySample.l; | |||
| delete [] delaySample.r; | |||
| } | |||
| //get the delay value in samples; xlfo is the current lfo value | |||
| float Chorus::getdelay(float xlfo) | |||
| { | |||
| float result = | |||
| (Pflangemode) ? 0 : (delay + xlfo * depth) * synth->samplerate_f; | |||
| //check if delay is too big (caused by bad setdelay() and setdepth() | |||
| if((result + 0.5f) >= maxdelay) { | |||
| cerr | |||
| << | |||
| "WARNING: Chorus.cpp::getdelay(..) too big delay (see setdelay and setdepth funcs.)" | |||
| << endl; | |||
| result = maxdelay - 1.0f; | |||
| } | |||
| return result; | |||
| } | |||
| //Apply the effect | |||
| void Chorus::out(const Stereo<float *> &input) | |||
| { | |||
| const float one = 1.0f; | |||
| dl1 = dl2; | |||
| dr1 = dr2; | |||
| lfo.effectlfoout(&lfol, &lfor); | |||
| dl2 = getdelay(lfol); | |||
| dr2 = getdelay(lfor); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float inL = input.l[i]; | |||
| float inR = input.r[i]; | |||
| //LRcross | |||
| Stereo<float> tmpc(inL, inR); | |||
| inL = tmpc.l * (1.0f - lrcross) + tmpc.r * lrcross; | |||
| inR = tmpc.r * (1.0f - lrcross) + tmpc.l * lrcross; | |||
| //Left channel | |||
| //compute the delay in samples using linear interpolation between the lfo delays | |||
| float mdel = | |||
| (dl1 * (synth->buffersize - i) + dl2 * i) / synth->buffersize_f; | |||
| if(++dlk >= maxdelay) | |||
| dlk = 0; | |||
| float tmp = dlk - mdel + maxdelay * 2.0f; //where should I get the sample from | |||
| dlhi = (int) tmp; | |||
| dlhi %= maxdelay; | |||
| float dlhi2 = (dlhi - 1 + maxdelay) % maxdelay; | |||
| float dllo = 1.0f - fmod(tmp, one); | |||
| efxoutl[i] = cinterpolate(delaySample.l, maxdelay, dlhi2) * dllo | |||
| + cinterpolate(delaySample.l, maxdelay, | |||
| dlhi) * (1.0f - dllo); | |||
| delaySample.l[dlk] = inL + efxoutl[i] * fb; | |||
| //Right channel | |||
| //compute the delay in samples using linear interpolation between the lfo delays | |||
| mdel = (dr1 * (synth->buffersize - i) + dr2 * i) / synth->buffersize_f; | |||
| if(++drk >= maxdelay) | |||
| drk = 0; | |||
| tmp = drk * 1.0f - mdel + maxdelay * 2.0f; //where should I get the sample from | |||
| dlhi = (int) tmp; | |||
| dlhi %= maxdelay; | |||
| dlhi2 = (dlhi - 1 + maxdelay) % maxdelay; | |||
| dllo = 1.0f - fmodf(tmp, one); | |||
| efxoutr[i] = cinterpolate(delaySample.r, maxdelay, dlhi2) * dllo | |||
| + cinterpolate(delaySample.r, maxdelay, | |||
| dlhi) * (1.0f - dllo); | |||
| delaySample.r[dlk] = inR + efxoutr[i] * fb; | |||
| } | |||
| if(Poutsub) | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] *= -1.0f; | |||
| efxoutr[i] *= -1.0f; | |||
| } | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] *= pangainL; | |||
| efxoutr[i] *= pangainR; | |||
| } | |||
| } | |||
| //Cleanup the effect | |||
| void Chorus::cleanup(void) | |||
| { | |||
| memset(delaySample.l, 0, maxdelay * sizeof(float)); | |||
| memset(delaySample.r, 0, maxdelay * sizeof(float)); | |||
| } | |||
| //Parameter control | |||
| void Chorus::setdepth(unsigned char _Pdepth) | |||
| { | |||
| Pdepth = _Pdepth; | |||
| depth = (powf(8.0f, (Pdepth / 127.0f) * 2.0f) - 1.0f) / 1000.0f; //seconds | |||
| } | |||
| void Chorus::setdelay(unsigned char _Pdelay) | |||
| { | |||
| Pdelay = _Pdelay; | |||
| delay = (powf(10.0f, (Pdelay / 127.0f) * 2.0f) - 1.0f) / 1000.0f; //seconds | |||
| } | |||
| void Chorus::setfb(unsigned char _Pfb) | |||
| { | |||
| Pfb = _Pfb; | |||
| fb = (Pfb - 64.0f) / 64.1f; | |||
| } | |||
| void Chorus::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| outvolume = Pvolume / 127.0f; | |||
| volume = (!insertion) ? 1.0f : outvolume; | |||
| } | |||
| void Chorus::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 12; | |||
| const int NUM_PRESETS = 10; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| //Chorus1 | |||
| {64, 64, 50, 0, 0, 90, 40, 85, 64, 119, 0, 0}, | |||
| //Chorus2 | |||
| {64, 64, 45, 0, 0, 98, 56, 90, 64, 19, 0, 0}, | |||
| //Chorus3 | |||
| {64, 64, 29, 0, 1, 42, 97, 95, 90, 127, 0, 0}, | |||
| //Celeste1 | |||
| {64, 64, 26, 0, 0, 42, 115, 18, 90, 127, 0, 0}, | |||
| //Celeste2 | |||
| {64, 64, 29, 117, 0, 50, 115, 9, 31, 127, 0, 1}, | |||
| //Flange1 | |||
| {64, 64, 57, 0, 0, 60, 23, 3, 62, 0, 0, 0}, | |||
| //Flange2 | |||
| {64, 64, 33, 34, 1, 40, 35, 3, 109, 0, 0, 0}, | |||
| //Flange3 | |||
| {64, 64, 53, 34, 1, 94, 35, 3, 54, 0, 0, 1}, | |||
| //Flange4 | |||
| {64, 64, 40, 0, 1, 62, 12, 19, 97, 0, 0, 0}, | |||
| //Flange5 | |||
| {64, 64, 55, 105, 0, 24, 39, 19, 17, 0, 0, 1} | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| Ppreset = npreset; | |||
| } | |||
| void Chorus::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| lfo.Pfreq = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 3: | |||
| lfo.Prandomness = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 4: | |||
| lfo.PLFOtype = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 5: | |||
| lfo.Pstereo = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 6: | |||
| setdepth(value); | |||
| break; | |||
| case 7: | |||
| setdelay(value); | |||
| break; | |||
| case 8: | |||
| setfb(value); | |||
| break; | |||
| case 9: | |||
| setlrcross(value); | |||
| break; | |||
| case 10: | |||
| Pflangemode = (value > 1) ? 1 : value; | |||
| break; | |||
| case 11: | |||
| Poutsub = (value > 1) ? 1 : value; | |||
| break; | |||
| } | |||
| } | |||
| unsigned char Chorus::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return lfo.Pfreq; | |||
| case 3: return lfo.Prandomness; | |||
| case 4: return lfo.PLFOtype; | |||
| case 5: return lfo.Pstereo; | |||
| case 6: return Pdepth; | |||
| case 7: return Pdelay; | |||
| case 8: return Pfb; | |||
| case 9: return Plrcross; | |||
| case 10: return Pflangemode; | |||
| case 11: return Poutsub; | |||
| default: return 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,106 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Chorus.h - Chorus and Flange effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef CHORUS_H | |||
| #define CHORUS_H | |||
| #include "Effect.h" | |||
| #include "EffectLFO.h" | |||
| #include "../Misc/Stereo.h" | |||
| #define MAX_CHORUS_DELAY 250.0f //ms | |||
| /**Chorus and Flange effects*/ | |||
| class Chorus:public Effect | |||
| { | |||
| public: | |||
| Chorus(bool insertion_, float *efxoutl_, float *efxoutr_); | |||
| /**Destructor*/ | |||
| ~Chorus(); | |||
| void out(const Stereo<float *> &input); | |||
| void setpreset(unsigned char npreset); | |||
| /** | |||
| * Sets the value of the chosen variable | |||
| * | |||
| * The possible parameters are: | |||
| * -# Volume | |||
| * -# Panning | |||
| * -# LFO Frequency | |||
| * -# LFO Randomness | |||
| * -# LFO Type | |||
| * -# LFO stereo | |||
| * -# Depth | |||
| * -# Delay | |||
| * -# Feedback | |||
| * -# Flange Mode | |||
| * -# Subtractive | |||
| * @param npar number of chosen parameter | |||
| * @param value the new value | |||
| */ | |||
| void changepar(int npar, unsigned char value); | |||
| /** | |||
| * Gets the value of the chosen variable | |||
| * | |||
| * The possible parameters are: | |||
| * -# Volume | |||
| * -# Panning | |||
| * -# LFO Frequency | |||
| * -# LFO Randomness | |||
| * -# LFO Type | |||
| * -# LFO stereo | |||
| * -# Depth | |||
| * -# Delay | |||
| * -# Feedback | |||
| * -# Flange Mode | |||
| * -# Subtractive | |||
| * @param npar number of chosen parameter | |||
| * @return the value of the parameter | |||
| */ | |||
| unsigned char getpar(int npar) const; | |||
| void cleanup(void); | |||
| private: | |||
| //Chorus Parameters | |||
| unsigned char Pvolume; | |||
| unsigned char Pdepth; //the depth of the Chorus(ms) | |||
| unsigned char Pdelay; //the delay (ms) | |||
| unsigned char Pfb; //feedback | |||
| unsigned char Pflangemode; //how the LFO is scaled, to result chorus or flange | |||
| unsigned char Poutsub; //if I wish to substract the output instead of the adding it | |||
| EffectLFO lfo; //lfo-ul chorus | |||
| //Parameter Controls | |||
| void setvolume(unsigned char _Pvolume); | |||
| void setdepth(unsigned char _Pdepth); | |||
| void setdelay(unsigned char _Pdelay); | |||
| void setfb(unsigned char _Pfb); | |||
| //Internal Values | |||
| float depth, delay, fb; | |||
| float dl1, dl2, dr1, dr2, lfol, lfor; | |||
| int maxdelay; | |||
| Stereo<float *> delaySample; | |||
| int dlk, drk, dlhi; | |||
| float getdelay(float xlfo); | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,245 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Distorsion.cpp - Distorsion effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "Distorsion.h" | |||
| #include "../DSP/AnalogFilter.h" | |||
| #include "../Misc/WaveShapeSmps.h" | |||
| #include <cmath> | |||
| Distorsion::Distorsion(bool insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), | |||
| Pvolume(50), | |||
| Pdrive(90), | |||
| Plevel(64), | |||
| Ptype(0), | |||
| Pnegate(0), | |||
| Plpf(127), | |||
| Phpf(0), | |||
| Pstereo(0), | |||
| Pprefiltering(0) | |||
| { | |||
| lpfl = new AnalogFilter(2, 22000, 1, 0); | |||
| lpfr = new AnalogFilter(2, 22000, 1, 0); | |||
| hpfl = new AnalogFilter(3, 20, 1, 0); | |||
| hpfr = new AnalogFilter(3, 20, 1, 0); | |||
| setpreset(Ppreset); | |||
| cleanup(); | |||
| } | |||
| Distorsion::~Distorsion() | |||
| { | |||
| delete lpfl; | |||
| delete lpfr; | |||
| delete hpfl; | |||
| delete hpfr; | |||
| } | |||
| //Cleanup the effect | |||
| void Distorsion::cleanup(void) | |||
| { | |||
| lpfl->cleanup(); | |||
| hpfl->cleanup(); | |||
| lpfr->cleanup(); | |||
| hpfr->cleanup(); | |||
| } | |||
| //Apply the filters | |||
| void Distorsion::applyfilters(float *efxoutl, float *efxoutr) | |||
| { | |||
| lpfl->filterout(efxoutl); | |||
| hpfl->filterout(efxoutl); | |||
| if(Pstereo != 0) { //stereo | |||
| lpfr->filterout(efxoutr); | |||
| hpfr->filterout(efxoutr); | |||
| } | |||
| } | |||
| //Effect output | |||
| void Distorsion::out(const Stereo<float *> &smp) | |||
| { | |||
| float inputvol = powf(5.0f, (Pdrive - 32.0f) / 127.0f); | |||
| if(Pnegate) | |||
| inputvol *= -1.0f; | |||
| if(Pstereo) //Stereo | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] = smp.l[i] * inputvol * pangainL; | |||
| efxoutr[i] = smp.r[i] * inputvol * pangainR; | |||
| } | |||
| else //Mono | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| efxoutl[i] = (smp.l[i] * pangainL + smp.r[i] * pangainR) * inputvol; | |||
| if(Pprefiltering) | |||
| applyfilters(efxoutl, efxoutr); | |||
| waveShapeSmps(synth->buffersize, efxoutl, Ptype + 1, Pdrive); | |||
| if(Pstereo) | |||
| waveShapeSmps(synth->buffersize, efxoutr, Ptype + 1, Pdrive); | |||
| if(!Pprefiltering) | |||
| applyfilters(efxoutl, efxoutr); | |||
| if(!Pstereo) | |||
| memcpy(efxoutr, efxoutl, synth->bufferbytes); | |||
| float level = dB2rap(60.0f * Plevel / 127.0f - 40.0f); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float lout = efxoutl[i]; | |||
| float rout = efxoutr[i]; | |||
| float l = lout * (1.0f - lrcross) + rout * lrcross; | |||
| float r = rout * (1.0f - lrcross) + lout * lrcross; | |||
| lout = l; | |||
| rout = r; | |||
| efxoutl[i] = lout * 2.0f * level; | |||
| efxoutr[i] = rout * 2.0f * level; | |||
| } | |||
| } | |||
| //Parameter control | |||
| void Distorsion::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| if(insertion == 0) { | |||
| outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
| volume = 1.0f; | |||
| } | |||
| else | |||
| volume = outvolume = Pvolume / 127.0f; | |||
| if(Pvolume == 0) | |||
| cleanup(); | |||
| } | |||
| void Distorsion::setlpf(unsigned char _Plpf) | |||
| { | |||
| Plpf = _Plpf; | |||
| float fr = expf(powf(Plpf / 127.0f, 0.5f) * logf(25000.0f)) + 40.0f; | |||
| lpfl->setfreq(fr); | |||
| lpfr->setfreq(fr); | |||
| } | |||
| void Distorsion::sethpf(unsigned char _Phpf) | |||
| { | |||
| Phpf = _Phpf; | |||
| float fr = expf(powf(Phpf / 127.0f, 0.5f) * logf(25000.0f)) + 20.0f; | |||
| hpfl->setfreq(fr); | |||
| hpfr->setfreq(fr); | |||
| } | |||
| void Distorsion::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 11; | |||
| const int NUM_PRESETS = 6; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| //Overdrive 1 | |||
| {127, 64, 35, 56, 70, 0, 0, 96, 0, 0, 0}, | |||
| //Overdrive 2 | |||
| {127, 64, 35, 29, 75, 1, 0, 127, 0, 0, 0}, | |||
| //A. Exciter 1 | |||
| {64, 64, 35, 75, 80, 5, 0, 127, 105, 1, 0}, | |||
| //A. Exciter 2 | |||
| {64, 64, 35, 85, 62, 1, 0, 127, 118, 1, 0}, | |||
| //Guitar Amp | |||
| {127, 64, 35, 63, 75, 2, 0, 55, 0, 0, 0}, | |||
| //Quantisize | |||
| {127, 64, 35, 88, 75, 4, 0, 127, 0, 1, 0} | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| if(!insertion) //lower the volume if this is system effect | |||
| changepar(0, (int) (presets[npreset][0] / 1.5f)); | |||
| Ppreset = npreset; | |||
| cleanup(); | |||
| } | |||
| void Distorsion::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| setlrcross(value); | |||
| break; | |||
| case 3: | |||
| Pdrive = value; | |||
| break; | |||
| case 4: | |||
| Plevel = value; | |||
| break; | |||
| case 5: | |||
| if(value > 13) | |||
| Ptype = 13; //this must be increased if more distorsion types are added | |||
| else | |||
| Ptype = value; | |||
| break; | |||
| case 6: | |||
| if(value > 1) | |||
| Pnegate = 1; | |||
| else | |||
| Pnegate = value; | |||
| break; | |||
| case 7: | |||
| setlpf(value); | |||
| break; | |||
| case 8: | |||
| sethpf(value); | |||
| break; | |||
| case 9: | |||
| Pstereo = (value > 1) ? 1 : value; | |||
| break; | |||
| case 10: | |||
| Pprefiltering = value; | |||
| break; | |||
| } | |||
| } | |||
| unsigned char Distorsion::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return Plrcross; | |||
| case 3: return Pdrive; | |||
| case 4: return Plevel; | |||
| case 5: return Ptype; | |||
| case 6: return Pnegate; | |||
| case 7: return Plpf; | |||
| case 8: return Phpf; | |||
| case 9: return Pstereo; | |||
| case 10: return Pprefiltering; | |||
| default: return 0; //in case of bogus parameter number | |||
| } | |||
| } | |||
| @@ -0,0 +1,61 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Distorsion.h - Distorsion Effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef DISTORSION_H | |||
| #define DISTORSION_H | |||
| #include "Effect.h" | |||
| /**Distortion Effect*/ | |||
| class Distorsion:public Effect | |||
| { | |||
| public: | |||
| Distorsion(bool insertion, float *efxoutl_, float *efxoutr_); | |||
| ~Distorsion(); | |||
| void out(const Stereo<float *> &smp); | |||
| void setpreset(unsigned char npreset); | |||
| void changepar(int npar, unsigned char value); | |||
| unsigned char getpar(int npar) const; | |||
| void cleanup(void); | |||
| void applyfilters(float *efxoutl, float *efxoutr); | |||
| private: | |||
| //Parameters | |||
| unsigned char Pvolume; //Volume or E/R | |||
| unsigned char Pdrive; //the input amplification | |||
| unsigned char Plevel; //the output amplification | |||
| unsigned char Ptype; //Distorsion type | |||
| unsigned char Pnegate; //if the input is negated | |||
| unsigned char Plpf; //lowpass filter | |||
| unsigned char Phpf; //highpass filter | |||
| unsigned char Pstereo; //0=mono, 1=stereo | |||
| unsigned char Pprefiltering; //if you want to do the filtering before the distorsion | |||
| void setvolume(unsigned char _Pvolume); | |||
| void setlpf(unsigned char _Plpf); | |||
| void sethpf(unsigned char _Phpf); | |||
| //Real Parameters | |||
| class AnalogFilter * lpfl, *lpfr, *hpfl, *hpfr; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,311 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| DynamicFilter.cpp - "WahWah" effect and others | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include "DynamicFilter.h" | |||
| #include "../DSP/Filter.h" | |||
| DynamicFilter::DynamicFilter(bool insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, new FilterParams(0, 64, 64), 0), | |||
| Pvolume(110), | |||
| Pdepth(0), | |||
| Pampsns(90), | |||
| Pampsnsinv(0), | |||
| Pampsmooth(60), | |||
| filterl(NULL), | |||
| filterr(NULL) | |||
| { | |||
| setpreset(Ppreset); | |||
| cleanup(); | |||
| } | |||
| DynamicFilter::~DynamicFilter() | |||
| { | |||
| delete filterpars; | |||
| delete filterl; | |||
| delete filterr; | |||
| } | |||
| // Apply the effect | |||
| void DynamicFilter::out(const Stereo<float *> &smp) | |||
| { | |||
| if(filterpars->changed) { | |||
| filterpars->changed = false; | |||
| cleanup(); | |||
| } | |||
| float lfol, lfor; | |||
| lfo.effectlfoout(&lfol, &lfor); | |||
| lfol *= depth * 5.0f; | |||
| lfor *= depth * 5.0f; | |||
| const float freq = filterpars->getfreq(); | |||
| const float q = filterpars->getq(); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] = smp.l[i]; | |||
| efxoutr[i] = smp.r[i]; | |||
| const float x = (fabsf(smp.l[i]) + fabsf(smp.l[i])) * 0.5f; | |||
| ms1 = ms1 * (1.0f - ampsmooth) + x * ampsmooth + 1e-10; | |||
| } | |||
| const float ampsmooth2 = powf(ampsmooth, 0.2f) * 0.3f; | |||
| ms2 = ms2 * (1.0f - ampsmooth2) + ms1 * ampsmooth2; | |||
| ms3 = ms3 * (1.0f - ampsmooth2) + ms2 * ampsmooth2; | |||
| ms4 = ms4 * (1.0f - ampsmooth2) + ms3 * ampsmooth2; | |||
| const float rms = (sqrtf(ms4)) * ampsns; | |||
| const float frl = Filter::getrealfreq(freq + lfol + rms); | |||
| const float frr = Filter::getrealfreq(freq + lfor + rms); | |||
| filterl->setfreq_and_q(frl, q); | |||
| filterr->setfreq_and_q(frr, q); | |||
| filterl->filterout(efxoutl); | |||
| filterr->filterout(efxoutr); | |||
| //panning | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] *= pangainL; | |||
| efxoutr[i] *= pangainR; | |||
| } | |||
| } | |||
| // Cleanup the effect | |||
| void DynamicFilter::cleanup(void) | |||
| { | |||
| reinitfilter(); | |||
| ms1 = ms2 = ms3 = ms4 = 0.0f; | |||
| } | |||
| //Parameter control | |||
| void DynamicFilter::setdepth(unsigned char _Pdepth) | |||
| { | |||
| Pdepth = _Pdepth; | |||
| depth = powf(Pdepth / 127.0f, 2.0f); | |||
| } | |||
| void DynamicFilter::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| outvolume = Pvolume / 127.0f; | |||
| if(!insertion) | |||
| volume = 1.0f; | |||
| else | |||
| volume = outvolume; | |||
| } | |||
| void DynamicFilter::setampsns(unsigned char _Pampsns) | |||
| { | |||
| Pampsns = _Pampsns; | |||
| ampsns = powf(Pampsns / 127.0f, 2.5f) * 10.0f; | |||
| if(Pampsnsinv) | |||
| ampsns = -ampsns; | |||
| ampsmooth = expf(-Pampsmooth / 127.0f * 10.0f) * 0.99f; | |||
| } | |||
| void DynamicFilter::reinitfilter(void) | |||
| { | |||
| delete filterl; | |||
| delete filterr; | |||
| filterl = Filter::generate(filterpars); | |||
| filterr = Filter::generate(filterpars); | |||
| } | |||
| void DynamicFilter::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 10; | |||
| const int NUM_PRESETS = 5; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| //WahWah | |||
| {110, 64, 80, 0, 0, 64, 0, 90, 0, 60}, | |||
| //AutoWah | |||
| {110, 64, 70, 0, 0, 80, 70, 0, 0, 60}, | |||
| //Sweep | |||
| {100, 64, 30, 0, 0, 50, 80, 0, 0, 60}, | |||
| //VocalMorph1 | |||
| {110, 64, 80, 0, 0, 64, 0, 64, 0, 60}, | |||
| //VocalMorph1 | |||
| {127, 64, 50, 0, 0, 96, 64, 0, 0, 60} | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| filterpars->defaults(); | |||
| switch(npreset) { | |||
| case 0: | |||
| filterpars->Pcategory = 0; | |||
| filterpars->Ptype = 2; | |||
| filterpars->Pfreq = 45; | |||
| filterpars->Pq = 64; | |||
| filterpars->Pstages = 1; | |||
| filterpars->Pgain = 64; | |||
| break; | |||
| case 1: | |||
| filterpars->Pcategory = 2; | |||
| filterpars->Ptype = 0; | |||
| filterpars->Pfreq = 72; | |||
| filterpars->Pq = 64; | |||
| filterpars->Pstages = 0; | |||
| filterpars->Pgain = 64; | |||
| break; | |||
| case 2: | |||
| filterpars->Pcategory = 0; | |||
| filterpars->Ptype = 4; | |||
| filterpars->Pfreq = 64; | |||
| filterpars->Pq = 64; | |||
| filterpars->Pstages = 2; | |||
| filterpars->Pgain = 64; | |||
| break; | |||
| case 3: | |||
| filterpars->Pcategory = 1; | |||
| filterpars->Ptype = 0; | |||
| filterpars->Pfreq = 50; | |||
| filterpars->Pq = 70; | |||
| filterpars->Pstages = 1; | |||
| filterpars->Pgain = 64; | |||
| filterpars->Psequencesize = 2; | |||
| // "I" | |||
| filterpars->Pvowels[0].formants[0].freq = 34; | |||
| filterpars->Pvowels[0].formants[0].amp = 127; | |||
| filterpars->Pvowels[0].formants[0].q = 64; | |||
| filterpars->Pvowels[0].formants[1].freq = 99; | |||
| filterpars->Pvowels[0].formants[1].amp = 122; | |||
| filterpars->Pvowels[0].formants[1].q = 64; | |||
| filterpars->Pvowels[0].formants[2].freq = 108; | |||
| filterpars->Pvowels[0].formants[2].amp = 112; | |||
| filterpars->Pvowels[0].formants[2].q = 64; | |||
| // "A" | |||
| filterpars->Pvowels[1].formants[0].freq = 61; | |||
| filterpars->Pvowels[1].formants[0].amp = 127; | |||
| filterpars->Pvowels[1].formants[0].q = 64; | |||
| filterpars->Pvowels[1].formants[1].freq = 71; | |||
| filterpars->Pvowels[1].formants[1].amp = 121; | |||
| filterpars->Pvowels[1].formants[1].q = 64; | |||
| filterpars->Pvowels[1].formants[2].freq = 99; | |||
| filterpars->Pvowels[1].formants[2].amp = 117; | |||
| filterpars->Pvowels[1].formants[2].q = 64; | |||
| break; | |||
| case 4: | |||
| filterpars->Pcategory = 1; | |||
| filterpars->Ptype = 0; | |||
| filterpars->Pfreq = 64; | |||
| filterpars->Pq = 70; | |||
| filterpars->Pstages = 1; | |||
| filterpars->Pgain = 64; | |||
| filterpars->Psequencesize = 2; | |||
| filterpars->Pnumformants = 2; | |||
| filterpars->Pvowelclearness = 0; | |||
| filterpars->Pvowels[0].formants[0].freq = 70; | |||
| filterpars->Pvowels[0].formants[0].amp = 127; | |||
| filterpars->Pvowels[0].formants[0].q = 64; | |||
| filterpars->Pvowels[0].formants[1].freq = 80; | |||
| filterpars->Pvowels[0].formants[1].amp = 122; | |||
| filterpars->Pvowels[0].formants[1].q = 64; | |||
| filterpars->Pvowels[1].formants[0].freq = 20; | |||
| filterpars->Pvowels[1].formants[0].amp = 127; | |||
| filterpars->Pvowels[1].formants[0].q = 64; | |||
| filterpars->Pvowels[1].formants[1].freq = 100; | |||
| filterpars->Pvowels[1].formants[1].amp = 121; | |||
| filterpars->Pvowels[1].formants[1].q = 64; | |||
| break; | |||
| } | |||
| // for (int i=0;i<5;i++){ | |||
| // printf("freq=%d amp=%d q=%d\n",filterpars->Pvowels[0].formants[i].freq,filterpars->Pvowels[0].formants[i].amp,filterpars->Pvowels[0].formants[i].q); | |||
| // }; | |||
| if(insertion == 0) //lower the volume if this is system effect | |||
| changepar(0, presets[npreset][0] * 0.5f); | |||
| Ppreset = npreset; | |||
| reinitfilter(); | |||
| } | |||
| void DynamicFilter::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| lfo.Pfreq = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 3: | |||
| lfo.Prandomness = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 4: | |||
| lfo.PLFOtype = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 5: | |||
| lfo.Pstereo = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 6: | |||
| setdepth(value); | |||
| break; | |||
| case 7: | |||
| setampsns(value); | |||
| break; | |||
| case 8: | |||
| Pampsnsinv = value; | |||
| setampsns(Pampsns); | |||
| break; | |||
| case 9: | |||
| Pampsmooth = value; | |||
| setampsns(Pampsns); | |||
| break; | |||
| } | |||
| } | |||
| unsigned char DynamicFilter::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return lfo.Pfreq; | |||
| case 3: return lfo.Prandomness; | |||
| case 4: return lfo.PLFOtype; | |||
| case 5: return lfo.Pstereo; | |||
| case 6: return Pdepth; | |||
| case 7: return Pampsns; | |||
| case 8: return Pampsnsinv; | |||
| case 9: return Pampsmooth; | |||
| default: return 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,65 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| DynamicFilter.h - "WahWah" effect and others | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef DYNAMICFILTER_H | |||
| #define DYNAMICFILTER_H | |||
| #include "Effect.h" | |||
| #include "EffectLFO.h" | |||
| /**DynamicFilter Effect*/ | |||
| class DynamicFilter:public Effect | |||
| { | |||
| public: | |||
| DynamicFilter(bool insertion_, float *efxoutl_, float *efxoutr_); | |||
| ~DynamicFilter(); | |||
| void out(const Stereo<float *> &smp); | |||
| void setpreset(unsigned char npreset); | |||
| void changepar(int npar, unsigned char value); | |||
| unsigned char getpar(int npar) const; | |||
| void cleanup(void); | |||
| private: | |||
| //Parametrii DynamicFilter | |||
| EffectLFO lfo; //lfo-ul DynamicFilter | |||
| unsigned char Pvolume; //Volume | |||
| unsigned char Pdepth; //the depth of the lfo | |||
| unsigned char Pampsns; //how the filter varies according to the input amplitude | |||
| unsigned char Pampsnsinv; //if the filter freq is lowered if the input amplitude rises | |||
| unsigned char Pampsmooth; //how smooth the input amplitude changes the filter | |||
| //Parameter Control | |||
| void setvolume(unsigned char _Pvolume); | |||
| void setdepth(unsigned char _Pdepth); | |||
| void setampsns(unsigned char _Pampsns); | |||
| void reinitfilter(void); | |||
| //Internal Values | |||
| float depth, ampsns, ampsmooth; | |||
| class Filter * filterl, *filterr; | |||
| float ms1, ms2, ms3, ms4; //mean squares | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,198 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| EQ.cpp - EQ effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include "EQ.h" | |||
| #include "../DSP/AnalogFilter.h" | |||
| EQ::EQ(bool insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0) | |||
| { | |||
| for(int i = 0; i < MAX_EQ_BANDS; ++i) { | |||
| filter[i].Ptype = 0; | |||
| filter[i].Pfreq = 64; | |||
| filter[i].Pgain = 64; | |||
| filter[i].Pq = 64; | |||
| filter[i].Pstages = 0; | |||
| filter[i].l = new AnalogFilter(6, 1000.0f, 1.0f, 0); | |||
| filter[i].r = new AnalogFilter(6, 1000.0f, 1.0f, 0); | |||
| } | |||
| //default values | |||
| Pvolume = 50; | |||
| setpreset(Ppreset); | |||
| cleanup(); | |||
| } | |||
| // Cleanup the effect | |||
| void EQ::cleanup(void) | |||
| { | |||
| for(int i = 0; i < MAX_EQ_BANDS; ++i) { | |||
| filter[i].l->cleanup(); | |||
| filter[i].r->cleanup(); | |||
| } | |||
| } | |||
| //Effect output | |||
| void EQ::out(const Stereo<float *> &smp) | |||
| { | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] = smp.l[i] * volume; | |||
| efxoutr[i] = smp.r[i] * volume; | |||
| } | |||
| for(int i = 0; i < MAX_EQ_BANDS; ++i) { | |||
| if(filter[i].Ptype == 0) | |||
| continue; | |||
| filter[i].l->filterout(efxoutl); | |||
| filter[i].r->filterout(efxoutr); | |||
| } | |||
| } | |||
| //Parameter control | |||
| void EQ::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| outvolume = powf(0.005f, (1.0f - Pvolume / 127.0f)) * 10.0f; | |||
| volume = (!insertion) ? 1.0f : outvolume; | |||
| } | |||
| void EQ::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 1; | |||
| const int NUM_PRESETS = 2; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| {67}, //EQ 1 | |||
| {67} //EQ 2 | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| Ppreset = npreset; | |||
| } | |||
| void EQ::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| } | |||
| if(npar < 10) | |||
| return; | |||
| int nb = (npar - 10) / 5; //number of the band (filter) | |||
| if(nb >= MAX_EQ_BANDS) | |||
| return; | |||
| int bp = npar % 5; //band paramenter | |||
| float tmp; | |||
| switch(bp) { | |||
| case 0: | |||
| filter[nb].Ptype = value; | |||
| if(value > 9) | |||
| filter[nb].Ptype = 0; //has to be changed if more filters will be added | |||
| if(filter[nb].Ptype != 0) { | |||
| filter[nb].l->settype(value - 1); | |||
| filter[nb].r->settype(value - 1); | |||
| } | |||
| break; | |||
| case 1: | |||
| filter[nb].Pfreq = value; | |||
| tmp = 600.0f * powf(30.0f, (value - 64.0f) / 64.0f); | |||
| filter[nb].l->setfreq(tmp); | |||
| filter[nb].r->setfreq(tmp); | |||
| break; | |||
| case 2: | |||
| filter[nb].Pgain = value; | |||
| tmp = 30.0f * (value - 64.0f) / 64.0f; | |||
| filter[nb].l->setgain(tmp); | |||
| filter[nb].r->setgain(tmp); | |||
| break; | |||
| case 3: | |||
| filter[nb].Pq = value; | |||
| tmp = powf(30.0f, (value - 64.0f) / 64.0f); | |||
| filter[nb].l->setq(tmp); | |||
| filter[nb].r->setq(tmp); | |||
| break; | |||
| case 4: | |||
| filter[nb].Pstages = value; | |||
| if(value >= MAX_FILTER_STAGES) | |||
| filter[nb].Pstages = MAX_FILTER_STAGES - 1; | |||
| filter[nb].l->setstages(value); | |||
| filter[nb].r->setstages(value); | |||
| break; | |||
| } | |||
| } | |||
| unsigned char EQ::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| return Pvolume; | |||
| break; | |||
| } | |||
| if(npar < 10) | |||
| return 0; | |||
| int nb = (npar - 10) / 5; //number of the band (filter) | |||
| if(nb >= MAX_EQ_BANDS) | |||
| return 0; | |||
| int bp = npar % 5; //band paramenter | |||
| switch(bp) { | |||
| case 0: | |||
| return filter[nb].Ptype; | |||
| break; | |||
| case 1: | |||
| return filter[nb].Pfreq; | |||
| break; | |||
| case 2: | |||
| return filter[nb].Pgain; | |||
| break; | |||
| case 3: | |||
| return filter[nb].Pq; | |||
| break; | |||
| case 4: | |||
| return filter[nb].Pstages; | |||
| break; | |||
| default: return 0; //in case of bogus parameter number | |||
| } | |||
| } | |||
| float EQ::getfreqresponse(float freq) | |||
| { | |||
| float resp = 1.0f; | |||
| for(int i = 0; i < MAX_EQ_BANDS; ++i) { | |||
| if(filter[i].Ptype == 0) | |||
| continue; | |||
| resp *= filter[i].l->H(freq); | |||
| } | |||
| return rap2dB(resp * outvolume); | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| EQ.h - EQ Effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef EQ_H | |||
| #define EQ_H | |||
| #include "Effect.h" | |||
| /**EQ Effect*/ | |||
| class EQ:public Effect | |||
| { | |||
| public: | |||
| EQ(bool insertion_, float *efxoutl_, float *efxoutr_); | |||
| ~EQ() {} | |||
| void out(const Stereo<float *> &smp); | |||
| void setpreset(unsigned char npreset); | |||
| void changepar(int npar, unsigned char value); | |||
| unsigned char getpar(int npar) const; | |||
| void cleanup(void); | |||
| float getfreqresponse(float freq); | |||
| private: | |||
| //Parameters | |||
| unsigned char Pvolume; | |||
| void setvolume(unsigned char _Pvolume); | |||
| struct { | |||
| //parameters | |||
| unsigned char Ptype, Pfreq, Pgain, Pq, Pstages; | |||
| //internal values | |||
| class AnalogFilter * l, *r; | |||
| } filter[MAX_EQ_BANDS]; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,231 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Echo.cpp - Echo effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright (C) 2009-2010 Mark McCurry | |||
| Author: Nasca Octavian Paul | |||
| Mark McCurry | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include "Echo.h" | |||
| #define MAX_DELAY 2 | |||
| Echo::Echo(bool insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), | |||
| Pvolume(50), | |||
| Pdelay(60), | |||
| Plrdelay(100), | |||
| Pfb(40), | |||
| Phidamp(60), | |||
| delayTime(1), | |||
| lrdelay(0), | |||
| avgDelay(0), | |||
| delay(new float[(int)(MAX_DELAY * synth->samplerate)], | |||
| new float[(int)(MAX_DELAY * synth->samplerate)]), | |||
| old(0.0f), | |||
| pos(0), | |||
| delta(1), | |||
| ndelta(1) | |||
| { | |||
| initdelays(); | |||
| setpreset(Ppreset); | |||
| } | |||
| Echo::~Echo() | |||
| { | |||
| delete[] delay.l; | |||
| delete[] delay.r; | |||
| } | |||
| //Cleanup the effect | |||
| void Echo::cleanup(void) | |||
| { | |||
| memset(delay.l, 0, MAX_DELAY * synth->samplerate * sizeof(float)); | |||
| memset(delay.r, 0, MAX_DELAY * synth->samplerate * sizeof(float)); | |||
| old = Stereo<float>(0.0f); | |||
| } | |||
| inline int max(int a, int b) | |||
| { | |||
| return a > b ? a : b; | |||
| } | |||
| //Initialize the delays | |||
| void Echo::initdelays(void) | |||
| { | |||
| cleanup(); | |||
| //number of seconds to delay left chan | |||
| float dl = avgDelay - lrdelay; | |||
| //number of seconds to delay right chan | |||
| float dr = avgDelay + lrdelay; | |||
| ndelta.l = max(1, (int) (dl * synth->samplerate)); | |||
| ndelta.r = max(1, (int) (dr * synth->samplerate)); | |||
| } | |||
| //Effect output | |||
| void Echo::out(const Stereo<float *> &input) | |||
| { | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float ldl = delay.l[pos.l]; | |||
| float rdl = delay.r[pos.r]; | |||
| ldl = ldl * (1.0f - lrcross) + rdl * lrcross; | |||
| rdl = rdl * (1.0f - lrcross) + ldl * lrcross; | |||
| efxoutl[i] = ldl * 2.0f; | |||
| efxoutr[i] = rdl * 2.0f; | |||
| ldl = input.l[i] * pangainL - ldl * fb; | |||
| rdl = input.r[i] * pangainR - rdl * fb; | |||
| //LowPass Filter | |||
| old.l = delay.l[(pos.l + delta.l) % (MAX_DELAY * synth->samplerate)] = | |||
| ldl * hidamp + old.l * (1.0f - hidamp); | |||
| old.r = delay.r[(pos.r + delta.r) % (MAX_DELAY * synth->samplerate)] = | |||
| rdl * hidamp + old.r * (1.0f - hidamp); | |||
| //increment | |||
| ++pos.l; // += delta.l; | |||
| ++pos.r; // += delta.r; | |||
| //ensure that pos is still in bounds | |||
| pos.l %= MAX_DELAY * synth->samplerate; | |||
| pos.r %= MAX_DELAY * synth->samplerate; | |||
| //adjust delay if needed | |||
| delta.l = (15 * delta.l + ndelta.l) / 16; | |||
| delta.r = (15 * delta.r + ndelta.r) / 16; | |||
| } | |||
| } | |||
| //Parameter control | |||
| void Echo::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| if(insertion == 0) { | |||
| outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
| volume = 1.0f; | |||
| } | |||
| else | |||
| volume = outvolume = Pvolume / 127.0f; | |||
| if(Pvolume == 0) | |||
| cleanup(); | |||
| } | |||
| void Echo::setdelay(unsigned char _Pdelay) | |||
| { | |||
| Pdelay = _Pdelay; | |||
| avgDelay = (Pdelay / 127.0f * 1.5f); //0 .. 1.5 sec | |||
| initdelays(); | |||
| } | |||
| void Echo::setlrdelay(unsigned char _Plrdelay) | |||
| { | |||
| float tmp; | |||
| Plrdelay = _Plrdelay; | |||
| tmp = | |||
| (powf(2.0f, fabsf(Plrdelay - 64.0f) / 64.0f * 9.0f) - 1.0f) / 1000.0f; | |||
| if(Plrdelay < 64.0f) | |||
| tmp = -tmp; | |||
| lrdelay = tmp; | |||
| initdelays(); | |||
| } | |||
| void Echo::setfb(unsigned char _Pfb) | |||
| { | |||
| Pfb = _Pfb; | |||
| fb = Pfb / 128.0f; | |||
| } | |||
| void Echo::sethidamp(unsigned char _Phidamp) | |||
| { | |||
| Phidamp = _Phidamp; | |||
| hidamp = 1.0f - Phidamp / 127.0f; | |||
| } | |||
| void Echo::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 7; | |||
| const int NUM_PRESETS = 9; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| {67, 64, 35, 64, 30, 59, 0 }, //Echo 1 | |||
| {67, 64, 21, 64, 30, 59, 0 }, //Echo 2 | |||
| {67, 75, 60, 64, 30, 59, 10}, //Echo 3 | |||
| {67, 60, 44, 64, 30, 0, 0 }, //Simple Echo | |||
| {67, 60, 102, 50, 30, 82, 48}, //Canyon | |||
| {67, 64, 44, 17, 0, 82, 24}, //Panning Echo 1 | |||
| {81, 60, 46, 118, 100, 68, 18}, //Panning Echo 2 | |||
| {81, 60, 26, 100, 127, 67, 36}, //Panning Echo 3 | |||
| {62, 64, 28, 64, 100, 90, 55} //Feedback Echo | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| if(insertion) | |||
| setvolume(presets[npreset][0] / 2); //lower the volume if this is insertion effect | |||
| Ppreset = npreset; | |||
| } | |||
| void Echo::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| setdelay(value); | |||
| break; | |||
| case 3: | |||
| setlrdelay(value); | |||
| break; | |||
| case 4: | |||
| setlrcross(value); | |||
| break; | |||
| case 5: | |||
| setfb(value); | |||
| break; | |||
| case 6: | |||
| sethidamp(value); | |||
| break; | |||
| } | |||
| } | |||
| unsigned char Echo::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return Pdelay; | |||
| case 3: return Plrdelay; | |||
| case 4: return Plrcross; | |||
| case 5: return Pfb; | |||
| case 6: return Phidamp; | |||
| default: return 0; // in case of bogus parameter number | |||
| } | |||
| } | |||
| @@ -0,0 +1,104 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Echo.h - Echo Effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef ECHO_H | |||
| #define ECHO_H | |||
| #include "Effect.h" | |||
| #include "../Misc/Stereo.h" | |||
| /**Echo Effect*/ | |||
| class Echo:public Effect | |||
| { | |||
| public: | |||
| Echo(bool insertion_, float *efxoutl_, float *efxoutr_); | |||
| ~Echo(); | |||
| void out(const Stereo<float *> &input); | |||
| void setpreset(unsigned char npreset); | |||
| /** | |||
| * Sets the value of the chosen variable | |||
| * | |||
| * The possible parameters are: | |||
| * -# Volume | |||
| * -# Panning | |||
| * -# Delay | |||
| * -# L/R Delay | |||
| * -# L/R Crossover | |||
| * -# Feedback | |||
| * -# Dampening | |||
| * @param npar number of chosen parameter | |||
| * @param value the new value | |||
| */ | |||
| void changepar(int npar, unsigned char value); | |||
| /** | |||
| * Gets the specified parameter | |||
| * | |||
| * The possible parameters are | |||
| * -# Volume | |||
| * -# Panning | |||
| * -# Delay | |||
| * -# L/R Delay | |||
| * -# L/R Crossover | |||
| * -# Feedback | |||
| * -# Dampening | |||
| * @param npar number of chosen parameter | |||
| * @return value of parameter | |||
| */ | |||
| unsigned char getpar(int npar) const; | |||
| int getnumparams(void); | |||
| void cleanup(void); | |||
| private: | |||
| //Parameters | |||
| unsigned char Pvolume; /**<#1 Volume or Dry/Wetness*/ | |||
| unsigned char Pdelay; /**<#3 Delay of the Echo*/ | |||
| unsigned char Plrdelay; /**<#4 L/R delay difference*/ | |||
| unsigned char Pfb; /**<#6Feedback*/ | |||
| unsigned char Phidamp; /**<#7Dampening of the Echo*/ | |||
| void setvolume(unsigned char _Pvolume); | |||
| void setdelay(unsigned char _Pdelay); | |||
| void setlrdelay(unsigned char _Plrdelay); | |||
| void setfb(unsigned char _Pfb); | |||
| void sethidamp(unsigned char _Phidamp); | |||
| //Real Parameters | |||
| float fb, hidamp; | |||
| //Left/Right delay lengths | |||
| Stereo<int> delayTime; | |||
| float lrdelay; | |||
| float avgDelay; | |||
| void initdelays(void); | |||
| //2 channel ring buffer | |||
| Stereo<float *> delay; | |||
| Stereo<float> old; | |||
| //position of reading/writing from delaysample | |||
| Stereo<int> pos; | |||
| //step size for delay buffer | |||
| Stereo<int> delta; | |||
| Stereo<int> ndelta; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,62 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Effect.cpp - this class is inherited by the all effects(Reverb, Echo, ..) | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright 2011, Alan Calvert | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "Effect.h" | |||
| #include "../Params/FilterParams.h" | |||
| #include <cmath> | |||
| Effect::Effect(bool insertion_, float *efxoutl_, float *efxoutr_, | |||
| FilterParams *filterpars_, unsigned char Ppreset_) | |||
| :Ppreset(Ppreset_), | |||
| efxoutl(efxoutl_), | |||
| efxoutr(efxoutr_), | |||
| filterpars(filterpars_), | |||
| insertion(insertion_) | |||
| {} | |||
| void Effect::out(float *const smpsl, float *const smpsr) | |||
| { | |||
| out(Stereo<float *>(smpsl, smpsr)); | |||
| } | |||
| void Effect::crossover(float &a, float &b, float crossover) | |||
| { | |||
| float tmpa = a; | |||
| float tmpb = b; | |||
| a = tmpa * (1.0f - crossover) + tmpb * crossover; | |||
| b = tmpb * (1.0f - crossover) + tmpa * crossover; | |||
| } | |||
| void Effect::setpanning(char Ppanning_) | |||
| { | |||
| Ppanning = Ppanning_; | |||
| float t = (Ppanning > 0) ? (float)(Ppanning - 1) / 126.0f : 0.0f; | |||
| pangainL = cosf(t * PI / 2.0f); | |||
| pangainR = cosf((1.0f - t) * PI / 2.0f); | |||
| } | |||
| void Effect::setlrcross(char Plrcross_) | |||
| { | |||
| Plrcross = Plrcross_; | |||
| lrcross = (float)Plrcross / 127.0f; | |||
| } | |||
| @@ -0,0 +1,105 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Effect.h - this class is inherited by the all effects(Reverb, Echo, ..) | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef EFFECT_H | |||
| #define EFFECT_H | |||
| #include "../Misc/Util.h" | |||
| #include "../globals.h" | |||
| #include "../Params/FilterParams.h" | |||
| #include "../Misc/Stereo.h" | |||
| class FilterParams; | |||
| /**this class is inherited by the all effects(Reverb, Echo, ..)*/ | |||
| class Effect | |||
| { | |||
| public: | |||
| /** | |||
| * Effect Constructor | |||
| * @param insertion_ 1 when it is an insertion Effect | |||
| * @param efxoutl_ Effect output buffer Left channel | |||
| * @param efxoutr_ Effect output buffer Right channel | |||
| * @param filterpars_ pointer to FilterParams array | |||
| * @param Ppreset_ chosen preset | |||
| * @return Initialized Effect object*/ | |||
| Effect(bool insertion_, float *efxoutl_, float *efxoutr_, | |||
| FilterParams *filterpars_, unsigned char Ppreset_); | |||
| virtual ~Effect() {} | |||
| /** | |||
| * Choose a preset | |||
| * @param npreset number of chosen preset*/ | |||
| virtual void setpreset(unsigned char npreset) = 0; | |||
| /**Change parameter npar to value | |||
| * @param npar chosen parameter | |||
| * @param value chosen new value*/ | |||
| virtual void changepar(int npar, unsigned char value) = 0; | |||
| /**Get the value of parameter npar | |||
| * @param npar chosen parameter | |||
| * @return the value of the parameter in an unsigned char or 0 if it | |||
| * does not exist*/ | |||
| virtual unsigned char getpar(int npar) const = 0; | |||
| /**Output result of effect based on the given buffers | |||
| * | |||
| * This method should result in the effect generating its results | |||
| * and placing them into the efxoutl and efxoutr buffers. | |||
| * Every Effect should overide this method. | |||
| * | |||
| * @param smpsl Input buffer for the Left channel | |||
| * @param smpsr Input buffer for the Right channel | |||
| */ | |||
| void out(float *const smpsl, float *const smpsr); | |||
| virtual void out(const Stereo<float *> &smp) = 0; | |||
| /**Reset the state of the effect*/ | |||
| virtual void cleanup(void) {} | |||
| virtual float getfreqresponse(float freq) { return freq; } | |||
| unsigned char Ppreset; /**<Currently used preset*/ | |||
| float *const efxoutl; /**<Effect out Left Channel*/ | |||
| float *const efxoutr; /**<Effect out Right Channel*/ | |||
| float outvolume; /**<This is the volume of effect and is public because | |||
| * it is needed in system effects. | |||
| * The out volume of such effects are always 1.0f, so | |||
| * this setting tells me how is the volume to the | |||
| * Master Output only.*/ | |||
| float volume; | |||
| FilterParams *filterpars; /**<Parameters for filters used by Effect*/ | |||
| //Perform L/R crossover | |||
| static void crossover(float &a, float &b, float crossover); | |||
| protected: | |||
| void setpanning(char Ppanning_); | |||
| void setlrcross(char Plrcross_); | |||
| const bool insertion; | |||
| //panning parameters | |||
| char Ppanning; | |||
| float pangainL; | |||
| float pangainR; | |||
| char Plrcross; // L/R mix | |||
| float lrcross; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,111 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| EffectLFO.cpp - Stereo LFO used by some effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "EffectLFO.h" | |||
| #include "../Misc/Util.h" | |||
| #include <cmath> | |||
| EffectLFO::EffectLFO(void) | |||
| :Pfreq(40), | |||
| Prandomness(0), | |||
| PLFOtype(0), | |||
| Pstereo(64), | |||
| xl(0.0f), | |||
| xr(0.0f), | |||
| ampl1(RND), | |||
| ampl2(RND), | |||
| ampr1(RND), | |||
| ampr2(RND), | |||
| lfornd(0.0f) | |||
| { | |||
| updateparams(); | |||
| } | |||
| EffectLFO::~EffectLFO() {} | |||
| //Update the changed parameters | |||
| void EffectLFO::updateparams(void) | |||
| { | |||
| float lfofreq = (powf(2.0f, Pfreq / 127.0f * 10.0f) - 1.0f) * 0.03f; | |||
| incx = fabsf(lfofreq) * synth->buffersize_f / synth->samplerate_f; | |||
| if(incx > 0.49999999f) | |||
| incx = 0.499999999f; //Limit the Frequency | |||
| lfornd = Prandomness / 127.0f; | |||
| lfornd = (lfornd > 1.0f) ? 1.0f : lfornd; | |||
| if(PLFOtype > 1) | |||
| PLFOtype = 1; //this has to be updated if more lfo's are added | |||
| lfotype = PLFOtype; | |||
| xr = fmodf(xl + (Pstereo - 64.0f) / 127.0f + 1.0f, 1.0f); | |||
| } | |||
| //Compute the shape of the LFO | |||
| float EffectLFO::getlfoshape(float x) | |||
| { | |||
| float out; | |||
| switch(lfotype) { | |||
| case 1: //EffectLFO_TRIANGLE | |||
| if((x > 0.0f) && (x < 0.25f)) | |||
| out = 4.0f * x; | |||
| else | |||
| if((x > 0.25f) && (x < 0.75f)) | |||
| out = 2.0f - 4.0f * x; | |||
| else | |||
| out = 4.0f * x - 4.0f; | |||
| break; | |||
| //when adding more, ensure ::updateparams() gets updated | |||
| default: | |||
| out = cosf(x * 2.0f * PI); //EffectLFO_SINE | |||
| } | |||
| return out; | |||
| } | |||
| //LFO output | |||
| void EffectLFO::effectlfoout(float *outl, float *outr) | |||
| { | |||
| float out; | |||
| out = getlfoshape(xl); | |||
| if((lfotype == 0) || (lfotype == 1)) | |||
| out *= (ampl1 + xl * (ampl2 - ampl1)); | |||
| xl += incx; | |||
| if(xl > 1.0f) { | |||
| xl -= 1.0f; | |||
| ampl1 = ampl2; | |||
| ampl2 = (1.0f - lfornd) + lfornd * RND; | |||
| } | |||
| *outl = (out + 1.0f) * 0.5f; | |||
| out = getlfoshape(xr); | |||
| if((lfotype == 0) || (lfotype == 1)) | |||
| out *= (ampr1 + xr * (ampr2 - ampr1)); | |||
| xr += incx; | |||
| if(xr > 1.0f) { | |||
| xr -= 1.0f; | |||
| ampr1 = ampr2; | |||
| ampr2 = (1.0f - lfornd) + lfornd * RND; | |||
| } | |||
| *outr = (out + 1.0f) * 0.5f; | |||
| } | |||
| @@ -0,0 +1,50 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| EffectLFO.h - Stereo LFO used by some effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef EFFECT_LFO_H | |||
| #define EFFECT_LFO_H | |||
| /**LFO for some of the Effect objects | |||
| * \todo see if this should inherit LFO*/ | |||
| class EffectLFO | |||
| { | |||
| public: | |||
| EffectLFO(); | |||
| ~EffectLFO(); | |||
| void effectlfoout(float *outl, float *outr); | |||
| void updateparams(void); | |||
| unsigned char Pfreq; | |||
| unsigned char Prandomness; | |||
| unsigned char PLFOtype; | |||
| unsigned char Pstereo; // 64 is centered | |||
| private: | |||
| float getlfoshape(float x); | |||
| float xl, xr; | |||
| float incx; | |||
| float ampl1, ampl2, ampr1, ampr2; //necessary for "randomness" | |||
| float lfointensity; | |||
| float lfornd; | |||
| char lfotype; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,311 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| EffectMgr.cpp - Effect manager, an interface betwen the program and effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "EffectMgr.h" | |||
| #include "Effect.h" | |||
| #include "Reverb.h" | |||
| #include "Echo.h" | |||
| #include "Chorus.h" | |||
| #include "Distorsion.h" | |||
| #include "EQ.h" | |||
| #include "DynamicFilter.h" | |||
| #include "../Misc/XMLwrapper.h" | |||
| #include "../Params/FilterParams.h" | |||
| #include <iostream> | |||
| using namespace std; | |||
| EffectMgr::EffectMgr(const bool insertion_, pthread_mutex_t *mutex_) | |||
| :insertion(insertion_), | |||
| efxoutl(new float[synth->buffersize]), | |||
| efxoutr(new float[synth->buffersize]), | |||
| filterpars(NULL), | |||
| nefx(0), | |||
| efx(NULL), | |||
| mutex(mutex_), | |||
| dryonly(false) | |||
| { | |||
| setpresettype("Peffect"); | |||
| memset(efxoutl, 0, synth->bufferbytes); | |||
| memset(efxoutr, 0, synth->bufferbytes); | |||
| defaults(); | |||
| } | |||
| EffectMgr::~EffectMgr() | |||
| { | |||
| delete efx; | |||
| delete [] efxoutl; | |||
| delete [] efxoutr; | |||
| } | |||
| void EffectMgr::defaults(void) | |||
| { | |||
| changeeffect(0); | |||
| setdryonly(false); | |||
| } | |||
| //Change the effect | |||
| void EffectMgr::changeeffect(int _nefx) | |||
| { | |||
| cleanup(); | |||
| if(nefx == _nefx) | |||
| return; | |||
| nefx = _nefx; | |||
| memset(efxoutl, 0, synth->bufferbytes); | |||
| memset(efxoutr, 0, synth->bufferbytes); | |||
| delete efx; | |||
| switch(nefx) { | |||
| case 1: | |||
| efx = new Reverb(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 2: | |||
| efx = new Echo(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 3: | |||
| efx = new Chorus(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 4: | |||
| efx = new Phaser(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 5: | |||
| efx = new Alienwah(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 6: | |||
| efx = new Distorsion(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 7: | |||
| efx = new EQ(insertion, efxoutl, efxoutr); | |||
| break; | |||
| case 8: | |||
| efx = new DynamicFilter(insertion, efxoutl, efxoutr); | |||
| break; | |||
| //put more effect here | |||
| default: | |||
| efx = NULL; | |||
| break; //no effect (thru) | |||
| } | |||
| if(efx) | |||
| filterpars = efx->filterpars; | |||
| } | |||
| //Obtain the effect number | |||
| int EffectMgr::geteffect(void) | |||
| { | |||
| return nefx; | |||
| } | |||
| // Cleanup the current effect | |||
| void EffectMgr::cleanup(void) | |||
| { | |||
| if(efx) | |||
| efx->cleanup(); | |||
| } | |||
| // Get the preset of the current effect | |||
| unsigned char EffectMgr::getpreset(void) | |||
| { | |||
| if(efx) | |||
| return efx->Ppreset; | |||
| else | |||
| return 0; | |||
| } | |||
| // Change the preset of the current effect | |||
| void EffectMgr::changepreset_nolock(unsigned char npreset) | |||
| { | |||
| if(efx) | |||
| efx->setpreset(npreset); | |||
| } | |||
| //Change the preset of the current effect(with thread locking) | |||
| void EffectMgr::changepreset(unsigned char npreset) | |||
| { | |||
| pthread_mutex_lock(mutex); | |||
| changepreset_nolock(npreset); | |||
| pthread_mutex_unlock(mutex); | |||
| } | |||
| //Change a parameter of the current effect | |||
| void EffectMgr::seteffectpar_nolock(int npar, unsigned char value) | |||
| { | |||
| if(!efx) | |||
| return; | |||
| efx->changepar(npar, value); | |||
| } | |||
| // Change a parameter of the current effect (with thread locking) | |||
| void EffectMgr::seteffectpar(int npar, unsigned char value) | |||
| { | |||
| pthread_mutex_lock(mutex); | |||
| seteffectpar_nolock(npar, value); | |||
| pthread_mutex_unlock(mutex); | |||
| } | |||
| //Get a parameter of the current effect | |||
| unsigned char EffectMgr::geteffectpar(int npar) | |||
| { | |||
| if(!efx) | |||
| return 0; | |||
| return efx->getpar(npar); | |||
| } | |||
| // Apply the effect | |||
| void EffectMgr::out(float *smpsl, float *smpsr) | |||
| { | |||
| if(!efx) { | |||
| if(!insertion) | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| smpsl[i] = 0.0f; | |||
| smpsr[i] = 0.0f; | |||
| efxoutl[i] = 0.0f; | |||
| efxoutr[i] = 0.0f; | |||
| } | |||
| return; | |||
| } | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| smpsl[i] += denormalkillbuf[i]; | |||
| smpsr[i] += denormalkillbuf[i]; | |||
| efxoutl[i] = 0.0f; | |||
| efxoutr[i] = 0.0f; | |||
| } | |||
| efx->out(smpsl, smpsr); | |||
| float volume = efx->volume; | |||
| if(nefx == 7) { //this is need only for the EQ effect | |||
| memcpy(smpsl, efxoutl, synth->bufferbytes); | |||
| memcpy(smpsr, efxoutr, synth->bufferbytes); | |||
| return; | |||
| } | |||
| //Insertion effect | |||
| if(insertion != 0) { | |||
| float v1, v2; | |||
| if(volume < 0.5f) { | |||
| v1 = 1.0f; | |||
| v2 = volume * 2.0f; | |||
| } | |||
| else { | |||
| v1 = (1.0f - volume) * 2.0f; | |||
| v2 = 1.0f; | |||
| } | |||
| if((nefx == 1) || (nefx == 2)) | |||
| v2 *= v2; //for Reverb and Echo, the wet function is not liniar | |||
| if(dryonly) //this is used for instrument effect only | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| smpsl[i] *= v1; | |||
| smpsr[i] *= v1; | |||
| efxoutl[i] *= v2; | |||
| efxoutr[i] *= v2; | |||
| } | |||
| else // normal instrument/insertion effect | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| smpsl[i] = smpsl[i] * v1 + efxoutl[i] * v2; | |||
| smpsr[i] = smpsr[i] * v1 + efxoutr[i] * v2; | |||
| } | |||
| } | |||
| else // System effect | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] *= 2.0f * volume; | |||
| efxoutr[i] *= 2.0f * volume; | |||
| smpsl[i] = efxoutl[i]; | |||
| smpsr[i] = efxoutr[i]; | |||
| } | |||
| } | |||
| // Get the effect volume for the system effect | |||
| float EffectMgr::sysefxgetvolume(void) | |||
| { | |||
| return (!efx) ? 1.0f : efx->outvolume; | |||
| } | |||
| // Get the EQ response | |||
| float EffectMgr::getEQfreqresponse(float freq) | |||
| { | |||
| return (nefx == 7) ? efx->getfreqresponse(freq) : 0.0f; | |||
| } | |||
| void EffectMgr::setdryonly(bool value) | |||
| { | |||
| dryonly = value; | |||
| } | |||
| void EffectMgr::add2XML(XMLwrapper *xml) | |||
| { | |||
| xml->addpar("type", geteffect()); | |||
| if(!efx || !geteffect()) | |||
| return; | |||
| xml->addpar("preset", efx->Ppreset); | |||
| xml->beginbranch("EFFECT_PARAMETERS"); | |||
| for(int n = 0; n < 128; ++n) { | |||
| int par = geteffectpar(n); | |||
| if(par == 0) | |||
| continue; | |||
| xml->beginbranch("par_no", n); | |||
| xml->addpar("par", par); | |||
| xml->endbranch(); | |||
| } | |||
| if(filterpars) { | |||
| xml->beginbranch("FILTER"); | |||
| filterpars->add2XML(xml); | |||
| xml->endbranch(); | |||
| } | |||
| xml->endbranch(); | |||
| } | |||
| void EffectMgr::getfromXML(XMLwrapper *xml) | |||
| { | |||
| changeeffect(xml->getpar127("type", geteffect())); | |||
| if(!efx || !geteffect()) | |||
| return; | |||
| efx->Ppreset = xml->getpar127("preset", efx->Ppreset); | |||
| if(xml->enterbranch("EFFECT_PARAMETERS")) { | |||
| for(int n = 0; n < 128; ++n) { | |||
| seteffectpar_nolock(n, 0); //erase effect parameter | |||
| if(xml->enterbranch("par_no", n) == 0) | |||
| continue; | |||
| int par = geteffectpar(n); | |||
| seteffectpar_nolock(n, xml->getpar127("par", par)); | |||
| xml->exitbranch(); | |||
| } | |||
| if(filterpars) | |||
| if(xml->enterbranch("FILTER")) { | |||
| filterpars->getfromXML(xml); | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| cleanup(); | |||
| } | |||
| @@ -0,0 +1,86 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| EffectMgr.h - Effect manager, an interface betwen the program and effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef EFFECTMGR_H | |||
| #define EFFECTMGR_H | |||
| #include <pthread.h> | |||
| #include "Alienwah.h" | |||
| #include "Phaser.h" | |||
| #include "../Params/Presets.h" | |||
| class Effect; | |||
| class FilterParams; | |||
| class XMLwrapper; | |||
| #include "Distorsion.h" | |||
| #include "EQ.h" | |||
| #include "DynamicFilter.h" | |||
| #include "../Misc/XMLwrapper.h" | |||
| #include "../Params/FilterParams.h" | |||
| #include "../Params/Presets.h" | |||
| /**Effect manager, an interface betwen the program and effects*/ | |||
| class EffectMgr:public Presets | |||
| { | |||
| public: | |||
| EffectMgr(const bool insertion_, pthread_mutex_t *mutex_); | |||
| ~EffectMgr(); | |||
| void add2XML(XMLwrapper *xml); | |||
| void defaults(void); | |||
| void getfromXML(XMLwrapper *xml); | |||
| void out(float *smpsl, float *smpsr); | |||
| void setdryonly(bool value); | |||
| /**get the output(to speakers) volume of the systemeffect*/ | |||
| float sysefxgetvolume(void); | |||
| void cleanup(void); | |||
| void changeeffect(int nefx_); | |||
| int geteffect(void); | |||
| void changepreset(unsigned char npreset); | |||
| void changepreset_nolock(unsigned char npreset); | |||
| unsigned char getpreset(void); | |||
| void seteffectpar(int npar, unsigned char value); | |||
| void seteffectpar_nolock(int npar, unsigned char value); | |||
| unsigned char geteffectpar(int npar); | |||
| const bool insertion; | |||
| float *efxoutl, *efxoutr; | |||
| // used by UI | |||
| float getEQfreqresponse(float freq); | |||
| FilterParams *filterpars; | |||
| private: | |||
| int nefx; | |||
| Effect *efx; | |||
| pthread_mutex_t *mutex; | |||
| bool dryonly; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,462 @@ | |||
| /* | |||
| Phaser.cpp - Phasing and Approximate digital model of an analog JFET phaser. | |||
| Analog modeling implemented by Ryan Billing aka Transmogrifox. | |||
| ZynAddSubFX - a software synthesizer | |||
| Phaser.cpp - Phaser effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright (C) 2009-2010 Ryan Billing | |||
| Copyright (C) 2010-2010 Mark McCurry | |||
| Author: Nasca Octavian Paul | |||
| Ryan Billing | |||
| Mark McCurry | |||
| DSP analog modeling theory & practice largely influenced by various CCRMA publications, particularly works by Julius O. Smith. | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <cmath> | |||
| #include <algorithm> | |||
| #include "Phaser.h" | |||
| using namespace std; | |||
| #define PHASER_LFO_SHAPE 2 | |||
| #define ONE_ 0.99999f // To prevent LFO ever reaching 1.0f for filter stability purposes | |||
| #define ZERO_ 0.00001f // Same idea as above. | |||
| Phaser::Phaser(const int &insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), old(NULL), xn1(NULL), | |||
| yn1(NULL), diff(0.0f), oldgain(0.0f), fb(0.0f) | |||
| { | |||
| analog_setup(); | |||
| setpreset(Ppreset); | |||
| cleanup(); | |||
| } | |||
| void Phaser::analog_setup() | |||
| { | |||
| //model mismatch between JFET devices | |||
| offset[0] = -0.2509303f; | |||
| offset[1] = 0.9408924f; | |||
| offset[2] = 0.998f; | |||
| offset[3] = -0.3486182f; | |||
| offset[4] = -0.2762545f; | |||
| offset[5] = -0.5215785f; | |||
| offset[6] = 0.2509303f; | |||
| offset[7] = -0.9408924f; | |||
| offset[8] = -0.998f; | |||
| offset[9] = 0.3486182f; | |||
| offset[10] = 0.2762545f; | |||
| offset[11] = 0.5215785f; | |||
| barber = 0; //Deactivate barber pole phasing by default | |||
| mis = 1.0f; | |||
| Rmin = 625.0f; // 2N5457 typical on resistance at Vgs = 0 | |||
| Rmax = 22000.0f; // Resistor parallel to FET | |||
| Rmx = Rmin / Rmax; | |||
| Rconst = 1.0f + Rmx; // Handle parallel resistor relationship | |||
| C = 0.00000005f; // 50 nF | |||
| CFs = 2.0f * synth->samplerate_f * C; | |||
| invperiod = 1.0f / synth->buffersize_f; | |||
| } | |||
| Phaser::~Phaser() | |||
| { | |||
| if(xn1.l) | |||
| delete[] xn1.l; | |||
| if(yn1.l) | |||
| delete[] yn1.l; | |||
| if(xn1.r) | |||
| delete[] xn1.r; | |||
| if(yn1.r) | |||
| delete[] yn1.r; | |||
| } | |||
| /* | |||
| * Effect output | |||
| */ | |||
| void Phaser::out(const Stereo<float *> &input) | |||
| { | |||
| if(Panalog) | |||
| AnalogPhase(input); | |||
| else | |||
| normalPhase(input); | |||
| } | |||
| void Phaser::AnalogPhase(const Stereo<float *> &input) | |||
| { | |||
| Stereo<float> gain(0.0f), lfoVal(0.0f), mod(0.0f), g(0.0f), b(0.0f), hpf( | |||
| 0.0f); | |||
| lfo.effectlfoout(&lfoVal.l, &lfoVal.r); | |||
| mod.l = lfoVal.l * width + (depth - 0.5f); | |||
| mod.r = lfoVal.r * width + (depth - 0.5f); | |||
| mod.l = limit(mod.l, ZERO_, ONE_); | |||
| mod.r = limit(mod.r, ZERO_, ONE_); | |||
| if(Phyper) { | |||
| //Triangle wave squared is approximately sin on bottom, tri on top | |||
| //Result is exponential sweep more akin to filter in synth with | |||
| //exponential generator circuitry. | |||
| mod.l *= mod.l; | |||
| mod.r *= mod.r; | |||
| } | |||
| //g.l,g.r is Vp - Vgs. Typical FET drain-source resistance follows constant/[1-sqrt(Vp - Vgs)] | |||
| mod.l = sqrtf(1.0f - mod.l); | |||
| mod.r = sqrtf(1.0f - mod.r); | |||
| diff.r = (mod.r - oldgain.r) * invperiod; | |||
| diff.l = (mod.l - oldgain.l) * invperiod; | |||
| g = oldgain; | |||
| oldgain = mod; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| g.l += diff.l; // Linear interpolation between LFO samples | |||
| g.r += diff.r; | |||
| Stereo<float> xn(input.l[i] * pangainL, input.r[i] * pangainR); | |||
| if(barber) { | |||
| g.l = fmodf((g.l + 0.25f), ONE_); | |||
| g.r = fmodf((g.r + 0.25f), ONE_); | |||
| } | |||
| xn.l = applyPhase(xn.l, g.l, fb.l, hpf.l, yn1.l, xn1.l); | |||
| xn.r = applyPhase(xn.r, g.r, fb.r, hpf.r, yn1.r, xn1.r); | |||
| fb.l = xn.l * feedback; | |||
| fb.r = xn.r * feedback; | |||
| efxoutl[i] = xn.l; | |||
| efxoutr[i] = xn.r; | |||
| } | |||
| if(Poutsub) { | |||
| invSignal(efxoutl, synth->buffersize); | |||
| invSignal(efxoutr, synth->buffersize); | |||
| } | |||
| } | |||
| float Phaser::applyPhase(float x, float g, float fb, | |||
| float &hpf, float *yn1, float *xn1) | |||
| { | |||
| for(int j = 0; j < Pstages; ++j) { //Phasing routine | |||
| mis = 1.0f + offsetpct * offset[j]; | |||
| //This is symmetrical. | |||
| //FET is not, so this deviates slightly, however sym dist. is | |||
| //better sounding than a real FET. | |||
| float d = (1.0f + 2.0f * (0.25f + g) * hpf * hpf * distortion) * mis; | |||
| Rconst = 1.0f + mis * Rmx; | |||
| // This is 1/R. R is being modulated to control filter fc. | |||
| float b = (Rconst - g) / (d * Rmin); | |||
| float gain = (CFs - b) / (CFs + b); | |||
| yn1[j] = gain * (x + yn1[j]) - xn1[j]; | |||
| //high pass filter: | |||
| //Distortion depends on the high-pass part of the AP stage. | |||
| hpf = yn1[j] + (1.0f - gain) * xn1[j]; | |||
| xn1[j] = x; | |||
| x = yn1[j]; | |||
| if(j == 1) | |||
| x += fb; //Insert feedback after first phase stage | |||
| } | |||
| return x; | |||
| } | |||
| void Phaser::normalPhase(const Stereo<float *> &input) | |||
| { | |||
| Stereo<float> gain(0.0f), lfoVal(0.0f); | |||
| lfo.effectlfoout(&lfoVal.l, &lfoVal.r); | |||
| gain.l = | |||
| (expf(lfoVal.l | |||
| * PHASER_LFO_SHAPE) - 1) / (expf(PHASER_LFO_SHAPE) - 1.0f); | |||
| gain.r = | |||
| (expf(lfoVal.r | |||
| * PHASER_LFO_SHAPE) - 1) / (expf(PHASER_LFO_SHAPE) - 1.0f); | |||
| gain.l = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * gain.l * depth; | |||
| gain.r = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * gain.r * depth; | |||
| gain.l = limit(gain.l, ZERO_, ONE_); | |||
| gain.r = limit(gain.r, ZERO_, ONE_); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float x = (float) i / synth->buffersize_f; | |||
| float x1 = 1.0f - x; | |||
| //TODO think about making panning an external feature | |||
| Stereo<float> xn(input.l[i] * pangainL + fb.l, | |||
| input.r[i] * pangainR + fb.r); | |||
| Stereo<float> g(gain.l * x + oldgain.l * x1, | |||
| gain.r * x + oldgain.r * x1); | |||
| xn.l = applyPhase(xn.l, g.l, old.l); | |||
| xn.r = applyPhase(xn.r, g.r, old.r); | |||
| //Left/Right crossing | |||
| crossover(xn.l, xn.r, lrcross); | |||
| fb.l = xn.l * feedback; | |||
| fb.r = xn.r * feedback; | |||
| efxoutl[i] = xn.l; | |||
| efxoutr[i] = xn.r; | |||
| } | |||
| oldgain = gain; | |||
| if(Poutsub) { | |||
| invSignal(efxoutl, synth->buffersize); | |||
| invSignal(efxoutr, synth->buffersize); | |||
| } | |||
| } | |||
| float Phaser::applyPhase(float x, float g, float *old) | |||
| { | |||
| for(int j = 0; j < Pstages * 2; ++j) { //Phasing routine | |||
| float tmp = old[j]; | |||
| old[j] = g * tmp + x; | |||
| x = tmp - g * old[j]; | |||
| } | |||
| return x; | |||
| } | |||
| /* | |||
| * Cleanup the effect | |||
| */ | |||
| void Phaser::cleanup() | |||
| { | |||
| fb = oldgain = Stereo<float>(0.0f); | |||
| for(int i = 0; i < Pstages * 2; ++i) { | |||
| old.l[i] = 0.0f; | |||
| old.r[i] = 0.0f; | |||
| } | |||
| for(int i = 0; i < Pstages; ++i) { | |||
| xn1.l[i] = 0.0f; | |||
| yn1.l[i] = 0.0f; | |||
| xn1.r[i] = 0.0f; | |||
| yn1.r[i] = 0.0f; | |||
| } | |||
| } | |||
| /* | |||
| * Parameter control | |||
| */ | |||
| void Phaser::setwidth(unsigned char Pwidth) | |||
| { | |||
| this->Pwidth = Pwidth; | |||
| width = ((float)Pwidth / 127.0f); | |||
| } | |||
| void Phaser::setfb(unsigned char Pfb) | |||
| { | |||
| this->Pfb = Pfb; | |||
| feedback = (float) (Pfb - 64) / 64.2f; | |||
| } | |||
| void Phaser::setvolume(unsigned char Pvolume) | |||
| { | |||
| this->Pvolume = Pvolume; | |||
| outvolume = Pvolume / 127.0f; | |||
| if(insertion == 0) | |||
| volume = 1.0f; | |||
| else | |||
| volume = outvolume; | |||
| } | |||
| void Phaser::setdistortion(unsigned char Pdistortion) | |||
| { | |||
| this->Pdistortion = Pdistortion; | |||
| distortion = (float)Pdistortion / 127.0f; | |||
| } | |||
| void Phaser::setoffset(unsigned char Poffset) | |||
| { | |||
| this->Poffset = Poffset; | |||
| offsetpct = (float)Poffset / 127.0f; | |||
| } | |||
| void Phaser::setstages(unsigned char Pstages) | |||
| { | |||
| if(xn1.l) | |||
| delete[] xn1.l; | |||
| if(yn1.l) | |||
| delete[] yn1.l; | |||
| if(xn1.r) | |||
| delete[] xn1.r; | |||
| if(yn1.r) | |||
| delete[] yn1.r; | |||
| this->Pstages = min(MAX_PHASER_STAGES, (int)Pstages); | |||
| old = Stereo<float *>(new float[Pstages * 2], | |||
| new float[Pstages * 2]); | |||
| xn1 = Stereo<float *>(new float[Pstages], | |||
| new float[Pstages]); | |||
| yn1 = Stereo<float *>(new float[Pstages], | |||
| new float[Pstages]); | |||
| cleanup(); | |||
| } | |||
| void Phaser::setphase(unsigned char Pphase) | |||
| { | |||
| this->Pphase = Pphase; | |||
| phase = (Pphase / 127.0f); | |||
| } | |||
| void Phaser::setdepth(unsigned char Pdepth) | |||
| { | |||
| this->Pdepth = Pdepth; | |||
| depth = (float)(Pdepth) / 127.0f; | |||
| } | |||
| void Phaser::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 15; | |||
| const int NUM_PRESETS = 12; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| //Phaser | |||
| //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |||
| {64, 64, 36, 0, 0, 64, 110, 64, 1, 0, 0, 20, | |||
| 0, 0, | |||
| 0 }, | |||
| {64, 64, 35, 0, 0, 88, 40, 64, 3, 0, 0, 20, 0, 0, | |||
| 0 }, | |||
| {64, 64, 31, 0, 0, 66, 68, 107, 2, 0, 0, 20, 0, 0, | |||
| 0 }, | |||
| {39, 64, 22, 0, 0, 66, 67, 10, 5, 0, 1, 20, 0, 0, | |||
| 0 }, | |||
| {64, 64, 20, 0, 1, 110, 67, 78, 10, 0, 0, 20, 0, 0, | |||
| 0 }, | |||
| {64, 64, 53, 100, 0, 58, 37, 78, 3, 0, 0, 20, 0, 0, | |||
| 0 }, | |||
| //APhaser | |||
| //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |||
| {64, 64, 14, 0, 1, 64, 64, 40, 4, 10, 0, 110,1, 20, | |||
| 1 }, | |||
| {64, 64, 14, 5, 1, 64, 70, 40, 6, 10, 0, 110,1, 20, | |||
| 1 }, | |||
| {64, 64, 9, 0, 0, 64, 60, 40, 8, 10, 0, 40, 0, 20, | |||
| 1 }, | |||
| {64, 64, 14, 10, 0, 64, 45, 80, 7, 10, 1, 110,1, 20, | |||
| 1 }, | |||
| {25, 64, 127, 10, 0, 64, 25, 16, 8, 100, 0, 25, 0, 20, | |||
| 1 }, | |||
| {64, 64, 1, 10, 1, 64, 70, 40, 12, 10, 0, 110,1, 20, | |||
| 1 } | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| Ppreset = npreset; | |||
| } | |||
| void Phaser::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| lfo.Pfreq = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 3: | |||
| lfo.Prandomness = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 4: | |||
| lfo.PLFOtype = value; | |||
| lfo.updateparams(); | |||
| barber = (2 == value); | |||
| break; | |||
| case 5: | |||
| lfo.Pstereo = value; | |||
| lfo.updateparams(); | |||
| break; | |||
| case 6: | |||
| setdepth(value); | |||
| break; | |||
| case 7: | |||
| setfb(value); | |||
| break; | |||
| case 8: | |||
| setstages(value); | |||
| break; | |||
| case 9: | |||
| setlrcross(value); | |||
| setoffset(value); | |||
| break; | |||
| case 10: | |||
| Poutsub = min((int)value, 1); | |||
| break; | |||
| case 11: | |||
| setphase(value); | |||
| setwidth(value); | |||
| break; | |||
| case 12: | |||
| Phyper = min((int)value, 1); | |||
| break; | |||
| case 13: | |||
| setdistortion(value); | |||
| break; | |||
| case 14: | |||
| Panalog = value; | |||
| break; | |||
| } | |||
| } | |||
| unsigned char Phaser::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return lfo.Pfreq; | |||
| case 3: return lfo.Prandomness; | |||
| case 4: return lfo.PLFOtype; | |||
| case 5: return lfo.Pstereo; | |||
| case 6: return Pdepth; | |||
| case 7: return Pfb; | |||
| case 8: return Pstages; | |||
| case 9: return Plrcross; | |||
| return Poffset; //same | |||
| case 10: return Poutsub; | |||
| case 11: return Pphase; | |||
| return Pwidth; //same | |||
| case 12: return Phyper; | |||
| case 13: return Pdistortion; | |||
| case 14: return Panalog; | |||
| default: return 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,98 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Phaser.h - Phaser effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright (C) 2009-2010 Ryan Billing | |||
| Copyright (C) 2010-2010 Mark McCurry | |||
| Author: Nasca Octavian Paul | |||
| Ryan Billing | |||
| Mark McCurry | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef PHASER_H | |||
| #define PHASER_H | |||
| #include "../globals.h" | |||
| #include "Effect.h" | |||
| #include "EffectLFO.h" | |||
| #define MAX_PHASER_STAGES 12 | |||
| class Phaser:public Effect | |||
| { | |||
| public: | |||
| Phaser(const int &insertion_, float *efxoutl_, float *efxoutr_); | |||
| ~Phaser(); | |||
| void out(const Stereo<float *> &input); | |||
| void setpreset(unsigned char npreset); | |||
| void changepar(int npar, unsigned char value); | |||
| unsigned char getpar(int npar) const; | |||
| void cleanup(); | |||
| private: | |||
| //Phaser parameters | |||
| EffectLFO lfo; //Phaser modulator | |||
| unsigned char Pvolume; //Used to set wet/dry mix | |||
| unsigned char Pdistortion; //Model distortion added by FET element | |||
| unsigned char Pdepth; //Depth of phaser sweep | |||
| unsigned char Pwidth; //Phaser width (LFO amplitude) | |||
| unsigned char Pfb; //feedback | |||
| unsigned char Poffset; //Model mismatch between variable resistors | |||
| unsigned char Pstages; //Number of first-order All-Pass stages | |||
| unsigned char Poutsub; //if I wish to subtract the output instead of adding | |||
| unsigned char Pphase; | |||
| unsigned char Phyper; //lfo^2 -- converts tri into hyper-sine | |||
| unsigned char Panalog; | |||
| //Control parameters | |||
| void setvolume(unsigned char Pvolume); | |||
| void setdepth(unsigned char Pdepth); | |||
| void setfb(unsigned char Pfb); | |||
| void setdistortion(unsigned char Pdistortion); | |||
| void setwidth(unsigned char Pwidth); | |||
| void setoffset(unsigned char Poffset); | |||
| void setstages(unsigned char Pstages); | |||
| void setphase(unsigned char Pphase); | |||
| //Internal Variables | |||
| bool barber; //Barber pole phasing flag | |||
| float distortion, width, offsetpct; | |||
| float feedback, depth, phase; | |||
| Stereo<float *> old, xn1, yn1; | |||
| Stereo<float> diff, oldgain, fb; | |||
| float invperiod; | |||
| float offset[12]; | |||
| float mis; | |||
| float Rmin; // 3N5457 typical on resistance at Vgs = 0 | |||
| float Rmax; // Resistor parallel to FET | |||
| float Rmx; // Rmin/Rmax to avoid division in loop | |||
| float Rconst; // Handle parallel resistor relationship | |||
| float C; // Capacitor | |||
| float CFs; // A constant derived from capacitor and resistor relationships | |||
| void analog_setup(); | |||
| void AnalogPhase(const Stereo<float *> &input); | |||
| //analog case | |||
| float applyPhase(float x, float g, float fb, | |||
| float &hpf, float *yn1, float *xn1); | |||
| void normalPhase(const Stereo<float *> &input); | |||
| float applyPhase(float x, float g, float *old); | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,498 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Reverb.cpp - Reverberation effect | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "Reverb.h" | |||
| #include "../Misc/Util.h" | |||
| #include "../DSP/AnalogFilter.h" | |||
| #include "../DSP/Unison.h" | |||
| #include <cmath> | |||
| //todo: EarlyReflections, Prdelay, Perbalance | |||
| Reverb::Reverb(bool insertion_, float *efxoutl_, float *efxoutr_) | |||
| :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), | |||
| // defaults | |||
| Pvolume(48), | |||
| Ptime(64), | |||
| Pidelay(40), | |||
| Pidelayfb(0), | |||
| Prdelay(0), | |||
| Perbalance(64), | |||
| Plpf(127), | |||
| Phpf(0), | |||
| Plohidamp(80), | |||
| Ptype(1), | |||
| Proomsize(64), | |||
| Pbandwidth(30), | |||
| roomsize(1.0f), | |||
| rs(1.0f), | |||
| bandwidth(NULL), | |||
| idelay(NULL), | |||
| lpf(NULL), | |||
| hpf(NULL) // no filter | |||
| { | |||
| for(int i = 0; i < REV_COMBS * 2; ++i) { | |||
| comblen[i] = 800 + (int)(RND * 1400.0f); | |||
| combk[i] = 0; | |||
| lpcomb[i] = 0; | |||
| combfb[i] = -0.97f; | |||
| comb[i] = NULL; | |||
| } | |||
| for(int i = 0; i < REV_APS * 2; ++i) { | |||
| aplen[i] = 500 + (int)(RND * 500.0f); | |||
| apk[i] = 0; | |||
| ap[i] = NULL; | |||
| } | |||
| setpreset(Ppreset); | |||
| cleanup(); //do not call this before the comb initialisation | |||
| } | |||
| Reverb::~Reverb() | |||
| { | |||
| delete [] idelay; | |||
| delete hpf; | |||
| delete lpf; | |||
| for(int i = 0; i < REV_APS * 2; ++i) | |||
| delete [] ap[i]; | |||
| for(int i = 0; i < REV_COMBS * 2; ++i) | |||
| delete [] comb[i]; | |||
| if(bandwidth) | |||
| delete bandwidth; | |||
| } | |||
| //Cleanup the effect | |||
| void Reverb::cleanup(void) | |||
| { | |||
| int i, j; | |||
| for(i = 0; i < REV_COMBS * 2; ++i) { | |||
| lpcomb[i] = 0.0f; | |||
| for(j = 0; j < comblen[i]; ++j) | |||
| comb[i][j] = 0.0f; | |||
| } | |||
| for(i = 0; i < REV_APS * 2; ++i) | |||
| for(j = 0; j < aplen[i]; ++j) | |||
| ap[i][j] = 0.0f; | |||
| if(idelay) | |||
| for(i = 0; i < idelaylen; ++i) | |||
| idelay[i] = 0.0f; | |||
| if(hpf) | |||
| hpf->cleanup(); | |||
| if(lpf) | |||
| lpf->cleanup(); | |||
| } | |||
| //Process one channel; 0=left, 1=right | |||
| void Reverb::processmono(int ch, float *output, float *inputbuf) | |||
| { | |||
| //todo: implement the high part from lohidamp | |||
| for(int j = REV_COMBS * ch; j < REV_COMBS * (ch + 1); ++j) { | |||
| int &ck = combk[j]; | |||
| const int comblength = comblen[j]; | |||
| float &lpcombj = lpcomb[j]; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float fbout = comb[j][ck] * combfb[j]; | |||
| fbout = fbout * (1.0f - lohifb) + lpcombj * lohifb; | |||
| lpcombj = fbout; | |||
| comb[j][ck] = inputbuf[i] + fbout; | |||
| output[i] += fbout; | |||
| if((++ck) >= comblength) | |||
| ck = 0; | |||
| } | |||
| } | |||
| for(int j = REV_APS * ch; j < REV_APS * (1 + ch); ++j) { | |||
| int &ak = apk[j]; | |||
| const int aplength = aplen[j]; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float tmp = ap[j][ak]; | |||
| ap[j][ak] = 0.7f * tmp + output[i]; | |||
| output[i] = tmp - 0.7f * ap[j][ak]; | |||
| if((++ak) >= aplength) | |||
| ak = 0; | |||
| } | |||
| } | |||
| } | |||
| //Effect output | |||
| void Reverb::out(const Stereo<float *> &smp) | |||
| { | |||
| if(!Pvolume && insertion) | |||
| return; | |||
| float *inputbuf = getTmpBuffer(); | |||
| for(int i = 0; i < synth->buffersize; ++i) | |||
| inputbuf[i] = (smp.l[i] + smp.r[i]) / 2.0f; | |||
| if(idelay) | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| //Initial delay r | |||
| float tmp = inputbuf[i] + idelay[idelayk] * idelayfb; | |||
| inputbuf[i] = idelay[idelayk]; | |||
| idelay[idelayk] = tmp; | |||
| idelayk++; | |||
| if(idelayk >= idelaylen) | |||
| idelayk = 0; | |||
| } | |||
| if(bandwidth) | |||
| bandwidth->process(synth->buffersize, inputbuf); | |||
| if(lpf) | |||
| lpf->filterout(inputbuf); | |||
| if(hpf) | |||
| hpf->filterout(inputbuf); | |||
| processmono(0, efxoutl, inputbuf); //left | |||
| processmono(1, efxoutr, inputbuf); //right | |||
| returnTmpBuffer(inputbuf); | |||
| float lvol = rs / REV_COMBS * pangainL; | |||
| float rvol = rs / REV_COMBS * pangainR; | |||
| if(insertion != 0) { | |||
| lvol *= 2.0f; | |||
| rvol *= 2.0f; | |||
| } | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| efxoutl[i] *= lvol; | |||
| efxoutr[i] *= rvol; | |||
| } | |||
| } | |||
| //Parameter control | |||
| void Reverb::setvolume(unsigned char _Pvolume) | |||
| { | |||
| Pvolume = _Pvolume; | |||
| if(!insertion) { | |||
| outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; | |||
| volume = 1.0f; | |||
| } | |||
| else { | |||
| volume = outvolume = Pvolume / 127.0f; | |||
| if(Pvolume == 0) | |||
| cleanup(); | |||
| } | |||
| } | |||
| void Reverb::settime(unsigned char _Ptime) | |||
| { | |||
| Ptime = _Ptime; | |||
| float t = powf(60.0f, Ptime / 127.0f) - 0.97f; | |||
| for(int i = 0; i < REV_COMBS * 2; ++i) | |||
| combfb[i] = | |||
| -expf((float)comblen[i] / synth->samplerate_f * logf(0.001f) / t); | |||
| //the feedback is negative because it removes the DC | |||
| } | |||
| void Reverb::setlohidamp(unsigned char _Plohidamp) | |||
| { | |||
| Plohidamp = (_Plohidamp < 64) ? 64 : _Plohidamp; | |||
| //remove this when the high part from lohidamp is added | |||
| if(Plohidamp == 64) { | |||
| lohidamptype = 0; | |||
| lohifb = 0.0f; | |||
| } | |||
| else { | |||
| if(Plohidamp < 64) | |||
| lohidamptype = 1; | |||
| if(Plohidamp > 64) | |||
| lohidamptype = 2; | |||
| float x = fabsf((float)(Plohidamp - 64) / 64.1f); | |||
| lohifb = x * x; | |||
| } | |||
| } | |||
| void Reverb::setidelay(unsigned char _Pidelay) | |||
| { | |||
| Pidelay = _Pidelay; | |||
| float delay = powf(50.0f * Pidelay / 127.0f, 2.0f) - 1.0f; | |||
| if(idelay) | |||
| delete [] idelay; | |||
| idelay = NULL; | |||
| idelaylen = (int) (synth->samplerate_f * delay / 1000); | |||
| if(idelaylen > 1) { | |||
| idelayk = 0; | |||
| idelay = new float[idelaylen]; | |||
| memset(idelay, 0, idelaylen * sizeof(float)); | |||
| } | |||
| } | |||
| void Reverb::setidelayfb(unsigned char _Pidelayfb) | |||
| { | |||
| Pidelayfb = _Pidelayfb; | |||
| idelayfb = Pidelayfb / 128.0f; | |||
| } | |||
| void Reverb::sethpf(unsigned char _Phpf) | |||
| { | |||
| Phpf = _Phpf; | |||
| if(Phpf == 0) { //No HighPass | |||
| if(hpf) | |||
| delete hpf; | |||
| hpf = NULL; | |||
| } | |||
| else { | |||
| float fr = expf(powf(Phpf / 127.0f, 0.5f) * logf(10000.0f)) + 20.0f; | |||
| if(hpf == NULL) | |||
| hpf = new AnalogFilter(3, fr, 1, 0); | |||
| else | |||
| hpf->setfreq(fr); | |||
| } | |||
| } | |||
| void Reverb::setlpf(unsigned char _Plpf) | |||
| { | |||
| Plpf = _Plpf; | |||
| if(Plpf == 127) { //No LowPass | |||
| if(lpf) | |||
| delete lpf; | |||
| lpf = NULL; | |||
| } | |||
| else { | |||
| float fr = expf(powf(Plpf / 127.0f, 0.5f) * logf(25000.0f)) + 40.0f; | |||
| if(!lpf) | |||
| lpf = new AnalogFilter(2, fr, 1, 0); | |||
| else | |||
| lpf->setfreq(fr); | |||
| } | |||
| } | |||
| void Reverb::settype(unsigned char _Ptype) | |||
| { | |||
| Ptype = _Ptype; | |||
| const int NUM_TYPES = 3; | |||
| const int combtunings[NUM_TYPES][REV_COMBS] = { | |||
| //this is unused (for random) | |||
| {0, 0, 0, 0, 0, 0, 0, 0 }, | |||
| //Freeverb by Jezar at Dreampoint | |||
| {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }, | |||
| //duplicate of Freeverb by Jezar at Dreampoint | |||
| {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 } | |||
| }; | |||
| const int aptunings[NUM_TYPES][REV_APS] = { | |||
| //this is unused (for random) | |||
| {0, 0, 0, 0 }, | |||
| //Freeverb by Jezar at Dreampoint | |||
| {225, 341, 441, 556 }, | |||
| //duplicate of Freeverb by Jezar at Dreampoint | |||
| {225, 341, 441, 556 } | |||
| }; | |||
| if(Ptype >= NUM_TYPES) | |||
| Ptype = NUM_TYPES - 1; | |||
| // adjust the combs according to the samplerate | |||
| float samplerate_adjust = synth->samplerate_f / 44100.0f; | |||
| float tmp; | |||
| for(int i = 0; i < REV_COMBS * 2; ++i) { | |||
| if(Ptype == 0) | |||
| tmp = 800.0f + (int)(RND * 1400.0f); | |||
| else | |||
| tmp = combtunings[Ptype][i % REV_COMBS]; | |||
| tmp *= roomsize; | |||
| if(i > REV_COMBS) | |||
| tmp += 23.0f; | |||
| tmp *= samplerate_adjust; //adjust the combs according to the samplerate | |||
| if(tmp < 10.0f) | |||
| tmp = 10.0f; | |||
| comblen[i] = (int) tmp; | |||
| combk[i] = 0; | |||
| lpcomb[i] = 0; | |||
| if(comb[i]) | |||
| delete [] comb[i]; | |||
| comb[i] = new float[comblen[i]]; | |||
| } | |||
| for(int i = 0; i < REV_APS * 2; ++i) { | |||
| if(Ptype == 0) | |||
| tmp = 500 + (int)(RND * 500.0f); | |||
| else | |||
| tmp = aptunings[Ptype][i % REV_APS]; | |||
| tmp *= roomsize; | |||
| if(i > REV_APS) | |||
| tmp += 23.0f; | |||
| tmp *= samplerate_adjust; //adjust the combs according to the samplerate | |||
| if(tmp < 10) | |||
| tmp = 10; | |||
| aplen[i] = (int) tmp; | |||
| apk[i] = 0; | |||
| if(ap[i]) | |||
| delete [] ap[i]; | |||
| ap[i] = new float[aplen[i]]; | |||
| } | |||
| delete bandwidth; | |||
| bandwidth = NULL; | |||
| if(Ptype == 2) { //bandwidth | |||
| //TODO the size of the unison buffer may be too small, though this has | |||
| //not been verified yet. | |||
| //As this cannot be resized in a RT context, a good upper bound should | |||
| //be found | |||
| bandwidth = new Unison(synth->buffersize / 4 + 1, 2.0f); | |||
| bandwidth->setSize(50); | |||
| bandwidth->setBaseFrequency(1.0f); | |||
| } | |||
| settime(Ptime); | |||
| cleanup(); | |||
| } | |||
| void Reverb::setroomsize(unsigned char _Proomsize) | |||
| { | |||
| Proomsize = _Proomsize; | |||
| if(!Proomsize) | |||
| this->Proomsize = 64; //this is because the older versions consider roomsize=0 | |||
| roomsize = (this->Proomsize - 64.0f) / 64.0f; | |||
| if(roomsize > 0.0f) | |||
| roomsize *= 2.0f; | |||
| roomsize = powf(10.0f, roomsize); | |||
| rs = sqrtf(roomsize); | |||
| settype(Ptype); | |||
| } | |||
| void Reverb::setbandwidth(unsigned char _Pbandwidth) | |||
| { | |||
| Pbandwidth = _Pbandwidth; | |||
| float v = Pbandwidth / 127.0f; | |||
| if(bandwidth) | |||
| bandwidth->setBandwidth(powf(v, 2.0f) * 200.0f); | |||
| } | |||
| void Reverb::setpreset(unsigned char npreset) | |||
| { | |||
| const int PRESET_SIZE = 13; | |||
| const int NUM_PRESETS = 13; | |||
| unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||
| //Cathedral1 | |||
| {80, 64, 63, 24, 0, 0, 0, 85, 5, 83, 1, 64, 20}, | |||
| //Cathedral2 | |||
| {80, 64, 69, 35, 0, 0, 0, 127, 0, 71, 0, 64, 20}, | |||
| //Cathedral3 | |||
| {80, 64, 69, 24, 0, 0, 0, 127, 75, 78, 1, 85, 20}, | |||
| //Hall1 | |||
| {90, 64, 51, 10, 0, 0, 0, 127, 21, 78, 1, 64, 20}, | |||
| //Hall2 | |||
| {90, 64, 53, 20, 0, 0, 0, 127, 75, 71, 1, 64, 20}, | |||
| //Room1 | |||
| {100, 64, 33, 0, 0, 0, 0, 127, 0, 106, 0, 30, 20}, | |||
| //Room2 | |||
| {100, 64, 21, 26, 0, 0, 0, 62, 0, 77, 1, 45, 20}, | |||
| //Basement | |||
| {110, 64, 14, 0, 0, 0, 0, 127, 5, 71, 0, 25, 20}, | |||
| //Tunnel | |||
| {85, 80, 84, 20, 42, 0, 0, 51, 0, 78, 1, 105, 20}, | |||
| //Echoed1 | |||
| {95, 64, 26, 60, 71, 0, 0, 114, 0, 64, 1, 64, 20}, | |||
| //Echoed2 | |||
| {90, 64, 40, 88, 71, 0, 0, 114, 0, 88, 1, 64, 20}, | |||
| //VeryLong1 | |||
| {90, 64, 93, 15, 0, 0, 0, 114, 0, 77, 0, 95, 20}, | |||
| //VeryLong2 | |||
| {90, 64, 111, 30, 0, 0, 0, 114, 90, 74, 1, 80, 20} | |||
| }; | |||
| if(npreset >= NUM_PRESETS) | |||
| npreset = NUM_PRESETS - 1; | |||
| for(int n = 0; n < PRESET_SIZE; ++n) | |||
| changepar(n, presets[npreset][n]); | |||
| if(insertion) | |||
| changepar(0, presets[npreset][0] / 2); //lower the volume if reverb is insertion effect | |||
| Ppreset = npreset; | |||
| } | |||
| void Reverb::changepar(int npar, unsigned char value) | |||
| { | |||
| switch(npar) { | |||
| case 0: | |||
| setvolume(value); | |||
| break; | |||
| case 1: | |||
| setpanning(value); | |||
| break; | |||
| case 2: | |||
| settime(value); | |||
| break; | |||
| case 3: | |||
| setidelay(value); | |||
| break; | |||
| case 4: | |||
| setidelayfb(value); | |||
| break; | |||
| // case 5: | |||
| // setrdelay(value); | |||
| // break; | |||
| // case 6: | |||
| // seterbalance(value); | |||
| // break; | |||
| case 7: | |||
| setlpf(value); | |||
| break; | |||
| case 8: | |||
| sethpf(value); | |||
| break; | |||
| case 9: | |||
| setlohidamp(value); | |||
| break; | |||
| case 10: | |||
| settype(value); | |||
| break; | |||
| case 11: | |||
| setroomsize(value); | |||
| break; | |||
| case 12: | |||
| setbandwidth(value); | |||
| break; | |||
| } | |||
| } | |||
| unsigned char Reverb::getpar(int npar) const | |||
| { | |||
| switch(npar) { | |||
| case 0: return Pvolume; | |||
| case 1: return Ppanning; | |||
| case 2: return Ptime; | |||
| case 3: return Pidelay; | |||
| case 4: return Pidelayfb; | |||
| // case 5: return Prdelay; | |||
| // case 6: return Perbalance; | |||
| case 7: return Plpf; | |||
| case 8: return Phpf; | |||
| case 9: return Plohidamp; | |||
| case 10: return Ptype; | |||
| case 11: return Proomsize; | |||
| case 12: return Pbandwidth; | |||
| default: return 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,97 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Reverb.h - Reverberation effect | |||
| Copyright (C) 2002-2009 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef REVERB_H | |||
| #define REVERB_H | |||
| #include "Effect.h" | |||
| #define REV_COMBS 8 | |||
| #define REV_APS 4 | |||
| /**Creates Reverberation Effects*/ | |||
| class Reverb:public Effect | |||
| { | |||
| public: | |||
| Reverb(bool insertion_, float *efxoutl_, float *efxoutr_); | |||
| ~Reverb(); | |||
| void out(const Stereo<float *> &smp); | |||
| void cleanup(void); | |||
| void setpreset(unsigned char npreset); | |||
| void changepar(int npar, unsigned char value); | |||
| unsigned char getpar(int npar) const; | |||
| private: | |||
| //Parametrii | |||
| unsigned char Pvolume; | |||
| unsigned char Ptime; //duration | |||
| unsigned char Pidelay; //initial delay | |||
| unsigned char Pidelayfb; //initial feedback | |||
| unsigned char Prdelay; //delay between ER/Reverbs | |||
| unsigned char Perbalance; //EarlyReflections/Reverb Balance | |||
| unsigned char Plpf; | |||
| unsigned char Phpf; | |||
| unsigned char Plohidamp; //Low/HighFrequency Damping | |||
| unsigned char Ptype; //reverb type | |||
| unsigned char Proomsize; //room size | |||
| unsigned char Pbandwidth; //bandwidth | |||
| //parameter control | |||
| void setvolume(unsigned char _Pvolume); | |||
| void settime(unsigned char _Ptime); | |||
| void setlohidamp(unsigned char _Plohidamp); | |||
| void setidelay(unsigned char _Pidelay); | |||
| void setidelayfb(unsigned char _Pidelayfb); | |||
| void sethpf(unsigned char _Phpf); | |||
| void setlpf(unsigned char _Plpf); | |||
| void settype(unsigned char _Ptype); | |||
| void setroomsize(unsigned char _Proomsize); | |||
| void setbandwidth(unsigned char _Pbandwidth); | |||
| void processmono(int ch, float *output, float *inputbuf); | |||
| float erbalance; | |||
| //Parameters | |||
| int lohidamptype; //0=disable, 1=highdamp (lowpass), 2=lowdamp (highpass) | |||
| int idelaylen, rdelaylen; | |||
| int idelayk; | |||
| float lohifb; | |||
| float idelayfb; | |||
| float roomsize; | |||
| float rs; //rs is used to "normalise" the volume according to the roomsize | |||
| int comblen[REV_COMBS * 2]; | |||
| int aplen[REV_APS * 2]; | |||
| class Unison * bandwidth; | |||
| //Internal Variables | |||
| float *comb[REV_COMBS * 2]; | |||
| int combk[REV_COMBS * 2]; | |||
| float combfb[REV_COMBS * 2]; //feedback-ul fiecarui filtru "comb" | |||
| float lpcomb[REV_COMBS * 2]; //pentru Filtrul LowPass | |||
| float *ap[REV_APS * 2]; | |||
| int apk[REV_APS * 2]; | |||
| float *idelay; | |||
| class AnalogFilter * lpf, *hpf; //filters | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,176 @@ | |||
| #!/usr/bin/make -f | |||
| # Makefile for carla-native plugins # | |||
| # ----------------------------------------------- # | |||
| # Created by falkTX | |||
| # | |||
| include ../../Makefile.mk | |||
| WANT_GUI = $(shell pkg-config --exists ntk ntk_images && echo true) | |||
| # -------------------------------------------------------------- | |||
| BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. | |||
| BUILD_CXX_FLAGS += -DASM_F2I_YES -DVERSION=\"2.4.3\" | |||
| # BUILD_CXX_FLAGS += -DIN_DEFAULT=\"\" -DOUT_DEFAULT=\"\" | |||
| BUILD_CXX_FLAGS += -DIN_DEFAULT=\"JACK\" -DOUT_DEFAULT=\"JACK\" -DJACK=1 | |||
| BUILD_CXX_FLAGS += $(shell pkg-config --cflags fftw3 mxml jack) | |||
| LINK_FLAGS += $(shell pkg-config --libs fftw3 mxml jack) | |||
| OBJS = \ | |||
| DSP/AnalogFilter.o \ | |||
| DSP/FFTwrapper.o \ | |||
| DSP/Filter.o \ | |||
| DSP/FormantFilter.o \ | |||
| DSP/SVFilter.o \ | |||
| DSP/Unison.o \ | |||
| Effects/Alienwah.o \ | |||
| Effects/Chorus.o \ | |||
| Effects/Distorsion.o \ | |||
| Effects/DynamicFilter.o \ | |||
| Effects/Echo.o \ | |||
| Effects/Effect.o \ | |||
| Effects/EffectLFO.o \ | |||
| Effects/EffectMgr.o \ | |||
| Effects/EQ.o \ | |||
| Effects/Phaser.o \ | |||
| Effects/Reverb.o \ | |||
| Misc/Bank.o \ | |||
| Misc/Config.o \ | |||
| Misc/Dump.o \ | |||
| Misc/Master.o \ | |||
| Misc/Microtonal.o \ | |||
| Misc/Part.o \ | |||
| Misc/Recorder.o \ | |||
| Misc/Util.o \ | |||
| Misc/WavFile.o \ | |||
| Misc/WaveShapeSmps.o \ | |||
| Misc/XMLwrapper.o \ | |||
| Nio/AudioOut.o \ | |||
| Nio/Engine.o \ | |||
| Nio/EngineMgr.o \ | |||
| Nio/Nio.o \ | |||
| Nio/NulEngine.o \ | |||
| Nio/InMgr.o \ | |||
| Nio/OutMgr.o \ | |||
| Nio/WavEngine.o \ | |||
| Params/ADnoteParameters.o \ | |||
| Params/Controller.o \ | |||
| Params/EnvelopeParams.o \ | |||
| Params/FilterParams.o \ | |||
| Params/LFOParams.o \ | |||
| Params/PADnoteParameters.o \ | |||
| Params/Presets.o \ | |||
| Params/PresetsArray.o \ | |||
| Params/PresetsStore.o \ | |||
| Params/SUBnoteParameters.o \ | |||
| Synth/ADnote.o \ | |||
| Synth/Envelope.o \ | |||
| Synth/LFO.o \ | |||
| Synth/OscilGen.o \ | |||
| Synth/PADnote.o \ | |||
| Synth/Resonance.o \ | |||
| Synth/SUBnote.o \ | |||
| Synth/SynthNote.o | |||
| # Misc/Stereo.o | |||
| # Nio/MidiIn.o | |||
| OBJS += Nio/JackEngine.o | |||
| # ifeq ($(WANT_GUI),true) | |||
| # BUILD_CXX_FLAGS += -DFLTK_GUI=1 | |||
| BUILD_CXX_FLAGS += -DNTK_GUI=1 | |||
| # BUILD_CXX_FLAGS += -DVSTAUDIOOUT=1 # TESTING | |||
| BUILD_CXX_FLAGS += -DPIXMAP_PATH=\"/usr/share/zynaddsubfx/pixmaps/\" | |||
| BUILD_CXX_FLAGS += -DSOURCE_DIR=\"/usr/share/zynaddsubfx/pixmaps/nothing-here\" | |||
| # BUILD_CXX_FLAGS += $(shell fltk-config --use-images --cxxflags) | |||
| # LINK_FLAGS += $(shell fltk-config --use-images --ldflags) | |||
| BUILD_CXX_FLAGS += $(shell pkg-config --cflags ntk ntk_images) | |||
| LINK_FLAGS += $(shell pkg-config --libs ntk ntk_images) | |||
| FILES = \ | |||
| UI/ADnoteUI.cc \ | |||
| UI/BankUI.cc \ | |||
| UI/ConfigUI.cc \ | |||
| UI/EffUI.cc \ | |||
| UI/EnvelopeUI.cc \ | |||
| UI/FilterUI.cc \ | |||
| UI/LFOUI.cc \ | |||
| UI/MasterUI.cc \ | |||
| UI/MicrotonalUI.cc \ | |||
| UI/OscilGenUI.cc \ | |||
| UI/PADnoteUI.cc \ | |||
| UI/PartUI.cc \ | |||
| UI/PresetsUI.cc \ | |||
| UI/ResonanceUI.cc \ | |||
| UI/SUBnoteUI.cc \ | |||
| UI/VirKeyboard.cc | |||
| HEADERS = \ | |||
| UI/ADnoteUI.h \ | |||
| UI/BankUI.h \ | |||
| UI/ConfigUI.h \ | |||
| UI/EffUI.h \ | |||
| UI/EnvelopeUI.h \ | |||
| UI/FilterUI.h \ | |||
| UI/LFOUI.h \ | |||
| UI/MasterUI.h \ | |||
| UI/MicrotonalUI.h \ | |||
| UI/OscilGenUI.h \ | |||
| UI/PADnoteUI.h \ | |||
| UI/PartUI.h \ | |||
| UI/PresetsUI.h \ | |||
| UI/ResonanceUI.h \ | |||
| UI/SUBnoteUI.h \ | |||
| UI/VirKeyboard.h | |||
| OBJS += \ | |||
| UI/ADnoteUI.o \ | |||
| UI/BankUI.o \ | |||
| UI/ConfigUI.o \ | |||
| UI/EffUI.o \ | |||
| UI/EnvelopeUI.o \ | |||
| UI/FilterUI.o \ | |||
| UI/LFOUI.o \ | |||
| UI/MasterUI.o \ | |||
| UI/MicrotonalUI.o \ | |||
| UI/OscilGenUI.o \ | |||
| UI/PADnoteUI.o \ | |||
| UI/PartUI.o \ | |||
| UI/PresetsUI.o \ | |||
| UI/ResonanceUI.o \ | |||
| UI/SUBnoteUI.o \ | |||
| UI/VirKeyboard.o \ | |||
| UI/WidgetPDial.o \ | |||
| UI/NioUI.o | |||
| # endif | |||
| TARGET = ../zynaddsubfx.a | |||
| # -------------------------------------------------------------- | |||
| all: $(TARGET) | |||
| $(TARGET): $(FILES) $(OBJS) | |||
| $(AR) rs $@ $(OBJS) | |||
| test: $(FILES) $(OBJS) main.o | |||
| $(CXX) $(OBJS) main.o $(LINK_FLAGS) -o $@ | |||
| # -------------------------------------------------------------- | |||
| %.cc: %.fl | |||
| # FIXME | |||
| cd UI; ntk-fluid -c ../$<; cd .. | |||
| # cd UI; fluid -c ../$<; cd .. | |||
| .cc.o: | |||
| $(CXX) -c $< $(BUILD_CXX_FLAGS) -o $@ | |||
| .cpp.o: | |||
| $(CXX) -c $< $(BUILD_CXX_FLAGS) -o $@ | |||
| clean: | |||
| rm -f $(TARGET) $(FILES) $(HEADERS) $(OBJS) main.o | |||
| @@ -0,0 +1,469 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Bank.cpp - Instrument Bank | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Copyright (C) 2010-2010 Mark McCurry | |||
| Author: Nasca Octavian Paul | |||
| Mark McCurry | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "Bank.h" | |||
| #include <string.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <dirent.h> | |||
| #include <sys/stat.h> | |||
| #include <algorithm> | |||
| #include <iostream> | |||
| #include <sys/types.h> | |||
| #include <fcntl.h> | |||
| #include <unistd.h> | |||
| #include <errno.h> | |||
| #include "Config.h" | |||
| #include "Util.h" | |||
| #include "Part.h" | |||
| #define INSTRUMENT_EXTENSION ".xiz" | |||
| //if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file | |||
| #define FORCE_BANK_DIR_FILE ".bankdir" | |||
| using namespace std; | |||
| Bank::Bank() | |||
| :defaultinsname(" ") | |||
| { | |||
| clearbank(); | |||
| bankfiletitle = dirname; | |||
| loadbank(config.cfg.currentBankDir); | |||
| } | |||
| Bank::~Bank() | |||
| { | |||
| clearbank(); | |||
| } | |||
| /* | |||
| * Get the name of an instrument from the bank | |||
| */ | |||
| string Bank::getname(unsigned int ninstrument) | |||
| { | |||
| if(emptyslot(ninstrument)) | |||
| return defaultinsname; | |||
| return ins[ninstrument].name; | |||
| } | |||
| /* | |||
| * Get the numbered name of an instrument from the bank | |||
| */ | |||
| string Bank::getnamenumbered(unsigned int ninstrument) | |||
| { | |||
| if(emptyslot(ninstrument)) | |||
| return defaultinsname; | |||
| return stringFrom(ninstrument + 1) + ". " + getname(ninstrument); | |||
| } | |||
| /* | |||
| * Changes the name of an instrument (and the filename) | |||
| */ | |||
| void Bank::setname(unsigned int ninstrument, const string &newname, int newslot) | |||
| { | |||
| if(emptyslot(ninstrument)) | |||
| return; | |||
| string newfilename; | |||
| char tmpfilename[100 + 1]; | |||
| tmpfilename[100] = 0; | |||
| if(newslot >= 0) | |||
| snprintf(tmpfilename, 100, "%4d-%s", newslot + 1, newname.c_str()); | |||
| else | |||
| snprintf(tmpfilename, 100, "%4d-%s", ninstrument + 1, newname.c_str()); | |||
| //add the zeroes at the start of filename | |||
| for(int i = 0; i < 4; ++i) | |||
| if(tmpfilename[i] == ' ') | |||
| tmpfilename[i] = '0'; | |||
| newfilename = dirname + '/' + legalizeFilename(tmpfilename) + ".xiz"; | |||
| rename(ins[ninstrument].filename.c_str(), newfilename.c_str()); | |||
| ins[ninstrument].filename = newfilename; | |||
| ins[ninstrument].name = newname; | |||
| } | |||
| /* | |||
| * Check if there is no instrument on a slot from the bank | |||
| */ | |||
| bool Bank::emptyslot(unsigned int ninstrument) | |||
| { | |||
| if(ninstrument >= BANK_SIZE) | |||
| return true; | |||
| if(ins[ninstrument].filename.empty()) | |||
| return true; | |||
| if(ins[ninstrument].used) | |||
| return false; | |||
| else | |||
| return true; | |||
| } | |||
| /* | |||
| * Removes the instrument from the bank | |||
| */ | |||
| void Bank::clearslot(unsigned int ninstrument) | |||
| { | |||
| if(emptyslot(ninstrument)) | |||
| return; | |||
| remove(ins[ninstrument].filename.c_str()); | |||
| deletefrombank(ninstrument); | |||
| } | |||
| /* | |||
| * Save the instrument to a slot | |||
| */ | |||
| void Bank::savetoslot(unsigned int ninstrument, Part *part) | |||
| { | |||
| clearslot(ninstrument); | |||
| const int maxfilename = 200; | |||
| char tmpfilename[maxfilename + 20]; | |||
| ZERO(tmpfilename, maxfilename + 20); | |||
| snprintf(tmpfilename, | |||
| maxfilename, | |||
| "%4d-%s", | |||
| ninstrument + 1, | |||
| (char *)part->Pname); | |||
| //add the zeroes at the start of filename | |||
| for(int i = 0; i < 4; ++i) | |||
| if(tmpfilename[i] == ' ') | |||
| tmpfilename[i] = '0'; | |||
| string filename = dirname + '/' + legalizeFilename(tmpfilename) + ".xiz"; | |||
| remove(filename.c_str()); | |||
| part->saveXML(filename.c_str()); | |||
| addtobank(ninstrument, legalizeFilename(tmpfilename) + ".xiz", (char *) part->Pname); | |||
| } | |||
| /* | |||
| * Loads the instrument from the bank | |||
| */ | |||
| void Bank::loadfromslot(unsigned int ninstrument, Part *part) | |||
| { | |||
| if(emptyslot(ninstrument)) | |||
| return; | |||
| part->AllNotesOff(); | |||
| part->defaultsinstrument(); | |||
| part->loadXMLinstrument(ins[ninstrument].filename.c_str()); | |||
| } | |||
| /* | |||
| * Makes current a bank directory | |||
| */ | |||
| int Bank::loadbank(string bankdirname) | |||
| { | |||
| DIR *dir = opendir(bankdirname.c_str()); | |||
| clearbank(); | |||
| if(dir == NULL) | |||
| return -1; | |||
| dirname = bankdirname; | |||
| bankfiletitle = dirname; | |||
| struct dirent *fn; | |||
| while((fn = readdir(dir))) { | |||
| const char *filename = fn->d_name; | |||
| //check for extension | |||
| if(strstr(filename, INSTRUMENT_EXTENSION) == NULL) | |||
| continue; | |||
| //verify if the name is like this NNNN-name (where N is a digit) | |||
| int no = 0; | |||
| unsigned int startname = 0; | |||
| for(unsigned int i = 0; i < 4; ++i) { | |||
| if(strlen(filename) <= i) | |||
| break; | |||
| if((filename[i] >= '0') && (filename[i] <= '9')) { | |||
| no = no * 10 + (filename[i] - '0'); | |||
| startname++; | |||
| } | |||
| } | |||
| if((startname + 1) < strlen(filename)) | |||
| startname++; //to take out the "-" | |||
| string name = filename; | |||
| //remove the file extension | |||
| for(int i = name.size() - 1; i >= 2; i--) | |||
| if(name[i] == '.') { | |||
| name = name.substr(0, i); | |||
| break; | |||
| } | |||
| if(no != 0) //the instrument position in the bank is found | |||
| addtobank(no - 1, filename, name.substr(startname)); | |||
| else | |||
| addtobank(-1, filename, name); | |||
| } | |||
| closedir(dir); | |||
| if(!dirname.empty()) | |||
| config.cfg.currentBankDir = dirname; | |||
| return 0; | |||
| } | |||
| /* | |||
| * Makes a new bank, put it on a file and makes it current bank | |||
| */ | |||
| int Bank::newbank(string newbankdirname) | |||
| { | |||
| string bankdir; | |||
| bankdir = config.cfg.bankRootDirList[0]; | |||
| if(((bankdir[bankdir.size() - 1]) != '/') | |||
| && ((bankdir[bankdir.size() - 1]) != '\\')) | |||
| bankdir += "/"; | |||
| bankdir += newbankdirname; | |||
| if(mkdir(bankdir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) | |||
| return -1; | |||
| const string tmpfilename = bankdir + '/' + FORCE_BANK_DIR_FILE; | |||
| FILE *tmpfile = fopen(tmpfilename.c_str(), "w+"); | |||
| fclose(tmpfile); | |||
| return loadbank(bankdir); | |||
| } | |||
| /* | |||
| * Check if the bank is locked (i.e. the file opened was readonly) | |||
| */ | |||
| int Bank::locked() | |||
| { | |||
| return dirname.empty(); | |||
| } | |||
| /* | |||
| * Swaps a slot with another | |||
| */ | |||
| void Bank::swapslot(unsigned int n1, unsigned int n2) | |||
| { | |||
| if((n1 == n2) || (locked())) | |||
| return; | |||
| if(emptyslot(n1) && (emptyslot(n2))) | |||
| return; | |||
| if(emptyslot(n1)) //change n1 to n2 in order to make | |||
| swap(n1, n2); | |||
| if(emptyslot(n2)) { //this is just a movement from slot1 to slot2 | |||
| setname(n1, getname(n1), n2); | |||
| ins[n2] = ins[n1]; | |||
| ins[n1] = ins_t(); | |||
| } | |||
| else { //if both slots are used | |||
| if(ins[n1].name == ins[n2].name) //change the name of the second instrument if the name are equal | |||
| ins[n2].name += "2"; | |||
| setname(n1, getname(n1), n2); | |||
| setname(n2, getname(n2), n1); | |||
| swap(ins[n2], ins[n1]); | |||
| } | |||
| } | |||
| bool Bank::bankstruct::operator<(const bankstruct &b) const | |||
| { | |||
| return name < b.name; | |||
| } | |||
| /* | |||
| * Re-scan for directories containing instrument banks | |||
| */ | |||
| void Bank::rescanforbanks() | |||
| { | |||
| //remove old banks | |||
| banks.clear(); | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| if(!config.cfg.bankRootDirList[i].empty()) | |||
| scanrootdir(config.cfg.bankRootDirList[i]); | |||
| //sort the banks | |||
| sort(banks.begin(), banks.end()); | |||
| //remove duplicate bank names | |||
| int dupl = 0; | |||
| for(int j = 0; j < (int) banks.size() - 1; ++j) | |||
| for(int i = j + 1; i < (int) banks.size(); ++i) { | |||
| if(banks[i].name == banks[j].name) { | |||
| //add a [1] to the first bankname and [n] to others | |||
| banks[i].name = banks[i].name + '[' | |||
| + stringFrom(dupl + 2) + ']'; | |||
| if(dupl == 0) | |||
| banks[j].name += "[1]"; | |||
| dupl++; | |||
| } | |||
| else | |||
| dupl = 0; | |||
| } | |||
| } | |||
| // private stuff | |||
| void Bank::scanrootdir(string rootdir) | |||
| { | |||
| DIR *dir = opendir(rootdir.c_str()); | |||
| if(dir == NULL) | |||
| return; | |||
| bankstruct bank; | |||
| const char *separator = "/"; | |||
| if(rootdir.size()) { | |||
| char tmp = rootdir[rootdir.size() - 1]; | |||
| if((tmp == '/') || (tmp == '\\')) | |||
| separator = ""; | |||
| } | |||
| struct dirent *fn; | |||
| while((fn = readdir(dir))) { | |||
| const char *dirname = fn->d_name; | |||
| if(dirname[0] == '.') | |||
| continue; | |||
| bank.dir = rootdir + separator + dirname + '/'; | |||
| bank.name = dirname; | |||
| //find out if the directory contains at least 1 instrument | |||
| bool isbank = false; | |||
| DIR *d = opendir(bank.dir.c_str()); | |||
| if(d == NULL) | |||
| continue; | |||
| struct dirent *fname; | |||
| while((fname = readdir(d))) { | |||
| if((strstr(fname->d_name, INSTRUMENT_EXTENSION) != NULL) | |||
| || (strstr(fname->d_name, FORCE_BANK_DIR_FILE) != NULL)) { | |||
| isbank = true; | |||
| break; //could put a #instrument counter here instead | |||
| } | |||
| } | |||
| if(isbank) | |||
| banks.push_back(bank); | |||
| closedir(d); | |||
| } | |||
| closedir(dir); | |||
| } | |||
| void Bank::clearbank() | |||
| { | |||
| for(int i = 0; i < BANK_SIZE; ++i) | |||
| ins[i] = ins_t(); | |||
| bankfiletitle.clear(); | |||
| dirname.clear(); | |||
| } | |||
| int Bank::addtobank(int pos, string filename, string name) | |||
| { | |||
| if((pos >= 0) && (pos < BANK_SIZE)) { | |||
| if(ins[pos].used) | |||
| pos = -1; //force it to find a new free position | |||
| } | |||
| else | |||
| if(pos >= BANK_SIZE) | |||
| pos = -1; | |||
| if(pos < 0) //find a free position | |||
| for(int i = BANK_SIZE - 1; i >= 0; i--) | |||
| if(!ins[i].used) { | |||
| pos = i; | |||
| break; | |||
| } | |||
| if(pos < 0) | |||
| return -1; //the bank is full | |||
| deletefrombank(pos); | |||
| ins[pos].used = true; | |||
| ins[pos].name = name; | |||
| ins[pos].filename = dirname + '/' + filename; | |||
| //see if PADsynth is used | |||
| if(config.cfg.CheckPADsynth) { | |||
| XMLwrapper xml; | |||
| xml.loadXMLfile(ins[pos].filename); | |||
| ins[pos].info.PADsynth_used = xml.hasPadSynth(); | |||
| } | |||
| else | |||
| ins[pos].info.PADsynth_used = false; | |||
| return 0; | |||
| } | |||
| bool Bank::isPADsynth_used(unsigned int ninstrument) | |||
| { | |||
| if(config.cfg.CheckPADsynth == 0) | |||
| return 0; | |||
| else | |||
| return ins[ninstrument].info.PADsynth_used; | |||
| } | |||
| void Bank::deletefrombank(int pos) | |||
| { | |||
| if((pos < 0) || (pos >= (int) banks.size())) | |||
| return; | |||
| ins[pos] = ins_t(); | |||
| } | |||
| Bank::ins_t::ins_t() | |||
| :used(false), name(""), filename("") | |||
| { | |||
| info.PADsynth_used = false; | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Bank.h - Instrument Bank | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef BANK_H | |||
| #define BANK_H | |||
| #include <string> | |||
| #include <vector> | |||
| //entries in a bank | |||
| #define BANK_SIZE 160 | |||
| /**The instrument Bank*/ | |||
| class Bank | |||
| { | |||
| public: | |||
| /**Constructor*/ | |||
| Bank(); | |||
| ~Bank(); | |||
| std::string getname(unsigned int ninstrument); | |||
| std::string getnamenumbered(unsigned int ninstrument); | |||
| void setname(unsigned int ninstrument, | |||
| const std::string &newname, | |||
| int newslot); //if newslot==-1 then this is ignored, else it will be put on that slot | |||
| bool isPADsynth_used(unsigned int ninstrument); | |||
| /**returns true when slot is empty*/ | |||
| bool emptyslot(unsigned int ninstrument); | |||
| /**Empties out the selected slot*/ | |||
| void clearslot(unsigned int ninstrument); | |||
| /**Saves the given Part to slot*/ | |||
| void savetoslot(unsigned int ninstrument, class Part * part); | |||
| /**Loads the given slot into a Part*/ | |||
| void loadfromslot(unsigned int ninstrument, class Part * part); | |||
| /**Swaps Slots*/ | |||
| void swapslot(unsigned int n1, unsigned int n2); | |||
| int loadbank(std::string bankdirname); | |||
| int newbank(std::string newbankdirname); | |||
| std::string bankfiletitle; //this is shown on the UI of the bank (the title of the window) | |||
| int locked(); | |||
| void rescanforbanks(); | |||
| struct bankstruct { | |||
| bool operator<(const bankstruct &b) const; | |||
| std::string dir; | |||
| std::string name; | |||
| }; | |||
| std::vector<bankstruct> banks; | |||
| private: | |||
| //it adds a filename to the bank | |||
| //if pos is -1 it try to find a position | |||
| //returns -1 if the bank is full, or 0 if the instrument was added | |||
| int addtobank(int pos, std::string filename, std::string name); | |||
| void deletefrombank(int pos); | |||
| void clearbank(); | |||
| std::string defaultinsname; | |||
| struct ins_t { | |||
| ins_t(); | |||
| bool used; | |||
| std::string name; | |||
| std::string filename; | |||
| struct { | |||
| bool PADsynth_used; | |||
| } info; | |||
| } ins[BANK_SIZE]; | |||
| std::string dirname; | |||
| void scanrootdir(std::string rootdir); //scans a root dir for banks | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,28 @@ | |||
| include_directories(${MXML_INCLUDE_DIR}) | |||
| set(zynaddsubfx_misc_SRCS | |||
| Misc/Bank.cpp | |||
| Misc/Config.cpp | |||
| Misc/Dump.cpp | |||
| Misc/Master.cpp | |||
| Misc/Microtonal.cpp | |||
| Misc/Part.cpp | |||
| Misc/Util.cpp | |||
| Misc/XMLwrapper.cpp | |||
| Misc/Recorder.cpp | |||
| Misc/WavFile.cpp | |||
| Misc/WaveShapeSmps.cpp | |||
| ) | |||
| if(LashEnable) | |||
| set(zynaddsubfx_misc_SRCS | |||
| ${zynaddsubfx_misc_SRCS} | |||
| Misc/LASHClient.cpp | |||
| PARENT_SCOPE) | |||
| else() | |||
| set(zynaddsubfx_misc_SRCS | |||
| ${zynaddsubfx_misc_SRCS} | |||
| PARENT_SCOPE) | |||
| endif() | |||
| @@ -0,0 +1,300 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Config.cpp - Configuration file functions | |||
| Copyright (C) 2003-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <stdio.h> | |||
| #include <math.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "Config.h" | |||
| #include "XMLwrapper.h" | |||
| using namespace std; | |||
| Config::Config() | |||
| {} | |||
| void Config::init() | |||
| { | |||
| maxstringsize = MAX_STRING_SIZE; //for ui | |||
| //defaults | |||
| cfg.SampleRate = 44100; | |||
| cfg.SoundBufferSize = 256; | |||
| cfg.OscilSize = 1024; | |||
| cfg.SwapStereo = 0; | |||
| cfg.LinuxOSSWaveOutDev = new char[MAX_STRING_SIZE]; | |||
| snprintf(cfg.LinuxOSSWaveOutDev, MAX_STRING_SIZE, "/dev/dsp"); | |||
| cfg.LinuxOSSSeqInDev = new char[MAX_STRING_SIZE]; | |||
| snprintf(cfg.LinuxOSSSeqInDev, MAX_STRING_SIZE, "/dev/sequencer"); | |||
| cfg.DumpFile = "zynaddsubfx_dump.txt"; | |||
| cfg.WindowsWaveOutId = 0; | |||
| cfg.WindowsMidiInId = 0; | |||
| cfg.BankUIAutoClose = 0; | |||
| cfg.DumpNotesToFile = 0; | |||
| cfg.DumpAppend = 1; | |||
| cfg.GzipCompression = 3; | |||
| cfg.Interpolation = 0; | |||
| cfg.CheckPADsynth = 1; | |||
| cfg.UserInterfaceMode = 0; | |||
| cfg.VirKeybLayout = 1; | |||
| winwavemax = 1; | |||
| winmidimax = 1; | |||
| //try to find out how many input midi devices are there | |||
| winmididevices = new winmidionedevice[winmidimax]; | |||
| for(int i = 0; i < winmidimax; ++i) { | |||
| winmididevices[i].name = new char[MAX_STRING_SIZE]; | |||
| for(int j = 0; j < MAX_STRING_SIZE; ++j) | |||
| winmididevices[i].name[j] = '\0'; | |||
| } | |||
| //get the midi input devices name | |||
| cfg.currentBankDir = "./testbnk"; | |||
| char filename[MAX_STRING_SIZE]; | |||
| getConfigFileName(filename, MAX_STRING_SIZE); | |||
| readConfig(filename); | |||
| if(cfg.bankRootDirList[0].empty()) { | |||
| //banks | |||
| cfg.bankRootDirList[0] = "~/banks"; | |||
| cfg.bankRootDirList[1] = "./"; | |||
| cfg.bankRootDirList[2] = "/usr/share/zynaddsubfx/banks"; | |||
| cfg.bankRootDirList[3] = "/usr/local/share/zynaddsubfx/banks"; | |||
| cfg.bankRootDirList[4] = "../banks"; | |||
| cfg.bankRootDirList[5] = "banks"; | |||
| } | |||
| if(cfg.presetsDirList[0].empty()) { | |||
| //presets | |||
| cfg.presetsDirList[0] = "./"; | |||
| cfg.presetsDirList[1] = "../presets"; | |||
| cfg.presetsDirList[2] = "presets"; | |||
| cfg.presetsDirList[3] = "/usr/share/zynaddsubfx/presets"; | |||
| cfg.presetsDirList[4] = "/usr/local/share/zynaddsubfx/presets"; | |||
| } | |||
| cfg.LinuxALSAaudioDev = "default"; | |||
| cfg.nameTag = ""; | |||
| } | |||
| Config::~Config() | |||
| { | |||
| delete [] cfg.LinuxOSSWaveOutDev; | |||
| delete [] cfg.LinuxOSSSeqInDev; | |||
| for(int i = 0; i < winmidimax; ++i) | |||
| delete [] winmididevices[i].name; | |||
| delete [] winmididevices; | |||
| } | |||
| void Config::save() | |||
| { | |||
| char filename[MAX_STRING_SIZE]; | |||
| getConfigFileName(filename, MAX_STRING_SIZE); | |||
| saveConfig(filename); | |||
| } | |||
| void Config::clearbankrootdirlist() | |||
| { | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| cfg.bankRootDirList[i].clear(); | |||
| } | |||
| void Config::clearpresetsdirlist() | |||
| { | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| cfg.presetsDirList[i].clear(); | |||
| } | |||
| void Config::readConfig(const char *filename) | |||
| { | |||
| XMLwrapper xmlcfg; | |||
| if(xmlcfg.loadXMLfile(filename) < 0) | |||
| return; | |||
| if(xmlcfg.enterbranch("CONFIGURATION")) { | |||
| cfg.SampleRate = xmlcfg.getpar("sample_rate", | |||
| cfg.SampleRate, | |||
| 4000, | |||
| 1024000); | |||
| cfg.SoundBufferSize = xmlcfg.getpar("sound_buffer_size", | |||
| cfg.SoundBufferSize, | |||
| 16, | |||
| 8192); | |||
| cfg.OscilSize = xmlcfg.getpar("oscil_size", | |||
| cfg.OscilSize, | |||
| MAX_AD_HARMONICS * 2, | |||
| 131072); | |||
| cfg.SwapStereo = xmlcfg.getpar("swap_stereo", | |||
| cfg.SwapStereo, | |||
| 0, | |||
| 1); | |||
| cfg.BankUIAutoClose = xmlcfg.getpar("bank_window_auto_close", | |||
| cfg.BankUIAutoClose, | |||
| 0, | |||
| 1); | |||
| cfg.DumpNotesToFile = xmlcfg.getpar("dump_notes_to_file", | |||
| cfg.DumpNotesToFile, | |||
| 0, | |||
| 1); | |||
| cfg.DumpAppend = xmlcfg.getpar("dump_append", | |||
| cfg.DumpAppend, | |||
| 0, | |||
| 1); | |||
| cfg.DumpFile = xmlcfg.getparstr("dump_file", ""); | |||
| cfg.GzipCompression = xmlcfg.getpar("gzip_compression", | |||
| cfg.GzipCompression, | |||
| 0, | |||
| 9); | |||
| cfg.currentBankDir = xmlcfg.getparstr("bank_current", ""); | |||
| cfg.Interpolation = xmlcfg.getpar("interpolation", | |||
| cfg.Interpolation, | |||
| 0, | |||
| 1); | |||
| cfg.CheckPADsynth = xmlcfg.getpar("check_pad_synth", | |||
| cfg.CheckPADsynth, | |||
| 0, | |||
| 1); | |||
| cfg.UserInterfaceMode = xmlcfg.getpar("user_interface_mode", | |||
| cfg.UserInterfaceMode, | |||
| 0, | |||
| 2); | |||
| cfg.VirKeybLayout = xmlcfg.getpar("virtual_keyboard_layout", | |||
| cfg.VirKeybLayout, | |||
| 0, | |||
| 10); | |||
| //get bankroot dirs | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| if(xmlcfg.enterbranch("BANKROOT", i)) { | |||
| cfg.bankRootDirList[i] = xmlcfg.getparstr("bank_root", ""); | |||
| xmlcfg.exitbranch(); | |||
| } | |||
| //get preset root dirs | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| if(xmlcfg.enterbranch("PRESETSROOT", i)) { | |||
| cfg.presetsDirList[i] = xmlcfg.getparstr("presets_root", ""); | |||
| xmlcfg.exitbranch(); | |||
| } | |||
| //linux stuff | |||
| xmlcfg.getparstr("linux_oss_wave_out_dev", | |||
| cfg.LinuxOSSWaveOutDev, | |||
| MAX_STRING_SIZE); | |||
| xmlcfg.getparstr("linux_oss_seq_in_dev", | |||
| cfg.LinuxOSSSeqInDev, | |||
| MAX_STRING_SIZE); | |||
| //windows stuff | |||
| cfg.WindowsWaveOutId = xmlcfg.getpar("windows_wave_out_id", | |||
| cfg.WindowsWaveOutId, | |||
| 0, | |||
| winwavemax); | |||
| cfg.WindowsMidiInId = xmlcfg.getpar("windows_midi_in_id", | |||
| cfg.WindowsMidiInId, | |||
| 0, | |||
| winmidimax); | |||
| xmlcfg.exitbranch(); | |||
| } | |||
| cfg.OscilSize = (int) powf(2, ceil(logf(cfg.OscilSize - 1.0f) / logf(2.0f))); | |||
| } | |||
| void Config::saveConfig(const char *filename) | |||
| { | |||
| XMLwrapper *xmlcfg = new XMLwrapper(); | |||
| xmlcfg->beginbranch("CONFIGURATION"); | |||
| xmlcfg->addpar("sample_rate", cfg.SampleRate); | |||
| xmlcfg->addpar("sound_buffer_size", cfg.SoundBufferSize); | |||
| xmlcfg->addpar("oscil_size", cfg.OscilSize); | |||
| xmlcfg->addpar("swap_stereo", cfg.SwapStereo); | |||
| xmlcfg->addpar("bank_window_auto_close", cfg.BankUIAutoClose); | |||
| xmlcfg->addpar("dump_notes_to_file", cfg.DumpNotesToFile); | |||
| xmlcfg->addpar("dump_append", cfg.DumpAppend); | |||
| xmlcfg->addparstr("dump_file", cfg.DumpFile); | |||
| xmlcfg->addpar("gzip_compression", cfg.GzipCompression); | |||
| xmlcfg->addpar("check_pad_synth", cfg.CheckPADsynth); | |||
| xmlcfg->addparstr("bank_current", cfg.currentBankDir); | |||
| xmlcfg->addpar("user_interface_mode", cfg.UserInterfaceMode); | |||
| xmlcfg->addpar("virtual_keyboard_layout", cfg.VirKeybLayout); | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| if(!cfg.bankRootDirList[i].empty()) { | |||
| xmlcfg->beginbranch("BANKROOT", i); | |||
| xmlcfg->addparstr("bank_root", cfg.bankRootDirList[i]); | |||
| xmlcfg->endbranch(); | |||
| } | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| if(!cfg.presetsDirList[i].empty()) { | |||
| xmlcfg->beginbranch("PRESETSROOT", i); | |||
| xmlcfg->addparstr("presets_root", cfg.presetsDirList[i]); | |||
| xmlcfg->endbranch(); | |||
| } | |||
| xmlcfg->addpar("interpolation", cfg.Interpolation); | |||
| //linux stuff | |||
| xmlcfg->addparstr("linux_oss_wave_out_dev", cfg.LinuxOSSWaveOutDev); | |||
| xmlcfg->addparstr("linux_oss_seq_in_dev", cfg.LinuxOSSSeqInDev); | |||
| //windows stuff | |||
| xmlcfg->addpar("windows_wave_out_id", cfg.WindowsWaveOutId); | |||
| xmlcfg->addpar("windows_midi_in_id", cfg.WindowsMidiInId); | |||
| xmlcfg->endbranch(); | |||
| int tmp = cfg.GzipCompression; | |||
| cfg.GzipCompression = 0; | |||
| xmlcfg->saveXMLfile(filename); | |||
| cfg.GzipCompression = tmp; | |||
| delete (xmlcfg); | |||
| } | |||
| void Config::getConfigFileName(char *name, int namesize) | |||
| { | |||
| name[0] = 0; | |||
| snprintf(name, namesize, "%s%s", getenv("HOME"), "/.zynaddsubfxXML.cfg"); | |||
| } | |||
| @@ -0,0 +1,73 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Config.h - Configuration file functions | |||
| Copyright (C) 2003-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef CONFIG_H | |||
| #define CONFIG_H | |||
| #include "../globals.h" | |||
| #include <string> | |||
| #define MAX_STRING_SIZE 4000 | |||
| #define MAX_BANK_ROOT_DIRS 100 | |||
| /**Configuration file functions*/ | |||
| class Config | |||
| { | |||
| public: | |||
| /** Constructor*/ | |||
| Config(); | |||
| /** Destructor*/ | |||
| ~Config(); | |||
| struct { | |||
| char *LinuxOSSWaveOutDev, *LinuxOSSSeqInDev; | |||
| int SampleRate, SoundBufferSize, OscilSize, SwapStereo; | |||
| int WindowsWaveOutId, WindowsMidiInId; | |||
| int BankUIAutoClose; | |||
| int DumpNotesToFile, DumpAppend; | |||
| int GzipCompression; | |||
| int Interpolation; | |||
| std::string DumpFile; | |||
| std::string bankRootDirList[MAX_BANK_ROOT_DIRS], currentBankDir; | |||
| std::string presetsDirList[MAX_BANK_ROOT_DIRS]; | |||
| int CheckPADsynth; | |||
| int UserInterfaceMode; | |||
| int VirKeybLayout; | |||
| std::string LinuxALSAaudioDev; | |||
| std::string nameTag; | |||
| } cfg; | |||
| int winwavemax, winmidimax; //number of wave/midi devices on Windows | |||
| int maxstringsize; | |||
| struct winmidionedevice { | |||
| char *name; | |||
| }; | |||
| winmidionedevice *winmididevices; | |||
| void clearbankrootdirlist(); | |||
| void clearpresetsdirlist(); | |||
| void init(); | |||
| void save(); | |||
| private: | |||
| void readConfig(const char *filename); | |||
| void saveConfig(const char *filename); | |||
| void getConfigFileName(char *name, int namesize); | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,99 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Control.h - Defines a variable that can be controled from a frontend | |||
| Copyright (C) 2009 Harald Hvaal | |||
| Author: Harald Hvaal | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef _CONTROL_H_ | |||
| #define _CONTROL_H_ | |||
| #include <string> | |||
| class Control | |||
| { | |||
| public: | |||
| /** | |||
| * The parent is the logical owner of this control. Parent should only | |||
| * be null for the root node. | |||
| * The id is a string uniquely identifying this control within the | |||
| * context of the parent control. No spaces or dots are allowed in this | |||
| * id. | |||
| * Children id's are denoted by <parent-id>.<children-id>, so that one | |||
| * can refer to any control in the hierarchy by separating them with | |||
| * dots. Example: Main.AddSynth.FrequencyLFO.Amplitude | |||
| */ | |||
| Control(Control *parent, string id); | |||
| /** | |||
| * Will recursively get the XML representation for all the subcontrols. | |||
| * Used for saving to file and copy-pasting settings | |||
| */ | |||
| string getXMLRepresentation(); | |||
| /** | |||
| * Set the value of this (and possibly subcomponents as well) based on | |||
| * a xml description. | |||
| */ | |||
| void restoreFromXML(string xml); | |||
| /** | |||
| * Register a controluser. This will cause this user to be notified | |||
| * whenever the contents of the control changes. | |||
| */ | |||
| void registerControlUser(ControlUser *user); | |||
| /** | |||
| * This should return a string representation of the controls internal | |||
| * value | |||
| */ | |||
| virtual string getStringRepresentation() = 0; | |||
| }; | |||
| class FloatControl:public Control | |||
| { | |||
| public: | |||
| /** | |||
| * Set the value of this control. If the ControlUser variable is set, | |||
| * then this user will not be updated with the new value. This is to | |||
| * avoid setting a value being set back to the source that set it | |||
| * (which would be redundant, or possibly causing infinite setValue | |||
| * loops). | |||
| * NOTE: this function is thread-safe (using a mutex internally) | |||
| */ | |||
| void setValue(float value, ControlUser *user = NULL); | |||
| /** | |||
| * Reimplemented from Control | |||
| */ | |||
| virtual string getStringRepresentation(); | |||
| float value(); | |||
| }; | |||
| class ControlUser | |||
| { | |||
| public: | |||
| /** | |||
| * Pure virtual method, to notify the controluser that the value has | |||
| * been changed internally, and needs to be read again. | |||
| */ | |||
| virtual void controlUpdated(Control *control) = 0; | |||
| }; | |||
| #endif /* _CONTROL_H_ */ | |||
| @@ -0,0 +1,121 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Dump.cpp - It dumps the notes to a text file | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <stdlib.h> | |||
| #include <time.h> | |||
| #include "Util.h" | |||
| #include "Dump.h" | |||
| Dump dump; | |||
| Dump::Dump() | |||
| { | |||
| file = NULL; | |||
| tick = 0; | |||
| k = 0; | |||
| keyspressed = 0; | |||
| } | |||
| Dump::~Dump() | |||
| { | |||
| if(file != NULL) { | |||
| int duration = tick * synth->buffersize_f / synth->samplerate_f; | |||
| fprintf( | |||
| file, | |||
| "\n# statistics: duration = %d seconds; keyspressed = %d\n\n\n\n", | |||
| duration, | |||
| keyspressed); | |||
| fclose(file); | |||
| } | |||
| } | |||
| void Dump::startnow() | |||
| { | |||
| if(file != NULL) | |||
| return; //the file is already open | |||
| if(config.cfg.DumpNotesToFile != 0) { | |||
| if(config.cfg.DumpAppend != 0) | |||
| file = fopen(config.cfg.DumpFile.c_str(), "a"); | |||
| else | |||
| file = fopen(config.cfg.DumpFile.c_str(), "w"); | |||
| if(file == NULL) | |||
| return; | |||
| if(config.cfg.DumpAppend != 0) | |||
| fprintf(file, "%s", "#************************************\n"); | |||
| time_t tm = time(NULL); | |||
| fprintf(file, "#date/time = %s\n", ctime(&tm)); | |||
| fprintf(file, "#1 tick = %g milliseconds\n", | |||
| synth->buffersize_f * 1000.0f / synth->samplerate_f); | |||
| fprintf(file, "SAMPLERATE = %d\n", synth->samplerate); | |||
| fprintf(file, "TICKSIZE = %d #samples\n", synth->buffersize); | |||
| fprintf(file, "\n\nSTART\n"); | |||
| } | |||
| } | |||
| void Dump::inctick() | |||
| { | |||
| tick++; | |||
| } | |||
| void Dump::dumpnote(char chan, char note, char vel) | |||
| { | |||
| if(file == NULL) | |||
| return; | |||
| if(note == 0) | |||
| return; | |||
| if(vel == 0) | |||
| fprintf(file, "n %d -> %d %d \n", tick, chan, note); //note off | |||
| else | |||
| fprintf(file, "N %d -> %d %d %d \n", tick, chan, note, vel); //note on | |||
| if(vel != 0) | |||
| keyspressed++; | |||
| #ifndef JACKAUDIOOUT | |||
| if(k++ > 25) { | |||
| fflush(file); | |||
| k = 0; | |||
| } | |||
| #endif | |||
| } | |||
| void Dump::dumpcontroller(char chan, unsigned int type, int par) | |||
| { | |||
| if(file == NULL) | |||
| return; | |||
| switch(type) { | |||
| case C_pitchwheel: | |||
| fprintf(file, "P %d -> %d %d\n", tick, chan, par); | |||
| break; | |||
| default: | |||
| fprintf(file, "C %d -> %d %d %d\n", tick, chan, type, par); | |||
| break; | |||
| } | |||
| #ifndef JACKAUDIOOUT | |||
| if(k++ > 25) { | |||
| fflush(file); | |||
| k = 0; | |||
| } | |||
| #endif | |||
| } | |||
| @@ -0,0 +1,63 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Dump.h - It dumps the notes to a text file | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef DUMP_H | |||
| #define DUMP_H | |||
| #include <stdio.h> | |||
| /**Object used to dump the notes into a text file | |||
| * \todo see if this object should have knowledge about the file | |||
| * that it will write to | |||
| * \todo upgrade from stdio to iostream*/ | |||
| class Dump | |||
| { | |||
| public: | |||
| /**Constructor*/ | |||
| Dump(); | |||
| /**Destructor | |||
| * Closes the dumpfile*/ | |||
| ~Dump(); | |||
| /**Open dumpfile and prepare it for dumps | |||
| * \todo see if this fits better in the constructor*/ | |||
| void startnow(); | |||
| /**Tick the timestamp*/ | |||
| void inctick(); | |||
| /**Dump Note to dumpfile | |||
| * @param chan The channel of the note | |||
| * @param note The note | |||
| * @param vel The velocity of the note*/ | |||
| void dumpnote(char chan, char note, char vel); | |||
| /** Dump the Controller | |||
| * @param chan The channel of the Controller | |||
| * @param type The type | |||
| * @param par The value of the controller | |||
| * \todo figure out what type is exactly meaning*/ | |||
| void dumpcontroller(char chan, unsigned int type, int par); | |||
| private: | |||
| FILE *file; | |||
| int tick; | |||
| int k; //This appears to be a constant used to flush the file | |||
| //periodically when JACK is used | |||
| int keyspressed; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,103 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| LASHClient.cpp - LASH support | |||
| Copyright (C) 2006-2009 Lars Luthman | |||
| Author: Lars Luthman | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <unistd.h> | |||
| #include <iostream> | |||
| #include <string> | |||
| #include "LASHClient.h" | |||
| LASHClient::LASHClient(int *argc, char ***argv) | |||
| { | |||
| client = lash_init(lash_extract_args(argc, argv), "ZynAddSubFX", | |||
| LASH_Config_File, LASH_PROTOCOL(2, 0)); | |||
| } | |||
| void LASHClient::setalsaid(int id) | |||
| { | |||
| if(lash_enabled(client)) | |||
| if(id != -1) | |||
| lash_alsa_client_id(client, id); | |||
| } | |||
| void LASHClient::setjackname(const char *name) | |||
| { | |||
| if(lash_enabled(client)) | |||
| if(name != NULL) { | |||
| lash_jack_client_name(client, name); | |||
| lash_event_t *event = lash_event_new_with_type(LASH_Client_Name); | |||
| lash_event_set_string(event, name); | |||
| lash_send_event(client, event); | |||
| } | |||
| } | |||
| LASHClient::Event LASHClient::checkevents(std::string &filename) | |||
| { | |||
| if(!lash_enabled(client)) | |||
| return NoEvent; | |||
| Event received = NoEvent; | |||
| lash_event_t *event; | |||
| while((event = lash_get_event(client))) { | |||
| // save | |||
| if(lash_event_get_type(event) == LASH_Save_File) { | |||
| std::cerr << "LASH event: LASH_Save_File" << std::endl; | |||
| filename = std::string(lash_event_get_string(event)) | |||
| + "/master.xmz"; | |||
| received = Save; | |||
| break; | |||
| } | |||
| // restore | |||
| else | |||
| if(lash_event_get_type(event) == LASH_Restore_File) { | |||
| std::cerr << "LASH event: LASH_Restore_File" << std::endl; | |||
| filename = std::string(lash_event_get_string(event)) | |||
| + "/master.xmz"; | |||
| received = Restore; | |||
| break; | |||
| } | |||
| // quit | |||
| else | |||
| if(lash_event_get_type(event) == LASH_Quit) { | |||
| std::cerr << "LASH event: LASH_Quit" << std::endl; | |||
| received = Quit; | |||
| break; | |||
| } | |||
| lash_event_destroy(event); | |||
| } | |||
| return received; | |||
| } | |||
| void LASHClient::confirmevent(Event event) | |||
| { | |||
| if(event == Save) | |||
| lash_send_event(client, lash_event_new_with_type(LASH_Save_File)); | |||
| else | |||
| if(event == Restore) | |||
| lash_send_event(client, lash_event_new_with_type(LASH_Restore_File)); | |||
| } | |||
| @@ -0,0 +1,63 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| LASHClient.h - LASH support | |||
| Copyright (C) 2006-2009 Lars Luthman | |||
| Author: Lars Luthman | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef LASHClient_h | |||
| #define LASHClient_h | |||
| #include <string> | |||
| #include <pthread.h> | |||
| #include <lash/lash.h> | |||
| /** This class wraps up some functions for initialising and polling | |||
| * the LASH daemon.*/ | |||
| class LASHClient | |||
| { | |||
| public: | |||
| /**Enum to represent the LASH events that are currently handled*/ | |||
| enum Event { | |||
| Save, | |||
| Restore, | |||
| Quit, | |||
| NoEvent | |||
| }; | |||
| /** Constructor | |||
| * @param argc number of arguments | |||
| * @param argv the text arguments*/ | |||
| LASHClient(int *argc, char ***argv); | |||
| /**set the ALSA id | |||
| * @param id new ALSA id*/ | |||
| void setalsaid(int id); | |||
| /**Set the JACK name | |||
| * @param name the new name*/ | |||
| void setjackname(const char *name); | |||
| Event checkevents(std::string &filename); | |||
| void confirmevent(Event event); | |||
| private: | |||
| lash_client_t *client; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,797 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Master.cpp - It sends Midi Messages to Parts, receives samples from parts, | |||
| process them with system/insertion effects and mix them | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "Master.h" | |||
| #include "Part.h" | |||
| #include "../Params/LFOParams.h" | |||
| #include "../Effects/EffectMgr.h" | |||
| #include "../DSP/FFTwrapper.h" | |||
| #include <stdio.h> | |||
| #include <sys/stat.h> | |||
| #include <sys/types.h> | |||
| #include <iostream> | |||
| #include <algorithm> | |||
| #include <cmath> | |||
| #include <unistd.h> | |||
| using namespace std; | |||
| vuData::vuData(void) | |||
| :outpeakl(0.0f), outpeakr(0.0f), maxoutpeakl(0.0f), maxoutpeakr(0.0f), | |||
| rmspeakl(0.0f), rmspeakr(0.0f), clipped(0) | |||
| {} | |||
| Master::Master() | |||
| { | |||
| swaplr = 0; | |||
| pthread_mutex_init(&mutex, NULL); | |||
| pthread_mutex_init(&vumutex, NULL); | |||
| fft = new FFTwrapper(synth->oscilsize); | |||
| shutup = 0; | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| vuoutpeakpart[npart] = 1e-9; | |||
| fakepeakpart[npart] = 0; | |||
| } | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| part[npart] = new Part(µtonal, fft, &mutex); | |||
| //Insertion Effects init | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| insefx[nefx] = new EffectMgr(1, &mutex); | |||
| //System Effects init | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) | |||
| sysefx[nefx] = new EffectMgr(0, &mutex); | |||
| defaults(); | |||
| } | |||
| void Master::defaults() | |||
| { | |||
| volume = 1.0f; | |||
| setPvolume(80); | |||
| setPkeyshift(64); | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| part[npart]->defaults(); | |||
| part[npart]->Prcvchn = npart % NUM_MIDI_CHANNELS; | |||
| } | |||
| partonoff(0, 1); //enable the first part | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) { | |||
| insefx[nefx]->defaults(); | |||
| Pinsparts[nefx] = -1; | |||
| } | |||
| //System Effects init | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) { | |||
| sysefx[nefx]->defaults(); | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| setPsysefxvol(npart, nefx, 0); | |||
| for(int nefxto = 0; nefxto < NUM_SYS_EFX; ++nefxto) | |||
| setPsysefxsend(nefx, nefxto, 0); | |||
| } | |||
| microtonal.defaults(); | |||
| ShutUp(); | |||
| } | |||
| bool Master::mutexLock(lockset request) | |||
| { | |||
| switch(request) { | |||
| case MUTEX_TRYLOCK: | |||
| return !pthread_mutex_trylock(&mutex); | |||
| case MUTEX_LOCK: | |||
| return !pthread_mutex_lock(&mutex); | |||
| case MUTEX_UNLOCK: | |||
| return !pthread_mutex_unlock(&mutex); | |||
| } | |||
| return false; | |||
| } | |||
| Master &Master::getInstance() | |||
| { | |||
| static Master *instance = NULL; | |||
| if(!instance) | |||
| instance = new Master; | |||
| return *instance; | |||
| } | |||
| /* | |||
| * Note On Messages (velocity=0 for NoteOff) | |||
| */ | |||
| void Master::noteOn(char chan, char note, char velocity) | |||
| { | |||
| if(velocity) { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| if(chan == part[npart]->Prcvchn) { | |||
| fakepeakpart[npart] = velocity * 2; | |||
| if(part[npart]->Penabled) | |||
| part[npart]->NoteOn(note, velocity, keyshift); | |||
| } | |||
| } | |||
| else | |||
| this->noteOff(chan, note); | |||
| HDDRecorder.triggernow(); | |||
| } | |||
| /* | |||
| * Note Off Messages | |||
| */ | |||
| void Master::noteOff(char chan, char note) | |||
| { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| if((chan == part[npart]->Prcvchn) && part[npart]->Penabled) | |||
| part[npart]->NoteOff(note); | |||
| } | |||
| /* | |||
| * Pressure Messages (velocity=0 for NoteOff) | |||
| */ | |||
| void Master::polyphonicAftertouch(char chan, char note, char velocity) | |||
| { | |||
| if(velocity) { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| if(chan == part[npart]->Prcvchn) | |||
| if(part[npart]->Penabled) | |||
| part[npart]->PolyphonicAftertouch(note, velocity, keyshift); | |||
| } | |||
| else | |||
| this->noteOff(chan, note); | |||
| } | |||
| /* | |||
| * Controllers | |||
| */ | |||
| void Master::setController(char chan, int type, int par) | |||
| { | |||
| if((type == C_dataentryhi) || (type == C_dataentrylo) | |||
| || (type == C_nrpnhi) || (type == C_nrpnlo)) { //Process RPN and NRPN by the Master (ignore the chan) | |||
| ctl.setparameternumber(type, par); | |||
| int parhi = -1, parlo = -1, valhi = -1, vallo = -1; | |||
| if(ctl.getnrpn(&parhi, &parlo, &valhi, &vallo) == 0) //this is NRPN | |||
| //fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo); | |||
| switch(parhi) { | |||
| case 0x04: //System Effects | |||
| if(parlo < NUM_SYS_EFX) | |||
| sysefx[parlo]->seteffectpar_nolock(valhi, vallo); | |||
| ; | |||
| break; | |||
| case 0x08: //Insertion Effects | |||
| if(parlo < NUM_INS_EFX) | |||
| insefx[parlo]->seteffectpar_nolock(valhi, vallo); | |||
| ; | |||
| break; | |||
| } | |||
| ; | |||
| } | |||
| else | |||
| if(type == C_bankselectmsb) { // Change current bank | |||
| if(((unsigned int)par < bank.banks.size()) | |||
| && (bank.banks[par].dir != bank.bankfiletitle)) | |||
| bank.loadbank(bank.banks[par].dir); | |||
| } | |||
| else { //other controllers | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) //Send the controller to all part assigned to the channel | |||
| if((chan == part[npart]->Prcvchn) && (part[npart]->Penabled != 0)) | |||
| part[npart]->SetController(type, par); | |||
| ; | |||
| if(type == C_allsoundsoff) { //cleanup insertion/system FX | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) | |||
| sysefx[nefx]->cleanup(); | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| insefx[nefx]->cleanup(); | |||
| } | |||
| } | |||
| } | |||
| void Master::setProgram(char chan, unsigned int pgm) | |||
| { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| if(chan == part[npart]->Prcvchn) { | |||
| bank.loadfromslot(pgm, part[npart]); | |||
| //Hack to get pad note parameters to update | |||
| //this is not real time safe and makes assumptions about the calling | |||
| //convention of this function... | |||
| pthread_mutex_unlock(&mutex); | |||
| part[npart]->applyparameters(); | |||
| pthread_mutex_lock(&mutex); | |||
| } | |||
| } | |||
| void Master::vuUpdate(const float *outl, const float *outr) | |||
| { | |||
| //Peak computation (for vumeters) | |||
| vu.outpeakl = 1e-12; | |||
| vu.outpeakr = 1e-12; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| if(fabs(outl[i]) > vu.outpeakl) | |||
| vu.outpeakl = fabs(outl[i]); | |||
| if(fabs(outr[i]) > vu.outpeakr) | |||
| vu.outpeakr = fabs(outr[i]); | |||
| } | |||
| if((vu.outpeakl > 1.0f) || (vu.outpeakr > 1.0f)) | |||
| vu.clipped = 1; | |||
| if(vu.maxoutpeakl < vu.outpeakl) | |||
| vu.maxoutpeakl = vu.outpeakl; | |||
| if(vu.maxoutpeakr < vu.outpeakr) | |||
| vu.maxoutpeakr = vu.outpeakr; | |||
| //RMS Peak computation (for vumeters) | |||
| vu.rmspeakl = 1e-12; | |||
| vu.rmspeakr = 1e-12; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| vu.rmspeakl += outl[i] * outl[i]; | |||
| vu.rmspeakr += outr[i] * outr[i]; | |||
| } | |||
| vu.rmspeakl = sqrt(vu.rmspeakl / synth->buffersize_f); | |||
| vu.rmspeakr = sqrt(vu.rmspeakr / synth->buffersize_f); | |||
| //Part Peak computation (for Part vumeters or fake part vumeters) | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| vuoutpeakpart[npart] = 1.0e-12f; | |||
| if(part[npart]->Penabled != 0) { | |||
| float *outl = part[npart]->partoutl, | |||
| *outr = part[npart]->partoutr; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float tmp = fabs(outl[i] + outr[i]); | |||
| if(tmp > vuoutpeakpart[npart]) | |||
| vuoutpeakpart[npart] = tmp; | |||
| } | |||
| vuoutpeakpart[npart] *= volume; | |||
| } | |||
| else | |||
| if(fakepeakpart[npart] > 1) | |||
| fakepeakpart[npart]--; | |||
| } | |||
| } | |||
| /* | |||
| * Enable/Disable a part | |||
| */ | |||
| void Master::partonoff(int npart, int what) | |||
| { | |||
| if(npart >= NUM_MIDI_PARTS) | |||
| return; | |||
| if(what == 0) { //disable part | |||
| fakepeakpart[npart] = 0; | |||
| part[npart]->Penabled = 0; | |||
| part[npart]->cleanup(); | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) { | |||
| if(Pinsparts[nefx] == npart) | |||
| insefx[nefx]->cleanup(); | |||
| ; | |||
| } | |||
| } | |||
| else { //enabled | |||
| part[npart]->Penabled = 1; | |||
| fakepeakpart[npart] = 0; | |||
| } | |||
| } | |||
| /* | |||
| * Master audio out (the final sound) | |||
| */ | |||
| void Master::AudioOut(float *outl, float *outr) | |||
| { | |||
| //Swaps the Left channel with Right Channel | |||
| if(swaplr) | |||
| swap(outl, outr); | |||
| //clean up the output samples (should not be needed?) | |||
| memset(outl, 0, synth->bufferbytes); | |||
| memset(outr, 0, synth->bufferbytes); | |||
| //Compute part samples and store them part[npart]->partoutl,partoutr | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| if(part[npart]->Penabled != 0 && !pthread_mutex_trylock(&part[npart]->load_mutex)) { | |||
| part[npart]->ComputePartSmps(); | |||
| pthread_mutex_unlock(&part[npart]->load_mutex); | |||
| } | |||
| } | |||
| //Insertion effects | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| if(Pinsparts[nefx] >= 0) { | |||
| int efxpart = Pinsparts[nefx]; | |||
| if(part[efxpart]->Penabled) | |||
| insefx[nefx]->out(part[efxpart]->partoutl, | |||
| part[efxpart]->partoutr); | |||
| } | |||
| //Apply the part volumes and pannings (after insertion effects) | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| if(part[npart]->Penabled == 0) | |||
| continue; | |||
| Stereo<float> newvol(part[npart]->volume), | |||
| oldvol(part[npart]->oldvolumel, | |||
| part[npart]->oldvolumer); | |||
| float pan = part[npart]->panning; | |||
| if(pan < 0.5f) | |||
| newvol.l *= pan * 2.0f; | |||
| else | |||
| newvol.r *= (1.0f - pan) * 2.0f; | |||
| //the volume or the panning has changed and needs interpolation | |||
| if(ABOVE_AMPLITUDE_THRESHOLD(oldvol.l, newvol.l) | |||
| || ABOVE_AMPLITUDE_THRESHOLD(oldvol.r, newvol.r)) { | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| Stereo<float> vol(INTERPOLATE_AMPLITUDE(oldvol.l, newvol.l, | |||
| i, synth->buffersize), | |||
| INTERPOLATE_AMPLITUDE(oldvol.r, newvol.r, | |||
| i, synth->buffersize)); | |||
| part[npart]->partoutl[i] *= vol.l; | |||
| part[npart]->partoutr[i] *= vol.r; | |||
| } | |||
| part[npart]->oldvolumel = newvol.l; | |||
| part[npart]->oldvolumer = newvol.r; | |||
| } | |||
| else | |||
| for(int i = 0; i < synth->buffersize; ++i) { //the volume did not changed | |||
| part[npart]->partoutl[i] *= newvol.l; | |||
| part[npart]->partoutr[i] *= newvol.r; | |||
| } | |||
| } | |||
| //System effects | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) { | |||
| if(sysefx[nefx]->geteffect() == 0) | |||
| continue; //the effect is disabled | |||
| float *tmpmixl = getTmpBuffer(); | |||
| float *tmpmixr = getTmpBuffer(); | |||
| //Clean up the samples used by the system effects | |||
| memset(tmpmixl, 0, synth->bufferbytes); | |||
| memset(tmpmixr, 0, synth->bufferbytes); | |||
| //Mix the channels according to the part settings about System Effect | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| //skip if the part has no output to effect | |||
| if(Psysefxvol[nefx][npart] == 0) | |||
| continue; | |||
| //skip if the part is disabled | |||
| if(part[npart]->Penabled == 0) | |||
| continue; | |||
| //the output volume of each part to system effect | |||
| const float vol = sysefxvol[nefx][npart]; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| tmpmixl[i] += part[npart]->partoutl[i] * vol; | |||
| tmpmixr[i] += part[npart]->partoutr[i] * vol; | |||
| } | |||
| } | |||
| // system effect send to next ones | |||
| for(int nefxfrom = 0; nefxfrom < nefx; ++nefxfrom) | |||
| if(Psysefxsend[nefxfrom][nefx] != 0) { | |||
| const float vol = sysefxsend[nefxfrom][nefx]; | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| tmpmixl[i] += sysefx[nefxfrom]->efxoutl[i] * vol; | |||
| tmpmixr[i] += sysefx[nefxfrom]->efxoutr[i] * vol; | |||
| } | |||
| } | |||
| sysefx[nefx]->out(tmpmixl, tmpmixr); | |||
| //Add the System Effect to sound output | |||
| const float outvol = sysefx[nefx]->sysefxgetvolume(); | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| outl[i] += tmpmixl[i] * outvol; | |||
| outr[i] += tmpmixr[i] * outvol; | |||
| } | |||
| returnTmpBuffer(tmpmixl); | |||
| returnTmpBuffer(tmpmixr); | |||
| } | |||
| //Mix all parts | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| if(part[npart]->Penabled) //only mix active parts | |||
| for(int i = 0; i < synth->buffersize; ++i) { //the volume did not changed | |||
| outl[i] += part[npart]->partoutl[i]; | |||
| outr[i] += part[npart]->partoutr[i]; | |||
| } | |||
| //Insertion effects for Master Out | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| if(Pinsparts[nefx] == -2) | |||
| insefx[nefx]->out(outl, outr); | |||
| //Master Volume | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| outl[i] *= volume; | |||
| outr[i] *= volume; | |||
| } | |||
| if(!pthread_mutex_trylock(&vumutex)) { | |||
| vuUpdate(outl, outr); | |||
| pthread_mutex_unlock(&vumutex); | |||
| } | |||
| //Shutup if it is asked (with fade-out) | |||
| if(shutup) { | |||
| for(int i = 0; i < synth->buffersize; ++i) { | |||
| float tmp = (synth->buffersize_f - i) / synth->buffersize_f; | |||
| outl[i] *= tmp; | |||
| outr[i] *= tmp; | |||
| } | |||
| ShutUp(); | |||
| } | |||
| //update the LFO's time | |||
| LFOParams::time++; | |||
| dump.inctick(); | |||
| } | |||
| //TODO review the respective code from yoshimi for this | |||
| //If memory serves correctly, libsamplerate was used | |||
| void Master::GetAudioOutSamples(size_t nsamples, | |||
| unsigned samplerate, | |||
| float *outl, | |||
| float *outr) | |||
| { | |||
| static float *bufl = new float[synth->buffersize], | |||
| *bufr = new float[synth->buffersize]; | |||
| static off_t off = 0; | |||
| static size_t smps = 0; | |||
| off_t out_off = 0; | |||
| //Fail when resampling rather than doing a poor job | |||
| if(synth->samplerate != samplerate) { | |||
| printf("darn it: %d vs %d\n", synth->samplerate, samplerate); | |||
| return; | |||
| } | |||
| while(nsamples) { | |||
| //use all available samples | |||
| if(nsamples >= smps) { | |||
| memcpy(outl + out_off, bufl + off, sizeof(float) * smps); | |||
| memcpy(outr + out_off, bufr + off, sizeof(float) * smps); | |||
| //generate samples | |||
| AudioOut(bufl, bufr); | |||
| off = 0; | |||
| smps = synth->buffersize; | |||
| out_off += smps; | |||
| nsamples -= smps; | |||
| } | |||
| else { //use some samples | |||
| memcpy(outl + out_off, bufl + off, sizeof(float) * nsamples); | |||
| memcpy(outr + out_off, bufr + off, sizeof(float) * nsamples); | |||
| smps -= nsamples; | |||
| off += nsamples; | |||
| nsamples = 0; | |||
| } | |||
| } | |||
| } | |||
| Master::~Master() | |||
| { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| delete part[npart]; | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| delete insefx[nefx]; | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) | |||
| delete sysefx[nefx]; | |||
| delete fft; | |||
| pthread_mutex_destroy(&mutex); | |||
| pthread_mutex_destroy(&vumutex); | |||
| } | |||
| /* | |||
| * Parameter control | |||
| */ | |||
| void Master::setPvolume(char Pvolume_) | |||
| { | |||
| Pvolume = Pvolume_; | |||
| volume = dB2rap((Pvolume - 96.0f) / 96.0f * 40.0f); | |||
| } | |||
| void Master::setPkeyshift(char Pkeyshift_) | |||
| { | |||
| Pkeyshift = Pkeyshift_; | |||
| keyshift = (int)Pkeyshift - 64; | |||
| } | |||
| void Master::setPsysefxvol(int Ppart, int Pefx, char Pvol) | |||
| { | |||
| Psysefxvol[Pefx][Ppart] = Pvol; | |||
| sysefxvol[Pefx][Ppart] = powf(0.1f, (1.0f - Pvol / 96.0f) * 2.0f); | |||
| } | |||
| void Master::setPsysefxsend(int Pefxfrom, int Pefxto, char Pvol) | |||
| { | |||
| Psysefxsend[Pefxfrom][Pefxto] = Pvol; | |||
| sysefxsend[Pefxfrom][Pefxto] = powf(0.1f, (1.0f - Pvol / 96.0f) * 2.0f); | |||
| } | |||
| /* | |||
| * Panic! (Clean up all parts and effects) | |||
| */ | |||
| void Master::ShutUp() | |||
| { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| part[npart]->cleanup(); | |||
| fakepeakpart[npart] = 0; | |||
| } | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| insefx[nefx]->cleanup(); | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) | |||
| sysefx[nefx]->cleanup(); | |||
| vuresetpeaks(); | |||
| shutup = 0; | |||
| } | |||
| /* | |||
| * Reset peaks and clear the "cliped" flag (for VU-meter) | |||
| */ | |||
| void Master::vuresetpeaks() | |||
| { | |||
| pthread_mutex_lock(&vumutex); | |||
| vu.outpeakl = 1e-9; | |||
| vu.outpeakr = 1e-9; | |||
| vu.maxoutpeakl = 1e-9; | |||
| vu.maxoutpeakr = 1e-9; | |||
| vu.clipped = 0; | |||
| pthread_mutex_unlock(&vumutex); | |||
| } | |||
| vuData Master::getVuData() | |||
| { | |||
| vuData tmp; | |||
| pthread_mutex_lock(&vumutex); | |||
| tmp = vu; | |||
| pthread_mutex_unlock(&vumutex); | |||
| return tmp; | |||
| } | |||
| void Master::applyparameters(bool lockmutex) | |||
| { | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| part[npart]->applyparameters(lockmutex); | |||
| } | |||
| void Master::add2XML(XMLwrapper *xml) | |||
| { | |||
| xml->addpar("volume", Pvolume); | |||
| xml->addpar("key_shift", Pkeyshift); | |||
| xml->addparbool("nrpn_receive", ctl.NRPN.receive); | |||
| xml->beginbranch("MICROTONAL"); | |||
| microtonal.add2XML(xml); | |||
| xml->endbranch(); | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| xml->beginbranch("PART", npart); | |||
| part[npart]->add2XML(xml); | |||
| xml->endbranch(); | |||
| } | |||
| xml->beginbranch("SYSTEM_EFFECTS"); | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) { | |||
| xml->beginbranch("SYSTEM_EFFECT", nefx); | |||
| xml->beginbranch("EFFECT"); | |||
| sysefx[nefx]->add2XML(xml); | |||
| xml->endbranch(); | |||
| for(int pefx = 0; pefx < NUM_MIDI_PARTS; ++pefx) { | |||
| xml->beginbranch("VOLUME", pefx); | |||
| xml->addpar("vol", Psysefxvol[nefx][pefx]); | |||
| xml->endbranch(); | |||
| } | |||
| for(int tonefx = nefx + 1; tonefx < NUM_SYS_EFX; ++tonefx) { | |||
| xml->beginbranch("SENDTO", tonefx); | |||
| xml->addpar("send_vol", Psysefxsend[nefx][tonefx]); | |||
| xml->endbranch(); | |||
| } | |||
| xml->endbranch(); | |||
| } | |||
| xml->endbranch(); | |||
| xml->beginbranch("INSERTION_EFFECTS"); | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) { | |||
| xml->beginbranch("INSERTION_EFFECT", nefx); | |||
| xml->addpar("part", Pinsparts[nefx]); | |||
| xml->beginbranch("EFFECT"); | |||
| insefx[nefx]->add2XML(xml); | |||
| xml->endbranch(); | |||
| xml->endbranch(); | |||
| } | |||
| xml->endbranch(); | |||
| } | |||
| int Master::getalldata(char **data) | |||
| { | |||
| XMLwrapper *xml = new XMLwrapper(); | |||
| xml->beginbranch("MASTER"); | |||
| pthread_mutex_lock(&mutex); | |||
| add2XML(xml); | |||
| pthread_mutex_unlock(&mutex); | |||
| xml->endbranch(); | |||
| *data = xml->getXMLdata(); | |||
| delete (xml); | |||
| return strlen(*data) + 1; | |||
| } | |||
| void Master::putalldata(char *data, int /*size*/) | |||
| { | |||
| XMLwrapper *xml = new XMLwrapper(); | |||
| if(!xml->putXMLdata(data)) { | |||
| delete (xml); | |||
| return; | |||
| } | |||
| if(xml->enterbranch("MASTER") == 0) | |||
| return; | |||
| pthread_mutex_lock(&mutex); | |||
| getfromXML(xml); | |||
| pthread_mutex_unlock(&mutex); | |||
| xml->exitbranch(); | |||
| delete (xml); | |||
| } | |||
| int Master::saveXML(const char *filename) | |||
| { | |||
| XMLwrapper *xml = new XMLwrapper(); | |||
| xml->beginbranch("MASTER"); | |||
| add2XML(xml); | |||
| xml->endbranch(); | |||
| int result = xml->saveXMLfile(filename); | |||
| delete (xml); | |||
| return result; | |||
| } | |||
| int Master::loadXML(const char *filename) | |||
| { | |||
| XMLwrapper *xml = new XMLwrapper(); | |||
| if(xml->loadXMLfile(filename) < 0) { | |||
| delete (xml); | |||
| return -1; | |||
| } | |||
| if(xml->enterbranch("MASTER") == 0) | |||
| return -10; | |||
| getfromXML(xml); | |||
| xml->exitbranch(); | |||
| delete (xml); | |||
| return 0; | |||
| } | |||
| void Master::getfromXML(XMLwrapper *xml) | |||
| { | |||
| setPvolume(xml->getpar127("volume", Pvolume)); | |||
| setPkeyshift(xml->getpar127("key_shift", Pkeyshift)); | |||
| ctl.NRPN.receive = xml->getparbool("nrpn_receive", ctl.NRPN.receive); | |||
| part[0]->Penabled = 0; | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { | |||
| if(xml->enterbranch("PART", npart) == 0) | |||
| continue; | |||
| part[npart]->getfromXML(xml); | |||
| xml->exitbranch(); | |||
| } | |||
| if(xml->enterbranch("MICROTONAL")) { | |||
| microtonal.getfromXML(xml); | |||
| xml->exitbranch(); | |||
| } | |||
| sysefx[0]->changeeffect(0); | |||
| if(xml->enterbranch("SYSTEM_EFFECTS")) { | |||
| for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) { | |||
| if(xml->enterbranch("SYSTEM_EFFECT", nefx) == 0) | |||
| continue; | |||
| if(xml->enterbranch("EFFECT")) { | |||
| sysefx[nefx]->getfromXML(xml); | |||
| xml->exitbranch(); | |||
| } | |||
| for(int partefx = 0; partefx < NUM_MIDI_PARTS; ++partefx) { | |||
| if(xml->enterbranch("VOLUME", partefx) == 0) | |||
| continue; | |||
| setPsysefxvol(partefx, nefx, | |||
| xml->getpar127("vol", Psysefxvol[partefx][nefx])); | |||
| xml->exitbranch(); | |||
| } | |||
| for(int tonefx = nefx + 1; tonefx < NUM_SYS_EFX; ++tonefx) { | |||
| if(xml->enterbranch("SENDTO", tonefx) == 0) | |||
| continue; | |||
| setPsysefxsend(nefx, tonefx, | |||
| xml->getpar127("send_vol", | |||
| Psysefxsend[nefx][tonefx])); | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| if(xml->enterbranch("INSERTION_EFFECTS")) { | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) { | |||
| if(xml->enterbranch("INSERTION_EFFECT", nefx) == 0) | |||
| continue; | |||
| Pinsparts[nefx] = xml->getpar("part", | |||
| Pinsparts[nefx], | |||
| -2, | |||
| NUM_MIDI_PARTS); | |||
| if(xml->enterbranch("EFFECT")) { | |||
| insefx[nefx]->getfromXML(xml); | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,175 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Master.h - It sends Midi Messages to Parts, receives samples from parts, | |||
| process them with system/insertion effects and mix them | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef MASTER_H | |||
| #define MASTER_H | |||
| #include "../globals.h" | |||
| #include "Microtonal.h" | |||
| #include "Bank.h" | |||
| #include "Recorder.h" | |||
| #include "Dump.h" | |||
| #include "XMLwrapper.h" | |||
| #include "../Params/Controller.h" | |||
| typedef enum { | |||
| MUTEX_TRYLOCK, MUTEX_LOCK, MUTEX_UNLOCK | |||
| } lockset; | |||
| extern Dump dump; | |||
| struct vuData { | |||
| vuData(void); | |||
| float outpeakl, outpeakr, maxoutpeakl, maxoutpeakr, | |||
| rmspeakl, rmspeakr; | |||
| int clipped; | |||
| }; | |||
| /** It sends Midi Messages to Parts, receives samples from parts, | |||
| * process them with system/insertion effects and mix them */ | |||
| class Master | |||
| { | |||
| public: | |||
| /** Constructor TODO make private*/ | |||
| Master(); | |||
| /** Destructor*/ | |||
| ~Master(); | |||
| static Master &getInstance(); | |||
| /**Saves all settings to a XML file | |||
| * @return 0 for ok or <0 if there is an error*/ | |||
| int saveXML(const char *filename); | |||
| /**This adds the parameters to the XML data*/ | |||
| void add2XML(XMLwrapper *xml); | |||
| void defaults(); | |||
| /**loads all settings from a XML file | |||
| * @return 0 for ok or -1 if there is an error*/ | |||
| int loadXML(const char *filename); | |||
| void applyparameters(bool lockmutex = true); | |||
| void getfromXML(XMLwrapper *xml); | |||
| /**get all data to a newly allocated array (used for VST) | |||
| * @return the datasize*/ | |||
| int getalldata(char **data); | |||
| /**put all data from the *data array to zynaddsubfx parameters (used for VST)*/ | |||
| void putalldata(char *data, int size); | |||
| //Mutex control | |||
| /**Control the Master's mutex state. | |||
| * @param lockset either trylock, lock, or unlock. | |||
| * @return true when successful false otherwise.*/ | |||
| bool mutexLock(lockset request); | |||
| //Midi IN | |||
| void noteOn(char chan, char note, char velocity); | |||
| void noteOff(char chan, char note); | |||
| void polyphonicAftertouch(char chan, char note, char velocity); | |||
| void setController(char chan, int type, int par); | |||
| void setProgram(char chan, unsigned int pgm); | |||
| //void NRPN... | |||
| void ShutUp(); | |||
| int shutup; | |||
| void vuUpdate(const float *outl, const float *outr); | |||
| /**Audio Output*/ | |||
| void AudioOut(float *outl, float *outr); | |||
| /**Audio Output (for callback mode). This allows the program to be controled by an external program*/ | |||
| void GetAudioOutSamples(size_t nsamples, | |||
| unsigned samplerate, | |||
| float *outl, | |||
| float *outr); | |||
| void partonoff(int npart, int what); | |||
| /**parts \todo see if this can be made to be dynamic*/ | |||
| class Part * part[NUM_MIDI_PARTS]; | |||
| //parameters | |||
| unsigned char Pvolume; | |||
| unsigned char Pkeyshift; | |||
| unsigned char Psysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; | |||
| unsigned char Psysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; | |||
| //parameters control | |||
| void setPvolume(char Pvolume_); | |||
| void setPkeyshift(char Pkeyshift_); | |||
| void setPsysefxvol(int Ppart, int Pefx, char Pvol); | |||
| void setPsysefxsend(int Pefxfrom, int Pefxto, char Pvol); | |||
| //effects | |||
| class EffectMgr * sysefx[NUM_SYS_EFX]; //system | |||
| class EffectMgr * insefx[NUM_INS_EFX]; //insertion | |||
| // void swapcopyeffects(int what,int type,int neff1,int neff2); | |||
| //HDD recorder | |||
| Recorder HDDRecorder; | |||
| //part that's apply the insertion effect; -1 to disable | |||
| short int Pinsparts[NUM_INS_EFX]; | |||
| //peaks for VU-meter | |||
| void vuresetpeaks(); | |||
| //get VU-meter data | |||
| vuData getVuData(); | |||
| //peaks for part VU-meters | |||
| /**\todo synchronize this with a mutex*/ | |||
| float vuoutpeakpart[NUM_MIDI_PARTS]; | |||
| unsigned char fakepeakpart[NUM_MIDI_PARTS]; //this is used to compute the "peak" when the part is disabled | |||
| Controller ctl; | |||
| bool swaplr; //if L and R are swapped | |||
| //other objects | |||
| Microtonal microtonal; | |||
| Bank bank; | |||
| class FFTwrapper * fft; | |||
| pthread_mutex_t mutex; | |||
| pthread_mutex_t vumutex; | |||
| private: | |||
| bool nullRun; | |||
| vuData vu; | |||
| float volume; | |||
| float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; | |||
| float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; | |||
| int keyshift; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,694 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Microtonal.cpp - Tuning settings and microtonal capabilities | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <math.h> | |||
| #include <string.h> | |||
| #include "Microtonal.h" | |||
| #define MAX_LINE_SIZE 80 | |||
| Microtonal::Microtonal() | |||
| { | |||
| Pname = new unsigned char[MICROTONAL_MAX_NAME_LEN]; | |||
| Pcomment = new unsigned char[MICROTONAL_MAX_NAME_LEN]; | |||
| defaults(); | |||
| } | |||
| void Microtonal::defaults() | |||
| { | |||
| Pinvertupdown = 0; | |||
| Pinvertupdowncenter = 60; | |||
| octavesize = 12; | |||
| Penabled = 0; | |||
| PAnote = 69; | |||
| PAfreq = 440.0f; | |||
| Pscaleshift = 64; | |||
| Pfirstkey = 0; | |||
| Plastkey = 127; | |||
| Pmiddlenote = 60; | |||
| Pmapsize = 12; | |||
| Pmappingenabled = 0; | |||
| for(int i = 0; i < 128; ++i) | |||
| Pmapping[i] = i; | |||
| for(int i = 0; i < MAX_OCTAVE_SIZE; ++i) { | |||
| octave[i].tuning = tmpoctave[i].tuning = powf( | |||
| 2, | |||
| (i % octavesize | |||
| + 1) / 12.0f); | |||
| octave[i].type = tmpoctave[i].type = 1; | |||
| octave[i].x1 = tmpoctave[i].x1 = (i % octavesize + 1) * 100; | |||
| octave[i].x2 = tmpoctave[i].x2 = 0; | |||
| } | |||
| octave[11].type = 2; | |||
| octave[11].x1 = 2; | |||
| octave[11].x2 = 1; | |||
| for(int i = 0; i < MICROTONAL_MAX_NAME_LEN; ++i) { | |||
| Pname[i] = '\0'; | |||
| Pcomment[i] = '\0'; | |||
| } | |||
| snprintf((char *) Pname, MICROTONAL_MAX_NAME_LEN, "12tET"); | |||
| snprintf((char *) Pcomment, | |||
| MICROTONAL_MAX_NAME_LEN, | |||
| "Equal Temperament 12 notes per octave"); | |||
| Pglobalfinedetune = 64; | |||
| } | |||
| Microtonal::~Microtonal() | |||
| { | |||
| delete [] Pname; | |||
| delete [] Pcomment; | |||
| } | |||
| /* | |||
| * Get the size of the octave | |||
| */ | |||
| unsigned char Microtonal::getoctavesize() const | |||
| { | |||
| if(Penabled != 0) | |||
| return octavesize; | |||
| else | |||
| return 12; | |||
| } | |||
| /* | |||
| * Get the frequency according the note number | |||
| */ | |||
| float Microtonal::getnotefreq(int note, int keyshift) const | |||
| { | |||
| // in this function will appears many times things like this: | |||
| // var=(a+b*100)%b | |||
| // I had written this way because if I use var=a%b gives unwanted results when a<0 | |||
| // This is the same with divisions. | |||
| if((Pinvertupdown != 0) && ((Pmappingenabled == 0) || (Penabled == 0))) | |||
| note = (int) Pinvertupdowncenter * 2 - note; | |||
| //compute global fine detune | |||
| float globalfinedetunerap = powf(2.0f, | |||
| (Pglobalfinedetune - 64.0f) / 1200.0f); //-64.0f .. 63.0f cents | |||
| if(Penabled == 0) | |||
| return powf(2.0f, | |||
| (note - PAnote | |||
| + keyshift) / 12.0f) * PAfreq * globalfinedetunerap; //12tET | |||
| int scaleshift = | |||
| ((int)Pscaleshift - 64 + (int) octavesize * 100) % octavesize; | |||
| //compute the keyshift | |||
| float rap_keyshift = 1.0f; | |||
| if(keyshift != 0) { | |||
| int kskey = (keyshift + (int)octavesize * 100) % octavesize; | |||
| int ksoct = (keyshift + (int)octavesize * 100) / octavesize - 100; | |||
| rap_keyshift = (kskey == 0) ? (1.0f) : (octave[kskey - 1].tuning); | |||
| rap_keyshift *= powf(octave[octavesize - 1].tuning, ksoct); | |||
| } | |||
| //if the mapping is enabled | |||
| if(Pmappingenabled != 0) { | |||
| if((note < Pfirstkey) || (note > Plastkey)) | |||
| return -1.0f; | |||
| //Compute how many mapped keys are from middle note to reference note | |||
| //and find out the proportion between the freq. of middle note and "A" note | |||
| int tmp = PAnote - Pmiddlenote, minus = 0; | |||
| if(tmp < 0) { | |||
| tmp = -tmp; | |||
| minus = 1; | |||
| } | |||
| int deltanote = 0; | |||
| for(int i = 0; i < tmp; ++i) | |||
| if(Pmapping[i % Pmapsize] >= 0) | |||
| deltanote++; | |||
| float rap_anote_middlenote = | |||
| (deltanote == | |||
| 0) ? (1.0f) : (octave[(deltanote - 1) % octavesize].tuning); | |||
| if(deltanote != 0) | |||
| rap_anote_middlenote *= | |||
| powf(octave[octavesize - 1].tuning, | |||
| (deltanote - 1) / octavesize); | |||
| if(minus != 0) | |||
| rap_anote_middlenote = 1.0f / rap_anote_middlenote; | |||
| //Convert from note (midi) to degree (note from the tunning) | |||
| int degoct = | |||
| (note - (int)Pmiddlenote + (int) Pmapsize | |||
| * 200) / (int)Pmapsize - 200; | |||
| int degkey = (note - Pmiddlenote + (int)Pmapsize * 100) % Pmapsize; | |||
| degkey = Pmapping[degkey]; | |||
| if(degkey < 0) | |||
| return -1.0f; //this key is not mapped | |||
| //invert the keyboard upside-down if it is asked for | |||
| //TODO: do the right way by using Pinvertupdowncenter | |||
| if(Pinvertupdown != 0) { | |||
| degkey = octavesize - degkey - 1; | |||
| degoct = -degoct; | |||
| } | |||
| //compute the frequency of the note | |||
| degkey = degkey + scaleshift; | |||
| degoct += degkey / octavesize; | |||
| degkey %= octavesize; | |||
| float freq = (degkey == 0) ? (1.0f) : octave[degkey - 1].tuning; | |||
| freq *= powf(octave[octavesize - 1].tuning, degoct); | |||
| freq *= PAfreq / rap_anote_middlenote; | |||
| freq *= globalfinedetunerap; | |||
| if(scaleshift != 0) | |||
| freq /= octave[scaleshift - 1].tuning; | |||
| return freq * rap_keyshift; | |||
| } | |||
| else { //if the mapping is disabled | |||
| int nt = note - PAnote + scaleshift; | |||
| int ntkey = (nt + (int)octavesize * 100) % octavesize; | |||
| int ntoct = (nt - ntkey) / octavesize; | |||
| float oct = octave[octavesize - 1].tuning; | |||
| float freq = | |||
| octave[(ntkey + octavesize - 1) % octavesize].tuning * powf(oct, | |||
| ntoct) | |||
| * PAfreq; | |||
| if(ntkey == 0) | |||
| freq /= oct; | |||
| if(scaleshift != 0) | |||
| freq /= octave[scaleshift - 1].tuning; | |||
| // fprintf(stderr,"note=%d freq=%.3f cents=%d\n",note,freq,(int)floor(logf(freq/PAfreq)/logf(2.0f)*1200.0f+0.5f)); | |||
| freq *= globalfinedetunerap; | |||
| return freq * rap_keyshift; | |||
| } | |||
| } | |||
| bool Microtonal::operator==(const Microtonal µ) const | |||
| { | |||
| return !(*this != micro); | |||
| } | |||
| bool Microtonal::operator!=(const Microtonal µ) const | |||
| { | |||
| //A simple macro to test equality MiCRotonal EQuals (not the perfect | |||
| //approach, but good enough) | |||
| #define MCREQ(x) if(x != micro.x) \ | |||
| return true | |||
| //for floats | |||
| #define FMCREQ(x) if(!((x < micro.x + 0.0001f) && (x > micro.x - 0.0001f))) \ | |||
| return true | |||
| MCREQ(Pinvertupdown); | |||
| MCREQ(Pinvertupdowncenter); | |||
| MCREQ(octavesize); | |||
| MCREQ(Penabled); | |||
| MCREQ(PAnote); | |||
| FMCREQ(PAfreq); | |||
| MCREQ(Pscaleshift); | |||
| MCREQ(Pfirstkey); | |||
| MCREQ(Plastkey); | |||
| MCREQ(Pmiddlenote); | |||
| MCREQ(Pmapsize); | |||
| MCREQ(Pmappingenabled); | |||
| for(int i = 0; i < 128; ++i) | |||
| MCREQ(Pmapping[i]); | |||
| for(int i = 0; i < octavesize; ++i) { | |||
| FMCREQ(octave[i].tuning); | |||
| MCREQ(octave[i].type); | |||
| MCREQ(octave[i].x1); | |||
| MCREQ(octave[i].x2); | |||
| } | |||
| if(strcmp((const char *)this->Pname, (const char *)micro.Pname)) | |||
| return true; | |||
| if(strcmp((const char *)this->Pcomment, (const char *)micro.Pcomment)) | |||
| return true; | |||
| MCREQ(Pglobalfinedetune); | |||
| return false; | |||
| //undefine macros, as they are no longer needed | |||
| #undef MCREQ | |||
| #undef FMCREQ | |||
| } | |||
| /* | |||
| * Convert a line to tunings; returns -1 if it ok | |||
| */ | |||
| int Microtonal::linetotunings(unsigned int nline, const char *line) | |||
| { | |||
| int x1 = -1, x2 = -1, type = -1; | |||
| float x = -1.0f, tmp, tuning = 1.0f; | |||
| if(strstr(line, "/") == NULL) { | |||
| if(strstr(line, ".") == NULL) { // M case (M=M/1) | |||
| sscanf(line, "%d", &x1); | |||
| x2 = 1; | |||
| type = 2; //division | |||
| } | |||
| else { // float number case | |||
| sscanf(line, "%f", &x); | |||
| if(x < 0.000001f) | |||
| return 1; | |||
| type = 1; //float type(cents) | |||
| } | |||
| } | |||
| else { // M/N case | |||
| sscanf(line, "%d/%d", &x1, &x2); | |||
| if((x1 < 0) || (x2 < 0)) | |||
| return 1; | |||
| if(x2 == 0) | |||
| x2 = 1; | |||
| type = 2; //division | |||
| } | |||
| if(x1 <= 0) | |||
| x1 = 1; //not allow zero frequency sounds (consider 0 as 1) | |||
| //convert to float if the number are too big | |||
| if((type == 2) | |||
| && ((x1 > (128 * 128 * 128 - 1)) || (x2 > (128 * 128 * 128 - 1)))) { | |||
| type = 1; | |||
| x = ((float) x1) / x2; | |||
| } | |||
| switch(type) { | |||
| case 1: | |||
| x1 = (int) floor(x); | |||
| tmp = fmod(x, 1.0f); | |||
| x2 = (int) (floor(tmp * 1e6)); | |||
| tuning = powf(2.0f, x / 1200.0f); | |||
| break; | |||
| case 2: | |||
| x = ((float)x1) / x2; | |||
| tuning = x; | |||
| break; | |||
| } | |||
| tmpoctave[nline].tuning = tuning; | |||
| tmpoctave[nline].type = type; | |||
| tmpoctave[nline].x1 = x1; | |||
| tmpoctave[nline].x2 = x2; | |||
| return -1; //ok | |||
| } | |||
| /* | |||
| * Convert the text to tunnings | |||
| */ | |||
| int Microtonal::texttotunings(const char *text) | |||
| { | |||
| unsigned int i, k = 0, nl = 0; | |||
| char *lin; | |||
| lin = new char[MAX_LINE_SIZE + 1]; | |||
| while(k < strlen(text)) { | |||
| for(i = 0; i < MAX_LINE_SIZE; ++i) { | |||
| lin[i] = text[k++]; | |||
| if(lin[i] < 0x20) | |||
| break; | |||
| } | |||
| lin[i] = '\0'; | |||
| if(strlen(lin) == 0) | |||
| continue; | |||
| int err = linetotunings(nl, lin); | |||
| if(err != -1) { | |||
| delete [] lin; | |||
| return nl; //Parse error | |||
| } | |||
| nl++; | |||
| } | |||
| delete [] lin; | |||
| if(nl > MAX_OCTAVE_SIZE) | |||
| nl = MAX_OCTAVE_SIZE; | |||
| if(nl == 0) | |||
| return -2; //the input is empty | |||
| octavesize = nl; | |||
| for(i = 0; i < octavesize; ++i) { | |||
| octave[i].tuning = tmpoctave[i].tuning; | |||
| octave[i].type = tmpoctave[i].type; | |||
| octave[i].x1 = tmpoctave[i].x1; | |||
| octave[i].x2 = tmpoctave[i].x2; | |||
| } | |||
| return -1; //ok | |||
| } | |||
| /* | |||
| * Convert the text to mapping | |||
| */ | |||
| void Microtonal::texttomapping(const char *text) | |||
| { | |||
| unsigned int i, k = 0; | |||
| char *lin; | |||
| lin = new char[MAX_LINE_SIZE + 1]; | |||
| for(i = 0; i < 128; ++i) | |||
| Pmapping[i] = -1; | |||
| int tx = 0; | |||
| while(k < strlen(text)) { | |||
| for(i = 0; i < MAX_LINE_SIZE; ++i) { | |||
| lin[i] = text[k++]; | |||
| if(lin[i] < 0x20) | |||
| break; | |||
| } | |||
| lin[i] = '\0'; | |||
| if(strlen(lin) == 0) | |||
| continue; | |||
| int tmp = 0; | |||
| if(sscanf(lin, "%d", &tmp) == 0) | |||
| tmp = -1; | |||
| if(tmp < -1) | |||
| tmp = -1; | |||
| Pmapping[tx] = tmp; | |||
| if((tx++) > 127) | |||
| break; | |||
| } | |||
| delete [] lin; | |||
| if(tx == 0) | |||
| tx = 1; | |||
| Pmapsize = tx; | |||
| } | |||
| /* | |||
| * Convert tunning to text line | |||
| */ | |||
| void Microtonal::tuningtoline(int n, char *line, int maxn) | |||
| { | |||
| if((n > octavesize) || (n > MAX_OCTAVE_SIZE)) { | |||
| line[0] = '\0'; | |||
| return; | |||
| } | |||
| if(octave[n].type == 1) | |||
| snprintf(line, maxn, "%d.%06d", octave[n].x1, octave[n].x2); | |||
| if(octave[n].type == 2) | |||
| snprintf(line, maxn, "%d/%d", octave[n].x1, octave[n].x2); | |||
| } | |||
| int Microtonal::loadline(FILE *file, char *line) | |||
| { | |||
| do { | |||
| if(fgets(line, 500, file) == 0) | |||
| return 1; | |||
| } while(line[0] == '!'); | |||
| return 0; | |||
| } | |||
| /* | |||
| * Loads the tunnings from a scl file | |||
| */ | |||
| int Microtonal::loadscl(const char *filename) | |||
| { | |||
| FILE *file = fopen(filename, "r"); | |||
| char tmp[500]; | |||
| fseek(file, 0, SEEK_SET); | |||
| //loads the short description | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| for(int i = 0; i < 500; ++i) | |||
| if(tmp[i] < 32) | |||
| tmp[i] = 0; | |||
| snprintf((char *) Pname, MICROTONAL_MAX_NAME_LEN, "%s", tmp); | |||
| snprintf((char *) Pcomment, MICROTONAL_MAX_NAME_LEN, "%s", tmp); | |||
| //loads the number of the notes | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| int nnotes = MAX_OCTAVE_SIZE; | |||
| sscanf(&tmp[0], "%d", &nnotes); | |||
| if(nnotes > MAX_OCTAVE_SIZE) | |||
| return 2; | |||
| //load the tunnings | |||
| for(int nline = 0; nline < nnotes; ++nline) { | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| linetotunings(nline, &tmp[0]); | |||
| } | |||
| fclose(file); | |||
| octavesize = nnotes; | |||
| for(int i = 0; i < octavesize; ++i) { | |||
| octave[i].tuning = tmpoctave[i].tuning; | |||
| octave[i].type = tmpoctave[i].type; | |||
| octave[i].x1 = tmpoctave[i].x1; | |||
| octave[i].x2 = tmpoctave[i].x2; | |||
| } | |||
| return 0; | |||
| } | |||
| /* | |||
| * Loads the mapping from a kbm file | |||
| */ | |||
| int Microtonal::loadkbm(const char *filename) | |||
| { | |||
| FILE *file = fopen(filename, "r"); | |||
| int x; | |||
| char tmp[500]; | |||
| fseek(file, 0, SEEK_SET); | |||
| //loads the mapsize | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| if(sscanf(&tmp[0], "%d", &x) == 0) | |||
| return 2; | |||
| if(x < 1) | |||
| x = 0; | |||
| if(x > 127) | |||
| x = 127; //just in case... | |||
| Pmapsize = x; | |||
| //loads first MIDI note to retune | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| if(sscanf(&tmp[0], "%d", &x) == 0) | |||
| return 2; | |||
| if(x < 1) | |||
| x = 0; | |||
| if(x > 127) | |||
| x = 127; //just in case... | |||
| Pfirstkey = x; | |||
| //loads last MIDI note to retune | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| if(sscanf(&tmp[0], "%d", &x) == 0) | |||
| return 2; | |||
| if(x < 1) | |||
| x = 0; | |||
| if(x > 127) | |||
| x = 127; //just in case... | |||
| Plastkey = x; | |||
| //loads last the middle note where scale fro scale degree=0 | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| if(sscanf(&tmp[0], "%d", &x) == 0) | |||
| return 2; | |||
| if(x < 1) | |||
| x = 0; | |||
| if(x > 127) | |||
| x = 127; //just in case... | |||
| Pmiddlenote = x; | |||
| //loads the reference note | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| if(sscanf(&tmp[0], "%d", &x) == 0) | |||
| return 2; | |||
| if(x < 1) | |||
| x = 0; | |||
| if(x > 127) | |||
| x = 127; //just in case... | |||
| PAnote = x; | |||
| //loads the reference freq. | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| float tmpPAfreq = 440.0f; | |||
| if(sscanf(&tmp[0], "%f", &tmpPAfreq) == 0) | |||
| return 2; | |||
| PAfreq = tmpPAfreq; | |||
| //the scale degree(which is the octave) is not loaded, it is obtained by the tunnings with getoctavesize() method | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| //load the mappings | |||
| if(Pmapsize != 0) { | |||
| for(int nline = 0; nline < Pmapsize; ++nline) { | |||
| if(loadline(file, &tmp[0]) != 0) | |||
| return 2; | |||
| if(sscanf(&tmp[0], "%d", &x) == 0) | |||
| x = -1; | |||
| Pmapping[nline] = x; | |||
| } | |||
| Pmappingenabled = 1; | |||
| } | |||
| else { | |||
| Pmappingenabled = 0; | |||
| Pmapping[0] = 0; | |||
| Pmapsize = 1; | |||
| } | |||
| fclose(file); | |||
| return 0; | |||
| } | |||
| void Microtonal::add2XML(XMLwrapper *xml) const | |||
| { | |||
| xml->addparstr("name", (char *) Pname); | |||
| xml->addparstr("comment", (char *) Pcomment); | |||
| xml->addparbool("invert_up_down", Pinvertupdown); | |||
| xml->addpar("invert_up_down_center", Pinvertupdowncenter); | |||
| xml->addparbool("enabled", Penabled); | |||
| xml->addpar("global_fine_detune", Pglobalfinedetune); | |||
| xml->addpar("a_note", PAnote); | |||
| xml->addparreal("a_freq", PAfreq); | |||
| if((Penabled == 0) && (xml->minimal)) | |||
| return; | |||
| xml->beginbranch("SCALE"); | |||
| xml->addpar("scale_shift", Pscaleshift); | |||
| xml->addpar("first_key", Pfirstkey); | |||
| xml->addpar("last_key", Plastkey); | |||
| xml->addpar("middle_note", Pmiddlenote); | |||
| xml->beginbranch("OCTAVE"); | |||
| xml->addpar("octave_size", octavesize); | |||
| for(int i = 0; i < octavesize; ++i) { | |||
| xml->beginbranch("DEGREE", i); | |||
| if(octave[i].type == 1) | |||
| xml->addparreal("cents", octave[i].tuning); | |||
| ; | |||
| if(octave[i].type == 2) { | |||
| xml->addpar("numerator", octave[i].x1); | |||
| xml->addpar("denominator", octave[i].x2); | |||
| } | |||
| xml->endbranch(); | |||
| } | |||
| xml->endbranch(); | |||
| xml->beginbranch("KEYBOARD_MAPPING"); | |||
| xml->addpar("map_size", Pmapsize); | |||
| xml->addpar("mapping_enabled", Pmappingenabled); | |||
| for(int i = 0; i < Pmapsize; ++i) { | |||
| xml->beginbranch("KEYMAP", i); | |||
| xml->addpar("degree", Pmapping[i]); | |||
| xml->endbranch(); | |||
| } | |||
| xml->endbranch(); | |||
| xml->endbranch(); | |||
| } | |||
| void Microtonal::getfromXML(XMLwrapper *xml) | |||
| { | |||
| xml->getparstr("name", (char *) Pname, MICROTONAL_MAX_NAME_LEN); | |||
| xml->getparstr("comment", (char *) Pcomment, MICROTONAL_MAX_NAME_LEN); | |||
| Pinvertupdown = xml->getparbool("invert_up_down", Pinvertupdown); | |||
| Pinvertupdowncenter = xml->getpar127("invert_up_down_center", | |||
| Pinvertupdowncenter); | |||
| Penabled = xml->getparbool("enabled", Penabled); | |||
| Pglobalfinedetune = xml->getpar127("global_fine_detune", Pglobalfinedetune); | |||
| PAnote = xml->getpar127("a_note", PAnote); | |||
| PAfreq = xml->getparreal("a_freq", PAfreq, 1.0f, 10000.0f); | |||
| if(xml->enterbranch("SCALE")) { | |||
| Pscaleshift = xml->getpar127("scale_shift", Pscaleshift); | |||
| Pfirstkey = xml->getpar127("first_key", Pfirstkey); | |||
| Plastkey = xml->getpar127("last_key", Plastkey); | |||
| Pmiddlenote = xml->getpar127("middle_note", Pmiddlenote); | |||
| if(xml->enterbranch("OCTAVE")) { | |||
| octavesize = xml->getpar127("octave_size", octavesize); | |||
| for(int i = 0; i < octavesize; ++i) { | |||
| if(xml->enterbranch("DEGREE", i) == 0) | |||
| continue; | |||
| octave[i].x2 = 0; | |||
| octave[i].tuning = xml->getparreal("cents", octave[i].tuning); | |||
| octave[i].x1 = xml->getpar127("numerator", octave[i].x1); | |||
| octave[i].x2 = xml->getpar127("denominator", octave[i].x2); | |||
| if(octave[i].x2 != 0) | |||
| octave[i].type = 2; | |||
| else { | |||
| octave[i].type = 1; | |||
| //populate fields for display | |||
| float x = logf(octave[i].tuning) / LOG_2 * 1200.0f; | |||
| octave[i].x1 = (int) floor(x); | |||
| octave[i].x2 = (int) (floor(fmodf(x, 1.0f) * 1e6)); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| if(xml->enterbranch("KEYBOARD_MAPPING")) { | |||
| Pmapsize = xml->getpar127("map_size", Pmapsize); | |||
| Pmappingenabled = xml->getpar127("mapping_enabled", Pmappingenabled); | |||
| for(int i = 0; i < Pmapsize; ++i) { | |||
| if(xml->enterbranch("KEYMAP", i) == 0) | |||
| continue; | |||
| Pmapping[i] = xml->getpar127("degree", Pmapping[i]); | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| xml->exitbranch(); | |||
| } | |||
| } | |||
| int Microtonal::saveXML(const char *filename) const | |||
| { | |||
| XMLwrapper *xml = new XMLwrapper(); | |||
| xml->beginbranch("MICROTONAL"); | |||
| add2XML(xml); | |||
| xml->endbranch(); | |||
| int result = xml->saveXMLfile(filename); | |||
| delete (xml); | |||
| return result; | |||
| } | |||
| int Microtonal::loadXML(const char *filename) | |||
| { | |||
| XMLwrapper *xml = new XMLwrapper(); | |||
| if(xml->loadXMLfile(filename) < 0) { | |||
| delete (xml); | |||
| return -1; | |||
| } | |||
| if(xml->enterbranch("MICROTONAL") == 0) | |||
| return -10; | |||
| getfromXML(xml); | |||
| xml->exitbranch(); | |||
| delete (xml); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,134 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Microtonal.h - Tuning settings and microtonal capabilities | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef MICROTONAL_H | |||
| #define MICROTONAL_H | |||
| #include "../globals.h" | |||
| #include "XMLwrapper.h" | |||
| #define MAX_OCTAVE_SIZE 128 | |||
| #define MICROTONAL_MAX_NAME_LEN 120 | |||
| #include <stdio.h> | |||
| /**Tuning settings and microtonal capabilities*/ | |||
| class Microtonal | |||
| { | |||
| public: | |||
| /**Constructor*/ | |||
| Microtonal(); | |||
| /**Destructor*/ | |||
| ~Microtonal(); | |||
| void defaults(); | |||
| /**Calculates the frequency for a given note | |||
| */ | |||
| float getnotefreq(int note, int keyshift) const; | |||
| //Parameters | |||
| /**if the keys are inversed (the pitch is lower to keys from the right direction)*/ | |||
| unsigned char Pinvertupdown; | |||
| /**the central key of the inversion*/ | |||
| unsigned char Pinvertupdowncenter; | |||
| /**0 for 12 key temperate scale, 1 for microtonal*/ | |||
| unsigned char Penabled; | |||
| /**the note of "A" key*/ | |||
| unsigned char PAnote; | |||
| /**the frequency of the "A" note*/ | |||
| float PAfreq; | |||
| /**if the scale is "tuned" to a note, you can tune to other note*/ | |||
| unsigned char Pscaleshift; | |||
| //first and last key (to retune) | |||
| unsigned char Pfirstkey; | |||
| unsigned char Plastkey; | |||
| /**The middle note where scale degree 0 is mapped to*/ | |||
| unsigned char Pmiddlenote; | |||
| /**Map size*/ | |||
| unsigned char Pmapsize; | |||
| /**Mapping ON/OFF*/ | |||
| unsigned char Pmappingenabled; | |||
| /**Mapping (keys)*/ | |||
| short int Pmapping[128]; | |||
| /**Fine detune to be applied to all notes*/ | |||
| unsigned char Pglobalfinedetune; | |||
| // Functions | |||
| /** Return the current octave size*/ | |||
| unsigned char getoctavesize() const; | |||
| /**Convert tunning to string*/ | |||
| void tuningtoline(int n, char *line, int maxn); | |||
| /**load the tunnings from a .scl file*/ | |||
| int loadscl(const char *filename); | |||
| /**load the mapping from .kbm file*/ | |||
| int loadkbm(const char *filename); | |||
| /**Load text into the internal tunings | |||
| * | |||
| *\todo better description*/ | |||
| int texttotunings(const char *text); | |||
| /**Load text into the internal mappings | |||
| * | |||
| *\todo better description*/ | |||
| void texttomapping(const char *text); | |||
| /**Name of Microtonal tuning*/ | |||
| unsigned char *Pname; | |||
| /**Comment about the tuning*/ | |||
| unsigned char *Pcomment; | |||
| void add2XML(XMLwrapper *xml) const; | |||
| void getfromXML(XMLwrapper *xml); | |||
| int saveXML(const char *filename) const; | |||
| int loadXML(const char *filename); | |||
| //simple operators primarily for debug | |||
| bool operator==(const Microtonal µ) const; | |||
| bool operator!=(const Microtonal µ) const; | |||
| private: | |||
| int linetotunings(unsigned int nline, const char *line); | |||
| int loadline(FILE *file, char *line); //loads a line from the text file, while ignoring the lines beggining with "!" | |||
| unsigned char octavesize; | |||
| struct { | |||
| unsigned char type; //1 for cents or 2 for division | |||
| // the real tuning (eg. +1.05946f for one halftone) | |||
| // or 2.0f for one octave | |||
| float tuning; | |||
| //the real tunning is x1/x2 | |||
| unsigned int x1, x2; | |||
| } octave[MAX_OCTAVE_SIZE], tmpoctave[MAX_OCTAVE_SIZE]; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,201 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| Part.h - Part implementation | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| 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 (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #ifndef PART_H | |||
| #define PART_H | |||
| #define MAX_INFO_TEXT_SIZE 1000 | |||
| #include "../globals.h" | |||
| #include "../Params/Controller.h" | |||
| #include "../Misc/Microtonal.h" | |||
| #include <list> // For the monomemnotes list. | |||
| class EffectMgr; | |||
| class ADnoteParameters; | |||
| class SUBnoteParameters; | |||
| class PADnoteParameters; | |||
| class SynthNote; | |||
| class XMLWrapper; | |||
| class FFTwrapper; | |||
| /** Part implementation*/ | |||
| class Part | |||
| { | |||
| public: | |||
| /**Constructor | |||
| * @param microtonal_ Pointer to the microtonal object | |||
| * @param fft_ Pointer to the FFTwrapper | |||
| * @param mutex_ Pointer to the master pthread_mutex_t*/ | |||
| Part(Microtonal *microtonal_, FFTwrapper *fft_, pthread_mutex_t *mutex_); | |||
| /**Destructor*/ | |||
| ~Part(); | |||
| // Midi commands implemented | |||
| void NoteOn(unsigned char note, | |||
| unsigned char velocity, | |||
| int masterkeyshift); | |||
| void NoteOff(unsigned char note); | |||
| void PolyphonicAftertouch(unsigned char note, | |||
| unsigned char velocity, | |||
| int masterkeyshift); | |||
| void AllNotesOff(); //panic | |||
| void SetController(unsigned int type, int par); | |||
| void RelaseSustainedKeys(); //this is called when the sustain pedal is relased | |||
| void RelaseAllKeys(); //this is called on AllNotesOff controller | |||
| /* The synthesizer part output */ | |||
| void ComputePartSmps(); //Part output | |||
| //instrumentonly: 0 - save all, 1 - save only instrumnet, 2 - save only instrument without the name(used in bank) | |||
| //saves the instrument settings to a XML file | |||
| //returns 0 for ok or <0 if there is an error | |||
| int saveXML(const char *filename); | |||
| int loadXMLinstrument(const char *filename); | |||
| void add2XML(XMLwrapper *xml); | |||
| void add2XMLinstrument(XMLwrapper *xml); | |||
| void defaults(); | |||
| void defaultsinstrument(); | |||
| void applyparameters(bool lockmutex = true); | |||
| void getfromXML(XMLwrapper *xml); | |||
| void getfromXMLinstrument(XMLwrapper *xml); | |||
| void cleanup(bool final = false); | |||
| //the part's kit | |||
| struct { | |||
| unsigned char Penabled, Pmuted, Pminkey, Pmaxkey; | |||
| unsigned char *Pname; | |||
| unsigned char Padenabled, Psubenabled, Ppadenabled; | |||
| unsigned char Psendtoparteffect; | |||
| ADnoteParameters *adpars; | |||
| SUBnoteParameters *subpars; | |||
| PADnoteParameters *padpars; | |||
| } kit[NUM_KIT_ITEMS]; | |||
| //Part parameters | |||
| void setkeylimit(unsigned char Pkeylimit); | |||
| void setkititemstatus(int kititem, int Penabled_); | |||
| unsigned char Penabled; /**<if the part is enabled*/ | |||
| unsigned char Pvolume; /**<part volume*/ | |||
| unsigned char Pminkey; /**<the minimum key that the part receives noteon messages*/ | |||
| unsigned char Pmaxkey; //the maximum key that the part receives noteon messages | |||
| void setPvolume(char Pvolume); | |||
| unsigned char Pkeyshift; //Part keyshift | |||
| unsigned char Prcvchn; //from what midi channel it receive commnads | |||
| unsigned char Ppanning; //part panning | |||
| void setPpanning(char Ppanning); | |||
| unsigned char Pvelsns; //velocity sensing (amplitude velocity scale) | |||
| unsigned char Pveloffs; //velocity offset | |||
| unsigned char Pnoteon; //if the part receives NoteOn messages | |||
| unsigned char Pkitmode; //if the kitmode is enabled | |||
| unsigned char Pdrummode; //if all keys are mapped and the system is 12tET (used for drums) | |||
| unsigned char Ppolymode; //Part mode - 0=monophonic , 1=polyphonic | |||
| unsigned char Plegatomode; // 0=normal, 1=legato | |||
| unsigned char Pkeylimit; //how many keys are alowed to be played same time (0=off), the older will be relased | |||
| unsigned char *Pname; //name of the instrument | |||
| struct { //instrument additional information | |||
| unsigned char Ptype; | |||
| unsigned char Pauthor[MAX_INFO_TEXT_SIZE + 1]; | |||
| unsigned char Pcomments[MAX_INFO_TEXT_SIZE + 1]; | |||
| } info; | |||
| float *partoutl; //Left channel output of the part | |||
| float *partoutr; //Right channel output of the part | |||
| float *partfxinputl[NUM_PART_EFX + 1], //Left and right signal that pass thru part effects; | |||
| *partfxinputr[NUM_PART_EFX + 1]; //partfxinput l/r [NUM_PART_EFX] is for "no effect" buffer | |||
| enum NoteStatus { | |||
| KEY_OFF, KEY_PLAYING, KEY_RELASED_AND_SUSTAINED, KEY_RELASED | |||
| }; | |||
| float volume, oldvolumel, oldvolumer; //this is applied by Master | |||
| float panning; //this is applied by Master, too | |||
| Controller ctl; //Part controllers | |||
| EffectMgr *partefx[NUM_PART_EFX]; //insertion part effects (they are part of the instrument) | |||
| unsigned char Pefxroute[NUM_PART_EFX]; //how the effect's output is routed(to next effect/to out) | |||
| bool Pefxbypass[NUM_PART_EFX]; //if the effects are bypassed | |||
| pthread_mutex_t *mutex; | |||
| pthread_mutex_t load_mutex; | |||
| int lastnote; | |||
| private: | |||
| void RunNote(unsigned k); | |||
| void KillNotePos(int pos); | |||
| void RelaseNotePos(int pos); | |||
| void MonoMemRenote(); // MonoMem stuff. | |||
| int killallnotes; //is set to 1 if I want to kill all notes | |||
| struct PartNotes { | |||
| NoteStatus status; | |||
| int note; //if there is no note playing, the "note"=-1 | |||
| int itemsplaying; | |||
| struct { | |||
| SynthNote *adnote, | |||
| *subnote, | |||
| *padnote; | |||
| int sendtoparteffect; | |||
| } kititem[NUM_KIT_ITEMS]; | |||
| int time; | |||
| }; | |||
| int lastpos, lastposb; // To keep track of previously used pos and posb. | |||
| bool lastlegatomodevalid; // To keep track of previous legatomodevalid. | |||
| // MonoMem stuff | |||
| std::list<unsigned char> monomemnotes; // A list to remember held notes. | |||
| struct { | |||
| unsigned char velocity; | |||
| int mkeyshift; // I'm not sure masterkeyshift should be remembered. | |||
| } monomem[256]; | |||
| /* 256 is to cover all possible note values. | |||
| monomem[] is used in conjunction with the list to | |||
| store the velocity and masterkeyshift values of a given note (the list only store note values). | |||
| For example 'monomem[note].velocity' would be the velocity value of the note 'note'.*/ | |||
| PartNotes partnote[POLIPHONY]; | |||
| float oldfreq; //this is used for portamento | |||
| Microtonal *microtonal; | |||
| FFTwrapper *fft; | |||
| }; | |||
| #endif | |||