Browse Source

Add carla-native code

tags/1.9.4
falkTX 11 years ago
parent
commit
60e8c5ce53
100 changed files with 62950 additions and 0 deletions
  1. +17381
    -0
      source/backend/native/3bandeq/DistrhoArtwork3BandEQ.cpp
  2. +40
    -0
      source/backend/native/3bandeq/DistrhoArtwork3BandEQ.hpp
  3. +260
    -0
      source/backend/native/3bandeq/DistrhoPlugin3BandEQ.cpp
  4. +107
    -0
      source/backend/native/3bandeq/DistrhoPlugin3BandEQ.hpp
  5. +45
    -0
      source/backend/native/3bandeq/DistrhoPluginInfo.h
  6. +229
    -0
      source/backend/native/3bandeq/DistrhoUI3BandEQ.cpp
  7. +80
    -0
      source/backend/native/3bandeq/DistrhoUI3BandEQ.hpp
  8. BIN
      source/backend/native/3bandeq/artwork/about.png
  9. BIN
      source/backend/native/3bandeq/artwork/aboutButtonHover.png
  10. BIN
      source/backend/native/3bandeq/artwork/aboutButtonNormal.png
  11. BIN
      source/backend/native/3bandeq/artwork/background.png
  12. BIN
      source/backend/native/3bandeq/artwork/knob.png
  13. BIN
      source/backend/native/3bandeq/artwork/slider.png
  14. +17381
    -0
      source/backend/native/3bandsplitter/DistrhoArtwork3BandSplitter.cpp
  15. +40
    -0
      source/backend/native/3bandsplitter/DistrhoArtwork3BandSplitter.hpp
  16. +268
    -0
      source/backend/native/3bandsplitter/DistrhoPlugin3BandSplitter.cpp
  17. +102
    -0
      source/backend/native/3bandsplitter/DistrhoPlugin3BandSplitter.hpp
  18. +34
    -0
      source/backend/native/3bandsplitter/DistrhoPluginInfo.h
  19. +229
    -0
      source/backend/native/3bandsplitter/DistrhoUI3BandSplitter.cpp
  20. +76
    -0
      source/backend/native/3bandsplitter/DistrhoUI3BandSplitter.hpp
  21. BIN
      source/backend/native/3bandsplitter/artwork/about.png
  22. BIN
      source/backend/native/3bandsplitter/artwork/aboutButtonHover.png
  23. BIN
      source/backend/native/3bandsplitter/artwork/aboutButtonNormal.png
  24. BIN
      source/backend/native/3bandsplitter/artwork/background.png
  25. BIN
      source/backend/native/3bandsplitter/artwork/knob.png
  26. BIN
      source/backend/native/3bandsplitter/artwork/slider.png
  27. +96
    -0
      source/backend/native/bypass.c
  28. +58
    -0
      source/backend/native/distrho-3bandeq.cpp
  29. +58
    -0
      source/backend/native/distrho-3bandsplitter.cpp
  30. +58
    -0
      source/backend/native/distrho-pingpongpan.cpp
  31. +444
    -0
      source/backend/native/distrho/DistrhoPluginCarla.cpp
  32. +94
    -0
      source/backend/native/midi-split.cpp
  33. +14223
    -0
      source/backend/native/pingpongpan/DistrhoArtworkPingPongPan.cpp
  34. +35
    -0
      source/backend/native/pingpongpan/DistrhoArtworkPingPongPan.hpp
  35. +34
    -0
      source/backend/native/pingpongpan/DistrhoPluginInfo.h
  36. +165
    -0
      source/backend/native/pingpongpan/DistrhoPluginPingPongPan.cpp
  37. +93
    -0
      source/backend/native/pingpongpan/DistrhoPluginPingPongPan.hpp
  38. +138
    -0
      source/backend/native/pingpongpan/DistrhoUIPingPongPan.cpp
  39. +69
    -0
      source/backend/native/pingpongpan/DistrhoUIPingPongPan.hpp
  40. BIN
      source/backend/native/pingpongpan/artwork/about.png
  41. BIN
      source/backend/native/pingpongpan/artwork/aboutButtonHover.png
  42. BIN
      source/backend/native/pingpongpan/artwork/aboutButtonNormal.png
  43. BIN
      source/backend/native/pingpongpan/artwork/background.png
  44. BIN
      source/backend/native/pingpongpan/artwork/knob.png
  45. +51
    -0
      source/backend/native/zynaddsubfx-src.cpp
  46. +353
    -0
      source/backend/native/zynaddsubfx.cpp
  47. +366
    -0
      source/backend/native/zynaddsubfx/CMakeLists.txt
  48. +396
    -0
      source/backend/native/zynaddsubfx/DSP/AnalogFilter.cpp
  49. +85
    -0
      source/backend/native/zynaddsubfx/DSP/AnalogFilter.h
  50. +9
    -0
      source/backend/native/zynaddsubfx/DSP/CMakeLists.txt
  51. +85
    -0
      source/backend/native/zynaddsubfx/DSP/FFTwrapper.cpp
  52. +52
    -0
      source/backend/native/zynaddsubfx/DSP/FFTwrapper.h
  53. +62
    -0
      source/backend/native/zynaddsubfx/DSP/Filter.cpp
  54. +45
    -0
      source/backend/native/zynaddsubfx/DSP/Filter.h
  55. +231
    -0
      source/backend/native/zynaddsubfx/DSP/FormantFilter.cpp
  56. +66
    -0
      source/backend/native/zynaddsubfx/DSP/FormantFilter.h
  57. +178
    -0
      source/backend/native/zynaddsubfx/DSP/SVFilter.cpp
  58. +69
    -0
      source/backend/native/zynaddsubfx/DSP/SVFilter.h
  59. +198
    -0
      source/backend/native/zynaddsubfx/DSP/Unison.cpp
  60. +73
    -0
      source/backend/native/zynaddsubfx/DSP/Unison.h
  61. +235
    -0
      source/backend/native/zynaddsubfx/Effects/Alienwah.cpp
  62. +80
    -0
      source/backend/native/zynaddsubfx/Effects/Alienwah.h
  63. +14
    -0
      source/backend/native/zynaddsubfx/Effects/CMakeLists.txt
  64. +268
    -0
      source/backend/native/zynaddsubfx/Effects/Chorus.cpp
  65. +106
    -0
      source/backend/native/zynaddsubfx/Effects/Chorus.h
  66. +245
    -0
      source/backend/native/zynaddsubfx/Effects/Distorsion.cpp
  67. +61
    -0
      source/backend/native/zynaddsubfx/Effects/Distorsion.h
  68. +311
    -0
      source/backend/native/zynaddsubfx/Effects/DynamicFilter.cpp
  69. +65
    -0
      source/backend/native/zynaddsubfx/Effects/DynamicFilter.h
  70. +198
    -0
      source/backend/native/zynaddsubfx/Effects/EQ.cpp
  71. +55
    -0
      source/backend/native/zynaddsubfx/Effects/EQ.h
  72. +231
    -0
      source/backend/native/zynaddsubfx/Effects/Echo.cpp
  73. +104
    -0
      source/backend/native/zynaddsubfx/Effects/Echo.h
  74. +62
    -0
      source/backend/native/zynaddsubfx/Effects/Effect.cpp
  75. +105
    -0
      source/backend/native/zynaddsubfx/Effects/Effect.h
  76. +111
    -0
      source/backend/native/zynaddsubfx/Effects/EffectLFO.cpp
  77. +50
    -0
      source/backend/native/zynaddsubfx/Effects/EffectLFO.h
  78. +311
    -0
      source/backend/native/zynaddsubfx/Effects/EffectMgr.cpp
  79. +86
    -0
      source/backend/native/zynaddsubfx/Effects/EffectMgr.h
  80. +462
    -0
      source/backend/native/zynaddsubfx/Effects/Phaser.cpp
  81. +98
    -0
      source/backend/native/zynaddsubfx/Effects/Phaser.h
  82. +498
    -0
      source/backend/native/zynaddsubfx/Effects/Reverb.cpp
  83. +97
    -0
      source/backend/native/zynaddsubfx/Effects/Reverb.h
  84. +176
    -0
      source/backend/native/zynaddsubfx/Makefile
  85. +469
    -0
      source/backend/native/zynaddsubfx/Misc/Bank.cpp
  86. +103
    -0
      source/backend/native/zynaddsubfx/Misc/Bank.h
  87. +28
    -0
      source/backend/native/zynaddsubfx/Misc/CMakeLists.txt
  88. +300
    -0
      source/backend/native/zynaddsubfx/Misc/Config.cpp
  89. +73
    -0
      source/backend/native/zynaddsubfx/Misc/Config.h
  90. +99
    -0
      source/backend/native/zynaddsubfx/Misc/Control.h
  91. +121
    -0
      source/backend/native/zynaddsubfx/Misc/Dump.cpp
  92. +63
    -0
      source/backend/native/zynaddsubfx/Misc/Dump.h
  93. +103
    -0
      source/backend/native/zynaddsubfx/Misc/LASHClient.cpp
  94. +63
    -0
      source/backend/native/zynaddsubfx/Misc/LASHClient.h
  95. +797
    -0
      source/backend/native/zynaddsubfx/Misc/Master.cpp
  96. +175
    -0
      source/backend/native/zynaddsubfx/Misc/Master.h
  97. +694
    -0
      source/backend/native/zynaddsubfx/Misc/Microtonal.cpp
  98. +134
    -0
      source/backend/native/zynaddsubfx/Misc/Microtonal.h
  99. +1342
    -0
      source/backend/native/zynaddsubfx/Misc/Part.cpp
  100. +201
    -0
      source/backend/native/zynaddsubfx/Misc/Part.h

+ 17381
- 0
source/backend/native/3bandeq/DistrhoArtwork3BandEQ.cpp
File diff suppressed because it is too large
View File


+ 40
- 0
source/backend/native/3bandeq/DistrhoArtwork3BandEQ.hpp View File

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


+ 260
- 0
source/backend/native/3bandeq/DistrhoPlugin3BandEQ.cpp View File

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

+ 107
- 0
source/backend/native/3bandeq/DistrhoPlugin3BandEQ.hpp View File

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

+ 45
- 0
source/backend/native/3bandeq/DistrhoPluginInfo.h View File

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

+ 229
- 0
source/backend/native/3bandeq/DistrhoUI3BandEQ.cpp View File

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

+ 80
- 0
source/backend/native/3bandeq/DistrhoUI3BandEQ.hpp View File

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

BIN
source/backend/native/3bandeq/artwork/about.png View File

Before After
Width: 303  |  Height: 190  |  Size: 269KB

BIN
source/backend/native/3bandeq/artwork/aboutButtonHover.png View File

Before After
Width: 100  |  Height: 29  |  Size: 4.4KB

BIN
source/backend/native/3bandeq/artwork/aboutButtonNormal.png View File

Before After
Width: 100  |  Height: 29  |  Size: 4.8KB

BIN
source/backend/native/3bandeq/artwork/background.png View File

Before After
Width: 392  |  Height: 372  |  Size: 143KB

BIN
source/backend/native/3bandeq/artwork/knob.png View File

Before After
Width: 62  |  Height: 2480  |  Size: 30KB

BIN
source/backend/native/3bandeq/artwork/slider.png View File

Before After
Width: 50  |  Height: 30  |  Size: 3.4KB

+ 17381
- 0
source/backend/native/3bandsplitter/DistrhoArtwork3BandSplitter.cpp
File diff suppressed because it is too large
View File


+ 40
- 0
source/backend/native/3bandsplitter/DistrhoArtwork3BandSplitter.hpp View File

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


+ 268
- 0
source/backend/native/3bandsplitter/DistrhoPlugin3BandSplitter.cpp View File

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

+ 102
- 0
source/backend/native/3bandsplitter/DistrhoPlugin3BandSplitter.hpp View File

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

+ 34
- 0
source/backend/native/3bandsplitter/DistrhoPluginInfo.h View File

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

+ 229
- 0
source/backend/native/3bandsplitter/DistrhoUI3BandSplitter.cpp View File

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

+ 76
- 0
source/backend/native/3bandsplitter/DistrhoUI3BandSplitter.hpp View File

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

BIN
source/backend/native/3bandsplitter/artwork/about.png View File

Before After
Width: 303  |  Height: 190  |  Size: 63KB

BIN
source/backend/native/3bandsplitter/artwork/aboutButtonHover.png View File

Before After
Width: 100  |  Height: 29  |  Size: 4.4KB

BIN
source/backend/native/3bandsplitter/artwork/aboutButtonNormal.png View File

Before After
Width: 100  |  Height: 29  |  Size: 4.8KB

BIN
source/backend/native/3bandsplitter/artwork/background.png View File

Before After
Width: 392  |  Height: 372  |  Size: 149KB

BIN
source/backend/native/3bandsplitter/artwork/knob.png View File

Before After
Width: 62  |  Height: 2480  |  Size: 30KB

BIN
source/backend/native/3bandsplitter/artwork/slider.png View File

Before After
Width: 50  |  Height: 30  |  Size: 3.4KB

+ 96
- 0
source/backend/native/bypass.c View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 58
- 0
source/backend/native/distrho-3bandeq.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 58
- 0
source/backend/native/distrho-3bandsplitter.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 58
- 0
source/backend/native/distrho-pingpongpan.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 444
- 0
source/backend/native/distrho/DistrhoPluginCarla.cpp View File

@@ -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 &param;
}

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

// -----------------------------------------------------------------------

+ 94
- 0
source/backend/native/midi-split.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 14223
- 0
source/backend/native/pingpongpan/DistrhoArtworkPingPongPan.cpp
File diff suppressed because it is too large
View File


+ 35
- 0
source/backend/native/pingpongpan/DistrhoArtworkPingPongPan.hpp View File

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


+ 34
- 0
source/backend/native/pingpongpan/DistrhoPluginInfo.h View File

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

+ 165
- 0
source/backend/native/pingpongpan/DistrhoPluginPingPongPan.cpp View File

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

+ 93
- 0
source/backend/native/pingpongpan/DistrhoPluginPingPongPan.hpp View File

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

+ 138
- 0
source/backend/native/pingpongpan/DistrhoUIPingPongPan.cpp View File

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

+ 69
- 0
source/backend/native/pingpongpan/DistrhoUIPingPongPan.hpp View File

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

BIN
source/backend/native/pingpongpan/artwork/about.png View File

Before After
Width: 303  |  Height: 190  |  Size: 269KB

BIN
source/backend/native/pingpongpan/artwork/aboutButtonHover.png View File

Before After
Width: 96  |  Height: 25  |  Size: 4.5KB

BIN
source/backend/native/pingpongpan/artwork/aboutButtonNormal.png View File

Before After
Width: 96  |  Height: 25  |  Size: 4.5KB

BIN
source/backend/native/pingpongpan/artwork/background.png View File

Before After
Width: 369  |  Height: 136  |  Size: 51KB

BIN
source/backend/native/pingpongpan/artwork/knob.png View File

Before After
Width: 69  |  Height: 2691  |  Size: 176KB

+ 51
- 0
source/backend/native/zynaddsubfx-src.cpp View File

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

+ 353
- 0
source/backend/native/zynaddsubfx.cpp View File

@@ -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 &param;
}

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);
}

// -----------------------------------------------------------------------

+ 366
- 0
source/backend/native/zynaddsubfx/CMakeLists.txt View File

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

+ 396
- 0
source/backend/native/zynaddsubfx/DSP/AnalogFilter.cpp View File

@@ -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);
}

+ 85
- 0
source/backend/native/zynaddsubfx/DSP/AnalogFilter.h View File

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

+ 9
- 0
source/backend/native/zynaddsubfx/DSP/CMakeLists.txt View File

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

+ 85
- 0
source/backend/native/zynaddsubfx/DSP/FFTwrapper.cpp View File

@@ -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();
}

+ 52
- 0
source/backend/native/zynaddsubfx/DSP/FFTwrapper.h View File

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

+ 62
- 0
source/backend/native/zynaddsubfx/DSP/Filter.cpp View File

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

+ 45
- 0
source/backend/native/zynaddsubfx/DSP/Filter.h View File

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

+ 231
- 0
source/backend/native/zynaddsubfx/DSP/FormantFilter.cpp View File

@@ -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);
}

+ 66
- 0
source/backend/native/zynaddsubfx/DSP/FormantFilter.h View File

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

+ 178
- 0
source/backend/native/zynaddsubfx/DSP/SVFilter.cpp View File

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

+ 69
- 0
source/backend/native/zynaddsubfx/DSP/SVFilter.h View File

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

+ 198
- 0
source/backend/native/zynaddsubfx/DSP/Unison.cpp View File

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

+ 73
- 0
source/backend/native/zynaddsubfx/DSP/Unison.h View File

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

+ 235
- 0
source/backend/native/zynaddsubfx/Effects/Alienwah.cpp View File

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

+ 80
- 0
source/backend/native/zynaddsubfx/Effects/Alienwah.h View File

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

+ 14
- 0
source/backend/native/zynaddsubfx/Effects/CMakeLists.txt View File

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

+ 268
- 0
source/backend/native/zynaddsubfx/Effects/Chorus.cpp View File

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

+ 106
- 0
source/backend/native/zynaddsubfx/Effects/Chorus.h View File

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

+ 245
- 0
source/backend/native/zynaddsubfx/Effects/Distorsion.cpp View File

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

+ 61
- 0
source/backend/native/zynaddsubfx/Effects/Distorsion.h View File

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

+ 311
- 0
source/backend/native/zynaddsubfx/Effects/DynamicFilter.cpp View File

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

+ 65
- 0
source/backend/native/zynaddsubfx/Effects/DynamicFilter.h View File

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

+ 198
- 0
source/backend/native/zynaddsubfx/Effects/EQ.cpp View File

@@ -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);
}

+ 55
- 0
source/backend/native/zynaddsubfx/Effects/EQ.h View File

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

+ 231
- 0
source/backend/native/zynaddsubfx/Effects/Echo.cpp View File

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

+ 104
- 0
source/backend/native/zynaddsubfx/Effects/Echo.h View File

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

+ 62
- 0
source/backend/native/zynaddsubfx/Effects/Effect.cpp View File

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

+ 105
- 0
source/backend/native/zynaddsubfx/Effects/Effect.h View File

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

+ 111
- 0
source/backend/native/zynaddsubfx/Effects/EffectLFO.cpp View File

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

+ 50
- 0
source/backend/native/zynaddsubfx/Effects/EffectLFO.h View File

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

+ 311
- 0
source/backend/native/zynaddsubfx/Effects/EffectMgr.cpp View File

@@ -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();
}

+ 86
- 0
source/backend/native/zynaddsubfx/Effects/EffectMgr.h View File

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

+ 462
- 0
source/backend/native/zynaddsubfx/Effects/Phaser.cpp View File

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

+ 98
- 0
source/backend/native/zynaddsubfx/Effects/Phaser.h View File

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

+ 498
- 0
source/backend/native/zynaddsubfx/Effects/Reverb.cpp View File

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

+ 97
- 0
source/backend/native/zynaddsubfx/Effects/Reverb.h View File

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

+ 176
- 0
source/backend/native/zynaddsubfx/Makefile View File

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

+ 469
- 0
source/backend/native/zynaddsubfx/Misc/Bank.cpp View File

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

+ 103
- 0
source/backend/native/zynaddsubfx/Misc/Bank.h View File

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

+ 28
- 0
source/backend/native/zynaddsubfx/Misc/CMakeLists.txt View File

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

+ 300
- 0
source/backend/native/zynaddsubfx/Misc/Config.cpp View File

@@ -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");
}

+ 73
- 0
source/backend/native/zynaddsubfx/Misc/Config.h View File

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

+ 99
- 0
source/backend/native/zynaddsubfx/Misc/Control.h View File

@@ -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_ */

+ 121
- 0
source/backend/native/zynaddsubfx/Misc/Dump.cpp View File

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

+ 63
- 0
source/backend/native/zynaddsubfx/Misc/Dump.h View File

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

+ 103
- 0
source/backend/native/zynaddsubfx/Misc/LASHClient.cpp View File

@@ -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));
}

+ 63
- 0
source/backend/native/zynaddsubfx/Misc/LASHClient.h View 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

+ 797
- 0
source/backend/native/zynaddsubfx/Misc/Master.cpp View File

@@ -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(&microtonal, 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();
}
}

+ 175
- 0
source/backend/native/zynaddsubfx/Misc/Master.h View File

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

+ 694
- 0
source/backend/native/zynaddsubfx/Misc/Microtonal.cpp View File

@@ -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 &micro) const
{
return !(*this != micro);
}

bool Microtonal::operator!=(const Microtonal &micro) 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;
}

+ 134
- 0
source/backend/native/zynaddsubfx/Misc/Microtonal.h View File

@@ -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 &micro) const;
bool operator!=(const Microtonal &micro) 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

+ 1342
- 0
source/backend/native/zynaddsubfx/Misc/Part.cpp
File diff suppressed because it is too large
View File


+ 201
- 0
source/backend/native/zynaddsubfx/Misc/Part.h View File

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

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save