| @@ -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 | |||||