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