diff options
Diffstat (limited to 'muse/plugins')
23 files changed, 2170 insertions, 0 deletions
diff --git a/muse/plugins/Makefile.am b/muse/plugins/Makefile.am new file mode 100644 index 00000000..fbb995c4 --- /dev/null +++ b/muse/plugins/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = freeverb pandelay doublechorus + +include $(top_srcdir)/common.am + +EXTRA_DIST = plugins-install.am diff --git a/muse/plugins/doublechorus/Makefile.am b/muse/plugins/doublechorus/Makefile.am new file mode 100644 index 00000000..40022184 --- /dev/null +++ b/muse/plugins/doublechorus/Makefile.am @@ -0,0 +1,16 @@ +include $(top_srcdir)/common.am +include $(top_srcdir)/plugins/plugins-install.am + +AM_CXXFLAGS += -O3 -fno-exceptions -fno-rtti -ffast-math + +plugins_LTLIBRARIES = doublechorus.la + +plugins_DATA = + +doublechorus_la_SOURCES = \ + doublechorus.cpp \ + doublechorusmodel.cpp doublechorusmodel.h \ + simplechorusmodel.cpp simplechorusmodel.h +doublechorus_la_LDFLAGS = -module -avoid-version + + diff --git a/muse/plugins/doublechorus/doublechorus.cpp b/muse/plugins/doublechorus/doublechorus.cpp new file mode 100644 index 00000000..27d84336 --- /dev/null +++ b/muse/plugins/doublechorus/doublechorus.cpp @@ -0,0 +1,173 @@ +//========================================================= +// DoubleChorus for MusE +// +// (C) Copyright 2006 Nil Geisweiller +//========================================================= + +#include "doublechorusmodel.h" +#include <stdio.h> + +//--------------------------------------------------------- +// instantiate doublechorus +// Construct a new plugin instance. +//--------------------------------------------------------- + +LADSPA_Handle instantiate(const LADSPA_Descriptor* /*Descriptor*/, + unsigned long samplerate) +{ + return new DoubleChorusModel(samplerate); +} + +//--------------------------------------------------------- +// connect PortTo doublechorus +// Connect a port to a data location. +//--------------------------------------------------------- + +void connect(LADSPA_Handle Instance, unsigned long port, + LADSPA_Data* data) +{ + ((DoubleChorusModel *)Instance)->port[port] = data; +} + +//--------------------------------------------------------- +// activate +//--------------------------------------------------------- + +void activate(LADSPA_Handle instance) +{ + ((DoubleChorusModel *)instance)->activate(); +} + +//--------------------------------------------------------- +// deactivate +//--------------------------------------------------------- + +void deactivate(LADSPA_Handle /*Instance*/) +{ +} + +//--------------------------------------------------------- +// run doublechorus +//--------------------------------------------------------- + +void run(LADSPA_Handle Instance, unsigned long n) +{ + ((DoubleChorusModel *)Instance)->processReplace(n); +} + +//--------------------------------------------------------- +// runAdding doublechorus +// *ADD* the output to the output buffer. +//--------------------------------------------------------- + +void runAdding(LADSPA_Handle Instance, unsigned long n) +{ + ((DoubleChorusModel *)Instance)->processMix(n); +} + +//--------------------------------------------------------- +// set doublechorus RunAddingGain +//--------------------------------------------------------- + +void setGain(LADSPA_Handle /*Instance*/, LADSPA_Data /*Gain*/) +{ + printf("TEST setGain\n"); + // ((DoubleChorusModel *)Instance)->m_fRunAddingGain = Gain; +} + +//--------------------------------------------------------- +// cleanup doublechorus +//--------------------------------------------------------- + +void cleanup(LADSPA_Handle Instance) +{ + delete (DoubleChorusModel *)Instance; +} + +static const char* portNames[] = { + "Input (Left)", + "Input (Right)", + "Output (Left)", + "Output (Right)", + "Pan 1", + "LFOFreq 1", + "Depth 1", + "Pan 2", + "LFOFreq 2", + "Depth 2", + "Dry/Wet" +}; + +LADSPA_PortDescriptor portDescriptors[] = { + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL +}; + +LADSPA_PortRangeHint portRangeHints[] = { + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_HIGH, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_HIGH, MINFREQ, MAXFREQ }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_LOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_LOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_MIDDLE, MINFREQ, MAXFREQ }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_LOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MIDDLE, 0.0, 1.0 }, +}; + +LADSPA_Descriptor descriptor = { + 1051, + "doublechorus1", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "DoubleChorus", + "Nil Geisweiller", + "GPL", + NBRPARAM + 4, + portDescriptors, + portNames, + portRangeHints, + 0, // impl. data + instantiate, + connect, + activate, + run, + runAdding, + setGain, + deactivate, + cleanup +}; + +//--------------------------------------------------------- +// _init +// called automatically when the plugin library is first +// loaded. +//--------------------------------------------------------- +void _init() { +} + +//--------------------------------------------------------- +// _fini +// called automatically when the library is unloaded. +//--------------------------------------------------------- +void _fini() { +} + +//--------------------------------------------------------- +// ladspa_descriptor +// Return a descriptor of the requested plugin type. +//--------------------------------------------------------- +const LADSPA_Descriptor* ladspa_descriptor(unsigned long i) { + return (i == 0) ? &descriptor : 0; +} + diff --git a/muse/plugins/doublechorus/doublechorusmodel.cpp b/muse/plugins/doublechorus/doublechorusmodel.cpp new file mode 100644 index 00000000..01def026 --- /dev/null +++ b/muse/plugins/doublechorus/doublechorusmodel.cpp @@ -0,0 +1,214 @@ +//=========================================================================== +// +// doublechorusmodel +// +// Version 0.0.1 +// +// +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#include "doublechorusmodel.h" + +//--------------------------------------------------------- +// DoubleChorusModel +//--------------------------------------------------------- + +DoubleChorusModel::DoubleChorusModel(unsigned long samplerate) { + _simpleChorus1 = new SimpleChorusModel((float)samplerate); + _simpleChorus2 = new SimpleChorusModel((float)samplerate); + + param[0] = getPan1(); + param[1] = getLFOFreq1(); + param[2] = getDepth1(); + param[3] = getPan2(); + param[4] = getLFOFreq2(); + param[5] = getDepth2(); + param[6] = getDryWet(); +} + +DoubleChorusModel::~DoubleChorusModel() { + delete(_simpleChorus1); + delete(_simpleChorus2); +} + +//--------------------------------------------------------- +// activate +//--------------------------------------------------------- + +void DoubleChorusModel::activate() { + *port[4] = param[0]; + *port[5] = param[1]; + *port[6] = param[2]; + *port[7] = param[3]; + *port[8] = param[4]; + *port[9] = param[5]; + *port[10] = param[6]; +} + +//--------------------------------------------------------- +// processReplace +//--------------------------------------------------------- + +void DoubleChorusModel::processReplace(long n) { + float tmpLeftOutput1; + float tmpRightOutput1; + float tmpLeftOutput2; + float tmpRightOutput2; + //update parameters + if (param[0] != *port[4]) { + param[0] = *port[4]; + setPan1(param[0]); + } + if (param[1] != *port[5]) { + param[1] = *port[5]; + setLFOFreq1(param[1]); + } + if (param[2] != *port[6]) { + param[2] = *port[6]; + setDepth1(param[2]); + } + if (param[3] != *port[7]) { + param[3] = *port[7]; + setPan2(param[3]); + } + if (param[4] != *port[8]) { + param[4] = *port[8]; + setLFOFreq2(param[4]); + } + if (param[5] != *port[9]) { + param[5] = *port[9]; + setDepth2(param[5]); + } + if (param[6] != *port[10]) { + param[6] = *port[10]; + setDryWet(param[6]); + } + //process the effect + for (int i = 0; i < n; ++i) { + _simpleChorus1->process_chorus(port[0][i], port[1][i], + &tmpLeftOutput1, &tmpRightOutput1); + _simpleChorus2->process_chorus(port[0][i], port[1][i], + &tmpLeftOutput2, &tmpRightOutput2); + port[2][i] = _dryWet * (tmpLeftOutput1 + tmpLeftOutput2) + + (1.0 - _dryWet) * port[0][i]; + port[3][i] = _dryWet * (tmpRightOutput1 + tmpRightOutput2) + + (1.0 - _dryWet) * port[1][i]; + } +} + +void DoubleChorusModel::processMix(long n) { + float tmpLeftOutput1; + float tmpRightOutput1; + float tmpLeftOutput2; + float tmpRightOutput2; + //update parameters + if (param[0] != *port[4]) { + param[0] = *port[4]; + setPan1(param[0]); + } + if (param[1] != *port[5]) { + param[1] = *port[5]; + setLFOFreq1(param[1]); + } + if (param[2] != *port[6]) { + param[2] = *port[6]; + setDepth1(param[2]); + } + if (param[3] != *port[7]) { + param[3] = *port[7]; + setPan2(param[3]); + } + if (param[4] != *port[8]) { + param[4] = *port[8]; + setLFOFreq2(param[4]); + } + if (param[5] != *port[9]) { + param[5] = *port[9]; + setDepth2(param[5]); + } + if (param[6] != *port[10]) { + param[6] = *port[10]; + setDryWet(param[6]); + } + //process the effect + for (int i = 0; i < n; ++i) { + _simpleChorus1->process_chorus(port[0][i], port[1][i], + &tmpLeftOutput1, &tmpRightOutput1); + _simpleChorus2->process_chorus(port[0][i], port[1][i], + &tmpLeftOutput2, &tmpRightOutput2); + port[2][i] += _dryWet * (tmpLeftOutput1 + tmpLeftOutput2) + + (1.0 - _dryWet) * port[0][i]; + port[3][i] += _dryWet * (tmpRightOutput1 + tmpRightOutput2) + + (1.0 - _dryWet) * port[1][i]; + } +} + +//------------------------------------------------------------------ +// set parameters +//------------------------------------------------------------------ +void DoubleChorusModel::setPan1(float value) { + _simpleChorus1->setPan(value); +} +void DoubleChorusModel::setLFOFreq1(float value) { + _simpleChorus1->setLFOFreq(value); +} +void DoubleChorusModel::setDepth1(float value) { + _simpleChorus1->setDepth(value); +} +void DoubleChorusModel::setPan2(float value) { + _simpleChorus2->setPan(value); +} +void DoubleChorusModel::setLFOFreq2(float value) { + _simpleChorus2->setLFOFreq(value); +} +void DoubleChorusModel::setDepth2(float value) { + _simpleChorus2->setDepth(value); +} +void DoubleChorusModel::setDryWet(float value) { + _dryWet = value; +} + +//---------------------------------------------------------------- +// get parameters +//---------------------------------------------------------------- +float DoubleChorusModel::getPan1() { + return _simpleChorus1->getPan(); +} +float DoubleChorusModel::getLFOFreq1() { + return _simpleChorus1->getLFOFreq(); +} +float DoubleChorusModel::getDepth1() { + return _simpleChorus1->getDepth(); +} +float DoubleChorusModel::getPan2() { + return _simpleChorus2->getPan(); +} +float DoubleChorusModel::getLFOFreq2() { + return _simpleChorus2->getLFOFreq(); +} +float DoubleChorusModel::getDepth2() { + return _simpleChorus2->getDepth(); +} +float DoubleChorusModel::getDryWet() { + return _dryWet; +} diff --git a/muse/plugins/doublechorus/doublechorusmodel.h b/muse/plugins/doublechorus/doublechorusmodel.h new file mode 100644 index 00000000..40ce9f3f --- /dev/null +++ b/muse/plugins/doublechorus/doublechorusmodel.h @@ -0,0 +1,72 @@ +//=========================================================================== +// +// doublechorusmodel +// +// Version 0.0.1 +// +// +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#ifndef __DOUBLECHORUSMODEL_H +#define __DOUBLECHORUSMODEL_H + +#include "simplechorusmodel.h" +#include "../../muse/ladspa.h" + +#define NBRPARAM 7 + +class SimpleChorusModel; + +class DoubleChorusModel { + SimpleChorusModel* _simpleChorus1; + SimpleChorusModel* _simpleChorus2; + + float _dryWet; //0.0 : dry, 1.0 : wet + + public: + LADSPA_Data* port[NBRPARAM + 4]; + float param[NBRPARAM]; + + DoubleChorusModel(unsigned long samplerate); + ~DoubleChorusModel(); + void processMix(long numsamples); + void processReplace(long numsamples); + void setPan1(float value); + void setLFOFreq1(float value); + void setDepth1(float value); + void setPan2(float value); + void setLFOFreq2(float value); + void setDepth2(float value); + void setDryWet(float value); + float getPan1(); + float getLFOFreq1(); + float getDepth1(); + float getPan2(); + float getLFOFreq2(); + float getDepth2(); + float getDryWet(); + + void activate(); +}; + +#endif diff --git a/muse/plugins/doublechorus/simplechorusmodel.cpp b/muse/plugins/doublechorus/simplechorusmodel.cpp new file mode 100644 index 00000000..72015465 --- /dev/null +++ b/muse/plugins/doublechorus/simplechorusmodel.cpp @@ -0,0 +1,157 @@ +//=========================================================================== +// +// simplechorus +// +// Version 0.0.1 +// +// +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#include "simplechorusmodel.h" +#include <math.h> +#include <stdio.h> + +#define ABS(x) (x>=0?x:-x) + +// Linearly interpolate [ = a * (1 - f) + b * f] +inline float lin_interp(float f, float a, float b) { + return a + f * (b - a); +} + +// Cubic interpolation function +inline float cube_interp(const float fr, + const float inm1, + const float in, + const float inp1, + const float inp2) { + return in + 0.5f * fr * (inp1 - inm1 + + fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 + + fr * (3.0f * (in - inp1) - inm1 + inp2))); +} + +float SimpleChorusModel::sinus[MAXSINUSRESOLUTION]; +int SimpleChorusModel::useCount = 0; + +SimpleChorusModel::SimpleChorusModel(float samplerate) { + _sampleRate = samplerate; + //sinus + if (useCount++ == 0) + for(int i = 0; i < MAXSINUSRESOLUTION; i++) + sinus[i] = (float)(sin(((double)i * 2.0 * M_PI) / + (double)MAXSINUSRESOLUTION)); + _index = 0.0; + //init buffer + for(int i = 0; i < MAXBUFFERLENGTH; i++) { + _leftBuffer[i] = 0.0; + _rightBuffer[i] = 0.0; + } + _position = 0; + //initial parameters + _pan = 0.5; + _LFOFreq = 1.0; + _depth = 0.5; + setChorus(); +} + +SimpleChorusModel::~SimpleChorusModel() { +} + +void SimpleChorusModel::process_chorus(float leftInput, float rightInput, + float* leftOutput, float* rightOutput) { + float ocsDiff; + + _ocsDistance = _depthAmp * sinus[(int)_index]; + + ocsDiff = _ocsDistance - floorf(_ocsDistance); + + _past_position_left = MAXBUFFERLENGTH //to be sure that _past_position_left>0 + + _position - _leftMidDistance + (int)_ocsDistance; + _past_position_right = MAXBUFFERLENGTH + + _position - _rightMidDistance + (int)_ocsDistance; + + *leftOutput = _leftAmp * + lin_interp(ocsDiff, _leftBuffer[_past_position_left%MAXBUFFERLENGTH], + _leftBuffer[(_past_position_left+1)%MAXBUFFERLENGTH]); + *rightOutput = _rightAmp * + lin_interp(ocsDiff, _rightBuffer[_past_position_right%MAXBUFFERLENGTH], + _rightBuffer[(_past_position_right+1)%MAXBUFFERLENGTH]); + + _leftBuffer[_position] = leftInput; + _rightBuffer[_position] = rightInput; + + _position++; + _position %= MAXBUFFERLENGTH; + + _index += _inct; + _index = (_index<MAXSINUSRESOLUTION?_index:_index-MAXSINUSRESOLUTION); +} + +void SimpleChorusModel::setPan(float p) { + _pan = p; + setChorus(); +} +void SimpleChorusModel::setLFOFreq(float l) { + _LFOFreq = l; + setChorus(); +} +void SimpleChorusModel::setDepth(float d) { + _depth = d; + setChorus(); +} +void SimpleChorusModel::setSampleRate(float s) { + _sampleRate = s; + setChorus(); +} + +float SimpleChorusModel::getPan() { + return _pan; +} +float SimpleChorusModel::getLFOFreq() { + return _LFOFreq; +} +float SimpleChorusModel::getDepth() { + return _depth; +} + +void SimpleChorusModel::setChorus() { + //inct + _inct = (float)MAXSINUSRESOLUTION/_sampleRate * _LFOFreq; + //left & right amp + _leftAmp = lin_interp(1.0 - _pan, 1.0 - PANAMP, 1.0 + PANAMP); + _rightAmp = lin_interp(_pan, 1.0 - PANAMP, 1.0 + PANAMP); + //left & right midDistance + float leftmdm; //left mid distance in meter + float rightmdm; //right mid distance in meter + leftmdm = MIDSOURCEDISTANCE - EARSDISTANCE * (0.5 - _pan); + rightmdm = MIDSOURCEDISTANCE + EARSDISTANCE * (0.5 - _pan); + + _leftMidDistance = (int)(_sampleRate * leftmdm / SOUNDSPEED); + _rightMidDistance = (int)(_sampleRate * rightmdm / SOUNDSPEED); + + //depthAmp + _depthAmp = + _sampleRate * (MAXDEPTH * _depth) /SOUNDSPEED; + //filter coef + _filterCoef1 = 1 - COEFFILTER; + _filterCoef2 = COEFFILTER; +} diff --git a/muse/plugins/doublechorus/simplechorusmodel.h b/muse/plugins/doublechorus/simplechorusmodel.h new file mode 100644 index 00000000..797e7030 --- /dev/null +++ b/muse/plugins/doublechorus/simplechorusmodel.h @@ -0,0 +1,96 @@ +//=========================================================================== +// +// simplechorus +// +// Version 0.0.1 +// +// +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#ifndef __SIMPLECHORUSMODEL_H +#define __SIMPLECHORUSMODEL_H + +#define MAXBUFFERLENGTH 192000 +#define MAXSINUSRESOLUTION 192000 +#define MINFREQ 0.05 //in Hz +#define MAXFREQ 5.0 //in Hz +#define EARSDISTANCE 0.12 //in meter +#define MIDSOURCEDISTANCE 2.0 //in meter +#define MAXDEPTH 1.0 //in meter, radius +#define SOUNDSPEED 330.0 //in meter per second +#define MINDELAYSEC 0.01 //in second +#define MAXDELAYSEC 1.0 //in second +#define COEFFILTER 0.97576 //0.26795 +#define PANAMP 0.75 +//with cutoff = samplerate/256 +//following (2-cos(x)) - sqrt((2-cos(x))^2 - 1) with x = 2*pi*cutoff/samplerate +//#define M_PI 3.14159265358979 + +class SimpleChorusModel { + private : + //parameters + float _pan; + float _LFOFreq; + float _depth; + //parameter state + float _sampleRate; + float _depthAmp; + float _leftAmp; + float _rightAmp; + float _filterCoef1; + float _filterCoef2; + int _leftMidDistance; //distance of the left micro in samples + int _rightMidDistance; //distance of the right micro in samples + //state + float _inct; + float _index; //time at the scale of sampleRate + float _leftBuffer[MAXBUFFERLENGTH]; + float _rightBuffer[MAXBUFFERLENGTH]; + float _ocsDistance; //in sample, distance of the micro with initial position + int _past_position_left; + int _past_position_right; + int _position; + public : + static int useCount; + static float sinus[MAXSINUSRESOLUTION]; + + + void process_chorus(float leftInput, float rightInput, + float* leftOutput, float* rightOutput); + + void setPan(float); + void setLFOFreq(float); + void setDepth(float); + void setSampleRate(float); + float getPan(); + float getLFOFreq(); + float getDepth(); + + void setChorus(); + + SimpleChorusModel(float samplerate); + ~SimpleChorusModel(); + +}; + +#endif diff --git a/muse/plugins/freeverb/Makefile.am b/muse/plugins/freeverb/Makefile.am new file mode 100644 index 00000000..81dbec2d --- /dev/null +++ b/muse/plugins/freeverb/Makefile.am @@ -0,0 +1,17 @@ +include $(top_srcdir)/common.am +include $(top_srcdir)/plugins/plugins-install.am + +AM_CXXFLAGS += -O3 -fno-exceptions -fno-rtti -ffast-math + +plugins_LTLIBRARIES = freeverb.la + +plugins_DATA = + +freeverb_la_SOURCES = \ + freeverb.cpp \ + revmodel.cpp revmodel.h \ + allpass.h comb.h denormals.h tuning.h +freeverb_la_LDFLAGS = -module -avoid-version + +EXTRA_DIST = readme.txt + diff --git a/muse/plugins/freeverb/allpass.h b/muse/plugins/freeverb/allpass.h new file mode 100644 index 00000000..4eb1c1a0 --- /dev/null +++ b/muse/plugins/freeverb/allpass.h @@ -0,0 +1,50 @@ +// Allpass filter declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _allpass_ +#define _allpass_ +#include "denormals.h" + +//--------------------------------------------------------- +// allpass +//--------------------------------------------------------- + +class allpass + { + float feedback; + float *buffer; + int bufsize; + int bufidx; + + public: + allpass() { bufidx = 0; } + void setbuffer(float *buf, int size) { + buffer = buf; + bufsize = size; + } + float process(float input) { + float bufout = buffer[bufidx]; + undenormalise(bufout); + float output = -input + bufout; + buffer[bufidx] = input + (bufout*feedback); + if (++bufidx >= bufsize) + bufidx = 0; +// bufidx = ++bufidx % bufsize; + return output; + } + void mute() { + for (int i=0; i<bufsize; i++) + buffer[i]=0; + } + void setfeedback(float val) { feedback = val; } + float getfeedback() { return feedback; } + }; + + +// Big to inline - but crucial for speed + + +#endif//_allpass diff --git a/muse/plugins/freeverb/comb.h b/muse/plugins/freeverb/comb.h new file mode 100644 index 00000000..d2e0f871 --- /dev/null +++ b/muse/plugins/freeverb/comb.h @@ -0,0 +1,66 @@ +// Comb filter class declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _comb_ +#define _comb_ + +#include "denormals.h" + + +//--------------------------------------------------------- +// comb +//--------------------------------------------------------- + +class comb + { + float feedback; + float filterstore; + float damp1; + float damp2; + float *buffer; + int bufsize; + int bufidx; + +public: + comb() { + filterstore = 0; + bufidx = 0; + } + void setbuffer(float *buf, int size) { + buffer = buf; + bufsize = size; + } + float process(float input) { + float output = buffer[bufidx]; + undenormalise(output); + filterstore = (output*damp2) + (filterstore*damp1); + undenormalise(filterstore); + buffer[bufidx] = input + (filterstore*feedback); + if (++bufidx >= bufsize) + bufidx = 0; +// bufidx = ++bufidx % bufsize; + return output; + } + void mute() { + for (int i=0; i<bufsize; i++) + buffer[i]=0; + } + void setdamp(float val) { + damp1 = val; + damp2 = 1-val; + } + float getdamp() { return damp1; } + void setfeedback(float val) { feedback = val; } + float getfeedback() { return feedback; } + }; + + +// Big to inline - but crucial for speed + + +#endif //_comb_ + +//ends diff --git a/muse/plugins/freeverb/denormals.h b/muse/plugins/freeverb/denormals.h new file mode 100644 index 00000000..d18412b4 --- /dev/null +++ b/muse/plugins/freeverb/denormals.h @@ -0,0 +1,28 @@ +// Macro for killing denormalled numbers +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// Based on IS_DENORMAL macro by Jon Watte +// This code is public domain + +#ifndef _denormals_ +#define _denormals_ + +// this does not work with at least gcc3.3 and -O2: +// #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f +// +// from Laurent de Soras Paper: Denormal numbers in floating point +// signal processing applications +// (ws) + +#define undenormalise(sample) \ + { \ + float anti_denormal = 1e-18; \ + sample += anti_denormal; \ + sample -= anti_denormal; \ + } + +#endif//_denormals_ + +//ends + diff --git a/muse/plugins/freeverb/freeverb.cpp b/muse/plugins/freeverb/freeverb.cpp new file mode 100644 index 00000000..0385e887 --- /dev/null +++ b/muse/plugins/freeverb/freeverb.cpp @@ -0,0 +1,166 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: freeverb.cpp,v 1.1.1.1 2003/10/27 18:57:03 wschweer Exp $ +// (C) Copyright 2000 Werner Schweer (ws@seh.de) +//========================================================= + +#include "revmodel.h" + +//--------------------------------------------------------- +// instantiateFreeverb +// Construct a new plugin instance. +//--------------------------------------------------------- + +LADSPA_Handle instantiate(const LADSPA_Descriptor* /*Descriptor*/, + unsigned long /* samplerate*/) + { + return new Revmodel; + } + +//--------------------------------------------------------- +// connectPortToFreeverb +// Connect a port to a data location. +//--------------------------------------------------------- + +void connect(LADSPA_Handle Instance, unsigned long port, + LADSPA_Data* data) + { + ((Revmodel *)Instance)->port[port] = data; + } + +//--------------------------------------------------------- +// activate +//--------------------------------------------------------- + +void activate(LADSPA_Handle instance) + { + ((Revmodel *)instance)->activate(); + } + +//--------------------------------------------------------- +// deactivate +//--------------------------------------------------------- + +void deactivate(LADSPA_Handle /*Instance*/) + { + } + +//--------------------------------------------------------- +// runFreeverb +//--------------------------------------------------------- + +void run(LADSPA_Handle Instance, unsigned long n) + { + ((Revmodel*)Instance)->processreplace(n); + } + +//--------------------------------------------------------- +// runAddingFreeverb +// *ADD* the output to the output buffer. +//--------------------------------------------------------- + +void runAdding(LADSPA_Handle Instance, unsigned long n) + { + ((Revmodel*)Instance)->processmix(n); + } + +//--------------------------------------------------------- +// setFreeverbRunAddingGain +//--------------------------------------------------------- + +void setGain(LADSPA_Handle /*Instance*/, LADSPA_Data /*Gain*/) + { +// ((Freeverb *)Instance)->m_fRunAddingGain = Gain; + } + +//--------------------------------------------------------- +// cleanupFreeverb +//--------------------------------------------------------- + +void cleanup(LADSPA_Handle Instance) + { + delete (Revmodel *)Instance; + } + +static const char* portNames[] = { + "Input (Left)", + "Input (Right)", + "Output (Left)", + "Output (Right)", + "Room Size", + "Damping", + "Wet Level", + }; + +LADSPA_PortDescriptor portDescriptors[] = { + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + }; + +LADSPA_PortRangeHint portRangeHints[] = { + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, 0.0, 1.0 }, + }; + +LADSPA_Descriptor descriptor = { + 1050, + "freeverb1", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Freeverb", + "Werner Schweer", + "None", + 7, + portDescriptors, + portNames, + portRangeHints, + 0, // impl. data + instantiate, + connect, + activate, + run, + runAdding, + setGain, + deactivate, + cleanup + }; + +//--------------------------------------------------------- +// _init +// called automatically when the plugin library is first +// loaded. +//--------------------------------------------------------- + +void _init() + { + } + +//--------------------------------------------------------- +// _fini +// called automatically when the library is unloaded. +//--------------------------------------------------------- + +void _fini() + { + } + +//--------------------------------------------------------- +// ladspa_descriptor +// Return a descriptor of the requested plugin type. +//--------------------------------------------------------- + +const LADSPA_Descriptor* ladspa_descriptor(unsigned long i) + { + return (i == 0) ? &descriptor : 0; + } + diff --git a/muse/plugins/freeverb/readme.txt b/muse/plugins/freeverb/readme.txt new file mode 100644 index 00000000..2c1349a3 --- /dev/null +++ b/muse/plugins/freeverb/readme.txt @@ -0,0 +1,147 @@ +readme from original freeverb-source: +============================================== + + +Freeverb - Free, studio-quality reverb SOURCE CODE in the public domain +----------------------------------------------------------------------- + +Written by Jezar at Dreampoint - http://www.dreampoint.co.uk + + +Introduction +------------ + +Hello. + +I'll try to keep this "readme" reasonably small. +There are few things in the world that I hate more than long "readme" files. +Except "coding conventions" - but more on that later... + +In this zip file you will find two folders of C++ source code: + +"Components" - Contains files that should clean-compile + ON ANY TYPE OF COMPUTER OR SYSTEM WHATSOEVER. It should not be necessary + to make ANY changes to these files to get them to compile, except to make + up for inadequacies of certain compilers. These files create three classes + - a comb filter, an allpass filter, and a reverb model made up of a number + of instances of the filters, with some features to control the filters at + a macro level. You will need to link these classes into another program that + interfaces with them. The files in the components drawer are completely + independant, and can be built without dependancies on anything else. + Because of the simple interface, it should be possible to interface + these files to any system - VST, DirectX, anything - without changing + them AT ALL. + +"FreeverbVST" - Contains a Steinberg VST implementation of this version of + Freeverb, using the components in (surprise) the components folder. + It was built on a PC but may compile properly for the Macintosh with + no problems. I don't know - I don't have a Macintosh. If you've + figured out how to compile the examples in the Steinberg VST + Development Kit, then you should easilly figure out how to bring the + files into a project and get it working in a few minutes. It should + be very simple. + +Note that this version of Freeverb doesn't contain predelay, or any EQ. +I thought that might make it difficult to understand the "reverb" part of +the code. Once you figure out how Freeverb works, you should find it trivial +to add such features with little CPU overhead. + +Also, the code in this version of Freeverb has been optimised. This has changed +the sound *slightly*, but not significantly compared to how much processing +power it saves. + +Finally, note that there is also a built copy of this version of Freeverb called +"Freeverb3.dll" - this is a VST plugin for the PC. If you want a version for +the Mac or anything else, then you'll need to build it yourself from the code. + + +Technical Explanation +--------------------- + +Freeverb is a simple implementation of the standard Schroeder/Moorer reverb +model. I guess the only reason why it sounds better than other reverbs, +is simply because I spent a long while doing listening tests in order to create +the values found in "tuning.h". It uses 8 comb filters on both the left and right +channels), and you might possibly be able to get away with less if CPU power +is a serious constraint for you. It then feeds the result of the reverb through +4 allpass filters on both the left and right channels. These "smooth" the sound. +Adding more than four allpasses doesn't seem to add anything significant +to the sound, and if you use less, the sound gets a bit "grainy". +The filters on the right channel are slightly detuned compared to the left channel +in order to create a stereo effect. + +Hopefully, you should find the code in the components drawer a model of +brevity and clarity. Notice that I don't use any "coding conventions". +Personally, I think that coding conventions suck. They are meant to make +the code "clearer", but they inevitably do the complete opposite, making +the code completely unfathomable. Anyone whose done Windows programming +with its - frankly stupid - "Hungarian notation" will know exactly what +I mean. Coding conventions typically promote issues that are irrelevant +up to the status of appearing supremely important. It may have helped back +people in the days when compilers where somewhat feeble in their type-safety, +but not in the new millenium with advanced C++ compilers. + +Imagine if we rewrote the English language to conform to coding conventions. +After all, The arguments should be just as valid for the English language as +they are for a computer language. For example, we could put a lower-case "n" +in front of every noun, a lower-case "p" in front of a persons name, +a lower-case "v" in front of every verb, and a lower-case "a" in front +of every adjective. Can you imagine what the English language would look like? +All in the name of "clarity". It's just as stupid to do this for computer +code as it would be to do it for the English language. I hope that the +code for Freeverb in the components drawer demonstrates this, and helps start +a movement back towards sanity in coding practices. + + +Background +---------- + +Why is the Freeverb code now public domain? Simple. I only intended to create +Freeverb to provide me and my friends with studio-quality reverb for free. +I never intended to make any money out of it. However, I simply do not have the +time to develop it any further. I'm working on a "concept album" at the moment, +and I'll never finish it if I spend any more time programming. + +In any case, I make more far money as a contract programmer - making Mobile +Internet products - than I ever could writing plugins, so it simply doesn't +make financial sense for me to spend any more time on it. + +Rather than give Freeverb to any particular individual or organisation +to profit from it, I've decided to give it away to the internet community +at large, so that quality, FREE (or at the very least, low-cost) reverbs can +be developed for all platforms. + +Feel free to use the source code for Freeverb in any of your own products, +whether they are also available for free, or even if they are commercial - +I really don't mind. You may do with the code whatever you wish. If you use +it in a product (whether commercial or not), it would be very nice of you, +if you were to send me a copy of your product - although I appreciate that +this isn't always possible in all circumstances. + +HOWEVER, please don't bug me with questions about how to use this code. +I gave away Freeverb because I don't have time to maintain it. That means +I *certainly* don't have time to answer questions about the source code, so +please don't email questions to me. I *will* ignore them. If you can't figure +the code for Freeverb out - then find somebody who can. I hope that either +way, you enjoy experimenting with it. + + +Disclaimer +---------- + +This software and source code is given away for free, without any warranties +of any kind. It has been given away to the internet community as a free gift, +so please treat it in the same spirit. + + +I hope this code is useful and interesting to you all! +I hope you have lots of fun experimenting with it and make good products! + +Very best regards, +Jezar. +Technology Consultant +Dreampoint Design and Engineering +http://www.dreampoint.co.uk + + +//ends diff --git a/muse/plugins/freeverb/revmodel.cpp b/muse/plugins/freeverb/revmodel.cpp new file mode 100644 index 00000000..c72ee22b --- /dev/null +++ b/muse/plugins/freeverb/revmodel.cpp @@ -0,0 +1,232 @@ +// Reverb model implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include <stdio.h> +#include "revmodel.h" + +//--------------------------------------------------------- +// Revmodel +//--------------------------------------------------------- + +Revmodel::Revmodel() + { + // Tie the components to their buffers + combL[0].setbuffer(bufcombL1,combtuningL1); + combR[0].setbuffer(bufcombR1,combtuningR1); + combL[1].setbuffer(bufcombL2,combtuningL2); + combR[1].setbuffer(bufcombR2,combtuningR2); + combL[2].setbuffer(bufcombL3,combtuningL3); + combR[2].setbuffer(bufcombR3,combtuningR3); + combL[3].setbuffer(bufcombL4,combtuningL4); + combR[3].setbuffer(bufcombR4,combtuningR4); + combL[4].setbuffer(bufcombL5,combtuningL5); + combR[4].setbuffer(bufcombR5,combtuningR5); + combL[5].setbuffer(bufcombL6,combtuningL6); + combR[5].setbuffer(bufcombR6,combtuningR6); + combL[6].setbuffer(bufcombL7,combtuningL7); + combR[6].setbuffer(bufcombR7,combtuningR7); + combL[7].setbuffer(bufcombL8,combtuningL8); + combR[7].setbuffer(bufcombR8,combtuningR8); + allpassL[0].setbuffer(bufallpassL1,allpasstuningL1); + allpassR[0].setbuffer(bufallpassR1,allpasstuningR1); + allpassL[1].setbuffer(bufallpassL2,allpasstuningL2); + allpassR[1].setbuffer(bufallpassR2,allpasstuningR2); + allpassL[2].setbuffer(bufallpassL3,allpasstuningL3); + allpassR[2].setbuffer(bufallpassR3,allpasstuningR3); + allpassL[3].setbuffer(bufallpassL4,allpasstuningL4); + allpassR[3].setbuffer(bufallpassR4,allpasstuningR4); + + // Set default values + allpassL[0].setfeedback(0.5f); + allpassR[0].setfeedback(0.5f); + allpassL[1].setfeedback(0.5f); + allpassR[1].setfeedback(0.5f); + allpassL[2].setfeedback(0.5f); + allpassR[2].setfeedback(0.5f); + allpassL[3].setfeedback(0.5f); + allpassR[3].setfeedback(0.5f); + + param[0] = initialroom; + param[1] = initialdamp; + param[2] = initialwet; + + setroomsize(initialroom); + setdamp(initialdamp); + setwidth(initialwidth); + setmode(initialmode); + + // Buffer will be full of rubbish - so we MUST mute them + + for (int i = 0; i < numcombs; i++) { + combL[i].mute(); + combR[i].mute(); + } + for (int i=0;i<numallpasses;i++) { + allpassL[i].mute(); + allpassR[i].mute(); + } + } + +//--------------------------------------------------------- +// activate +//--------------------------------------------------------- + +void Revmodel::activate() + { + *port[4] = param[0]; + *port[5] = param[1]; + *port[6] = param[2]; + } + +//--------------------------------------------------------- +// processreplace +//--------------------------------------------------------- + +void Revmodel::processreplace(long n) + { + if (param[0] != *port[4]) { + param[0] = *port[4]; + setroomsize(param[0]); + } + if (param[1] != *port[5]) { + param[1] = *port[5]; + setdamp(param[1]); + } + + float wet = (1.0f - *port[6]) * scalewet; + float dry = *port[6] * scaledry; + float wet1 = wet * (width/2 + 0.5f); + float wet2 = wet * ((1-width)/2); + + for (int i = 0; i < n; ++i) { + float outL = 0; + float outR = 0; + float input = (port[0][i] + port[1][i]) * gain; + + // Accumulate comb filters in parallel + for (int k = 0; k < numcombs; k++) { + outL += combL[k].process(input); + outR += combR[k].process(input); + } + + // Feed through allpasses in series + for (int k=0; k < numallpasses; k++) { + outL = allpassL[k].process(outL); + outR = allpassR[k].process(outR); + } + + // Calculate output REPLACING anything already there + port[2][i] = outL*wet1 + outR*wet2 + port[0][i]*dry; + port[3][i] = outR*wet1 + outL*wet2 + port[1][i]*dry; + } + } + +void Revmodel::processmix(long n) + { + if (param[0] != *port[4]) { + param[0] = *port[4]; + setroomsize(param[0]); + } + if (param[1] != *port[5]) { + param[1] = *port[5]; + setdamp(param[1]); + } + + float wet = (1.0f - *port[6]) * scalewet; + float dry = *port[6] * scaledry; + float wet1 = wet * (width/2 + 0.5f); + float wet2 = wet * ((1-width)/2); + + for (int i = 0; i < n; ++i) { + float outL = 0; + float outR = 0; + float input = (port[0][i] + port[1][i]) * gain; + + // Accumulate comb filters in parallel + for (int k = 0; k < numcombs; k++) { + outL += combL[k].process(input); + outR += combR[k].process(input); + } + + // Feed through allpasses in series + for (int k=0; k < numallpasses; k++) { + outL = allpassL[k].process(outL); + outR = allpassR[k].process(outR); + } + + // Calculate output REPLACING anything already there + port[2][i] += outL*wet1 + outR*wet2 + port[0][i]*dry; + port[3][i] += outR*wet1 + outL*wet2 + port[1][i]*dry; + } + } + +//--------------------------------------------------------- +// update +// Recalculate internal values after parameter change +//--------------------------------------------------------- + +void Revmodel::update() + { + if (mode >= freezemode) { + roomsize1 = 1; + damp1 = 0; + gain = muted; + } + else { + roomsize1 = roomsize; + damp1 = damp; + gain = fixedgain; + } + + for (int i = 0; i < numcombs; i++) { + combL[i].setfeedback(roomsize1); + combR[i].setfeedback(roomsize1); + } + + for (int i = 0; i < numcombs; i++) { + combL[i].setdamp(damp1); + combR[i].setdamp(damp1); + } + } + +// The following get/set functions are not inlined, because +// speed is never an issue when calling them, and also +// because as you develop the reverb model, you may +// wish to take dynamic action when they are called. + +void Revmodel::setroomsize(float value) + { + roomsize = (value*scaleroom) + offsetroom; + update(); + } + +float Revmodel::getroomsize() + { + return (roomsize-offsetroom)/scaleroom; + } + +void Revmodel::setdamp(float value) + { + damp = value*scaledamp; + update(); + } + +void Revmodel::setwidth(float value) + { + width = value; + update(); + } + +void Revmodel::setmode(float value) + { + mode = value; + update(); + } + +float Revmodel::getmode() + { + return (mode >= freezemode) ? 1 : 0; + } diff --git a/muse/plugins/freeverb/revmodel.h b/muse/plugins/freeverb/revmodel.h new file mode 100644 index 00000000..bfa1f0b3 --- /dev/null +++ b/muse/plugins/freeverb/revmodel.h @@ -0,0 +1,79 @@ +// Reverb model declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _revmodel_ +#define _revmodel_ + +#include "comb.h" +#include "allpass.h" +#include "tuning.h" +#include "../../muse/ladspa.h" + +//--------------------------------------------------------- +// Revmodel +//--------------------------------------------------------- + +class Revmodel { + float gain; + float roomsize,roomsize1; + float damp,damp1; + float width; + float mode; + + // Comb filters + comb combL[numcombs]; + comb combR[numcombs]; + + // Allpass filters + allpass allpassL[numallpasses]; + allpass allpassR[numallpasses]; + + // Buffers for the combs + float bufcombL1[combtuningL1]; + float bufcombR1[combtuningR1]; + float bufcombL2[combtuningL2]; + float bufcombR2[combtuningR2]; + float bufcombL3[combtuningL3]; + float bufcombR3[combtuningR3]; + float bufcombL4[combtuningL4]; + float bufcombR4[combtuningR4]; + float bufcombL5[combtuningL5]; + float bufcombR5[combtuningR5]; + float bufcombL6[combtuningL6]; + float bufcombR6[combtuningR6]; + float bufcombL7[combtuningL7]; + float bufcombR7[combtuningR7]; + float bufcombL8[combtuningL8]; + float bufcombR8[combtuningR8]; + + // Buffers for the allpasses + float bufallpassL1[allpasstuningL1]; + float bufallpassR1[allpasstuningR1]; + float bufallpassL2[allpasstuningL2]; + float bufallpassR2[allpasstuningR2]; + float bufallpassL3[allpasstuningL3]; + float bufallpassR3[allpasstuningR3]; + float bufallpassL4[allpasstuningL4]; + float bufallpassR4[allpasstuningR4]; + void update(); + + public: + LADSPA_Data* port[7]; + float param[3]; + + Revmodel(); + void processmix(long numsamples); + void processreplace(long numsamples); + void setroomsize(float value); + float getroomsize(); + void setdamp(float value); + void setwidth(float value); + void setmode(float value); + float getmode(); + void activate(); + }; + +#endif diff --git a/muse/plugins/freeverb/tuning.h b/muse/plugins/freeverb/tuning.h new file mode 100644 index 00000000..ced89252 --- /dev/null +++ b/muse/plugins/freeverb/tuning.h @@ -0,0 +1,60 @@ +// Reverb model tuning values
+//
+// Written by Jezar at Dreampoint, June 2000
+// http://www.dreampoint.co.uk
+// This code is public domain
+
+#ifndef _tuning_
+#define _tuning_
+
+const int numcombs = 8;
+const int numallpasses = 4;
+const float muted = 0;
+const float fixedgain = 0.015f;
+const float scalewet = 3;
+const float scaledry = 2;
+const float scaledamp = 0.4f;
+const float scaleroom = 0.28f;
+const float offsetroom = 0.7f;
+const float initialroom = 0.5f;
+const float initialdamp = 0.5f;
+const float initialwet = 1/scalewet;
+const float initialdry = 0;
+const float initialwidth = 1;
+const float initialmode = 0;
+const float freezemode = 0.5f;
+const int stereospread = 23;
+
+// These values assume 44.1KHz sample rate
+// they will probably be OK for 48KHz sample rate
+// but would need scaling for 96KHz (or other) sample rates.
+// The values were obtained by listening tests.
+const int combtuningL1 = 1116;
+const int combtuningR1 = 1116+stereospread;
+const int combtuningL2 = 1188;
+const int combtuningR2 = 1188+stereospread;
+const int combtuningL3 = 1277;
+const int combtuningR3 = 1277+stereospread;
+const int combtuningL4 = 1356;
+const int combtuningR4 = 1356+stereospread;
+const int combtuningL5 = 1422;
+const int combtuningR5 = 1422+stereospread;
+const int combtuningL6 = 1491;
+const int combtuningR6 = 1491+stereospread;
+const int combtuningL7 = 1557;
+const int combtuningR7 = 1557+stereospread;
+const int combtuningL8 = 1617;
+const int combtuningR8 = 1617+stereospread;
+const int allpasstuningL1 = 556;
+const int allpasstuningR1 = 556+stereospread;
+const int allpasstuningL2 = 441;
+const int allpasstuningR2 = 441+stereospread;
+const int allpasstuningL3 = 341;
+const int allpasstuningR3 = 341+stereospread;
+const int allpasstuningL4 = 225;
+const int allpasstuningR4 = 225+stereospread;
+
+#endif//_tuning_
+
+//ends
+
diff --git a/muse/plugins/pandelay/Makefile.am b/muse/plugins/pandelay/Makefile.am new file mode 100644 index 00000000..664b3170 --- /dev/null +++ b/muse/plugins/pandelay/Makefile.am @@ -0,0 +1,16 @@ +include $(top_srcdir)/common.am +include $(top_srcdir)/plugins/plugins-install.am + +AM_CXXFLAGS += -O3 -fno-exceptions -fno-rtti -ffast-math + +plugins_LTLIBRARIES = pandelay.la + +plugins_DATA = + +pandelay_la_SOURCES = \ + ladspapandelay.cpp ladspapandelay.h \ + pandelay.cpp \ + pandelaymodel.cpp pandelaymodel.h +pandelay_la_LDFLAGS = -module -avoid-version + + diff --git a/muse/plugins/pandelay/ladspapandelay.cpp b/muse/plugins/pandelay/ladspapandelay.cpp new file mode 100644 index 00000000..b5680d3e --- /dev/null +++ b/muse/plugins/pandelay/ladspapandelay.cpp @@ -0,0 +1,100 @@ +//=========================================================================== +// +// ladspapandelay +// +// Version 0.0.1 +// +// +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#include "ladspapandelay.h" + +//--------------------------------------------------------- +// PanDelay +//--------------------------------------------------------- + +LADSPAPanDelay::LADSPAPanDelay(unsigned long samplerate) + : PanDelayModel(samplerate) { + //TODO init param +} + +LADSPAPanDelay::~LADSPAPanDelay() { +} + +//--------------------------------------------------------- +// activate +//--------------------------------------------------------- + +void LADSPAPanDelay::activate() { + *port[4] = param[0]; + *port[5] = param[1]; + *port[6] = param[2]; + *port[7] = param[3]; + *port[8] = param[4]; + *port[9] = param[5]; +} + +void LADSPAPanDelay::updateParameters() { + if (param[0] != *port[4]) { + param[0] = *port[4]; + setBPM(param[0]); + } + if (param[1] != *port[5]) { + param[1] = *port[5]; + setBeatRatio(param[1]); + } + if (param[2] != *port[6]) { + param[2] = *port[6]; + setFeedback(param[2]); + } + if (param[3] != *port[7]) { + param[3] = *port[7]; + setPanLFOFreq(param[3]); + } + if (param[4] != *port[8]) { + param[4] = *port[8]; + setPanLFODepth(param[4]); + } + if (param[5] != *port[9]) { + param[5] = *port[9]; + setDryWet(param[5]); + } +} + +//--------------------------------------------------------- +// processReplace +//--------------------------------------------------------- + +void LADSPAPanDelay::processReplace(long n) { + updateParameters(); + PanDelayModel::processReplace(port[0], port[1], port[2], port[3], n); +} + +//--------------------------------------------------------- +// processMix +//--------------------------------------------------------- + +void LADSPAPanDelay::processMix(long n) { + updateParameters(); + PanDelayModel::processMix(port[0], port[1], port[2], port[3], n); +} diff --git a/muse/plugins/pandelay/ladspapandelay.h b/muse/plugins/pandelay/ladspapandelay.h new file mode 100644 index 00000000..ab5427a1 --- /dev/null +++ b/muse/plugins/pandelay/ladspapandelay.h @@ -0,0 +1,55 @@ +//=========================================================================== +// +// ladspapandelay +// +// Version 0.0.1 +// +// +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#ifndef __LADSPAPANDELAY_H +#define __LADSPAPANDELAY_H + +#include "pandelaymodel.h" +#include "../../muse/ladspa.h" + +#define NBRPARAM 6 + +class LADSPAPanDelay : public PanDelayModel { + private: + + public: + LADSPAPanDelay(unsigned long samplerate); + ~LADSPAPanDelay(); + + LADSPA_Data* port[NBRPARAM + 4]; + float param[NBRPARAM]; + + void updateParameters(); + void processMix(long numsamples); + void processReplace(long numsamples); + + void activate(); +}; + +#endif diff --git a/muse/plugins/pandelay/pandelay.cpp b/muse/plugins/pandelay/pandelay.cpp new file mode 100644 index 00000000..18ce1a41 --- /dev/null +++ b/muse/plugins/pandelay/pandelay.cpp @@ -0,0 +1,170 @@ +//========================================================= +// PanDelay for MusE +// +// (C) Copyright 2006 Nil Geisweiller +//========================================================= + +#include "ladspapandelay.h" +#include <stdio.h> + +//--------------------------------------------------------- +// instantiate pandelay +// Construct a new plugin instance. +//--------------------------------------------------------- + +LADSPA_Handle instantiate(const LADSPA_Descriptor* /*Descriptor*/, + unsigned long samplerate) +{ + return new LADSPAPanDelay(samplerate); +} + +//--------------------------------------------------------- +// connect PortTo pandelay +// Connect a port to a data location. +//--------------------------------------------------------- + +void connect(LADSPA_Handle Instance, unsigned long port, + LADSPA_Data* data) +{ + ((LADSPAPanDelay*)Instance)->port[port] = data; +} + +//--------------------------------------------------------- +// activate +//--------------------------------------------------------- + +void activate(LADSPA_Handle instance) +{ + ((LADSPAPanDelay*)instance)->activate(); +} + +//--------------------------------------------------------- +// deactivate +//--------------------------------------------------------- + +void deactivate(LADSPA_Handle /*Instance*/) +{ +} + +//--------------------------------------------------------- +// run pandelay +//--------------------------------------------------------- + +void run(LADSPA_Handle Instance, unsigned long n) +{ + ((LADSPAPanDelay*)Instance)->processReplace(n); +} + +//--------------------------------------------------------- +// runAdding pandelay +// *ADD* the output to the output buffer. +//--------------------------------------------------------- + +void runAdding(LADSPA_Handle Instance, unsigned long n) +{ + ((LADSPAPanDelay*)Instance)->processMix(n); +} + +//--------------------------------------------------------- +// set pandelay RunAddingGain +//--------------------------------------------------------- + +void setGain(LADSPA_Handle /*Instance*/, LADSPA_Data /*Gain*/) +{ + printf("TEST setGain\n"); + // ((LADSPAPanDelay*)Instance)->m_fRunAddingGain = Gain; +} + +//--------------------------------------------------------- +// cleanup pandelay +//--------------------------------------------------------- + +void cleanup(LADSPA_Handle Instance) +{ + delete (LADSPAPanDelay*)Instance; +} + +static const char* portNames[] = { + "Input (Left)", + "Input (Right)", + "Output (Left)", + "Output (Right)", + "BMP", + "Beat Ratio", + "Feedback", + "Pan LFO Freq", + "Pan LFO Depth", + "Dry/Wet" +}; + +LADSPA_PortDescriptor portDescriptors[] = { + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL +}; + +LADSPA_PortRangeHint portRangeHints[] = { + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_100, MINBPM, MAXBPM }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_1, MINBEATRATIO, MAXBEATRATIO }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_HIGH, -1.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_HIGH, MINFREQ, MAXFREQ }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_HIGH, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MIDDLE, 0.0, 1.0 } +}; + +LADSPA_Descriptor descriptor = { + 1052, + "pandelay", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "PanDelay", + "Nil Geisweiller", + "GPL", + NBRPARAM + 4, + portDescriptors, + portNames, + portRangeHints, + 0, // impl. data + instantiate, + connect, + activate, + run, + runAdding, + setGain, + deactivate, + cleanup +}; + +//--------------------------------------------------------- +// _init +// called automatically when the plugin library is first +// loaded. +//--------------------------------------------------------- +void _init() { +} + +//--------------------------------------------------------- +// _fini +// called automatically when the library is unloaded. +//--------------------------------------------------------- +void _fini() { +} + +//--------------------------------------------------------- +// ladspa_descriptor +// Return a descriptor of the requested plugin type. +//--------------------------------------------------------- +const LADSPA_Descriptor* ladspa_descriptor(unsigned long i) { + return (i == 0) ? &descriptor : 0; +} + diff --git a/muse/plugins/pandelay/pandelaymodel.cpp b/muse/plugins/pandelay/pandelaymodel.cpp new file mode 100644 index 00000000..a30d0646 --- /dev/null +++ b/muse/plugins/pandelay/pandelaymodel.cpp @@ -0,0 +1,157 @@ +//=========================================================================== +// +// PanDelay, panoramic rotating delay +// +// version 0.0.1 +// +// pandelaymodel.cpp +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#include "pandelaymodel.h" +#include <stdio.h> + +PanDelayModel::PanDelayModel(int samplerate) { + for(int i = 0; i < MAXBUFFERLENGTH; i++) { + _leftBuffer[i] = 0.0; + _rightBuffer[i] = 0.0; + } + _bufferPointer = 0; + _inc = 0.0; + _l = 1.0; + _r = 1.0; + + _samplerate = samplerate; + _beatRatio = 4; + setBPM(120); + setPanDelay(); +} + +PanDelayModel::~PanDelayModel() { +} + +void PanDelayModel::setSamplerate(int sr) { + _samplerate = sr; + setPanDelay(); +} + +void PanDelayModel::setBPM(float bpm) { + _BPM = bpm; + _delayTime = _beatRatio * 60.0 / _BPM; + setPanDelay(); +} + +void PanDelayModel::setBeatRatio(float br) { + _beatRatio = br; + _delayTime = _beatRatio * 60.0 / _BPM; + setPanDelay(); +} + +void PanDelayModel::setDelayTime(float dt) { + if(dt < MINDELAYTIME) _delayTime = MINDELAYTIME; + else if(dt > MAXDELAYTIME) _delayTime = MAXDELAYTIME; + else _delayTime = dt; + setPanDelay(); +} + +void PanDelayModel::setFeedback(float fb) { + _feedback = fb; + setPanDelay(); +} + +void PanDelayModel::setPanLFOFreq(float pf) { + _panLFOFreq = pf; + setPanDelay(); +} + +void PanDelayModel::setPanLFODepth(float pd) { + _panLFODepth = pd; + setPanDelay(); +} + +void PanDelayModel::setDryWet(float dw) { + _dryWet = dw; +} + +void PanDelayModel::setPanDelay() { + float numLFOSample = (1.0/_panLFOFreq) * (float)_samplerate; + _inc = 2.0 / numLFOSample; + _delaySampleSize = (int)(_delayTime * (float)_samplerate); + _lBound = 1.0 - _panLFODepth; + _rBound = 1.0 + _panLFODepth; +} + +void PanDelayModel::processMix(float* leftSamplesIn, float* rightSamplesIn, + float* leftSamplesOut, float* rightSamplesOut, + unsigned n) { + float ls, rs, p; + p = 1.0 - _dryWet; + for(unsigned i = 0; i < n; i++) { + //read buffer + ls = _leftBuffer[_bufferPointer]; + rs = _rightBuffer[_bufferPointer]; + //write buffer + _leftBuffer[_bufferPointer] *= _feedback; + _leftBuffer[_bufferPointer] += leftSamplesIn[i]; + _rightBuffer[_bufferPointer] *= _feedback; + _rightBuffer[_bufferPointer] += rightSamplesIn[i]; + //write out + leftSamplesOut[i] += _l * _dryWet * ls + p * leftSamplesIn[i]; + rightSamplesOut[i] += _r * _dryWet * rs + p * rightSamplesIn[i]; + //update _bufferPointer + _bufferPointer++; + _bufferPointer%=_delaySampleSize; + //update _l _r + _r += _inc; + _l -= _inc; + //update _inc + if(_r > _rBound || _r < _lBound) _inc = -_inc; + } +} + +void PanDelayModel::processReplace(float* leftSamplesIn, float* rightSamplesIn, + float* leftSamplesOut, + float* rightSamplesOut, unsigned n) { + float ls, rs, p; + p = 1.0 - _dryWet; + for(unsigned i = 0; i < n; i++) { + //read buffer + ls = _leftBuffer[_bufferPointer]; + rs = _rightBuffer[_bufferPointer]; + //write buffer + _leftBuffer[_bufferPointer] *= _feedback; + _leftBuffer[_bufferPointer] += leftSamplesIn[i]; + _rightBuffer[_bufferPointer] *= _feedback; + _rightBuffer[_bufferPointer] += rightSamplesIn[i]; + //write out + leftSamplesOut[i] = _l * _dryWet * ls + p * leftSamplesIn[i]; + rightSamplesOut[i] = _r * _dryWet * rs + p * rightSamplesIn[i]; + //update _bufferPointer + _bufferPointer++; + _bufferPointer%=_delaySampleSize; + //update _l _r + _r += _inc; + _l -= _inc; + //update _inc + if(_r > _rBound || _r < _lBound) _inc = -_inc; + } +} diff --git a/muse/plugins/pandelay/pandelaymodel.h b/muse/plugins/pandelay/pandelaymodel.h new file mode 100644 index 00000000..65983187 --- /dev/null +++ b/muse/plugins/pandelay/pandelaymodel.h @@ -0,0 +1,93 @@ +//=========================================================================== +// +// PanDelay, panoramic rotating delay +// +// version 0.0.1 +// +// pandelaymodel.h +// +// +// Copyright (c) 2006 Nil Geisweiller +// +// +// +// 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 (at your option) 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA or point your web browser to http://www.gnu.org. +//=========================================================================== + +#ifndef __PANDELAYMODEL_H +#define __PANDELAYMODEL_H + +#include <math.h> + +#define MAXBUFFERLENGTH 192000 +#define MINFREQ 0.1 //in Hz +#define MAXFREQ 10.0 //in Hz +#define MINBPM 60.0 +#define MAXBPM 255.0 +#define MINBEATRATIO 0.125 +#define MAXBEATRATIO 2.0 +#define MINDELAYTIME 0.01 //in second +#define MAXDELAYTIME 2.0 //in second + +#define NBRPARAM 5 + +class PanDelayModel { + private: + int _samplerate; + + //bool _beatFraction; //if true then the delay is calculated in beat fraction + float _BPM; + float _beatRatio; + float _delayTime; //delay is calculated according to BMP and ratioBMP + float _feedback; + float _panLFOFreq; + float _panLFODepth; + float _dryWet; //0.0 : dry, 1.0 : wet + + int _delaySampleSize; + float _lBound; + float _rBound; + float _inc; + float _l; + float _r; + + float _leftBuffer[MAXBUFFERLENGTH]; + float _rightBuffer[MAXBUFFERLENGTH]; + int _bufferPointer; + + public: + PanDelayModel(int samplerate); + ~PanDelayModel(); + + void setSamplerate(int sr); + void setBeatRatio(float br); + void setBPM(float bpm); + void setDelayTime(float dt); + void setFeedback(float dt); + void setPanLFOFreq(float pf); + void setPanLFODepth(float pd); + void setDryWet(float dw); + void setPanDelay(); + + void processMix(float* leftInSamples, float* rightInSamples, + float* leftOutSamples, float* rightOutSamples, + unsigned n); + void processReplace(float* leftInSamples, float* rightInSamples, + float* leftOutSamples, float* rightOutSamples, + unsigned n); +}; + +#endif /* __PANDELAYMODEL_H */ diff --git a/muse/plugins/plugins-install.am b/muse/plugins/plugins-install.am new file mode 100644 index 00000000..86b41ecb --- /dev/null +++ b/muse/plugins/plugins-install.am @@ -0,0 +1 @@ +pluginsdir = $(pkglibdir)/plugins
\ No newline at end of file |