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