├── Source ├── DSPCode │ ├── GlobalFunctions.cpp │ ├── rosic_RealFunctions.cpp │ ├── rosic_NumberManipulations.h │ ├── rosic_NumberManipulations.cpp │ ├── rosic_FunctionTemplates.cpp │ ├── rosic_EllipticQuarterBandFilter.cpp │ ├── rosic_AcidPattern.cpp │ ├── rosic_MidiNoteEvent.cpp │ ├── rosic_DecayEnvelope.cpp │ ├── rosic_Complex.cpp │ ├── rosic_MidiNoteEvent.h │ ├── rosic_BlendOscillator.cpp │ ├── rosic_AcidSequencer.cpp │ ├── rosic_LeakyIntegrator.cpp │ ├── rosic_LeakyIntegrator.h │ ├── GlobalDefinitions.h │ ├── rosic_TeeBeeFilter.cpp │ ├── rosic_DecayEnvelope.h │ ├── rosic_BiquadFilter.h │ ├── rosic_EllipticQuarterBandFilter.h │ ├── rosic_OnePoleFilter.cpp │ ├── rosic_OnePoleFilter.h │ ├── rosic_AcidPattern.h │ ├── rosic_AnalogEnvelope.cpp │ ├── rosic_BiquadFilter.cpp │ ├── rosic_RealFunctions.h │ ├── rosic_BlendOscillator.h │ ├── rosic_FourierTransformerRadix2.h │ ├── rosic_Complex.h │ ├── rosic_AcidSequencer.h │ ├── rosic_MipMappedWaveTable.h │ ├── rosic_AnalogEnvelope.h │ ├── rosic_MipMappedWaveTable.cpp │ ├── rosic_Open303.cpp │ ├── rosic_FourierTransformerRadix2.cpp │ ├── rosic_TeeBeeFilter.h │ └── rosic_FunctionTemplates.h └── VSTPlugIn │ ├── StringConversions.c │ └── Open303VST.h ├── Build ├── VisualStudio2008 │ ├── Open303.suo │ ├── Open303.layout │ ├── Open303.sln │ ├── Open303.vcproj.XYZ-3B339B6A6CF.xyz.user │ └── Open303.cbp └── CodeBlocks │ ├── Open303.workspace │ ├── Open303.layout │ ├── Open303.cbp │ └── Open303.depend ├── ReadMe.txt ├── License.txt └── CMakeLists.txt /Source/DSPCode/GlobalFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "GlobalFunctions.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_RealFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_RealFunctions.h" 2 | using namespace rosic; 3 | 4 | -------------------------------------------------------------------------------- /Build/VisualStudio2008/Open303.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddanio/open303/HEAD/Build/VisualStudio2008/Open303.suo -------------------------------------------------------------------------------- /Source/DSPCode/rosic_NumberManipulations.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddanio/open303/HEAD/Source/DSPCode/rosic_NumberManipulations.h -------------------------------------------------------------------------------- /Source/DSPCode/rosic_NumberManipulations.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_NumberManipulations.h" 2 | using namespace rosic; 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_FunctionTemplates.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_FunctionTemplates.h" 2 | using namespace rosic; 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Build/VisualStudio2008/Open303.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Build/CodeBlocks/Open303.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_EllipticQuarterBandFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_EllipticQuarterBandFilter.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | EllipticQuarterBandFilter::EllipticQuarterBandFilter() 8 | { 9 | reset(); 10 | } 11 | 12 | //------------------------------------------------------------------------------------------------- 13 | // parameter settings: 14 | 15 | void EllipticQuarterBandFilter::reset() 16 | { 17 | for(int i=0; i<12; i++) 18 | w[i] = 0.0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Build/VisualStudio2008/Open303.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Open303", "Open303.vcproj", "{863D9E7E-5322-49C8-89BA-A761DC0EE438}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {863D9E7E-5322-49C8-89BA-A761DC0EE438}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {863D9E7E-5322-49C8-89BA-A761DC0EE438}.Debug|Win32.Build.0 = Debug|Win32 14 | {863D9E7E-5322-49C8-89BA-A761DC0EE438}.Release|Win32.ActiveCfg = Release|Win32 15 | {863D9E7E-5322-49C8-89BA-A761DC0EE438}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | Open303 is a free and open source emulation of the famous Roland TB-303 bass synthesizer for the VST plugin interface (VST is a trademark of Steinberg Media Technologies GmbH). 2 | 3 | In order to compile it from the source code, you need the VST-SDK v2.4 from Steinberg and drop it into the folder 'Libraries', such that the directory vstsdk2.4 (from the SDK) exists as direct subfolder of 'Libraries'. 4 | 5 | Compilation with Microsoft Visual Studio 2008: 6 | Load the solution-file Open303.sln (in the folder 'Build/VisualStudio2008') with Microsoft Visual Studio 2008 and try to build the plugin. If it works, you will find the results of the compilation (the final .dll and some intermediate files) in the subfolder 'Debug' or 'Release' of 'Build/VisualStudio2008', depending on whether you selected a debug- or release-build. 7 | 8 | Compilation with CodeBlocks: 9 | Load the CodeBlocks project file Open303.cbp (in the folder 'Build/CodeBlocks') - and build away. The results will be found in the subfolder bin/Debug or bin/Release. On my setup, i get 15 compiler warnings which are all rooted in source files of the VST-SDK (not the Open303 code itself) - so i guess we may safely ignore them. 10 | 11 | 12 | good luck, Robin Schmidt -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | The Open303 source code is released under the terms of the MIT license: 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2009 Robin Schmidt (www.rs-met.com) 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. -------------------------------------------------------------------------------- /Source/DSPCode/rosic_AcidPattern.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_AcidPattern.h" 2 | using namespace rosic; 3 | 4 | AcidPattern::AcidPattern() 5 | { 6 | numSteps = 16; 7 | stepLength = 0.5; 8 | } 9 | 10 | //------------------------------------------------------------------------------------------------- 11 | // setup: 12 | 13 | void AcidPattern::clear() 14 | { 15 | for(int i=0; i=0 && initKey <= 127) 18 | key = initKey; 19 | else 20 | key = 64; 21 | 22 | if( initVel >=0 && initVel <= 127) 23 | vel = initVel; 24 | else 25 | vel = 64; 26 | 27 | if( initPriority >=0 ) 28 | priority = initPriority; 29 | else 30 | priority = 0; 31 | 32 | detune = initDetune; 33 | } 34 | 35 | MidiNoteEvent::~MidiNoteEvent() 36 | { 37 | 38 | } 39 | 40 | //------------------------------------------------------------------------------------------------- 41 | // parameter settings: 42 | 43 | void MidiNoteEvent::setKey(int newKey) 44 | { 45 | if( newKey >=0 && newKey <= 127) 46 | key = newKey; 47 | } 48 | 49 | void MidiNoteEvent::setVelocity(int newVelocity) 50 | { 51 | if( newVelocity >=0 && newVelocity <= 127) 52 | vel = newVelocity; 53 | } 54 | 55 | void MidiNoteEvent::setDetune(double newDetune) 56 | { 57 | detune = newDetune; 58 | } 59 | 60 | void MidiNoteEvent::setPriority(int newPriority) 61 | { 62 | if( newPriority >=0 ) 63 | priority = newPriority; 64 | } 65 | -------------------------------------------------------------------------------- /Build/VisualStudio2008/Open303.vcproj.XYZ-3B339B6A6CF.xyz.user: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 35 | 36 | 39 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6.3 FATAL_ERROR) 2 | project(open303) 3 | 4 | add_library(open303 5 | Source/DSPCode/GlobalDefinitions.h 6 | Source/DSPCode/GlobalFunctions.cpp 7 | Source/DSPCode/GlobalFunctions.h 8 | Source/DSPCode/fft4g.c 9 | Source/DSPCode/rosic_AcidPattern.cpp 10 | Source/DSPCode/rosic_AcidPattern.h 11 | Source/DSPCode/rosic_AcidSequencer.cpp 12 | Source/DSPCode/rosic_AcidSequencer.h 13 | Source/DSPCode/rosic_AnalogEnvelope.cpp 14 | Source/DSPCode/rosic_AnalogEnvelope.h 15 | Source/DSPCode/rosic_BiquadFilter.cpp 16 | Source/DSPCode/rosic_BiquadFilter.h 17 | Source/DSPCode/rosic_BlendOscillator.cpp 18 | Source/DSPCode/rosic_BlendOscillator.h 19 | Source/DSPCode/rosic_Complex.cpp 20 | Source/DSPCode/rosic_Complex.h 21 | Source/DSPCode/rosic_DecayEnvelope.cpp 22 | Source/DSPCode/rosic_DecayEnvelope.h 23 | Source/DSPCode/rosic_EllipticQuarterBandFilter.cpp 24 | Source/DSPCode/rosic_EllipticQuarterBandFilter.h 25 | Source/DSPCode/rosic_FourierTransformerRadix2.cpp 26 | Source/DSPCode/rosic_FourierTransformerRadix2.h 27 | Source/DSPCode/rosic_FunctionTemplates.cpp 28 | Source/DSPCode/rosic_FunctionTemplates.h 29 | Source/DSPCode/rosic_LeakyIntegrator.cpp 30 | Source/DSPCode/rosic_LeakyIntegrator.h 31 | Source/DSPCode/rosic_MidiNoteEvent.cpp 32 | Source/DSPCode/rosic_MidiNoteEvent.h 33 | Source/DSPCode/rosic_MipMappedWaveTable.cpp 34 | Source/DSPCode/rosic_MipMappedWaveTable.h 35 | Source/DSPCode/rosic_NumberManipulations.cpp 36 | Source/DSPCode/rosic_NumberManipulations.h 37 | Source/DSPCode/rosic_OnePoleFilter.cpp 38 | Source/DSPCode/rosic_OnePoleFilter.h 39 | Source/DSPCode/rosic_Open303.cpp 40 | Source/DSPCode/rosic_Open303.h 41 | Source/DSPCode/rosic_RealFunctions.cpp 42 | Source/DSPCode/rosic_RealFunctions.h 43 | Source/DSPCode/rosic_TeeBeeFilter.cpp 44 | Source/DSPCode/rosic_TeeBeeFilter.h 45 | ) 46 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_DecayEnvelope.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_DecayEnvelope.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | DecayEnvelope::DecayEnvelope() 8 | { 9 | c = 1.0; 10 | y = 1.0; 11 | yInit = 1.0; 12 | tau = 200.0; 13 | fs = 44100.0; 14 | normalizeSum = false; 15 | calculateCoefficient(); 16 | } 17 | 18 | DecayEnvelope::~DecayEnvelope() 19 | { 20 | 21 | } 22 | 23 | //------------------------------------------------------------------------------------------------- 24 | // parameter settings: 25 | 26 | void DecayEnvelope::setSampleRate(double newSampleRate) 27 | { 28 | if( newSampleRate > 0.0 ) 29 | { 30 | fs = newSampleRate; 31 | calculateCoefficient(); 32 | } 33 | } 34 | 35 | void DecayEnvelope::setDecayTimeConstant(double newTimeConstant) 36 | { 37 | if( newTimeConstant > 0.001 ) // at least 0.001 ms decay 38 | { 39 | tau = newTimeConstant; 40 | calculateCoefficient(); 41 | } 42 | } 43 | 44 | void DecayEnvelope::setNormalizeSum(bool shouldNormalizeSum) 45 | { 46 | normalizeSum = shouldNormalizeSum; 47 | calculateCoefficient(); 48 | } 49 | 50 | //------------------------------------------------------------------------------------------------- 51 | // others: 52 | 53 | void DecayEnvelope::trigger() 54 | { 55 | y = yInit; 56 | } 57 | 58 | bool DecayEnvelope::endIsReached(double threshold) 59 | { 60 | if( y < threshold ) 61 | return true; 62 | else 63 | return false; 64 | } 65 | 66 | //------------------------------------------------------------------------------------------------- 67 | // internal functions: 68 | 69 | void DecayEnvelope::calculateCoefficient() 70 | { 71 | c = exp( -1.0 / (0.001*tau*fs) ); 72 | if( normalizeSum == true ) 73 | yInit = (1.0-c)/c; 74 | else 75 | yInit = 1.0/c; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_Complex.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_Complex.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | Complex::Complex() 8 | { 9 | re = im = 0.0; 10 | } 11 | 12 | Complex::Complex(double reInit) 13 | { 14 | re = reInit; 15 | im = 0.0; 16 | } 17 | 18 | Complex::Complex(double reInit, double imInit) 19 | { 20 | re = reInit; 21 | im = imInit; 22 | } 23 | 24 | Complex::~Complex() 25 | { 26 | 27 | } 28 | 29 | //------------------------------------------------------------------------------------------------- 30 | // magnitude, angle, etc. 31 | 32 | double Complex::getRadius() 33 | { 34 | return sqrt(re*re + im*im); 35 | } 36 | 37 | double Complex::getAngle() 38 | { 39 | if((re==0.0) && (im==0)) 40 | return 0.0; 41 | else 42 | return atan2(im, re); 43 | } 44 | 45 | void Complex::setRadius(double newRadius) 46 | { 47 | double phi = getAngle(); 48 | sinCos(phi, &im, &re); 49 | re *= newRadius; // re = newRadius * cos(phi); 50 | im *= newRadius; // im = newRadius * sin(phi); 51 | } 52 | 53 | void Complex::setAngle(double newAngle) 54 | { 55 | double r = getRadius(); 56 | sinCos(newAngle, &im, &re); 57 | re *= r; // re = r * cos(newAngle); 58 | im *= r; // im = r * sin(newAngle); 59 | } 60 | 61 | void Complex::setRadiusAndAngle(double newRadius, double newAngle) 62 | { 63 | sinCos(newAngle, &im, &re); 64 | re *= newRadius; // re = newRadius * cos(newAngle); 65 | im *= newRadius; // im = newRadius * sin(newAngle); 66 | } 67 | 68 | Complex Complex::getConjugate() 69 | { 70 | return Complex(re, -im); 71 | } 72 | 73 | Complex Complex::getReciprocal() 74 | { 75 | double scaler = 1.0 / (re*re + im*im); 76 | return Complex(scaler*re, -scaler*im); 77 | } 78 | 79 | bool Complex::isReal() 80 | { 81 | return (im == 0.0); 82 | } 83 | 84 | bool Complex::isImaginary() 85 | { 86 | return (re == 0.0); 87 | } 88 | 89 | bool Complex::isInfinite() 90 | { 91 | if( re == INF || re == NEG_INF || im == INF || im == NEG_INF ) 92 | return true; 93 | else 94 | return false; 95 | } 96 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_MidiNoteEvent.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_MidiNoteEvent_h 2 | #define rosic_MidiNoteEvent_h 3 | 4 | namespace rosic 5 | { 6 | 7 | /** 8 | 9 | This is a class for representing MIDI note-events. 10 | 11 | */ 12 | 13 | class MidiNoteEvent 14 | { 15 | 16 | public: 17 | 18 | //--------------------------------------------------------------------------------------------- 19 | // construction/destruction: 20 | 21 | /** Default constructor. */ 22 | MidiNoteEvent(); 23 | 24 | /** Constructor with initializations. */ 25 | MidiNoteEvent(int initKey, int initVel, int initDetune = 0, int initPriority = 0 ); 26 | 27 | /** Destructor. */ 28 | ~MidiNoteEvent(); 29 | 30 | //--------------------------------------------------------------------------------------------- 31 | // parameter settings: 32 | 33 | /** Sets the key of the note (as MIDI note number between 0...127). */ 34 | void setKey(int newKey); 35 | 36 | /** Sets the velocity of the note (between 0...127). */ 37 | void setVelocity(int newVelocity); 38 | 39 | /** Sets the detuning of the note (in semitones). */ 40 | void setDetune(double newDetune); 41 | 42 | /** Sets the priority of the note. */ 43 | void setPriority(int newPriority); 44 | 45 | //--------------------------------------------------------------------------------------------- 46 | // inquiry: 47 | 48 | /** Returns the key of the note (as MIDI note number between 0...127). */ 49 | int getKey() const { return key; } 50 | 51 | /** Returns the velocity of the note (between 0...127). */ 52 | int getVelocity() const { return vel; } 53 | 54 | /** Returns the detuning of the note (in semitones). */ 55 | double getDetune() const { return detune; } 56 | 57 | /** Returns the priority of the note. */ 58 | int getPriority() const { return priority; } 59 | 60 | //--------------------------------------------------------------------------------------------- 61 | // overloaded operators: 62 | 63 | /** Note events are interpreted as equal if the have the same key. */ 64 | bool operator==(const MidiNoteEvent& note2) const 65 | { 66 | return note2.key == key; 67 | } 68 | 69 | protected: 70 | 71 | int key; // key of the note in the range 0...127 72 | int vel; // velocity of the note in the range 0...127 73 | double detune; // detuning in cents (for microtuning) 74 | int priority; // a priority value 75 | 76 | }; 77 | 78 | } // end namespace rosic 79 | 80 | #endif // MidiNoteEvent_h 81 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_BlendOscillator.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_BlendOscillator.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | BlendOscillator::BlendOscillator() 8 | { 9 | // init member variables: 10 | tableLengthDbl = (double) MipMappedWaveTable::tableLength; // typecasted version 11 | sampleRate = 44100.0; 12 | freq = 440.0; 13 | increment = (tableLengthDbl*freq)/sampleRate; 14 | phaseIndex = 0.0; 15 | startIndex = 0.0; 16 | waveTable1 = NULL; 17 | waveTable2 = NULL; 18 | 19 | // somewhat redundant: 20 | setSampleRate(44100.0); // sampleRate = 44100 Hz by default 21 | setFrequency (440.0); // frequency = 440 Hz by default 22 | setStartPhase(0.0); // sartPhase = 0 by default 23 | 24 | setWaveForm1(MipMappedWaveTable::SAW); 25 | setWaveForm2(MipMappedWaveTable::SQUARE); 26 | 27 | resetPhase(); 28 | } 29 | 30 | BlendOscillator::~BlendOscillator() 31 | { 32 | 33 | } 34 | 35 | //------------------------------------------------------------------------------------------------- 36 | // parameter settings: 37 | 38 | void BlendOscillator::setSampleRate(double newSampleRate) 39 | { 40 | if( newSampleRate > 0.0 ) 41 | sampleRate = newSampleRate; 42 | sampleRateRec = 1.0 / sampleRate; 43 | increment = tableLengthDbl*freq*sampleRateRec; 44 | } 45 | 46 | void BlendOscillator::setWaveForm1(int newWaveForm1) 47 | { 48 | if( waveTable1 != NULL ) 49 | waveTable1->setWaveform(newWaveForm1); 50 | } 51 | 52 | void BlendOscillator::setWaveForm2(int newWaveForm2) 53 | { 54 | if( waveTable2 != NULL ) 55 | waveTable2->setWaveform(newWaveForm2); 56 | } 57 | 58 | void BlendOscillator::setWaveTable1(MipMappedWaveTable* newWaveTable1) 59 | { 60 | waveTable1 = newWaveTable1; 61 | } 62 | 63 | void BlendOscillator::setWaveTable2(MipMappedWaveTable* newWaveTable2) 64 | { 65 | waveTable2 = newWaveTable2; 66 | } 67 | 68 | void BlendOscillator::setStartPhase(double StartPhase) 69 | { 70 | if( (StartPhase>=0) && (StartPhase<=360) ) 71 | startIndex = (StartPhase/360.0)*tableLengthDbl; 72 | } 73 | 74 | //------------------------------------------------------------------------------------------------- 75 | // event processing: 76 | 77 | void BlendOscillator::resetPhase() 78 | { 79 | phaseIndex = startIndex; 80 | } 81 | 82 | void BlendOscillator::setPhase(double PhaseIndex) 83 | { 84 | phaseIndex = startIndex+PhaseIndex; 85 | } 86 | -------------------------------------------------------------------------------- /Source/VSTPlugIn/StringConversions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "string.h" 4 | 5 | 6 | 7 | 8 | 9 | //-------------------------------------------------------------------------------------------------- 10 | //functions for conversion from float-vst-parameter to string: 11 | /* 12 | void bpm2String(float value, char *string) 13 | { 14 | double mappedValue = value*200 + 50; //from 50 to 250 bpm 15 | if(value==0.0) 16 | sprintf(string, //pointer where the string is to be stored 17 | "%s", //format string, indicates that a string type parameter follows 18 | "sync"); //the parameter of type string 19 | else 20 | sprintf(string, //pointer where the string is to be stored 21 | "%.2f", //format string, indicates that a double/float type parameter 22 | //follows and should be orunded to 2 digits 23 | mappedValue); //the parameter of type double/float 24 | } 25 | 26 | void percent2String(float value, char* string) 27 | { 28 | double mappedValue = 100*value; 29 | sprintf(string, //pointer where the string is to be stored 30 | "%.1f %s", //format string, indicates that the first parameter (after the 31 | //format parameters) will be a double/float type parameter 32 | //and should be runded to 1 digit and the second one will be a 33 | //string type parameter 34 | mappedValue, //the parameter of type double/float 35 | "%"); //the parameter of type string (the "%" character in this case) 36 | } 37 | 38 | void scaler2String(float value, char* string) 39 | { 40 | double mappedValue = pow(4, (2*value - 1) ); //between 4^(-1) = 0.25 and 4^1 = 4 41 | sprintf(string, "%s %.2f", "*", mappedValue); 42 | } 43 | 44 | void numAndDen2String(float value, char* string) 45 | { 46 | long mappedValue = (long) floor(127*value+1); //from 1 to 128 47 | sprintf(string, "%i", mappedValue); 48 | } 49 | 50 | void Freq2String(float value, char* string) 51 | { 52 | double mappedValue = pow(1000,value)*20; //from 20 to 20000Hz 53 | sprintf(string, "%.0f", mappedValue); 54 | } 55 | 56 | void timeFactor2String(float value, char* string) 57 | { 58 | double mappedValue = pow(2, (2*value - 1) ); //between 2^(-1) = 0.5 and 2^1 = 2 59 | sprintf(string, "%.4f", mappedValue); 60 | } 61 | */ 62 | 63 | /* 64 | void phaseString2float(char *string, float& output) 65 | { 66 | output = 45.09; 67 | } 68 | */ 69 | 70 | 71 | void value2String(float value, char *string) 72 | { 73 | sprintf(string, "%.2f", value); 74 | } 75 | 76 | void phase2String(float value, char *string) 77 | { 78 | double mappedValue = 360.0*value; 79 | 80 | if( mappedValue <= 359.99 ) 81 | sprintf(string, "%.2f", mappedValue); 82 | else 83 | sprintf(string, "%s", "free"); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_AcidSequencer.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_AcidSequencer.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | AcidSequencer::AcidSequencer() 8 | { 9 | sampleRate = 44100.0; 10 | bpm = 140.0; 11 | activePattern = 0; 12 | running = false; 13 | countDown = 0; 14 | step = 0; 15 | sequencerMode = OFF; 16 | driftError = 0.0; 17 | modeChanged = false; 18 | 19 | for(int k=0; k<=12; k++) 20 | keyPermissible[k] = true; 21 | } 22 | 23 | //------------------------------------------------------------------------------------------------- 24 | // parameter settings: 25 | 26 | void AcidSequencer::setSampleRate(double newSampleRate) 27 | { 28 | if( newSampleRate > 0.0 ) 29 | sampleRate = newSampleRate; 30 | } 31 | 32 | void AcidSequencer::setMode(int newMode) 33 | { 34 | if( newMode >= 0 && newMode < NUM_SEQUENCER_MODES ) 35 | { 36 | sequencerMode = newMode; 37 | modeChanged = true; 38 | } 39 | } 40 | 41 | void AcidSequencer::setKeyPermissible(int key, bool shouldBePermissible) 42 | { 43 | if( key >= 0 && key <= 12 ) 44 | keyPermissible[key] = shouldBePermissible; 45 | } 46 | 47 | void AcidSequencer::toggleKeyPermissibility(int key) 48 | { 49 | if( key >= 0 && key <= 12 ) 50 | keyPermissible[key] = !keyPermissible[key]; 51 | } 52 | 53 | //------------------------------------------------------------------------------------------------- 54 | // inquiry: 55 | 56 | AcidPattern* AcidSequencer::getPattern(int index) 57 | { 58 | if( index < 0 || index >= numPatterns ) 59 | return NULL; 60 | else 61 | return &patterns[index]; 62 | } 63 | 64 | bool AcidSequencer::modeWasChanged() 65 | { 66 | bool result = modeChanged; 67 | modeChanged = false; 68 | return result; 69 | // mmm...wouldn't we need mutexes here? the mode changes from the GUI and modeWasChanged 70 | // is called from the audio-thread - otherwise note-hangs could happen? 71 | } 72 | 73 | bool AcidSequencer::isKeyPermissible(int key) 74 | { 75 | if( key >= 0 && key <= 12 ) 76 | return keyPermissible[key]; 77 | else 78 | return false; 79 | } 80 | 81 | //------------------------------------------------------------------------------------------------- 82 | // event handling: 83 | 84 | void AcidSequencer::start() 85 | { 86 | // set up members such that we will trap in the else-branch in the next call to getNote(): 87 | running = true; 88 | countDown = -1; 89 | step = 0; 90 | driftError = 0.0; 91 | } 92 | 93 | void AcidSequencer::stop() 94 | { 95 | running = false; 96 | } 97 | 98 | //------------------------------------------------------------------------------------------------- 99 | // others: 100 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_LeakyIntegrator.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_LeakyIntegrator.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | LeakyIntegrator::LeakyIntegrator() 8 | { 9 | sampleRate = 44100.0f; 10 | tau = 10.0f; 11 | y1 = 0.0; 12 | 13 | calculateCoefficient(); 14 | } 15 | 16 | LeakyIntegrator::~LeakyIntegrator() 17 | { 18 | 19 | } 20 | 21 | //------------------------------------------------------------------------------------------------- 22 | // parameter settings: 23 | 24 | void LeakyIntegrator::setSampleRate(double newSampleRate) 25 | { 26 | if( newSampleRate > 0.0 ) 27 | { 28 | sampleRate = newSampleRate; 29 | calculateCoefficient(); 30 | } 31 | } 32 | 33 | void LeakyIntegrator::setTimeConstant(double newTimeConstant) 34 | { 35 | if( newTimeConstant >= 0.0 && newTimeConstant != tau ) 36 | { 37 | tau = newTimeConstant; 38 | calculateCoefficient(); 39 | } 40 | } 41 | 42 | //------------------------------------------------------------------------------------------------- 43 | // inquiry: 44 | 45 | double LeakyIntegrator::getNormalizer(double tau1, double tau2, double fs) 46 | { 47 | double td = 0.001*tau1; 48 | double ta = 0.001*tau2; 49 | 50 | // catch some special cases: 51 | if( ta == 0.0 && td == 0.0 ) 52 | return 1.0; 53 | else if( ta == 0.0 ) 54 | { 55 | return 1.0 / (1.0-exp(-1.0/(fs*td))); 56 | } 57 | else if( td == 0.0 ) 58 | { 59 | return 1.0 / (1.0-exp(-1.0/(fs*ta))); 60 | } 61 | 62 | // compute the filter coefficients: 63 | double x = exp( -1.0 / (fs*td) ); 64 | double bd = 1-x; 65 | double ad = -x; 66 | x = exp( -1.0 / (fs*ta) ); 67 | double ba = 1-x; 68 | double aa = -x; 69 | 70 | // compute the location and height of the peak: 71 | double xp; 72 | if( ta == td ) 73 | { 74 | double tp = ta; 75 | double np = fs*tp; 76 | xp = (np+1.0)*ba*ba*pow(aa, np); 77 | } 78 | else 79 | { 80 | double tp = log(ta/td) / ( (1.0/td) - (1.0/ta) ); 81 | double np = fs*tp; 82 | double s = 1.0 / (aa-ad); 83 | double b01 = s * aa*ba*bd; 84 | double b02 = s * ad*ba*bd; 85 | double a01 = s * (ad-aa)*aa; 86 | double a02 = s * (ad-aa)*ad; 87 | xp = b01*pow(a01, np) - b02*pow(a02, np); 88 | } 89 | 90 | // return the normalizer as reciprocal of the peak height: 91 | return 1.0/xp; 92 | } 93 | 94 | //------------------------------------------------------------------------------------------------- 95 | // others: 96 | 97 | void LeakyIntegrator::reset() 98 | { 99 | y1 = 0; 100 | } 101 | 102 | void LeakyIntegrator::calculateCoefficient() 103 | { 104 | if( tau > 0.0 ) 105 | coeff = exp( -1.0 / (sampleRate*0.001*tau) ); 106 | else 107 | coeff = 0.0; 108 | } 109 | 110 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_LeakyIntegrator.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_LeakyIntegrator_h 2 | #define rosic_LeakyIntegrator_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is a leaky integrator type lowpass filter with user adjustable time constant which is set 13 | up in milliseconds. 14 | 15 | */ 16 | 17 | class LeakyIntegrator 18 | { 19 | 20 | public: 21 | 22 | //--------------------------------------------------------------------------------------------- 23 | // construction/destruction: 24 | 25 | /** Constructor. */ 26 | LeakyIntegrator(); 27 | 28 | /** Destructor. */ 29 | ~LeakyIntegrator(); 30 | 31 | //--------------------------------------------------------------------------------------------- 32 | // parameter settings: 33 | 34 | /** Sets the sample-rate. */ 35 | void setSampleRate(double newSampleRate); 36 | 37 | /** Sets the time constant (tau), value is expected in milliseconds. */ 38 | void setTimeConstant(double newTimeConstant); 39 | 40 | /** Sets the internal state of the filter to the passed value. */ 41 | void setState(double newState) { y1 = newState; } 42 | 43 | //--------------------------------------------------------------------------------------------- 44 | // inquiry: 45 | 46 | /** Returns the time constant (tau) in milliseconds. */ 47 | double getTimeConstant() const { return tau; } 48 | 49 | /** Returns the normalizer, required to normalize the impulse response of a series connection 50 | of two digital RC-type filters with time constants tau1 and tau2 (in milliseconds) to unity at 51 | the given samplerate. */ 52 | static double getNormalizer(double tau1, double tau2, double sampleRate); 53 | 54 | //--------------------------------------------------------------------------------------------- 55 | // audio processing: 56 | 57 | /** Calculates one sample at a time. */ 58 | INLINE double getSample(double in); 59 | 60 | //--------------------------------------------------------------------------------------------- 61 | // others: 62 | 63 | /** Resets the internal state of the filter. */ 64 | void reset(); 65 | 66 | //============================================================================================= 67 | 68 | protected: 69 | 70 | /** Calculates the filter coefficient. */ 71 | void calculateCoefficient(); 72 | 73 | double coeff; // filter coefficient 74 | double y1; // previous output sample 75 | double sampleRate; // the samplerate 76 | double tau; // time constant in milliseconds 77 | 78 | }; 79 | 80 | //----------------------------------------------------------------------------------------------- 81 | // inlined functions: 82 | 83 | INLINE double LeakyIntegrator::getSample(double in) 84 | { 85 | return y1 = in + coeff*(y1-in); 86 | } 87 | 88 | } // end namespace rosic 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /Source/DSPCode/GlobalDefinitions.h: -------------------------------------------------------------------------------- 1 | #ifndef GlobalDefinitions_h 2 | #define GlobalDefinitions_h 3 | 4 | #include 5 | 6 | /** This file contains a bunch of useful macros which are not wrapped into the 7 | rosic namespace to facilitate their global use. */ 8 | 9 | #ifdef _MSC_VER 10 | #define INLINE __forceinline 11 | #else 12 | #define INLINE inline // something better to do here ? 13 | #endif 14 | 15 | //_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON) 16 | 17 | //------------------------------------------------------------------------------------------------- 18 | // mathematical constants: 19 | 20 | #define PI 3.1415926535897932384626433832795 21 | #define EULER 2.7182818284590452353602874713527 22 | #define SQRT2 1.4142135623730950488016887242097 23 | #define ONE_OVER_SQRT2 0.70710678118654752440084436210485 24 | #define LN10 2.3025850929940456840179914546844 25 | #define ONE_OVER_LN10 0.43429448190325182765112891891661 26 | #define LN2 0.69314718055994530941723212145818 27 | #define ONE_OVER_LN2 1.4426950408889634073599246810019 28 | #define SEMITONE_FACTOR 1.0594630943592952645618252949463 29 | 30 | //------------------------------------------------------------------------------------------------- 31 | // type definitions: 32 | 33 | // unsigned 64 bit integers: 34 | #ifdef _MSC_VER 35 | typedef unsigned __int64 UINT64; 36 | #else 37 | typedef unsigned long long UINT64; 38 | #endif 39 | 40 | // signed 64 bit integers: 41 | #ifdef _MSC_VER 42 | typedef signed __int64 INT64; 43 | #else 44 | typedef signed long long INT64; 45 | #endif 46 | 47 | // unsigned 32 bit integers: 48 | #ifdef _MSC_VER 49 | typedef unsigned __int32 UINT32; 50 | #else 51 | typedef unsigned long UINT32; 52 | #endif 53 | 54 | // ...constants for numerical precision issues, denorm, etc.: 55 | #define TINY FLT_MIN 56 | #define EPS DBL_EPSILON 57 | 58 | // define infinity values: 59 | 60 | inline double dummyFunction(double x) { return x; } 61 | #define INF (1.0/dummyFunction(0.0)) 62 | #define NEG_INF (-1.0/dummyFunction(0.0)) 63 | 64 | //------------------------------------------------------------------------------------------------- 65 | // debug stuff: 66 | 67 | // this will try to break the debugger if one is currently hosting this app: 68 | #ifdef _DEBUG 69 | 70 | #ifdef _MSC_VER 71 | #pragma intrinsic (__debugbreak) 72 | #define DEBUG_BREAK __debugbreak(); 73 | #else 74 | #define DEBUG_BREAK {} 75 | #endif 76 | 77 | #else 78 | 79 | #define DEBUG_BREAK {} // evaluate to no op in release builds 80 | 81 | #endif 82 | 83 | // an replacement of the ASSERT macro 84 | #define rassert(expression) { if (! (expression)) DEBUG_BREAK } 85 | 86 | //------------------------------------------------------------------------------------------------- 87 | // bit twiddling: 88 | 89 | //extract the exponent from a IEEE 754 floating point number (single and double precision): 90 | #define EXPOFFLT(value) (((*((reinterpret_cast(&value)))&0x7FFFFFFF)>>23)-127) 91 | #define EXPOFDBL(value) (((*((reinterpret_cast(&value)))&0x7FFFFFFFFFFFFFFFULL)>>52)-1023) 92 | // ULL indicates an unsigned long long literal constant 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_TeeBeeFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_TeeBeeFilter.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | TeeBeeFilter::TeeBeeFilter() 8 | { 9 | cutoff = 1000.0; 10 | drive = 0.0; 11 | driveFactor = 1.0; 12 | resonanceRaw = 0.0; 13 | resonanceSkewed = 0.0; 14 | g = 1.0; 15 | sampleRate = 44100.0; 16 | twoPiOverSampleRate = 2.0*PI/sampleRate; 17 | 18 | feedbackHighpass.setMode(OnePoleFilter::HIGHPASS); 19 | feedbackHighpass.setCutoff(150.0); 20 | 21 | //setMode(LP_18); 22 | setMode(TB_303); 23 | calculateCoefficientsExact(); 24 | reset(); 25 | } 26 | 27 | TeeBeeFilter::~TeeBeeFilter() 28 | { 29 | 30 | } 31 | 32 | //------------------------------------------------------------------------------------------------- 33 | // parameter settings: 34 | 35 | void TeeBeeFilter::setSampleRate(double newSampleRate) 36 | { 37 | if( newSampleRate > 0.0 ) 38 | sampleRate = newSampleRate; 39 | twoPiOverSampleRate = 2.0*PI/sampleRate; 40 | feedbackHighpass.setSampleRate(newSampleRate); 41 | calculateCoefficientsExact(); 42 | } 43 | 44 | void TeeBeeFilter::setDrive(double newDrive) 45 | { 46 | drive = newDrive; 47 | driveFactor = dB2amp(drive); 48 | } 49 | 50 | void TeeBeeFilter::setMode(int newMode) 51 | { 52 | if( newMode >= 0 && newMode < NUM_MODES ) 53 | { 54 | mode = newMode; 55 | switch(mode) 56 | { 57 | case FLAT: c0 = 1.0; c1 = 0.0; c2 = 0.0; c3 = 0.0; c4 = 0.0; break; 58 | case LP_6: c0 = 0.0; c1 = 1.0; c2 = 0.0; c3 = 0.0; c4 = 0.0; break; 59 | case LP_12: c0 = 0.0; c1 = 0.0; c2 = 1.0; c3 = 0.0; c4 = 0.0; break; 60 | case LP_18: c0 = 0.0; c1 = 0.0; c2 = 0.0; c3 = 1.0; c4 = 0.0; break; 61 | case LP_24: c0 = 0.0; c1 = 0.0; c2 = 0.0; c3 = 0.0; c4 = 1.0; break; 62 | case HP_6: c0 = 1.0; c1 = -1.0; c2 = 0.0; c3 = 0.0; c4 = 0.0; break; 63 | case HP_12: c0 = 1.0; c1 = -2.0; c2 = 1.0; c3 = 0.0; c4 = 0.0; break; 64 | case HP_18: c0 = 1.0; c1 = -3.0; c2 = 3.0; c3 = -1.0; c4 = 0.0; break; 65 | case HP_24: c0 = 1.0; c1 = -4.0; c2 = 6.0; c3 = -4.0; c4 = 1.0; break; 66 | case BP_12_12: c0 = 0.0; c1 = 0.0; c2 = 1.0; c3 = -2.0; c4 = 1.0; break; 67 | case BP_6_18: c0 = 0.0; c1 = 0.0; c2 = 0.0; c3 = 1.0; c4 = -1.0; break; 68 | case BP_18_6: c0 = 0.0; c1 = 1.0; c2 = -3.0; c3 = 3.0; c4 = -1.0; break; 69 | case BP_6_12: c0 = 0.0; c1 = 0.0; c2 = 1.0; c3 = -1.0; c4 = 0.0; break; 70 | case BP_12_6: c0 = 0.0; c1 = 1.0; c2 = -2.0; c3 = 1.0; c4 = 0.0; break; 71 | case BP_6_6: c0 = 0.0; c1 = 1.0; c2 = -1.0; c3 = 0.0; c4 = 0.0; break; 72 | default: c0 = 1.0; c1 = 0.0; c2 = 0.0; c3 = 0.0; c4 = 0.0; // flat 73 | } 74 | } 75 | calculateCoefficientsApprox4(); 76 | } 77 | 78 | //------------------------------------------------------------------------------------------------- 79 | // others: 80 | 81 | void TeeBeeFilter::reset() 82 | { 83 | feedbackHighpass.reset(); 84 | y1 = 0.0; 85 | y2 = 0.0; 86 | y3 = 0.0; 87 | y4 = 0.0; 88 | } 89 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_DecayEnvelope.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_DecayEnvelope_h 2 | #define rosic_DecayEnvelope_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is a class implements an envelope generator that realizes a pure exponential decay. The 13 | output of the envelope is normalized to the range 0...1. 14 | 15 | */ 16 | 17 | class DecayEnvelope 18 | { 19 | 20 | public: 21 | 22 | //--------------------------------------------------------------------------------------------- 23 | // construction/destruction: 24 | 25 | /** Constructor. */ 26 | DecayEnvelope(); 27 | 28 | /** Destructor. */ 29 | ~DecayEnvelope(); 30 | 31 | //--------------------------------------------------------------------------------------------- 32 | // parameter settings: 33 | 34 | /** Sets the sample-rate. */ 35 | void setSampleRate(double newSampleRate); 36 | 37 | /** Sets the time constant for the multiplicative accumulator (which we consider as primarily 38 | responsible for the decaying part) in milliseconds. */ 39 | void setDecayTimeConstant(double newTimeConstant); 40 | 41 | /** Switches into a mode where the normalization is not made with respect to the peak amplitude 42 | but to the sum of the impulse response - if true, the output will be equivalent to a leaky 43 | integrator's impulse response. */ 44 | void setNormalizeSum(bool shouldNormalizeSum); 45 | 46 | //--------------------------------------------------------------------------------------------- 47 | // inquiry: 48 | 49 | /** Returns the length of the decay phase (in milliseconds). */ 50 | double getDecayTimeConstant() const { return tau; } 51 | 52 | /** True, if output is below some threshold. */ 53 | bool endIsReached(double threshold); 54 | 55 | //--------------------------------------------------------------------------------------------- 56 | // audio processing: 57 | 58 | /** Calculates one output sample at a time. */ 59 | INLINE double getSample(); 60 | 61 | //--------------------------------------------------------------------------------------------- 62 | // others: 63 | 64 | /** Triggers the envelope - the next sample retrieved via getSample() will be 1. */ 65 | void trigger(); 66 | 67 | protected: 68 | 69 | /** Calculates the coefficient for multiplicative accumulation. */ 70 | void calculateCoefficient(); 71 | 72 | double c; // coefficient for multiplicative accumulation 73 | double y; // previous output 74 | double yInit; // initial yalue for previous output (= y/c) 75 | double tau; // time-constant (in milliseconds) 76 | double fs; // sample-rate 77 | bool normalizeSum; // flag to indicate that the output should be normalized such that the 78 | // sum of the impulse response is unity (instead of the peak) - if true 79 | // the output will be equivalent to a leaky integrator's impulse 80 | // response 81 | 82 | }; 83 | 84 | //----------------------------------------------------------------------------------------------- 85 | // inlined functions: 86 | 87 | INLINE double DecayEnvelope::getSample() 88 | { 89 | y *= c; 90 | return y; 91 | } 92 | 93 | } // end namespace rosic 94 | 95 | #endif // rosic_DecayEnvelope_h 96 | -------------------------------------------------------------------------------- /Build/CodeBlocks/Open303.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_BiquadFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_BiquadFilter_h 2 | #define rosic_BiquadFilter_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is an implementation of a simple one-pole filter unit. 13 | 14 | */ 15 | 16 | class BiquadFilter 17 | { 18 | 19 | public: 20 | 21 | /** Enumeration of the available filter modes. */ 22 | enum modes 23 | { 24 | BYPASS = 0, 25 | LOWPASS6, 26 | LOWPASS12, 27 | HIGHPASS6, 28 | HIGHPASS12, 29 | BANDPASS, 30 | BANDREJECT, 31 | PEAK, 32 | LOW_SHELF, 33 | //HIGH_SHELF, 34 | //ALLPASS, 35 | 36 | NUM_FILTER_MODES 37 | }; 38 | 39 | //--------------------------------------------------------------------------------------------- 40 | // construction/destruction: 41 | 42 | /** Constructor. */ 43 | BiquadFilter(); 44 | 45 | //--------------------------------------------------------------------------------------------- 46 | // parameter settings: 47 | 48 | /** Sets the sample-rate (in Hz) at which the filter runs. */ 49 | void setSampleRate(double newSampleRate); 50 | 51 | /** Sets the filter mode as one of the values in enum modes. */ 52 | void setMode(int newMode); 53 | 54 | /** Sets the center frequency in Hz. */ 55 | void setFrequency(double newFrequency); 56 | 57 | /** Sets the boost/cut gain in dB. */ 58 | void setGain(double newGain); 59 | 60 | /** Sets the bandwidth in octaves. */ 61 | void setBandwidth(double newBandwidth); 62 | 63 | //--------------------------------------------------------------------------------------------- 64 | // inquiry 65 | 66 | /** Sets the filter mode as one of the values in enum modes. */ 67 | int getMode() const { return mode; } 68 | 69 | /** Returns the center frequency in Hz. */ 70 | double getFrequency() const { return frequency; } 71 | 72 | /** Returns the boost/cut gain in dB. */ 73 | double getGain() const { return gain; } 74 | 75 | /** Returns the bandwidth in octaves. */ 76 | double getBandwidth() const { return bandwidth; } 77 | 78 | //--------------------------------------------------------------------------------------------- 79 | // audio processing: 80 | 81 | /** Calculates a single filtered output-sample. */ 82 | INLINE double getSample(double in); 83 | 84 | //--------------------------------------------------------------------------------------------- 85 | // others: 86 | 87 | /** Resets the internal buffers (for the \f$ x[n-1], y[n-1] \f$-samples) to zero. */ 88 | void reset(); 89 | 90 | //============================================================================================= 91 | 92 | protected: 93 | 94 | // internal functions: 95 | void calcCoeffs(); // calculates filter coefficients from filter parameters 96 | 97 | double b0, b1, b2, a1, a2; 98 | double x1, x2, y1, y2; 99 | 100 | double frequency, gain, bandwidth; 101 | double sampleRate; 102 | int mode; 103 | 104 | }; 105 | 106 | //----------------------------------------------------------------------------------------------- 107 | // inlined functions: 108 | 109 | INLINE double BiquadFilter::getSample(double in) 110 | { 111 | // calculate the output sample: 112 | double y = b0*in + b1*x1 + b2*x2 + a1*y1 + a2*y2 + TINY; 113 | 114 | // update the buffer variables: 115 | x2 = x1; 116 | x1 = in; 117 | y2 = y1; 118 | y1 = y; 119 | 120 | return y; 121 | } 122 | 123 | } // end namespace rosic 124 | 125 | #endif // rosic_BiquadFilter_h 126 | -------------------------------------------------------------------------------- /Source/VSTPlugIn/Open303VST.h: -------------------------------------------------------------------------------- 1 | #ifndef Open303VST_h 2 | #define Open303VST_h 3 | 4 | #include "public.sdk/source/vst2.x/audioeffectx.h" 5 | #include "../DSPCode/rosic_Open303.h" 6 | using namespace rosic; 7 | 8 | //#define SHOW_INTERNAL_PARAMETERS // comment this for builds that should only show 'user'-parameters 9 | 10 | enum Open303Parameters 11 | { 12 | WAVEFORM = 0, 13 | TUNING, 14 | CUTOFF, 15 | RESONANCE, 16 | ENVMOD, 17 | DECAY, 18 | ACCENT, 19 | VOLUME, 20 | 21 | FILTER_TYPE, 22 | 23 | #ifdef SHOW_INTERNAL_PARAMETERS 24 | AMP_SUSTAIN, 25 | TANH_SHAPER_DRIVE, 26 | TANH_SHAPER_OFFSET, 27 | PRE_FILTER_HPF, 28 | FEEDBACK_HPF, 29 | POST_FILTER_HPF, 30 | SQUARE_PHASE_SHIFT, 31 | #endif 32 | 33 | OPEN303_NUM_PARAMETERS 34 | }; 35 | 36 | //================================================================================================= 37 | // class Open303VSTProgram: 38 | 39 | class Open303VSTProgram 40 | { 41 | friend class Open303VST; 42 | public: 43 | Open303VSTProgram(); 44 | ~Open303VSTProgram() {} 45 | private: 46 | float parameters[OPEN303_NUM_PARAMETERS]; 47 | char name[kVstMaxProgNameLen+1]; 48 | }; 49 | 50 | //================================================================================================= 51 | // class Open303VST: 52 | 53 | class Open303VST : public AudioEffectX 54 | { 55 | public: 56 | 57 | // construction/destruction: 58 | Open303VST (audioMasterCallback audioMaster); 59 | ~Open303VST(); 60 | 61 | // audio- and event processing: 62 | virtual void processReplacing(float** inputs, float** outputs, VstInt32 sampleFrames); 63 | virtual VstInt32 processEvents (VstEvents* events); 64 | virtual void handleEvent (VstMidiEvent midiEvent); 65 | 66 | // program handling: 67 | virtual void setProgram (VstInt32 program); 68 | virtual void setProgramName (char* name); 69 | virtual void getProgramName (char* name); 70 | virtual bool getProgramNameIndexed(VstInt32 category, VstInt32 index, char* text); 71 | 72 | // parameter handling: 73 | virtual void setParameter (VstInt32 index, float value); 74 | virtual float getParameter (VstInt32 index); 75 | virtual void getParameterLabel (VstInt32 index, char* label); 76 | virtual void getParameterDisplay(VstInt32 index, char* text); 77 | virtual void getParameterName (VstInt32 index, char* text); 78 | 79 | // audio processing parameters: 80 | virtual void setSampleRate(float sampleRate); 81 | virtual void setBlockSize (VstInt32 blockSize); 82 | 83 | // callbacks to pass plugin info to the host: 84 | virtual bool getOutputProperties(VstInt32 index, VstPinProperties* properties); 85 | virtual bool getEffectName (char* name); 86 | virtual bool getVendorString (char* text); 87 | virtual bool getProductString(char* text); 88 | virtual VstInt32 getVendorVersion(); 89 | virtual VstInt32 canDo (char* text); 90 | virtual VstInt32 getNumMidiInputChannels () { return 1; } 91 | virtual VstInt32 getNumMidiOutputChannels() { return 0; } 92 | 93 | private: 94 | 95 | // internal functions: 96 | void noteOn(VstInt32 note, VstInt32 velocity, VstInt32 delta); 97 | 98 | /** Converts the data bytes of a MIDI pitchwheel message into a value in semitones. */ 99 | double convertToPitch(unsigned char highByte,unsigned char lowByte); 100 | 101 | static const int numOutputs = 2; 102 | static const int numPrograms = 128; 103 | 104 | // program handling: 105 | Open303VSTProgram* programs; 106 | VstInt32 channelPrograms[16]; 107 | 108 | // MIDI event handling: 109 | int eventBufferLength; 110 | VstEvent *eventBuffer; 111 | 112 | // the embedded core dsp object: 113 | Open303 open303Core; 114 | 115 | }; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_EllipticQuarterBandFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_EllipticQuarterBandFilter_h 2 | #define rosic_EllipticQuarterBandFilter_h 3 | 4 | #include // for memmove 5 | 6 | // rosic-indcludes: 7 | #include "GlobalDefinitions.h" 8 | 9 | namespace rosic 10 | { 11 | 12 | /** 13 | 14 | This is an elliptic subband filter of 12th order using a Direct Form II implementation structure. 15 | 16 | */ 17 | 18 | class EllipticQuarterBandFilter 19 | { 20 | 21 | public: 22 | 23 | //--------------------------------------------------------------------------------------------- 24 | // construction/destruction: 25 | 26 | /** Constructor. */ 27 | EllipticQuarterBandFilter(); 28 | 29 | //--------------------------------------------------------------------------------------------- 30 | // parameter settings: 31 | 32 | /** Resets the filter state. */ 33 | void reset(); 34 | 35 | //--------------------------------------------------------------------------------------------- 36 | // audio processing: 37 | 38 | /** Calculates a single filtered output-sample. */ 39 | INLINE double getSample(double in); 40 | 41 | //============================================================================================= 42 | 43 | protected: 44 | 45 | // state buffer: 46 | double w[12]; 47 | 48 | }; 49 | 50 | //----------------------------------------------------------------------------------------------- 51 | // inlined functions: 52 | 53 | INLINE double EllipticQuarterBandFilter::getSample(double in) 54 | { 55 | const double a01 = -9.1891604652189471; 56 | const double a02 = 40.177553696870497; 57 | const double a03 = -110.11636661771178; 58 | const double a04 = 210.18506612078195; 59 | const double a05 = -293.84744771903240; 60 | const double a06 = 308.16345558359234; 61 | const double a07 = -244.06786780384243; 62 | const double a08 = 144.81877911392738; 63 | const double a09 = -62.770692151724198; 64 | const double a10 = 18.867762095902137; 65 | const double a11 = -3.5327094230551848; 66 | const double a12 = 0.31183189275203149; 67 | 68 | const double b00 = 0.00013671732099945628; 69 | const double b01 = -0.00055538501265606384; 70 | const double b02 = 0.0013681887636296387; 71 | const double b03 = -0.0022158566490711852; 72 | const double b04 = 0.0028320091007278322; 73 | const double b05 = -0.0029776933151090413; 74 | const double b06 = 0.0030283628243514991; 75 | const double b07 = -0.0029776933151090413; 76 | const double b08 = 0.0028320091007278331; 77 | const double b09 = -0.0022158566490711861; 78 | const double b10 = 0.0013681887636296393; 79 | const double b11 = -0.00055538501265606384; 80 | const double b12 = 0.00013671732099945636; 81 | 82 | // calculate intermediate and output sample via direct form II - the parentheses facilitate 83 | // out-of-order execution of the independent additions (for performance optimization): 84 | double tmp = (in + TINY) 85 | - ( (a01*w[0] + a02*w[1] ) + (a03*w[2] + a04*w[3] ) ) 86 | - ( (a05*w[4] + a06*w[5] ) + (a07*w[6] + a08*w[7] ) ) 87 | - ( (a09*w[8] + a10*w[9] ) + (a11*w[10] + a12*w[11] ) ); 88 | 89 | double y = b00*tmp 90 | + ( (b01*w[0] + b02*w[1]) + (b03*w[2] + b04*w[3] ) ) 91 | + ( (b05*w[4] + b06*w[5]) + (b07*w[6] + b08*w[7] ) ) 92 | + ( (b09*w[8] + b10*w[9]) + (b11*w[10] + b12*w[11] ) ); 93 | 94 | // update state variables: 95 | memmove(&w[1], &w[0], 11*sizeof(double)); 96 | w[0] = tmp; 97 | 98 | return y; 99 | } 100 | 101 | } // end namespace rosic 102 | 103 | #endif // rosic_EllipticQuarterBandFilter_h 104 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_OnePoleFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_OnePoleFilter.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | OnePoleFilter::OnePoleFilter() 8 | { 9 | shelvingGain = 1.0; 10 | setSampleRate(44100.0); // sampleRate = 44100 Hz by default 11 | setMode (0); // bypass by default 12 | setCutoff (20000.0); // cutoff = 20000 Hz by default 13 | reset(); // reset memorized samples to zero 14 | } 15 | 16 | //------------------------------------------------------------------------------------------------- 17 | // parameter settings: 18 | 19 | void OnePoleFilter::setSampleRate(double newSampleRate) 20 | { 21 | if( newSampleRate > 0.0 ) 22 | sampleRate = newSampleRate; 23 | sampleRateRec = 1.0 / sampleRate; 24 | 25 | calcCoeffs(); 26 | return; 27 | } 28 | 29 | void OnePoleFilter::setMode(int newMode) 30 | { 31 | mode = newMode; // 0:bypass, 1:Low Pass, 2:High Pass 32 | calcCoeffs(); 33 | } 34 | 35 | void OnePoleFilter::setCutoff(double newCutoff) 36 | { 37 | if( (newCutoff>0.0) && (newCutoff<=20000.0) ) 38 | cutoff = newCutoff; 39 | else 40 | cutoff = 20000.0; 41 | 42 | calcCoeffs(); 43 | return; 44 | } 45 | 46 | void OnePoleFilter::setShelvingGain(double newGain) 47 | { 48 | if( newGain > 0.0 ) 49 | { 50 | shelvingGain = newGain; 51 | calcCoeffs(); 52 | } 53 | else 54 | DEBUG_BREAK; // this is a linear gain factor and must be >= 0.0 55 | } 56 | 57 | void OnePoleFilter::setShelvingGainInDecibels(double newGain) 58 | { 59 | setShelvingGain(dB2amp(newGain)); 60 | } 61 | 62 | void OnePoleFilter::setCoefficients(double newB0, double newB1, double newA1) 63 | { 64 | b0 = newB0; 65 | b1 = newB1; 66 | a1 = newA1; 67 | } 68 | 69 | void OnePoleFilter::setInternalState(double newX1, double newY1) 70 | { 71 | x1 = newX1; 72 | y1 = newY1; 73 | } 74 | 75 | //------------------------------------------------------------------------------------------------- 76 | //others: 77 | 78 | void OnePoleFilter::calcCoeffs() 79 | { 80 | switch(mode) 81 | { 82 | case LOWPASS: 83 | { 84 | // formula from dspguide: 85 | double x = exp( -2.0 * PI * cutoff * sampleRateRec); 86 | b0 = 1-x; 87 | b1 = 0.0; 88 | a1 = x; 89 | } 90 | break; 91 | case HIGHPASS: 92 | { 93 | // formula from dspguide: 94 | double x = exp( -2.0 * PI * cutoff * sampleRateRec); 95 | b0 = 0.5*(1+x); 96 | b1 = -0.5*(1+x); 97 | a1 = x; 98 | } 99 | break; 100 | case LOWSHELV: 101 | { 102 | // formula from DAFX: 103 | double c = 0.5*(shelvingGain-1.0); 104 | double t = tan(PI*cutoff*sampleRateRec); 105 | double a; 106 | if( shelvingGain >= 1.0 ) 107 | a = (t-1.0)/(t+1.0); 108 | else 109 | a = (t-shelvingGain)/(t+shelvingGain); 110 | 111 | b0 = 1.0 + c + c*a; 112 | b1 = c + c*a + a; 113 | a1 = -a; 114 | } 115 | break; 116 | case HIGHSHELV: 117 | { 118 | // formula from DAFX: 119 | double c = 0.5*(shelvingGain-1.0); 120 | double t = tan(PI*cutoff*sampleRateRec); 121 | double a; 122 | if( shelvingGain >= 1.0 ) 123 | a = (t-1.0)/(t+1.0); 124 | else 125 | a = (shelvingGain*t-1.0)/(shelvingGain*t+1.0); 126 | 127 | b0 = 1.0 + c - c*a; 128 | b1 = a + c*a - c; 129 | a1 = -a; 130 | } 131 | break; 132 | 133 | case ALLPASS: 134 | { 135 | // formula from DAFX: 136 | double t = tan(PI*cutoff*sampleRateRec); 137 | double x = (t-1.0) / (t+1.0); 138 | 139 | b0 = x; 140 | b1 = 1.0; 141 | a1 = -x; 142 | } 143 | break; 144 | 145 | default: // bypass 146 | { 147 | b0 = 1.0; 148 | b1 = 0.0; 149 | a1 = 0.0; 150 | }break; 151 | } 152 | } 153 | 154 | void OnePoleFilter::reset() 155 | { 156 | x1 = 0.0; 157 | y1 = 0.0; 158 | } 159 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_OnePoleFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_OnePoleFilter_h 2 | #define rosic_OnePoleFilter_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is an implementation of a simple one-pole filter unit. 13 | 14 | */ 15 | 16 | class OnePoleFilter 17 | { 18 | 19 | public: 20 | 21 | /** This is an enumeration of the available filter modes. */ 22 | enum modes 23 | { 24 | BYPASS = 0, 25 | LOWPASS, 26 | HIGHPASS, 27 | LOWSHELV, 28 | HIGHSHELV, 29 | ALLPASS 30 | }; 31 | // \todo (maybe): let the user choose between LP/HP versions obtained via bilinear trafo and 32 | // impulse invariant trafo 33 | 34 | //--------------------------------------------------------------------------------------------- 35 | // construction/destruction: 36 | 37 | /** Constructor. */ 38 | OnePoleFilter(); 39 | 40 | //--------------------------------------------------------------------------------------------- 41 | // parameter settings: 42 | 43 | /** Sets the sample-rate. */ 44 | void setSampleRate(double newSampleRate); 45 | 46 | /** Chooses the filter mode. See the enumeration for available modes. */ 47 | void setMode(int newMode); 48 | 49 | /** Sets the cutoff-frequency for this filter. */ 50 | void setCutoff(double newCutoff); 51 | 52 | /** This will set the time constant 'tau' for the case, when lowpass mode is chosen. This is 53 | the time, it takes for the impulse response to die away to 1/e = 0.368... or equivalently, the 54 | time it takes for the step response to raise to 1-1/e = 0.632... */ 55 | void setLowpassTimeConstant(double newTimeConstant) { setCutoff(1.0/(2*PI*newTimeConstant)); } 56 | 57 | /** Sets the gain factor for the shelving modes (this is not in decibels). */ 58 | void setShelvingGain(double newGain); 59 | 60 | /** Sets the gain for the shelving modes in decibels. */ 61 | void setShelvingGainInDecibels(double newGain); 62 | 63 | /** Sets the filter coefficients manually. */ 64 | void setCoefficients(double newB0, double newB1, double newA1); 65 | 66 | /** Sets up the internal state variables for both channels. */ 67 | void setInternalState(double newX1, double newY1); 68 | 69 | //--------------------------------------------------------------------------------------------- 70 | // inquiry 71 | 72 | /** Returns the cutoff-frequency. */ 73 | double getCutoff() const { return cutoff; } 74 | 75 | //--------------------------------------------------------------------------------------------- 76 | // audio processing: 77 | 78 | /** Calculates a single filtered output-sample. */ 79 | INLINE double getSample(double in); 80 | 81 | //--------------------------------------------------------------------------------------------- 82 | // others: 83 | 84 | /** Resets the internal buffers (for the \f$ x[n-1], y[n-1] \f$-samples) to zero. */ 85 | void reset(); 86 | 87 | //============================================================================================= 88 | 89 | protected: 90 | 91 | // buffering: 92 | double x1, y1; 93 | 94 | // filter coefficients: 95 | double b0; // feedforward coeffs 96 | double b1; 97 | double a1; // feedback coeff 98 | 99 | // filter parameters: 100 | double cutoff; 101 | double shelvingGain; 102 | int mode; 103 | 104 | double sampleRate; 105 | double sampleRateRec; // reciprocal of the sampleRate 106 | 107 | // internal functions: 108 | void calcCoeffs(); // calculates filter coefficients from filter parameters 109 | 110 | }; 111 | 112 | //----------------------------------------------------------------------------------------------- 113 | // inlined functions: 114 | 115 | INLINE double OnePoleFilter::getSample(double in) 116 | { 117 | // calculate the output sample: 118 | y1 = b0*in + b1*x1 + a1*y1 + TINY; 119 | 120 | // update the buffer variables: 121 | x1 = in; 122 | 123 | return y1; 124 | } 125 | 126 | } // end namespace rosic 127 | 128 | #endif // rosic_OnePoleFilter_h 129 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_AcidPattern.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_AcidPattern_h 2 | #define rosic_AcidPattern_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | #include "rosic_FunctionTemplates.h" 7 | 8 | namespace rosic 9 | { 10 | 11 | /** 12 | 13 | This is a class for representing note-events of acid-lines involving slides and accents. 14 | 15 | */ 16 | 17 | class AcidNote 18 | { 19 | public: 20 | 21 | int key; 22 | int octave; 23 | bool accent; 24 | bool slide; 25 | bool gate; 26 | 27 | AcidNote() 28 | { 29 | key = 0; 30 | octave = 0; 31 | accent = false; 32 | slide = false; 33 | gate = false; 34 | } 35 | 36 | bool isInDefaultState() 37 | { return key == 0 && octave == 0 && accent == false && slide == false && gate == false; } 38 | 39 | }; 40 | 41 | /** 42 | 43 | This is a class for representing typical acid-lines involving slides and accents. 44 | 45 | */ 46 | 47 | class AcidPattern 48 | { 49 | 50 | public: 51 | 52 | //--------------------------------------------------------------------------------------------- 53 | // construction/destruction: 54 | 55 | /** Constructor. */ 56 | AcidPattern(); 57 | 58 | //--------------------------------------------------------------------------------------------- 59 | // setup: 60 | 61 | /** Sets the length of one step (the time while gate is open) in units of one step (which 62 | is one 16th note). */ 63 | void setStepLength(double newStepLength) { stepLength = newStepLength; } 64 | 65 | /** Sets the key for one of the steps (between 0...12, where 0 and 12 is a C). */ 66 | void setKey(int step, int newKey) { notes[step].key = newKey; } 67 | 68 | /** Sets the octave for one of the steps (0 is the root octave between C2...B2). */ 69 | void setOctave(int step, int newOctave) { notes[step].octave = newOctave; } 70 | 71 | /** Sets the accent flag for one of the steps. */ 72 | void setAccent(int step, bool shouldBeAccented) { notes[step].accent = shouldBeAccented; } 73 | 74 | /** Sets the slide flag for one of the steps. */ 75 | void setSlide(int step, bool shouldHaveSlide) { notes[step].slide = shouldHaveSlide; } 76 | 77 | /** Sets the gate flag for one of the steps. */ 78 | void setGate(int step, bool shouldBeOpen) { notes[step].gate = shouldBeOpen; } 79 | 80 | /** Clears all notes in the pattern. */ 81 | void clear(); 82 | 83 | /** Randomizes all notes in the pattern. \todo: restrict possible note-values to some scales*/ 84 | void randomize(); 85 | 86 | /* 87 | void setRandomSeed(int newSeed); 88 | void resetRandomSeed(); 89 | void rendomizeGates(); 90 | void randomizeNotes(); 91 | void randomizeAccents(); 92 | void randomizeSlides(); 93 | void randomizeOctaves(int maxOctavesUp, int maxOctavesDown); 94 | */ 95 | 96 | /** Circularly shifts the whole pattern by the given number of steps. */ 97 | void circularShift(int numStepsToShift); 98 | 99 | //--------------------------------------------------------------------------------------------- 100 | // inquiry: 101 | 102 | /** Returns the length of one step (the time while gate is open) in units of one step (which 103 | is one 16th note). */ 104 | double getStepLength() const { return stepLength; } 105 | 106 | /** Returns the key for one of the steps (between 0...12, where 0 and 12 is a C). */ 107 | int getKey(int step) const { return notes[step].key; } 108 | 109 | /** Returns the octave for one of the steps (0 is the root octave between C2...B2). */ 110 | int getOctave(int step) const { return notes[step].octave; } 111 | 112 | /** Returns the accent flag for one of the steps. */ 113 | bool getAccent(int step) const { return notes[step].accent; } 114 | 115 | /** Returns the slide flag for one of the steps. */ 116 | bool getSlide(int step) const { return notes[step].slide; } 117 | 118 | /** Returns the gate flag for one of the steps. */ 119 | bool getGate(int step) const { return notes[step].gate; } 120 | 121 | /** Returns the maximum number of steps. */ 122 | static int getMaxNumSteps() { return maxNumSteps; } 123 | 124 | /** Returns the current number of steps. */ 125 | int getNumSteps() const { return numSteps; } 126 | 127 | /** Returns true if the pattern is empty, false otherwise. */ 128 | bool isEmpty() const; 129 | 130 | /** Returns a pointer to the note at the given step. */ 131 | AcidNote* getNote(int step) { return ¬es[step]; } 132 | 133 | //============================================================================================= 134 | 135 | protected: 136 | 137 | static const int maxNumSteps = 16; 138 | AcidNote notes[maxNumSteps]; 139 | 140 | int numSteps; // number of steps in the pattern 141 | double stepLength; // step length in step units (16th notes) 142 | 143 | }; 144 | 145 | } // end namespace rosic 146 | 147 | #endif // rosic_AcidPattern_h 148 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_AnalogEnvelope.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_AnalogEnvelope.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | AnalogEnvelope::AnalogEnvelope() 8 | { 9 | sampleRate = 44100.0; 10 | startLevel = 0.0; 11 | attackTime = 0.0; 12 | peakLevel = 1.0; 13 | holdTime = 0.0; 14 | decayTime = 0.1; 15 | sustainLevel = 0.5; 16 | releaseTime = 0.01; 17 | endLevel = 0.0; 18 | time = 0.0; 19 | timeScale = 1.0; 20 | peakByVel = 1.0; 21 | peakByKey = 1.0; 22 | timeScaleByVel = 1.0; 23 | timeScaleByKey = 1.0; 24 | increment = 1000.0*timeScale/sampleRate; 25 | tauScale = 1.0; 26 | peakScale = 1.0; 27 | noteIsOn = false; 28 | outputIsZero = true; 29 | 30 | previousOutput = 0.0; 31 | 32 | // call these functions to trigger the coefficient calculations: 33 | setAttack(attackTime); 34 | setDecay(decayTime); 35 | setRelease(releaseTime); 36 | } 37 | 38 | AnalogEnvelope::~AnalogEnvelope() 39 | { 40 | 41 | } 42 | 43 | //------------------------------------------------------------------------------------------------- 44 | // parameter settings: 45 | 46 | void AnalogEnvelope::setSampleRate(double newSampleRate) 47 | { 48 | if( newSampleRate > 0.0 ) 49 | sampleRate = newSampleRate; 50 | 51 | // adjust time increment: 52 | increment = 1000.0*timeScale/sampleRate; 53 | 54 | //re-calculate coefficients for the 3 filters: 55 | setAttack (attackTime); 56 | setDecay (decayTime); 57 | setRelease(releaseTime); 58 | } 59 | 60 | void AnalogEnvelope::setAttack(double newAttackTime) 61 | { 62 | if( newAttackTime > 0.0 ) 63 | { 64 | attackTime = newAttackTime; 65 | double tau = (sampleRate*0.001*attackTime) * tauScale/timeScale; 66 | attackCoeff = 1.0 - exp( -1.0 / tau ); 67 | } 68 | else // newAttackTime <= 0 69 | { 70 | attackTime = 0.0; 71 | attackCoeff = 1.0; 72 | } 73 | calculateAccumulatedTimes(); 74 | } 75 | 76 | void AnalogEnvelope::setHold(double newHoldTime) 77 | { 78 | if( newHoldTime >= 0 ) 79 | holdTime = newHoldTime; 80 | calculateAccumulatedTimes(); 81 | } 82 | 83 | void AnalogEnvelope::setDecay(double newDecayTime) 84 | { 85 | if( newDecayTime > 0.0 ) 86 | { 87 | decayTime = newDecayTime; 88 | double tau = (sampleRate*0.001*decayTime) * tauScale/timeScale; 89 | decayCoeff = 1.0 - exp( -1.0 / tau ); 90 | } 91 | else // newDecayTime <= 0 92 | { 93 | decayTime = 0.0; 94 | decayCoeff = 1.0; 95 | } 96 | calculateAccumulatedTimes(); 97 | } 98 | 99 | void AnalogEnvelope::setRelease(double newReleaseTime) 100 | { 101 | if( newReleaseTime > 0.0 ) 102 | { 103 | releaseTime = newReleaseTime; 104 | double tau = (sampleRate*0.001*releaseTime) * tauScale/timeScale; 105 | releaseCoeff = 1.0 - exp( -1.0 / tau ); 106 | } 107 | else // newReleaseTime <= 0 108 | { 109 | releaseTime = 0.0; 110 | releaseCoeff = 1.0; 111 | } 112 | calculateAccumulatedTimes(); 113 | } 114 | 115 | void AnalogEnvelope::setTimeScale(double newTimeScale) 116 | { 117 | if( newTimeScale > 0 ) 118 | timeScale = newTimeScale; 119 | 120 | increment = 1000.0*timeScale/sampleRate; 121 | 122 | //re-calculate coefficients for the 3 filters: 123 | setAttack (attackTime); 124 | setDecay (decayTime); 125 | setRelease(releaseTime); 126 | } 127 | 128 | void AnalogEnvelope::setTauScale(double newTauScale) 129 | { 130 | if( newTauScale > 0 ) 131 | tauScale = newTauScale; 132 | 133 | setAttack(attackTime); 134 | setDecay(decayTime); 135 | setRelease(releaseTime); 136 | } 137 | 138 | void AnalogEnvelope::setPeakScale(double newPeakScale) 139 | { 140 | if( newPeakScale > 0 ) 141 | peakScale = newPeakScale; 142 | } 143 | 144 | //------------------------------------------------------------------------------------------------- 145 | // others: 146 | 147 | void AnalogEnvelope::reset() 148 | { 149 | time = 0.0; 150 | } 151 | 152 | void AnalogEnvelope::noteOn(bool startFromCurrentLevel) 153 | { 154 | if( !startFromCurrentLevel ) 155 | previousOutput = startLevel; // may lead to clicks 156 | 157 | 158 | // \todo: calculate key and velocity scale factors for duration and peak-value... 159 | 160 | 161 | // reset time for the new note: 162 | time = 0.0; 163 | noteIsOn = true; 164 | outputIsZero = false; 165 | } 166 | 167 | void AnalogEnvelope::noteOff() 168 | { 169 | noteIsOn = false; 170 | 171 | // advance time to the beginnig of the release phase: 172 | time = (attackTime + holdTime + decayTime + increment); 173 | } 174 | 175 | bool AnalogEnvelope::endIsReached() 176 | { 177 | //return false; // test 178 | 179 | if( noteIsOn == false && previousOutput < 0.000001 ) 180 | return true; 181 | else 182 | return false; 183 | } 184 | 185 | //------------------------------------------------------------------------------------------------- 186 | // internal functions: 187 | 188 | void AnalogEnvelope::calculateAccumulatedTimes() 189 | { 190 | attPlusHld = attackTime + holdTime; 191 | attPlusHldPlusDec = attPlusHld + decayTime; 192 | attPlusHldPlusDecPlusRel = attPlusHldPlusDec + releaseTime; 193 | } 194 | -------------------------------------------------------------------------------- /Build/CodeBlocks/Open303.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 108 | 109 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_BiquadFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_BiquadFilter.h" 2 | using namespace rosic; 3 | 4 | //------------------------------------------------------------------------------------------------- 5 | // construction/destruction: 6 | 7 | BiquadFilter::BiquadFilter() 8 | { 9 | frequency = 1000.0; 10 | gain = 0.0; 11 | bandwidth = 2.0*asinh(1.0/sqrt(2.0))/log(2.0); 12 | sampleRate = 44100.0; 13 | mode = BYPASS; 14 | calcCoeffs(); 15 | reset(); 16 | } 17 | 18 | //------------------------------------------------------------------------------------------------- 19 | // parameter settings: 20 | 21 | void BiquadFilter::setSampleRate(double newSampleRate) 22 | { 23 | if( newSampleRate > 0.0 ) 24 | sampleRate = newSampleRate; 25 | calcCoeffs(); 26 | } 27 | 28 | void BiquadFilter::setMode(int newMode) 29 | { 30 | mode = newMode; // 0:bypass, 1:Low Pass, 2:High Pass 31 | calcCoeffs(); 32 | } 33 | 34 | void BiquadFilter::setFrequency(double newFrequency) 35 | { 36 | frequency = newFrequency; 37 | calcCoeffs(); 38 | } 39 | 40 | void BiquadFilter::setGain(double newGain) 41 | { 42 | gain = newGain; 43 | calcCoeffs(); 44 | } 45 | 46 | void BiquadFilter::setBandwidth(double newBandwidth) 47 | { 48 | bandwidth = newBandwidth; 49 | calcCoeffs(); 50 | } 51 | 52 | //------------------------------------------------------------------------------------------------- 53 | //others: 54 | 55 | void BiquadFilter::calcCoeffs() 56 | { 57 | double w = 2*PI*frequency/sampleRate; 58 | double s, c; 59 | switch(mode) 60 | { 61 | case LOWPASS6: 62 | { 63 | // formula from dspguide: 64 | double x = exp(-w); 65 | a1 = x; 66 | a2 = 0.0; 67 | b0 = 1.0-x; 68 | b1 = 0.0; 69 | b2 = 0.0; 70 | } 71 | break; 72 | case LOWPASS12: 73 | { 74 | // formula from Robert Bristow Johnson's biquad cookbook: 75 | sinCos(w, &s, &c); 76 | double q = dB2amp(gain); 77 | double alpha = s/(2.0*q); 78 | double scale = 1.0/(1.0+alpha); 79 | a1 = 2.0*c * scale; 80 | a2 = (alpha-1.0) * scale; 81 | b1 = (1.0-c) * scale; 82 | b0 = 0.5*b1; 83 | b2 = b0; 84 | } 85 | break; 86 | case HIGHPASS6: 87 | { 88 | // formula from dspguide: 89 | double x = exp(-w); 90 | a1 = x; 91 | a2 = 0.0; 92 | b0 = 0.5*(1.0+x); 93 | b1 = -b0; 94 | b2 = 0.0; 95 | } 96 | break; 97 | case HIGHPASS12: 98 | { 99 | // formula from Robert Bristow Johnson's biquad cookbook: 100 | sinCos(w, &s, &c); 101 | double q = dB2amp(gain); 102 | double alpha = s/(2.0*q); 103 | double scale = 1.0/(1.0+alpha); 104 | a1 = 2.0*c * scale; 105 | a2 = (alpha-1.0) * scale; 106 | b1 = -(1.0+c) * scale; 107 | b0 = -0.5*b1; 108 | b2 = b0; 109 | } 110 | break; 111 | case BANDPASS: 112 | { 113 | // formula from Robert Bristow Johnson's biquad cookbook: 114 | sinCos(w, &s, &c); 115 | double alpha = s * sinh( 0.5*log(2.0) * bandwidth * w / s ); 116 | double scale = 1.0/(1.0+alpha); 117 | a1 = 2.0*c * scale; 118 | a2 = (alpha-1.0) * scale; 119 | b1 = 0.0; 120 | b0 = 0.5*s * scale; 121 | b2 = -b0; 122 | } 123 | break; 124 | case BANDREJECT: 125 | { 126 | // formula from Robert Bristow Johnson's biquad cookbook: 127 | sinCos(w, &s, &c); 128 | double alpha = s * sinh( 0.5*log(2.0) * bandwidth * w / s ); 129 | double scale = 1.0/(1.0+alpha); 130 | a1 = 2.0*c * scale; 131 | a2 = (alpha-1.0) * scale; 132 | b0 = 1.0 * scale; 133 | b1 = -2.0*c * scale; 134 | b2 = 1.0 * scale; 135 | } 136 | break; 137 | case PEAK: 138 | { 139 | // formula from Robert Bristow Johnson's biquad cookbook: 140 | sinCos(w, &s, &c); 141 | double alpha = s * sinh( 0.5*log(2.0) * bandwidth * w / s ); 142 | double A = dB2amp(gain); 143 | double scale = 1.0/(1.0+alpha/A); 144 | a1 = 2.0*c * scale; 145 | a2 = ((alpha/A) - 1.0) * scale; 146 | b0 = (1.0+alpha*A) * scale; 147 | b1 = -2.0*c * scale; 148 | b2 = (1.0-alpha*A) * scale; 149 | } 150 | break; 151 | case LOW_SHELF: 152 | { 153 | // formula from Robert Bristow Johnson's biquad cookbook: 154 | sinCos(w, &s, &c); 155 | double A = dB2amp(0.5*gain); 156 | double q = 1.0 / (2.0*sinh( 0.5*log(2.0) * bandwidth )); 157 | double beta = sqrt(A) / q; 158 | double scale = 1.0 / ( (A+1.0) + (A-1.0)*c + beta*s); 159 | a1 = 2.0 * ( (A-1.0) + (A+1.0)*c ) * scale; 160 | a2 = - ( (A+1.0) + (A-1.0)*c - beta*s ) * scale; 161 | b0 = A * ( (A+1.0) - (A-1.0)*c + beta*s ) * scale; 162 | b1 = 2.0 * A * ( (A-1.0) - (A+1.0)*c ) * scale; 163 | b2 = A * ( (A+1.0) - (A-1.0)*c - beta*s ) * scale; 164 | } 165 | break; 166 | 167 | 168 | 169 | 170 | // \todo: implement shelving and allpass modes 171 | 172 | default: // bypass 173 | { 174 | b0 = 1.0; 175 | b1 = 0.0; 176 | b2 = 0.0; 177 | a1 = 0.0; 178 | a2 = 0.0; 179 | }break; 180 | } 181 | } 182 | 183 | void BiquadFilter::reset() 184 | { 185 | x1 = 0.0; 186 | x2 = 0.0; 187 | y1 = 0.0; 188 | y2 = 0.0; 189 | } 190 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_RealFunctions.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_RealFunctions_h 2 | #define rosic_RealFunctions_h 3 | 4 | // standard library includes: 5 | #include 6 | #include 7 | 8 | // rosic includes: 9 | #include "GlobalFunctions.h" 10 | #include "rosic_NumberManipulations.h" 11 | 12 | namespace rosic 13 | { 14 | 15 | /** Inverse hyperbolic sine. */ 16 | INLINE double asinh(double x); 17 | 18 | /** Returns -1.0 if x is below low, 0.0 if x is between low and high and 1.0 if x is above high. */ 19 | INLINE double belowOrAbove(double x, double low, double high); 20 | 21 | /** Clips x into the range min...max. */ 22 | template 23 | INLINE T clip(T x, T min, T max); 24 | 25 | /** Evaluates the quartic polynomial y = a4*x^4 + a3*x^3 + a2*x^2 + a1*x + a0 at x. */ 26 | INLINE double evaluateQuartic(double x, double a0, double a1, double a2, double a3, double a4); 27 | 28 | /** foldover at the specified value */ 29 | INLINE double foldOver(double x, double min, double max); 30 | 31 | /** Computes an integer power of x by successively multiplying x with itself. */ 32 | INLINE double integerPower(double x, int exponent); 33 | 34 | /** Generates a pseudo-random number between min and max. */ 35 | INLINE double random(double min=0.0, double max=1.0); 36 | 37 | /** Generates a 2*pi periodic saw wave. */ 38 | INLINE double sawWave(double x); 39 | 40 | /** Calculates sine and cosine of x - this is more efficient than calling sin(x) and 41 | cos(x) seperately. */ 42 | INLINE void sinCos(double x, double* sinResult, double* cosResult); 43 | 44 | /** Calculates a parabolic approximation of the sine and cosine of x. */ 45 | INLINE void sinCosApprox(double x, double* sinResult, double* cosResult); 46 | 47 | /** Generates a 2*pi periodic square wave. */ 48 | INLINE double sqrWave(double x); 49 | 50 | /** Rational approximation of the hyperbolic tangent. */ 51 | INLINE double tanhApprox(double x); 52 | 53 | /** Generates a 2*pi periodic triangle wave. */ 54 | INLINE double triWave(double x); 55 | 56 | //=============================================================================================== 57 | // implementation: 58 | 59 | INLINE double asinh(double x) 60 | { 61 | return log(x + sqrt(x*x+1) ); 62 | } 63 | 64 | INLINE double belowOrAbove(double x, double low, double high) 65 | { 66 | if( x < low ) 67 | return -1.0; 68 | else if ( x > high ) 69 | return 1.0; 70 | else 71 | return 0.0; 72 | } 73 | 74 | template 75 | INLINE T clip(T x, T min, T max) 76 | { 77 | if( x > max ) 78 | return max; 79 | else if ( x < min ) 80 | return min; 81 | else return x; 82 | } 83 | 84 | INLINE double evaluateQuartic(double x, double a0, double a1, double a2, double a3, double a4) 85 | { 86 | double x2 = x*x; 87 | return x*(a3*x2+a1) + x2*(a4*x2+a2) + a0; 88 | } 89 | 90 | INLINE double foldOver(double x, double min, double max) 91 | { 92 | if( x > max ) 93 | return max - (x-max); 94 | else if( x < min ) 95 | return min - (x-min); 96 | else return x; 97 | } 98 | 99 | INLINE double integerPower(double x, int exponent) 100 | { 101 | double accu = 1.0; 102 | for(int i=0; i 2.0*PI ) 144 | x -= 2*PI; 145 | while( x < 0.0 ) 146 | x += 2*PI; 147 | 148 | if( x < PI/2 ) 149 | { 150 | double tmp1 = x; 151 | double tmp2 = (2/PI) * tmp1 - 0.5; 152 | double tmp3 = (2-4*c)*tmp2*tmp2 + c; 153 | *sinResult = tmp3 + tmp2; 154 | *cosResult = tmp3 - tmp2; 155 | } 156 | else if( x < PI ) 157 | { 158 | double tmp1 = (x-PI/2); 159 | double tmp2 = 0.5 - (2/PI) * tmp1; 160 | double tmp3 = (2-4*c)*tmp2*tmp2 + c; 161 | *sinResult = tmp2 + tmp3; 162 | *cosResult = tmp2 - tmp3; 163 | } 164 | else if( x < 1.5*PI ) 165 | { 166 | double tmp1 = (x-PI); 167 | double tmp2 = (2/PI) * tmp1 - 0.5; 168 | double tmp3 = (4*c-2)*tmp2*tmp2 - c; 169 | *sinResult = tmp3 - tmp2; 170 | *cosResult = tmp3 + tmp2; 171 | } 172 | else 173 | { 174 | double tmp1 = (x-1.5*PI); 175 | double tmp2 = (2/PI) * tmp1 - 0.5; 176 | double tmp3 = (2-4*c)*tmp2*tmp2 + c; 177 | *sinResult = tmp2 - tmp3; 178 | *cosResult = tmp2 + tmp3; 179 | } 180 | } 181 | 182 | INLINE double sqrWave(double x) 183 | { 184 | double tmp = fmod(x, 2*PI); 185 | if( tmp < PI ) 186 | return 1.0; 187 | else 188 | return -1.0; 189 | } 190 | 191 | INLINE double tanhApprox(double x) 192 | { 193 | double a = fabs(2*x); 194 | double b = 24+a*(12+a*(6+a)); 195 | return 2*(x*b)/(a*b+48); 196 | } 197 | 198 | INLINE double triWave(double x) 199 | { 200 | double tmp = fmod(x, 2*PI); 201 | if( tmp < 0.5*PI ) 202 | return tmp/(0.5*PI); 203 | else if( tmp < 1.5*PI ) 204 | return 1.0 - ((tmp-0.5*PI)/(0.5*PI)); 205 | else 206 | return -1.0 + ((tmp-1.5*PI)/(0.5*PI)); 207 | } 208 | 209 | } // end namespace rosic 210 | 211 | #endif // #ifndef rosic_RealFunctions_h 212 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_BlendOscillator.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_BlendOscillator_h 2 | #define rosic_BlendOscillator_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_MipMappedWaveTable.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is an oscillator that can continuously blend between two waveforms - this is more efficient 13 | than using two separate oscillators because the phase-accumulator has to be calculated only once 14 | for both waveforms. 15 | 16 | */ 17 | 18 | class BlendOscillator 19 | { 20 | 21 | public: 22 | 23 | //--------------------------------------------------------------------------------------------- 24 | // construction/destruction: 25 | 26 | /** Constructor. */ 27 | BlendOscillator(); 28 | 29 | /** Destructor. */ 30 | ~BlendOscillator(); 31 | 32 | //--------------------------------------------------------------------------------------------- 33 | // parameter settings: 34 | 35 | /** Sets the sample-rateRate(). */ 36 | void setSampleRate(double newSampleRate); 37 | 38 | /** Sets the 1st waveform of the oscillator. */ 39 | void setWaveForm1(int newWaveForm1); 40 | 41 | /** Sets the 2nd waveform of the oscillator. */ 42 | void setWaveForm2(int newWaveForm2); 43 | 44 | /** Set start phase (range 0 - 360 degrees). */ 45 | void setStartPhase(double StartPhase); 46 | 47 | /** An object of class WaveTable should be passed with this function which will be used in the 48 | oscillator. Not to have "our own" WaveTable-object as member-variable avoids the need to have 49 | the same waveform for different synth-voices multiple times in the memory. This function sets 50 | the 1st wavetable. */ 51 | void setWaveTable1(MipMappedWaveTable* newWaveTable1); 52 | 53 | /** Sets the 2nd wavetable. @see setWaveTable1 */ 54 | void setWaveTable2(MipMappedWaveTable* newWaveTable2); 55 | 56 | /** Sets the blend/mix factor between the two waveforms. The value is expected between 0...1 57 | where 0 means waveform1 only, 1 means waveform2 only - in between there will be a linear blend 58 | between the two waveforms. */ 59 | void setBlendFactor(double newBlendFactor) { blend = newBlendFactor; } 60 | 61 | /** Sets the frequency of the oscillator. */ 62 | INLINE void setFrequency(double newFrequency); 63 | 64 | /** Sets the pulse width (or symmetry) of the oscillator. */ 65 | INLINE void setPulseWidth(double newPulseWidth); 66 | 67 | /** Sets the phase increment from outside. */ 68 | INLINE void setIncrement(double newIncrement) { increment = newIncrement; } 69 | 70 | //--------------------------------------------------------------------------------------------- 71 | // inquiry: 72 | 73 | /** Returns the blend/mix factor between the two waveforms as a value between 0...1 where 0 74 | means waveform1 only, 1 means waveform2 only - in between there will be a linear blend between 75 | the two waveforms. */ 76 | double getBlendFactor() const { return blend; } 77 | 78 | /** Returns the phase increment. */ 79 | INLINE double getIncrement() const { return increment; } 80 | 81 | //--------------------------------------------------------------------------------------------- 82 | // audio processing: 83 | 84 | /** Calculates one output sample at a time. */ 85 | INLINE double getSample(); 86 | 87 | //--------------------------------------------------------------------------------------------- 88 | // others: 89 | 90 | /** Calculates the phase-increments for first and second half-period according to freq and 91 | pulseWidth. */ 92 | INLINE void calculateIncrement(); 93 | 94 | /** Resets the phaseIndex to startIndex. */ 95 | void resetPhase(); 96 | 97 | /** Reset the phaseIndex to startIndex+PhaseIndex. */ 98 | void setPhase(double PhaseIndex); 99 | 100 | //============================================================================================= 101 | 102 | protected: 103 | 104 | double tableLengthDbl; // tableLength as double variable 105 | double phaseIndex; // current phase index 106 | double freq; // frequency of the oscillator 107 | double increment; // phase increment per sample 108 | double blend; // the blend factor between the two waveforms 109 | double startIndex; // start-phase-index of the osc (range: 0 - tableLength) 110 | double sampleRate; // the samplerate 111 | double sampleRateRec; // 1/sampleRate 112 | 113 | MipMappedWaveTable *waveTable1, *waveTable2; // the 2 wavetables between which we blend 114 | 115 | }; 116 | 117 | //----------------------------------------------------------------------------------------------- 118 | // inlined functions: 119 | 120 | INLINE void BlendOscillator::setFrequency(double newFrequency) 121 | { 122 | if( (newFrequency > 0.0) && (newFrequency < 20000.0) ) 123 | freq = newFrequency; 124 | } 125 | 126 | INLINE void BlendOscillator::setPulseWidth(double newPulseWidth) 127 | { 128 | waveTable1->setSymmetry(0.01*newPulseWidth); 129 | waveTable2->setSymmetry(0.01*newPulseWidth); 130 | } 131 | 132 | INLINE void BlendOscillator::calculateIncrement() 133 | { 134 | increment = tableLengthDbl*freq*sampleRateRec; 135 | } 136 | 137 | INLINE double BlendOscillator::getSample() 138 | { 139 | double out1, out2; 140 | int tableNumber; 141 | 142 | if( waveTable1 == NULL || waveTable2 == NULL ) 143 | return 0.0; 144 | 145 | // from this increment, decide which table is to be used: 146 | tableNumber = ((int)EXPOFDBL(increment)); 147 | //tableNumber += 1; // generate frequencies up to nyquist/2 on the highest note 148 | tableNumber += 2; // generate frequencies up to nyquist/4 on the highest note 149 | // \todo: make this number adjustable from outside 150 | 151 | // wraparound if necessary: 152 | while( phaseIndex>=tableLengthDbl ) 153 | phaseIndex -= tableLengthDbl; 154 | 155 | int intIndex = floorInt(phaseIndex); 156 | double frac = phaseIndex - (double) intIndex; 157 | out1 = (1.0-blend) * waveTable1->getValueLinear(intIndex, frac, tableNumber); 158 | out2 = blend * waveTable2->getValueLinear(intIndex, frac, tableNumber); 159 | 160 | out2 *= 0.5; // \todo: this is preliminary to scale the square in AciDevil we need to 161 | // implement something more general here (like a kind of crest-compensation in 162 | // the wavetable-class) 163 | 164 | phaseIndex += increment; 165 | return out1 + out2; 166 | } 167 | 168 | } // end namespace rosic 169 | 170 | #endif // rosic_BlendOscillator_h 171 | -------------------------------------------------------------------------------- /Build/VisualStudio2008/Open303.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 160 | 161 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_FourierTransformerRadix2.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_FourierTransformerRadix2_h 2 | #define rosic_FourierTransformerRadix2_h 3 | 4 | // standard includes: 5 | #include 6 | 7 | // rosic-indcludes: 8 | #include "rosic_Complex.h" 9 | #include "rosic_RealFunctions.h" 10 | 11 | namespace rosic 12 | { 13 | 14 | /** 15 | 16 | This class performs a fast Fourier Transform on a block of complex numbers (which are of class 17 | "Complex"). The length of the block has to be a power of 2. It uses the FFT library by Takuya Ooura 18 | which seems to be rather efficient. It handles the conversion between doubles and Complex numbers 19 | by means of some hacky pointer trickery which relies on the fact that an object of class Complex 20 | can be interpreted as two doubles stored in subsequent memory locations. This is true for the 21 | compiler in MSVC 2005 but may or may not be true for other compilers. In case of problems, try the 22 | class FourierTransfromerRadix2Clean which goes without such nasty hacks but is vastly inferior 23 | efficiency-wise. 24 | 25 | */ 26 | 27 | class FourierTransformerRadix2 28 | { 29 | 30 | public: 31 | 32 | /** The direction of the transform. */ 33 | enum directions 34 | { 35 | FORWARD, 36 | INVERSE 37 | }; 38 | 39 | /** These are the possible normalization modes. */ 40 | enum normalizationModes 41 | { 42 | NORMALIZE_ON_FORWARD_TRAFO, // divide by blockSize on forward FFT 43 | NORMALIZE_ON_INVERSE_TRAFO, // divide by blockSize on inverse FFT (default) 44 | ORTHONORMAL_TRAFO // divide by sqrt(blockSize) on both transforms 45 | }; 46 | 47 | //--------------------------------------------------------------------------------------------- 48 | // construction/destruction: 49 | 50 | /** Constructor. */ 51 | FourierTransformerRadix2(); 52 | 53 | /** Destructor. */ 54 | ~FourierTransformerRadix2(); 55 | 56 | //--------------------------------------------------------------------------------------------- 57 | // parameter settings: 58 | 59 | /** FFT-size, has to be a power of 2 and >= 2. */ 60 | void setBlockSize(int newBlockSize); 61 | 62 | /** Sets the direction of the transform (@see: directions). This will affect the sign of the 63 | exponent (or equivalently: theimaginary part) in the twiddling factors and the normalization 64 | constant. */ 65 | void setDirection(int newDirection); 66 | 67 | /** When you switch bewteen usage of this object for real or complex signals, you will need to 68 | call this switch-function in between which just triggers a re-computation of the twiddle 69 | factors (which must be different for the two cases). */ 70 | void setRealSignalMode(bool willBeUsedForRealSignals); 71 | 72 | /** Sets the mode for normalization of the output (@see: normalizationModes). */ 73 | void setNormalizationMode(int newNormalizationMode); 74 | 75 | //--------------------------------------------------------------------------------------------- 76 | // complex Fourier transforms: 77 | 78 | /** Transforms a buffer of complex numbers into its (forward or inverse) fourier transform. 79 | The inBuffer will remain intact. Both, inBuffer and outBuffer must be of the size which was 80 | specified when setting up the blockSize with setBlockSize(). */ 81 | void transformComplexBuffer(Complex *inBuffer, Complex *outBuffer); 82 | 83 | /** Does the same thing as transformComplexBuffer but performes in-place calculation 84 | (overwrites the input buffer). */ 85 | void transformComplexBufferInPlace(Complex *buffer); 86 | 87 | //--------------------------------------------------------------------------------------------- 88 | // some convenience functions for dealing with real signals: 89 | 90 | /** Transforms a real signal into its corresponding (conjugate symmetric) complex spectrum 91 | using an algorithm which exploits the symmetries for more efficiency. When the input array is 92 | an array of doubles of length N, the output array will be an array of complex numbers (class 93 | Complex) of length N/2 with the (purely real) transform value of bin N/2 stored in the 94 | imaginary part of the first array entry (outSpectrum[0].im = real(N/2)). */ 95 | void transformRealSignal(double *inSignal, Complex *outSpectrum); 96 | 97 | /** Calculates real and imaginary part of the spectrum as interleaved double buffer: 98 | buf[2]=re[1], buf[3]=im[1], buf[4]=re[2], buf[5]=im[2],... in general: buf[2*k]=re[k], 99 | buf[2k+1]=im[k], k=1,..,(N/2)-1 where N is the FFT-size. The first two elements of the buffer 100 | have a special meaning: buf[0] is the (purely real) DC and buf[1] is the (purely real) 101 | coefficient for the Nyquist frequency. The other fields contain the real and imaginary parts of 102 | the positive frequencies only (interleaved) because the negative frequencies are redundant 103 | (they are conjugate symmetric). */ 104 | void transformRealSignal(double *signal, double *reAndIm); 105 | 106 | /** Calculates spectral magnitudes and phases from a signal, where *signal should be of 107 | length N, where N is the block-size as chosen with setBlockSize() *magnitudes and *phases 108 | should be of length N/2. */ 109 | void getRealSignalMagnitudesAndPhases(double *signal, double *magnitudes, double *phases); 110 | 111 | /** Calculates the magnitudes only from a signal (useful for analyzer-stuff). */ 112 | void getRealSignalMagnitudes(double *signal, double *magnitudes); 113 | 114 | /** Transforms a complex conjugate symmetric spectrum (i.e. a spectrum of a real signal) into 115 | the corresponding real signal. */ 116 | void transformSymmetricSpectrum(Complex *inSpectrum, double *outSignal); 117 | 118 | /** Calculates a time signal from and interleaved buffer containing the real and imaginary 119 | parts of the positive frequencies (the negative frequencies are assumed to be conjugate 120 | symmetric). */ 121 | void transformSymmetricSpectrum(double *reAndIm, double *signal); 122 | 123 | /** Calculates a real time signal from its magnitudes and phases, *magnitudes and *phases 124 | should be of length N/2, *signal is of length N where N is the block-size as chosen with 125 | setBlockSize(). */ 126 | void getRealSignalFromMagnitudesAndPhases(double *magnitudes, double *phases, double *signal); 127 | 128 | //--------------------------------------------------------------------------------------------- 129 | // static functions 130 | 131 | /** Returns the physical frequency in Hz that corresponds to the given 'binIndex' for a given 132 | 'fftSize' and 'sampleRate'. */ 133 | static double binIndexToFrequency(int binIndex, int fftSize, double sampleRate) 134 | { return binIndex*sampleRate/fftSize; } 135 | 136 | 137 | //============================================================================================= 138 | 139 | protected: 140 | 141 | /** Updates the normalizationFactor member variable acording to a new blockSize, direction or 142 | normalizationMode. */ 143 | void updateNormalizationFactor(); 144 | 145 | int N; /**< the blocksize of the FFT. */ 146 | int logN; /**< Base 2 logarithm of the blocksize. */ 147 | int direction; /**< The direction of the transform (@see: directions). */ 148 | int normalizationMode; /**< The normalization mode (@see: normalizationModes. */ 149 | double normalizationFactor; /**< The normalization factor (can be 1, 1/N or 1/sqrt(N)). */ 150 | 151 | // work-area stuff for Ooura's fft-routines: 152 | double *w; /**< Table of the twiddle-factors. */ 153 | int *ip; /**< Work area for bit-reversal (index pointer?). */ 154 | 155 | // our own temporary storage area: 156 | Complex* tmpBuffer; 157 | 158 | }; 159 | 160 | } // end namespace rosic 161 | 162 | #endif // rosic_FourierTransformerRadix2_h 163 | -------------------------------------------------------------------------------- /Build/CodeBlocks/Open303.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1256315264 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_realfunctions.cpp 3 | "rosic_RealFunctions.h" 4 | 5 | 1271960317 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_realfunctions.h 6 | 7 | 8 | "GlobalFunctions.h" 9 | "rosic_NumberManipulations.h" 10 | 11 | 1256315264 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\globalfunctions.h 12 | 13 | 14 | "GlobalDefinitions.h" 15 | 16 | 1271960851 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\globaldefinitions.h 17 | 18 | 19 | 1271960486 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_numbermanipulations.h 20 | "GlobalDefinitions.h" 21 | 22 | 23 | 1256315264 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_numbermanipulations.cpp 24 | "rosic_NumberManipulations.h" 25 | 26 | 1256315264 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_functiontemplates.cpp 27 | "rosic_FunctionTemplates.h" 28 | 29 | 1271960405 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_functiontemplates.h 30 | "rosic_RealFunctions.h" 31 | 32 | 33 | 1271960984 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_open303.cpp 34 | "rosic_Open303.h" 35 | 36 | 1258100254 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_open303.h 37 | "rosic_MidiNoteEvent.h" 38 | "rosic_BlendOscillator.h" 39 | "rosic_BiquadFilter.h" 40 | "rosic_TeeBeeFilter.h" 41 | "rosic_AnalogEnvelope.h" 42 | "rosic_DecayEnvelope.h" 43 | "rosic_LeakyIntegrator.h" 44 | "rosic_EllipticQuarterBandFilter.h" 45 | "rosic_AcidSequencer.h" 46 | 47 | 48 | 1271961063 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_midinoteevent.h 49 | 50 | 1258100208 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_blendoscillator.h 51 | "rosic_MipMappedWaveTable.h" 52 | 53 | 1258100135 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_mipmappedwavetable.h 54 | "rosic_FunctionTemplates.h" 55 | "rosic_FourierTransformerRadix2.h" 56 | 57 | 1256315264 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_fouriertransformerradix2.h 58 | 59 | "rosic_Complex.h" 60 | "rosic_RealFunctions.h" 61 | 62 | 1260805766 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_complex.h 63 | "rosic_RealFunctions.h" 64 | 65 | 1256376058 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_biquadfilter.h 66 | "rosic_RealFunctions.h" 67 | 68 | 1256324674 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_teebeefilter.h 69 | 70 | "rosic_OnePoleFilter.h" 71 | 72 | 1256315265 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_onepolefilter.h 73 | "rosic_RealFunctions.h" 74 | 75 | 1256315265 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_analogenvelope.h 76 | "rosic_RealFunctions.h" 77 | 78 | 1256315265 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_decayenvelope.h 79 | "rosic_RealFunctions.h" 80 | 81 | 1256315264 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_leakyintegrator.h 82 | "rosic_RealFunctions.h" 83 | 84 | 1256315264 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_ellipticquarterbandfilter.h 85 | 86 | "GlobalDefinitions.h" 87 | 88 | 1256315264 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_acidsequencer.h 89 | "rosic_AcidPattern.h" 90 | 91 | 1266352322 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_acidpattern.h 92 | "rosic_RealFunctions.h" 93 | "rosic_FunctionTemplates.h" 94 | 95 | 1256315264 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\globalfunctions.cpp 96 | "GlobalFunctions.h" 97 | 98 | 1256315265 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\fft4g.c 99 | 100 | 101 | 1271960509 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_acidpattern.cpp 102 | "rosic_AcidPattern.h" 103 | 104 | 1271960529 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_acidsequencer.cpp 105 | "rosic_AcidSequencer.h" 106 | 107 | 1271960540 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_analogenvelope.cpp 108 | "rosic_AnalogEnvelope.h" 109 | 110 | 1256376048 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_biquadfilter.cpp 111 | "rosic_BiquadFilter.h" 112 | 113 | 1271960562 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_blendoscillator.cpp 114 | "rosic_BlendOscillator.h" 115 | 116 | 1271960606 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_complex.cpp 117 | "rosic_Complex.h" 118 | 119 | 1256315264 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_decayenvelope.cpp 120 | "rosic_DecayEnvelope.h" 121 | 122 | 1256315265 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_ellipticquarterbandfilter.cpp 123 | "rosic_EllipticQuarterBandFilter.h" 124 | 125 | 1256315265 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_fouriertransformerradix2.cpp 126 | "rosic_FourierTransformerRadix2.h" 127 | "fft4g.c" 128 | 129 | 1256315265 d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\fft4g.c 130 | 131 | 132 | 1256315265 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_leakyintegrator.cpp 133 | "rosic_LeakyIntegrator.h" 134 | 135 | 1271960900 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_midinoteevent.cpp 136 | "rosic_MidiNoteEvent.h" 137 | 138 | 1271960940 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_mipmappedwavetable.cpp 139 | "rosic_MipMappedWaveTable.h" 140 | 141 | 1256315264 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_onepolefilter.cpp 142 | "rosic_OnePoleFilter.h" 143 | 144 | 1271961125 source:d:\programming\collaborationprojects\open303\open303_r5\source\dspcode\rosic_teebeefilter.cpp 145 | "rosic_TeeBeeFilter.h" 146 | 147 | 1256315265 source:d:\programming\collaborationprojects\open303\open303_r5\source\vstplugin\stringconversions.c 148 | 149 | 150 | "string.h" 151 | 152 | 1271962061 source:d:\programming\collaborationprojects\open303\open303_r5\source\vstplugin\open303vst.cpp 153 | "Open303VST.h" 154 | 155 | 1271961796 d:\programming\collaborationprojects\open303\open303_r5\source\vstplugin\open303vst.h 156 | "public.sdk/source/vst2.x/audioeffectx.h" 157 | "../DSPCode/rosic_Open303.h" 158 | 159 | 1137047732 d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\public.sdk\source\vst2.x\audioeffectx.h 160 | "audioeffect.h" 161 | "pluginterfaces/vst2.x/aeffectx.h" 162 | 163 | 1137047732 d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\public.sdk\source\vst2.x\audioeffect.h 164 | "pluginterfaces/vst2.x/aeffect.h" 165 | 166 | 1137047696 d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\pluginterfaces\vst2.x\aeffect.h 167 | 168 | 169 | 1137047696 d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\pluginterfaces\vst2.x\aeffectx.h 170 | "aeffect.h" 171 | 172 | 1133154206 source:d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\public.sdk\source\vst2.x\audioeffect.cpp 173 | "audioeffect.h" 174 | "aeffeditor.h" 175 | 176 | 177 | 178 | 179 | 1137047732 d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\public.sdk\source\vst2.x\aeffeditor.h 180 | "audioeffectx.h" 181 | 182 | 1137047732 source:d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\public.sdk\source\vst2.x\audioeffectx.cpp 183 | "audioeffectx.h" 184 | "aeffeditor.h" 185 | 186 | 1137047732 source:d:\programming\collaborationprojects\open303\open303_r5\libraries\vstsdk2.4\public.sdk\source\vst2.x\vstplugmain.cpp 187 | "audioeffect.h" 188 | 189 | 190 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_Complex.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_Complex_h 2 | #define rosic_Complex_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is a class for complex numbers. It defines the basic arithmetic operations between complex 13 | numbers as well as the special cases when one of the operands is real (double). 14 | 15 | ATTENTION: do not define any further member variables, nor switch the ordering of re and im 16 | because the FourierTransformer classes rely on the fact that a complex number consists of two 17 | doubles re, im and nothing else (the algorithms actually run on buffers of doubles). 18 | 19 | */ 20 | 21 | class Complex 22 | { 23 | 24 | public: 25 | 26 | //--------------------------------------------------------------------------------------------- 27 | // public member variables: 28 | 29 | /** Real part */ 30 | double re; 31 | 32 | /** Imaginary part */ 33 | double im; 34 | 35 | //--------------------------------------------------------------------------------------------- 36 | // construction/destruction: 37 | 38 | /** Constructor. Initializes real and imaginary part to zero. */ 39 | Complex(); 40 | 41 | /** Constructor. Initializes real part to the argument "reInit" and imaginary part to zero. */ 42 | Complex(double reInit); 43 | 44 | /** Constructor. Initializes real and imaginary parts with the parameters. */ 45 | Complex(double reInit, double imInit); 46 | 47 | /** Destructor. */ 48 | ~Complex(); 49 | 50 | //--------------------------------------------------------------------------------------------- 51 | // overloaded operators: 52 | 53 | /** Compares two complex numbers of equality. */ 54 | bool operator==(const Complex& z) const 55 | { 56 | if( re == z.re && im == z.im ) 57 | return true; 58 | else 59 | return false; 60 | } 61 | 62 | /** Compares two complex numbers of inequality. */ 63 | bool operator!=(const Complex& z) const 64 | { 65 | if( re != z.re || im != z.im ) 66 | return true; 67 | else 68 | return false; 69 | } 70 | 71 | /** Defines the negative of a complex number. */ 72 | Complex operator-() 73 | { return Complex(-re, -im); } 74 | 75 | /** Adds another complex number to this complex and returns the result. */ 76 | Complex& operator+=(const Complex &z) 77 | { 78 | this->re += z.re; 79 | this->im += z.im; 80 | return *this; 81 | } 82 | 83 | /** Adds a real number to this complex and returns the result. */ 84 | Complex& operator+=(const double &r) 85 | { 86 | this->re += r; 87 | return *this; 88 | } 89 | 90 | /** Subtracts another complex number from this complex and returns the result. */ 91 | Complex& operator-=(const Complex &z) 92 | { 93 | this->re -= z.re; 94 | this->im -= z.im; 95 | return *this; 96 | } 97 | 98 | /** Subtracts a real number from this complex and returns the result. */ 99 | Complex& operator-=(const double &r) 100 | { 101 | this->re -= r; 102 | return *this; 103 | } 104 | 105 | /** Multiplies this complex number by another complex number and returns the result. */ 106 | Complex& operator*=(const Complex &z) 107 | { 108 | double reNew = re*z.re - im*z.im; 109 | double imNew = re*z.im + im*z.re; 110 | this->re = reNew; 111 | this->im = imNew; 112 | return *this; 113 | } 114 | 115 | /** Multiplies this complex number by a real number and returns the result. */ 116 | Complex& operator*=(const double &r) 117 | { 118 | this->re *= r; 119 | this->im *= r; 120 | return *this; 121 | } 122 | 123 | /** Divides this complex number by another complex number and returns the result. */ 124 | Complex& operator/=(const Complex &z) 125 | { 126 | double scale = 1.0 / (z.re*z.re + z.im*z.im); 127 | double reNew = scale*( re*z.re + im*z.im ); 128 | double imNew = scale*( im*z.re - re*z.im ); 129 | this->re = reNew; 130 | this->im = imNew; 131 | return *this; 132 | } 133 | 134 | /** Divides this complex number by a real number and returns the result. */ 135 | Complex& operator/=(const double &r) 136 | { 137 | double scale = 1.0 / r; 138 | this->re *= scale; 139 | this->im *= scale; 140 | return *this; 141 | } 142 | 143 | //--------------------------------------------------------------------------------------------- 144 | // set-functions: 145 | 146 | /** Adjusts the radius of this complex number leaving the angle unchanged. */ 147 | void setRadius(double newRadius); 148 | 149 | /** Adjusts the angle of this complex number leaving the magnitude unchanged. */ 150 | void setAngle(double newAngle); 151 | 152 | /** Sets the radius and angle of this complex number. */ 153 | void setRadiusAndAngle(double newRadius, double newAngle); 154 | 155 | //--------------------------------------------------------------------------------------------- 156 | // get-functions: 157 | 158 | /** Returns the radius of this complex number. */ 159 | double getRadius(); 160 | 161 | /** Returns the angle of this complex number. */ 162 | double getAngle(); 163 | 164 | /** Returns the complex conjugate of this complex number. */ 165 | Complex getConjugate(); 166 | 167 | /** Returns the reciprocal of this complex number. */ 168 | Complex getReciprocal(); 169 | 170 | /** Returns true, if this complex number is purely real. */ 171 | bool isReal(); 172 | 173 | /** Returns true, if this complex number is purely imaginary. */ 174 | bool isImaginary(); 175 | 176 | /** Returns true if real or imaginary part (or both) are plus or minus infinity, false 177 | otherwise. */ 178 | bool isInfinite(); 179 | 180 | }; // end of class Complex 181 | 182 | // some binary operators are defined outside the class such that the left hand operand does 183 | // not necesarrily need to be of class Complex 184 | 185 | /** Adds two complex numbers. */ 186 | INLINE Complex operator+(const Complex &z, const Complex &w) 187 | { return Complex(z.re+w.re, z.im+w.im); } 188 | 189 | /** Adds a complex and a real number. */ 190 | INLINE Complex operator+(const Complex &z, const double &r) 191 | { return Complex(z.re+r, z.im); } 192 | 193 | /** Adds a real and a complex number. */ 194 | INLINE Complex operator+(const double &r, const Complex &z) 195 | { return Complex(z.re+r, z.im); } 196 | 197 | /** Subtracts two complex numbers. */ 198 | INLINE Complex operator-(const Complex &z, const Complex &w) 199 | { return Complex(z.re-w.re, z.im-w.im); } 200 | 201 | /** Subtracts a real number from a complex number. */ 202 | INLINE Complex operator-(const Complex &z, const double &r) 203 | { return Complex(z.re-r, z.im); } 204 | 205 | /** Subtracts a complex number from a real number. */ 206 | INLINE Complex operator-(const double &r, const Complex &z) 207 | { return Complex(r-z.re, -z.im); } 208 | 209 | /** Multiplies two complex numbers. */ 210 | INLINE Complex operator*(const Complex &z, const Complex &w) 211 | { return Complex(z.re*w.re-z.im*w.im, z.re*w.im+z.im*w.re); } 212 | 213 | /** Multiplies a complex number and a real number. */ 214 | INLINE Complex operator*(const Complex &z, const double &r) 215 | { return Complex(z.re*r, z.im*r); } 216 | 217 | /** Multiplies a real number and a complex number. */ 218 | INLINE Complex operator*(const double &r, const Complex &z) 219 | { return Complex(z.re*r, z.im*r); } 220 | 221 | /** Divides two complex numbers. */ 222 | INLINE Complex operator/(const Complex &z, const Complex &w) 223 | { 224 | double scale = 1.0 / (w.re*w.re + w.im*w.im); 225 | return Complex( scale*( z.re*w.re + z.im*w.im), // real part 226 | scale*( z.im*w.re - z.re*w.im) ); // imaginary part 227 | } 228 | 229 | /** Divides a complex number by a real number. */ 230 | INLINE Complex operator/(const Complex &z, const double &r) 231 | { 232 | double scale = 1.0 / r; 233 | return Complex(scale*z.re, scale*z.im); 234 | } 235 | 236 | /** Divides a real number by a complex number. */ 237 | INLINE Complex operator/(const double &r, const Complex &z) 238 | { 239 | double scale = r / (z.re*z.re + z.im*z.im); 240 | return Complex(scale*z.re, -scale*z.im); 241 | } 242 | 243 | } // end namespace rosic 244 | 245 | #endif // rosic_Complex_h 246 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_AcidSequencer.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_AcidSequencer_h 2 | #define rosic_AcidSequencer_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_AcidPattern.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is a sequencer for typical acid-lines involving slides and accents. 13 | 14 | \todo: make the permissibility-thing work correctly 15 | 16 | */ 17 | 18 | class AcidSequencer 19 | { 20 | 21 | public: 22 | 23 | enum sequencerModes 24 | { 25 | OFF = 0, 26 | KEY_SYNC, 27 | HOST_SYNC, 28 | 29 | NUM_SEQUENCER_MODES 30 | }; 31 | 32 | //--------------------------------------------------------------------------------------------- 33 | // construction/destruction: 34 | 35 | /** Constructor. */ 36 | AcidSequencer(); 37 | 38 | //--------------------------------------------------------------------------------------------- 39 | // setup: 40 | 41 | /** Sets the sample-rate. */ 42 | void setSampleRate(double newSampleRate); 43 | 44 | /** Sets the tempo in BPM. */ 45 | void setTempo(double newTempoInBpm) { bpm = newTempoInBpm; } 46 | 47 | /** Sets the key in one of the patterns for one of the steps (between 0...11, 0 is C). */ 48 | void setKey(int pattern, int step, int newKey); 49 | 50 | /** Sets the octave for one of the steps (0 is the root octave between C2...B2). */ 51 | void setOctave(int pattern, int step, int newOctave); 52 | 53 | /** Sets the accent flag for one of the steps. */ 54 | void setAccent(int pattern, int step, bool shouldBeAccented); 55 | 56 | /** Sets the slide flag for one of the steps. */ 57 | void setSlide(int pattern, int step, bool shouldHaveSlide); 58 | 59 | /** Sets the gate flag for one of the steps. */ 60 | void setGate(int pattern, int step, bool shouldBeOpen); 61 | 62 | /** Selects one of the modes for the sequencer @see sequencerModes. */ 63 | void setMode(int newMode); 64 | 65 | /** Sets the length of one step (the time while gate is open) in units of one step (which 66 | is one 16th note). */ 67 | void setStepLength(double newStepLength) 68 | { patterns[activePattern].setStepLength(newStepLength); } 69 | 70 | /** Circularly shifts the active pattern by the given number of steps. */ 71 | void circularShift(int numSteps) { patterns[activePattern].circularShift(numSteps); } 72 | 73 | /** Marks a key (note value from 0...12, where 0 and 12 is a C) as permissible or not. 74 | Whenever the pattern currently played requires a key that is not permissible, the sequencer 75 | will play the closest key among the permissible ones (it will select the lower when two 76 | permissible keys are at equal distance). */ 77 | void setKeyPermissible(int key, bool shouldBePermissible); 78 | 79 | /** Toggles the permissibility of a key on/off. */ 80 | void toggleKeyPermissibility(int key); 81 | 82 | //--------------------------------------------------------------------------------------------- 83 | // inquiry: 84 | 85 | /** Returns the number of patterns. */ 86 | int getNumPatterns() const { return numPatterns; } 87 | 88 | /** Returns a pointer to the pattern with given index - NULL if index is out of range. */ 89 | AcidPattern* getPattern(int index); 90 | 91 | /** Returns true when the sequencer is running, false otherwise. */ 92 | bool isRunning() const { return running; } 93 | 94 | /** Returns once true, when the mode was changed due to a call to setMode. Thereafter, it will 95 | always return false until a new call to setMode happens - whereafter it will again return true 96 | once, ...and so on. The idea is that an outlying class may have to become aware of such changes 97 | in order to turn off running notes (trigger all-notes-off or something). */ 98 | bool modeWasChanged(); 99 | 100 | /** Returns the length of one step (the time while gate is open) in units of one step (which 101 | is one 16th note). */ 102 | double getStepLength() const { return patterns[activePattern].getStepLength(); } 103 | 104 | /** Returns the length of one step (the time while gate is open) in samples. */ 105 | int getStepLengthInSamples() const 106 | { return roundToInt(sampleRate*getStepLength()*beatsToSeconds(0.25, bpm)); } 107 | 108 | /** Returns the selected sequencer mode @see sequencerModes. */ 109 | int getSequencerMode() const { return sequencerMode; } 110 | 111 | /** Returns, if the given key is among the permissible ones. */ 112 | bool isKeyPermissible(int key); 113 | 114 | //--------------------------------------------------------------------------------------------- 115 | // audio processing: 116 | 117 | /** Returns a pointer to the note that occurs at this sample if any, NULL otherwise. */ 118 | INLINE AcidNote* getNote(); 119 | 120 | /** Returns the next note that will be scheduled - after getNote() has returned a non-NULL 121 | pointer, this will be the next non-NULL note that will be returned. So, if an event has 122 | occurred at some time instant, you may investigate the next upcoming event beforehand by 123 | calling this function. */ 124 | INLINE AcidNote* getNextScheduledNote() 125 | { 126 | AcidNote* note = patterns[activePattern].getNote(step); 127 | note->key = getClosestPermissibleKey(note->key); 128 | return note; 129 | } 130 | 131 | /** Returns the key among the permissible ones which is closest to the given key - if two keys 132 | are at the same distance, it returns the lower of them. If the passed key is itself 133 | permissible, it will be returned unchanged. */ 134 | INLINE int getClosestPermissibleKey(int key); 135 | 136 | //--------------------------------------------------------------------------------------------- 137 | // event handling: 138 | 139 | /** Lets the sequencer start playing. */ 140 | void start(); 141 | 142 | /** Lets the sequencer stop playing. */ 143 | void stop(); 144 | 145 | //--------------------------------------------------------------------------------------------- 146 | // others: 147 | 148 | //============================================================================================= 149 | 150 | protected: 151 | 152 | static const int numPatterns = 16; 153 | AcidPattern patterns[numPatterns]; 154 | 155 | int activePattern; // the currently selected pattern 156 | bool running; // flag to indicate that sequencer is running 157 | bool modeChanged; // flag that is set to true in setMode and to false in modeChanged 158 | double sampleRate; // the sample-rate 159 | double bpm; // the tempo in bpm 160 | int countDown; // a sample-countdown - counts down for the next step to occur 161 | int step; // the current step 162 | int sequencerMode; // the selected mode for the sequencer 163 | double driftError; // to keep track and compensate for accumulating timing error 164 | bool keyPermissible[13]; // array of flags to indicate if a particular key is permissible 165 | 166 | }; 167 | 168 | //----------------------------------------------------------------------------------------------- 169 | // from here: definitions of the functions to be inlined, i.e. all functions which are supposed 170 | // to be called at audio-rate (they can't be put into the .cpp file): 171 | 172 | INLINE AcidNote* AcidSequencer::getNote() 173 | { 174 | if( running == false ) 175 | return NULL; 176 | 177 | if( countDown > 0 ) 178 | { 179 | countDown--; 180 | return NULL; 181 | } 182 | else 183 | { 184 | double secondsToNextStep = beatsToSeconds(0.25, bpm); 185 | double samplesToNextStep = secondsToNextStep * sampleRate; 186 | countDown = roundToInt(samplesToNextStep); 187 | 188 | // keep track of accumulating error due to rounding and compensate when the accumulated error 189 | // exceeds half a sample: 190 | driftError += countDown - samplesToNextStep; 191 | if( driftError < -0.5 ) // negative errors indicate that we are too early 192 | { 193 | driftError += 1.0; 194 | countDown += 1; 195 | } 196 | else if( driftError >= 0.5 ) 197 | { 198 | driftError -= 1.0; 199 | countDown -= 1; 200 | } 201 | 202 | AcidNote* note = patterns[activePattern].getNote(step); 203 | note->key = getClosestPermissibleKey(note->key); 204 | step = (step+1) % patterns[activePattern].getNumSteps(); 205 | return note; 206 | } 207 | } 208 | 209 | INLINE int AcidSequencer::getClosestPermissibleKey(int key) 210 | { 211 | if( key >= 0 && key <= 12 ) 212 | { 213 | if( keyPermissible[key] ) 214 | return key; 215 | else 216 | { 217 | // find the closest lower permissible key: 218 | int kLo = key-1; 219 | while( kLo >= 0 ) 220 | { 221 | if( keyPermissible[kLo] ) 222 | break; 223 | kLo--; 224 | } 225 | 226 | // find the closest higher permissible key: 227 | int kHi = key+1; 228 | while( kHi < 12 ) 229 | { 230 | if( keyPermissible[kHi] ) 231 | break; 232 | kHi++; 233 | } 234 | 235 | // select the closest (subject to the constraint that it must be between 0 and 12): 236 | if( (kHi-key) < (kLo-key) && kHi <= 12 ) 237 | return kHi; 238 | else if( (kLo-key) < (kHi-key) && kLo >= 0 ) 239 | return kLo; 240 | else if( (kHi-key) == (kLo-key) && kLo >= 0 ) 241 | return kLo; 242 | else return -1; // none of the keys is permissible 243 | } 244 | } 245 | else 246 | return 0; 247 | } 248 | 249 | } // end namespace rosic 250 | 251 | #endif // rosic_AcidSequencer_h 252 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_MipMappedWaveTable.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_MipMappedWaveTable_h 2 | #define rosic_MipMappedWaveTable_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_FunctionTemplates.h" 6 | #include "rosic_FourierTransformerRadix2.h" 7 | 8 | namespace rosic 9 | { 10 | 11 | /** 12 | 13 | This is a class for generating and storing a single-cycle-waveform in a lookup-table and 14 | retrieving values form it at arbitrary positions by means of interpolation. 15 | 16 | */ 17 | 18 | class MipMappedWaveTable 19 | { 20 | 21 | // Oscillator and SuperOscillator classes need access to certain protected member-variables 22 | // (namely the tableLength and related quantities), so we declare them as friend-classes: 23 | friend class Oscillator; 24 | friend class BlendOscillator; 25 | friend class SuperOscillator; 26 | // \ todo: get rid of this by providing get-functions 27 | 28 | public: 29 | 30 | enum waveforms 31 | { 32 | SILENCE = 0, 33 | SINE, 34 | TRIANGLE, 35 | SQUARE, 36 | SAW, 37 | SQUARE303, 38 | SAW303 39 | }; 40 | 41 | //--------------------------------------------------------------------------------------------- 42 | // construction/destruction: 43 | 44 | /** Constructor. */ 45 | MipMappedWaveTable(); 46 | 47 | /** Destructor. */ 48 | ~MipMappedWaveTable(); 49 | 50 | //--------------------------------------------------------------------------------------------- 51 | // parmeter-settings: 52 | 53 | /** Selects a waveform from the set of built-in wavforms. The object generates the 54 | prototype-waveform by some algorithmic rules and renders various bandlimited version of it via 55 | FFT/iFFT. */ 56 | void setWaveform(int newWaveform); 57 | 58 | /** Overloaded function to set the waveform form outside this class. This function expects a 59 | pointer to the prototype-waveform to be handed over along with the length of this waveform. It 60 | copies the values into the internal buffers and renders various bandlimited version via 61 | FFT/iFFT. 62 | \todo: Interpolation for the case that lengthInSamples does not match the length of the 63 | internal table-length. */ 64 | void setWaveform(double* newWaveform, int lengthInSamples); 65 | 66 | /** Sets the time symmetry between the first and second half-wave (as value between 0...1) - 67 | for a square wave, this is also known as pulse-width. Currently only implemented for square and 68 | saw waveforms. */ 69 | void setSymmetry(double newSymmetry); 70 | 71 | // internal 'back-panel' parameters: 72 | 73 | /** Sets the drive (in dB) for the tanh-shaper for 303-square waveform - internal parameter, to 74 | be scrapped eventually. */ 75 | void setTanhShaperDriveFor303Square(double newDrive) 76 | { tanhShaperFactor = dB2amp(newDrive); fillWithSquare303(); } 77 | 78 | /** Sets the offset (as raw value for the tanh-shaper for 303-square waveform - internal 79 | parameter, to be scrapped eventually. */ 80 | void setTanhShaperOffsetFor303Square(double newOffset) 81 | { tanhShaperOffset = newOffset; fillWithSquare303(); } 82 | 83 | /** Sets the phase shift of tanh-shaped square wave with respect to the saw-wave (in degrees) 84 | - this is important when the two are mixed. */ 85 | void set303SquarePhaseShift(double newShift) 86 | { squarePhaseShift = newShift; fillWithSquare303(); } 87 | 88 | //--------------------------------------------------------------------------------------------- 89 | // inquiry: 90 | 91 | /** Returns the drive (in dB) for the tanh-shaper for 303-square waveform - internal parameter, to 92 | be scrapped eventually. */ 93 | double getTanhShaperDriveFor303Square() const { return amp2dB(tanhShaperFactor); } 94 | 95 | /** Returns the offset (as raw value for the tanh-shaper for 303-square waveform - internal 96 | parameter, to be scrapped eventually. */ 97 | double getTanhShaperOffsetFor303Square() const { return tanhShaperOffset; } 98 | 99 | /** Returns the phase shift of tanh-shaped square wave with respect to the saw-wave (in degrees) 100 | - this is important when the two are mixed. */ 101 | double get303SquarePhaseShift() const { return squarePhaseShift; } 102 | 103 | //--------------------------------------------------------------------------------------------- 104 | // audio processing: 105 | 106 | /** Returns the value at position 'integerPart+fractionalPart' of table 'tableIndex' with 107 | linear interpolation - this function may be preferred over 108 | getValueLinear(double phaseIndex, int tableIndex) when you want to calculate the integer and 109 | fractional part of the phase-index yourself. */ 110 | INLINE double getValueLinear(int integerPart, double fractionalPart, int tableIndex); 111 | 112 | /** Returns the value at position 'phaseIndex' of table 'tableIndex' with linear 113 | interpolation - this function computes the integer and fractional part of the phaseIndex 114 | internally. */ 115 | INLINE double getValueLinear(double phaseIndex, int tableIndex); 116 | 117 | protected: 118 | 119 | // functions to fill table with the built-in waveforms (these functions are 120 | // called from setWaveform(int newWaveform): 121 | void fillWithSine(); 122 | void fillWithTriangle(); 123 | void fillWithSquare(); 124 | void fillWithSaw(); 125 | void fillWithSquare303(); 126 | void fillWithSaw303(); 127 | void fillWithPeak(); 128 | void fillWithMoogSaw(); 129 | 130 | void initPrototypeTable(); 131 | // fills the "prototypeTable"-variable with all zeros 132 | 133 | void initTableSet(); 134 | // fills the "tableSet"-variable with all zeros 135 | 136 | void removeDC(); 137 | // removes dc-component from the waveform in the prototype-table 138 | 139 | void normalize(); 140 | // normalizes the amplitude of the prototype-table to 1.0 141 | 142 | void reverseTime(); 143 | // time-reverses the prototype-table 144 | 145 | /** Renders the prototype waveform and generates the mip-map from that. */ 146 | void renderWaveform(); 147 | 148 | void generateMipMap(); 149 | // generates a multisample from the prototype table, where each of the 150 | // successive tables contains one half of the spectrum of the previous one 151 | 152 | static const int tableLength = 2048; 153 | // Length of the lookup-table. The actual length of the allocated memory is 4 samples longer, 154 | // to store additional samples for the interpolator (which are the same values as at the 155 | // beginning of the buffer) */ 156 | 157 | 158 | double symmetry; // symmetry between 1st and 2nd half-wave 159 | 160 | static const int numTables = 12; 161 | // The Oscillator class uses a one table-per octave multisampling to avoid aliasing. With a 162 | // table-size of 8192 and a sample-sample rate of 44100, the 12th table will have a 163 | // fundamental frequency (the frequency where the increment is 1) of 11025 which is good for 164 | // the highest frequency. 165 | 166 | int waveform; // index of the currently chosen native waveform 167 | double sampleRate; // the sampleRate 168 | 169 | double prototypeTable[tableLength]; 170 | // this is the prototype-table with full bandwidth. one additional sample (same as 171 | // prototypeTable[0]) for linear interpolation without need for table wraparound at the last 172 | // sample (-> saves one if-statement each audio-cycle) ...and a three further addtional 173 | // samples for more elaborate interpolations like cubic (not implemented yet, also: 174 | // the fillWith...()-functions don't support these samples yet). */ 175 | 176 | double tableSet[numTables][tableLength+4]; 177 | // The multisample for anti-aliased waveform generation. The 4 additional values are equal 178 | // to the first 4 values in the table for easier interpolation. The first index is for the 179 | // table-number - index 0 accesses the first version which has full bandwidth, index 1 180 | // accesses the second version which is bandlimited to Nyquist/2, 2->Nyquist/4, 181 | // 3->Nyquist/8, etc. */ 182 | 183 | // embedded objects: 184 | FourierTransformerRadix2 fourierTransformer; 185 | 186 | // internal parameters: 187 | double tanhShaperFactor, tanhShaperOffset, squarePhaseShift; 188 | 189 | }; 190 | 191 | //----------------------------------------------------------------------------------------------- 192 | // inlined functions: 193 | 194 | INLINE double MipMappedWaveTable::getValueLinear(int integerPart, double fractionalPart, int tableIndex) 195 | { 196 | // ensure, that the table index is in the valid range: 197 | if( tableIndex<=0 ) 198 | tableIndex = 0; 199 | else if ( tableIndex>numTables ) 200 | tableIndex = 11; 201 | 202 | return (1.0-fractionalPart) * tableSet[tableIndex][integerPart] 203 | + fractionalPart * tableSet[tableIndex][integerPart+1]; 204 | } 205 | 206 | INLINE double MipMappedWaveTable::getValueLinear(double phaseIndex, int tableIndex) 207 | { 208 | /* 209 | // ensure, that the table index is in the valid range: 210 | if( tableIndex<=0 ) 211 | tableIndex = 0; 212 | else if ( tableIndex>numTables ) 213 | tableIndex = 11; 214 | */ 215 | 216 | // calculate integer and fractional part of the phaseIndex: 217 | int intIndex = floorInt(phaseIndex); 218 | double frac = phaseIndex - (double) intIndex; 219 | return getValueLinear(intIndex, frac, tableIndex); 220 | 221 | // lookup value in the table with linear interpolation and return it: 222 | //return (1.0-frac)*tableSet[tableIndex][intIndex] + frac*tableSet[tableIndex][intIndex+1]; 223 | } 224 | 225 | } // end namespace rosic 226 | 227 | #endif // rosic_MipMappedWaveTable_h 228 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_AnalogEnvelope.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_AnalogEnvelope_h 2 | #define rosic_AnalogEnvelope_h 3 | 4 | // rosic-indcludes: 5 | #include "rosic_RealFunctions.h" 6 | 7 | namespace rosic 8 | { 9 | 10 | /** 11 | 12 | This is a class which generates an exponential envelope with adjustable start-, attack-, peak-, 13 | hold-, decay-, sustain-, release- and end-values. It is based on feeding a stairstep-like 14 | input signal into a RC-filter unit. The filter input signal is switched to a new value 15 | according to the time and level values, at the same time the filter is switched to it's new 16 | time constant. This also implies, that the level-value will not really be reached (in theory) but 17 | only approached asymptotically. So the time values are not really the time between the levels, 18 | but rather time constants tau of the RC unit. The time constant tau is defined as the time until 19 | the filter reaches 63.2% of the end value (for an incoming step-function). This time constant can 20 | be scaled to re-define the ramp time to other values than 63.2%. 21 | 22 | */ 23 | 24 | class AnalogEnvelope 25 | { 26 | 27 | public: 28 | 29 | //--------------------------------------------------------------------------------------------- 30 | // construction/destruction: 31 | 32 | /** Constructor. */ 33 | AnalogEnvelope(); 34 | 35 | /** Destructor. */ 36 | ~AnalogEnvelope(); 37 | 38 | //--------------------------------------------------------------------------------------------- 39 | // parameter settings: 40 | 41 | /** sets the sample-rate. */ 42 | void setSampleRate(double newSampleRate); 43 | 44 | /** Sets the point where the envelope starts (as raw value). */ 45 | void setStartLevel(double newStart) { startLevel = newStart; } 46 | 47 | /** Sets the point where the envelope starts (in dB). */ 48 | void setStartInDecibels(double newStart) { setStartLevel(dB2amp(newStart)); } 49 | 50 | /** Sets the point where the envelope starts (in semitones). */ 51 | void setStartInSemitones(double newStart) { setStartLevel(pitchOffsetToFreqFactor(newStart)); } 52 | 53 | /** Sets the highest point of the envelope (as raw value). */ 54 | void setPeakLevel(double newPeak) { peakLevel = newPeak; } 55 | 56 | /** Sets the highest point of the envelope (in dB). */ 57 | void setPeakInDecibels(double newPeak) { setPeakLevel(dB2amp(newPeak)); } 58 | 59 | /** Sets the highest point of the envelope (in semitones). */ 60 | void setPeakInSemitones(double newPeak) { setPeakLevel(pitchOffsetToFreqFactor(newPeak)); } 61 | 62 | /** Sets the velocity dependence of the peak level as scaling factor of the peak by notes with 63 | velocity == 127. Notes with velocity == 1 will use the reciprocal value and notes with 64 | velocity == 64 will use the unmodified peak value. */ 65 | void setPeakLevelByVel(double newPeakByVel) { peakByVel = newPeakByVel; } 66 | 67 | /** Sets the velocity dependence of the peak level in dB - notes with velocity == 127 will peak 68 | this value louder, notes with velocity == 0 will peak this value more quiet and notes with 69 | velocity == 64 will have an unmodified peak amplitude. */ 70 | void setPeakByVelInDecibels(double newPeakByVel) { setPeakLevelByVel(dB2amp(newPeakByVel)); } 71 | 72 | /** Sets the velocity dependence of the peak level in semitones .... */ 73 | void setPeakByVelInSemitones(double newPeakByVel) 74 | { setPeakLevelByVel(pitchOffsetToFreqFactor(newPeakByVel)); } 75 | 76 | /** Sets the sustain level (as raw value). */ 77 | void setSustainLevel(double newSustain) { sustainLevel = newSustain; } 78 | 79 | /** Sets the sustain level (in dB). */ 80 | void setSustainInDecibels(double newSustain) { setSustainLevel(dB2amp(newSustain)); } 81 | 82 | /** Sets the sustain level (in semitones). */ 83 | void setSustainInSemitones(double newSustain) 84 | { setSustainLevel(pitchOffsetToFreqFactor(newSustain)); } 85 | 86 | /** Sets the end point of the envelope (as raw value). */ 87 | void setEndLevel(double newEnd) { endLevel = newEnd; } 88 | 89 | /** Sets the end point of the envelope (in dB). */ 90 | void setEndInDecibels(double newEnd) { setEndLevel(dB2amp(newEnd)); } 91 | 92 | /** Sets the end point of the envelope (in semitones). */ 93 | void setEndInSemitones(double newEnd) { setEndLevel(pitchOffsetToFreqFactor(newEnd)); } 94 | 95 | /** Sets the length of the attack phase (in milliseconds). */ 96 | void setAttack(double newAttackTime); 97 | 98 | /** Sets the hold time (in milliseconds). */ 99 | void setHold(double newHoldTime); 100 | 101 | /** Sets the length of the decay phase (in milliseconds). */ 102 | void setDecay(double newDecayTime); 103 | 104 | /** Sets the length of the release phase (in milliseconds). */ 105 | void setRelease(double newReleaseTime); 106 | 107 | /** Scales the A,D,H and R times by adjusting the increment. It is 1 if not used - a timescale 108 | of 2 means the envelope is twice as fast, 0.5 means half as fast -> useful for implementing a 109 | key/velocity-tracking feature for the overall length for the envelope. */ 110 | void setTimeScale(double newTimeScale); 111 | 112 | /** Scales the time constants tau. Can be used to reach other values than 63.2% in the 113 | specified time values */ 114 | void setTauScale(double newTauScale); 115 | 116 | /** Scales the peak-value of the envelope - useful for velocity response. */ 117 | void setPeakScale(double newPeakScale); 118 | 119 | /** Sets the internal state of the RC-filter. */ 120 | void setInternalState(double newState) { previousOutput = newState; } 121 | 122 | //--------------------------------------------------------------------------------------------- 123 | // inquiry: 124 | 125 | /** Returns the length of the attack phase (in milliseconds). */ 126 | double getAttack() const { return attackTime; } 127 | 128 | /** Returns the length of the decay phase (in milliseconds). */ 129 | double getDecay() const { return decayTime; } 130 | 131 | /** Returns the sustain level (as raw value). */ 132 | double getSustain() const { return sustainLevel; } 133 | 134 | /** Returns the length of the release phase (in milliseconds). */ 135 | double getRelease() const { return releaseTime; } 136 | 137 | /** Returns, when currently a note is on (the noteIsOn flag is set). */ 138 | bool isNoteOn() const { return noteIsOn; } 139 | 140 | /** True, if output is below 40 dB. */ 141 | bool endIsReached(); 142 | 143 | //--------------------------------------------------------------------------------------------- 144 | // audio processing: 145 | 146 | /** Calculates one output sample at a time. */ 147 | INLINE double getSample(); 148 | 149 | //--------------------------------------------------------------------------------------------- 150 | // others: 151 | 152 | /** Causes the envelope to start with its attack-phase. When the parameter 153 | 'startFromCurrentValue' is true, the internal state will not be reset to startLevel, such that 154 | the curve begins at the level, where the envelope currently is. */ 155 | void noteOn(bool startFromCurrentLevel = false); 156 | 157 | /** Causes the envelope to start with its release-phase. */ 158 | void noteOff(); 159 | 160 | /** Resets the time variable. */ 161 | void reset(); 162 | 163 | protected: 164 | 165 | /** Calculates our members that represent accumulated time values from attack, hold, etc. */ 166 | void calculateAccumulatedTimes(); 167 | 168 | // level and time parameters: 169 | double startLevel, peakLevel, sustainLevel, endLevel; 170 | double attackTime, holdTime, decayTime, releaseTime; // in seconds 171 | double peakByVel, peakByKey, timeScaleByVel, timeScaleByKey; 172 | 173 | // accumulated time values: 174 | double attPlusHld, attPlusHldPlusDec, attPlusHldPlusDecPlusRel; 175 | 176 | double time; // time since the last call to to trigger() 177 | double timeScale; // scale the time constants in the filters according to 178 | double increment; // increment for the time variable per sample 179 | double tauScale; // scale factor for the time constants of the filters 180 | double peakScale; // scale factor for the peak-value 181 | 182 | double attackCoeff, decayCoeff, releaseCoeff; // filter coefficients 183 | double previousOutput; // previous output sample 184 | double sampleRate; // sample-rate 185 | bool outputIsZero; // indicates if envelope has reached its end 186 | bool noteIsOn; // indicates if note is being held 187 | 188 | }; 189 | 190 | //----------------------------------------------------------------------------------------------- 191 | // inlined functions: 192 | 193 | INLINE double AnalogEnvelope::getSample() 194 | { 195 | double out; 196 | 197 | // attack or hold phase: 198 | if(time <= attPlusHld) // noteIsOn has not to be checked, because, time is advanced to the 199 | // beginning of the release phase in noteOff() 200 | { 201 | out = previousOutput + attackCoeff * (peakScale*peakLevel - previousOutput); 202 | time += increment; 203 | } 204 | 205 | // decay phase: 206 | else if(time <= (attPlusHldPlusDec)) // noteIsOn has not to be checked 207 | { 208 | out = previousOutput + decayCoeff * (sustainLevel - previousOutput); 209 | time += increment; 210 | } 211 | 212 | // sustain phase: 213 | else if(noteIsOn) 214 | { 215 | out = previousOutput + decayCoeff * (sustainLevel - previousOutput); 216 | // time is not incremented in sustain 217 | } 218 | 219 | // release phase: 220 | else 221 | { 222 | out = previousOutput + releaseCoeff * (endLevel - previousOutput); 223 | time += increment; 224 | } 225 | 226 | // store output sample for next call: 227 | previousOutput = out; // + TINY; // TINY is to avoid denorm problems 228 | 229 | return out; 230 | } 231 | 232 | } // end namespace rosic 233 | 234 | #endif // rosic_AnalogEnvelope_h 235 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_MipMappedWaveTable.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_MipMappedWaveTable.h" 2 | using namespace rosic; 3 | 4 | MipMappedWaveTable::MipMappedWaveTable() 5 | { 6 | // init member variables: 7 | sampleRate = 44100.0; 8 | waveform = 0; 9 | symmetry = 0.5; 10 | 11 | // initialize internal 'back-panel' parameters 12 | tanhShaperFactor = dB2amp(36.9); 13 | tanhShaperOffset = 4.37; 14 | squarePhaseShift = 180.0; 15 | 16 | // set up the fourier-transformer: 17 | fourierTransformer.setBlockSize(tableLength); 18 | 19 | // initialize the buffers: 20 | initPrototypeTable(); 21 | initTableSet(); 22 | } 23 | 24 | MipMappedWaveTable::~MipMappedWaveTable() 25 | { 26 | 27 | } 28 | 29 | //------------------------------------------------------------------------------------------------- 30 | // parameter settings: 31 | 32 | void MipMappedWaveTable::setWaveform(double* newWaveForm, int lengthInSamples) 33 | { 34 | int i; 35 | if( lengthInSamples == tableLength ) 36 | { 37 | // just copy the values into the internal buffer, when the length of the passed table and the 38 | // internal table match: 39 | for( i=0; i= 0) && (newWaveform != waveform) ) 52 | { 53 | waveform = newWaveform; 54 | renderWaveform(); 55 | } 56 | } 57 | 58 | void MipMappedWaveTable::setSymmetry(double newSymmetry) 59 | { 60 | symmetry = newSymmetry; 61 | renderWaveform(); 62 | } 63 | 64 | //------------------------------------------------------------------------------------------------- 65 | // internal functions: 66 | 67 | void MipMappedWaveTable::initPrototypeTable() 68 | { 69 | for(int i=0; i<(tableLength+4); i++) 70 | prototypeTable[i] = 0.0; 71 | } 72 | 73 | void MipMappedWaveTable::initTableSet() 74 | { 75 | int t, i; // indices fo table and position 76 | for(t=0; t max) 102 | max = fabs(prototypeTable[i]); 103 | 104 | // normalize to amplitude 1.0: 105 | double scale = 1.0/max; 106 | for(i=0; i= 0.0 ) 130 | { 131 | slideTime = newSlideTime; 132 | pitchSlewLimiter.setTimeConstant((float)(0.2*slideTime)); // \todo: tweak the scaling constant 133 | } 134 | } 135 | 136 | void Open303::setPitchBend(double newPitchBend) 137 | { 138 | pitchWheelFactor = pitchOffsetToFreqFactor(newPitchBend); 139 | } 140 | 141 | //------------------------------------------------------------------------------------------------------------ 142 | // others: 143 | 144 | void Open303::noteOn(int noteNumber, int velocity) 145 | { 146 | if( sequencer.modeWasChanged() ) 147 | allNotesOff(); 148 | 149 | if( sequencer.getSequencerMode() != AcidSequencer::OFF ) 150 | { 151 | if( velocity == 0 ) 152 | { 153 | sequencer.stop(); 154 | releaseNote(currentNote); 155 | currentNote = -1; 156 | } 157 | else 158 | { 159 | sequencer.start(); 160 | noteOffCountDown = std::numeric_limits::max(); 161 | slideToNextNote = false; 162 | currentNote = noteNumber; 163 | } 164 | idle = false; 165 | return; 166 | } 167 | 168 | if( velocity == 0 ) // velocity zero indicates note-off events 169 | { 170 | MidiNoteEvent releasedNote(noteNumber, 0); 171 | noteList.remove(releasedNote); 172 | if( noteList.empty() ) 173 | { 174 | currentNote = -1; 175 | } 176 | else 177 | { 178 | currentNote = noteList.front().getKey(); 179 | } 180 | releaseNote(noteNumber); 181 | } 182 | else // velocity was not zero, so this is an actual note-on 183 | { 184 | // check if the note-list is empty (indicating that currently no note is playing) - if so, 185 | // trigger a new note, otherwise, slide to the new note: 186 | if( noteList.empty() ) 187 | triggerNote(noteNumber, velocity >= 100); 188 | else 189 | slideToNote(noteNumber, velocity >= 100); 190 | 191 | currentNote = noteNumber; 192 | 193 | // and we need to add the new note to our list, of course: 194 | MidiNoteEvent newNote(noteNumber, velocity); 195 | noteList.push_front(newNote); 196 | } 197 | idle = false; 198 | } 199 | 200 | void Open303::allNotesOff() 201 | { 202 | noteList.clear(); 203 | ampEnv.noteOff(); 204 | currentNote = -1; 205 | } 206 | 207 | void Open303::triggerNote(int noteNumber, bool hasAccent) 208 | { 209 | // retrigger osc and reset filter buffers only if amplitude is near zero (to avoid clicks): 210 | if( idle ) 211 | { 212 | oscillator.resetPhase(); 213 | filter.reset(); 214 | highpass1.reset(); 215 | highpass2.reset(); 216 | allpass.reset(); 217 | notch.reset(); 218 | antiAliasFilter.reset(); 219 | ampDeClicker.reset(); 220 | } 221 | 222 | if( hasAccent ) 223 | { 224 | accentGain = accent; 225 | setMainEnvDecay(accentDecay); 226 | ampEnv.setRelease(accentAmpRelease); 227 | } 228 | else 229 | { 230 | accentGain = 0.0; 231 | setMainEnvDecay(normalDecay); 232 | ampEnv.setRelease(normalAmpRelease); 233 | } 234 | 235 | oscFreq = pitchToFreq(noteNumber, tuning); 236 | pitchSlewLimiter.setState(oscFreq); 237 | mainEnv.trigger(); 238 | ampEnv.noteOn(true); 239 | idle = false; 240 | } 241 | 242 | void Open303::slideToNote(int noteNumber, bool hasAccent) 243 | { 244 | oscFreq = pitchToFreq(noteNumber, tuning); 245 | 246 | if( hasAccent ) 247 | { 248 | accentGain = accent; 249 | setMainEnvDecay(accentDecay); 250 | ampEnv.setRelease(accentAmpRelease); 251 | } 252 | else 253 | { 254 | accentGain = 0.0; 255 | setMainEnvDecay(normalDecay); 256 | ampEnv.setRelease(normalAmpRelease); 257 | } 258 | idle = false; 259 | } 260 | 261 | void Open303::releaseNote(int noteNumber) 262 | { 263 | // check if the note-list is empty now. if so, trigger a release, otherwise slide to the note 264 | // at the beginning of the list (this is the most recent one which is still in the list). this 265 | // initiates a slide back to the most recent note that is still being held: 266 | if( noteList.empty() ) 267 | { 268 | ampEnv.noteOff(); 269 | } 270 | else 271 | { 272 | // initiate slide back: 273 | oscFreq = pitchToFreq(currentNote); 274 | } 275 | } 276 | 277 | void Open303::setMainEnvDecay(double newDecay) 278 | { 279 | mainEnv.setDecayTimeConstant(newDecay); 280 | updateNormalizer1(); 281 | updateNormalizer2(); 282 | } 283 | 284 | void Open303::calculateEnvModScalerAndOffset() 285 | { 286 | bool useMeasuredMapping = true; // might be shown as user parameter later 287 | if( useMeasuredMapping == true ) 288 | { 289 | // define some constants that arise from the measurements: 290 | const double c0 = 3.138152786059267e+002; // lowest nominal cutoff 291 | const double c1 = 2.394411986817546e+003; // highest nominal cutoff 292 | const double oF = 0.048292930943553; // factor in line equation for offset 293 | const double oC = 0.294391201442418; // constant in line equation for offset 294 | const double sLoF = 3.773996325111173; // factor in line eq. for scaler at low cutoff 295 | const double sLoC = 0.736965594166206; // constant in line eq. for scaler at low cutoff 296 | const double sHiF = 4.194548788411135; // factor in line eq. for scaler at high cutoff 297 | const double sHiC = 0.864344900642434; // constant in line eq. for scaler at high cutoff 298 | 299 | // do the calculation of the scaler and offset: 300 | double e = linToLin(envMod, 0.0, 100.0, 0.0, 1.0); 301 | double c = expToLin(cutoff, c0, c1, 0.0, 1.0); 302 | double sLo = sLoF*e + sLoC; 303 | double sHi = sHiF*e + sHiC; 304 | envScaler = (1-c)*sLo + c*sHi; 305 | envOffset = oF*c + oC; 306 | } 307 | else 308 | { 309 | double upRatio = pitchOffsetToFreqFactor( envUpFraction *envMod); 310 | double downRatio = pitchOffsetToFreqFactor(-(1.0-envUpFraction)*envMod); 311 | envScaler = upRatio - downRatio; 312 | if( envScaler != 0.0 ) // avoid division by zero 313 | envOffset = - (downRatio - 1.0) / (upRatio - downRatio); 314 | else 315 | envOffset = 0.0; 316 | } 317 | } 318 | 319 | void Open303::updateNormalizer1() 320 | { 321 | n1 = LeakyIntegrator::getNormalizer(mainEnv.getDecayTimeConstant(), rc1.getTimeConstant(), 322 | sampleRate); 323 | n1 = 1.0; // test 324 | } 325 | 326 | void Open303::updateNormalizer2() 327 | { 328 | n2 = LeakyIntegrator::getNormalizer(mainEnv.getDecayTimeConstant(), rc2.getTimeConstant(), 329 | sampleRate); 330 | n2 = 1.0; // test 331 | } 332 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_FourierTransformerRadix2.cpp: -------------------------------------------------------------------------------- 1 | #include "rosic_FourierTransformerRadix2.h" 2 | #include "fft4g.c" 3 | using namespace rosic; 4 | 5 | //------------------------------------------------------------------------------------------------- 6 | // construction/destruction: 7 | 8 | FourierTransformerRadix2::FourierTransformerRadix2() 9 | { 10 | N = 0; 11 | logN = 0; 12 | direction = FORWARD; 13 | normalizationMode = NORMALIZE_ON_INVERSE_TRAFO; 14 | normalizationFactor = 1.0; 15 | w = NULL; 16 | ip = NULL; 17 | tmpBuffer = NULL; 18 | 19 | setBlockSize(256); 20 | } 21 | 22 | FourierTransformerRadix2::~FourierTransformerRadix2() 23 | { 24 | // free dynamically allocated memory: 25 | if( w != NULL ) 26 | delete[] w; 27 | if( ip != NULL ) 28 | delete[] ip; 29 | if( tmpBuffer != NULL ) 30 | delete[] tmpBuffer; 31 | } 32 | 33 | //------------------------------------------------------------------------------------------------- 34 | // parameter settings: 35 | 36 | void FourierTransformerRadix2::setBlockSize(int newBlockSize) 37 | { 38 | // check new blocksize for validity: 39 | if( newBlockSize >= 2 && isPowerOfTwo(newBlockSize) ) 40 | { 41 | // check, if the new blocksize is actually different from the old one in order to avoid 42 | // unnecesarry re-allocations and re-computations: 43 | if( newBlockSize != N ) 44 | { 45 | N = newBlockSize; 46 | logN = (int) floor( log2((double) N + 0.5 ) ); 47 | updateNormalizationFactor(); 48 | 49 | if( w != NULL ) 50 | delete[] w; 51 | w = new double[2*N]; 52 | 53 | if( ip != NULL ) 54 | delete[] ip; 55 | ip = new int[(int) ceil(4.0+sqrt((double)N))]; 56 | ip[0] = 0; // indicate that re-initialization is necesarry 57 | 58 | if( tmpBuffer != NULL ) 59 | delete[] tmpBuffer; 60 | tmpBuffer = new Complex[N]; 61 | } 62 | } 63 | else if( !isPowerOfTwo(newBlockSize) || newBlockSize <= 1 ) 64 | DEBUG_BREAK; // this class can only deal with blocksizes >= 2 that are a power of two 65 | } 66 | 67 | void FourierTransformerRadix2::setDirection(int newDirection) 68 | { 69 | if( newDirection >= FORWARD && newDirection <= INVERSE ) 70 | { 71 | // only when the new direction is actually different form the old one, we have to conjugate 72 | // all the twiddle-factors, otherwise everything must stay as is: 73 | if( newDirection != direction ) 74 | { 75 | direction = newDirection; 76 | updateNormalizationFactor(); 77 | } 78 | } 79 | else 80 | DEBUG_BREAK; // passed int-parameter does not correspond to any meaningful enum-field 81 | } 82 | 83 | void FourierTransformerRadix2::setNormalizationMode(int newNormalizationMode) 84 | { 85 | if( newNormalizationMode >= NORMALIZE_ON_FORWARD_TRAFO && 86 | newNormalizationMode <= ORTHONORMAL_TRAFO ) 87 | { 88 | normalizationMode = newNormalizationMode; 89 | updateNormalizationFactor(); 90 | } 91 | else 92 | DEBUG_BREAK; // passed int-parameter does not correspond to any meaningful enum-field 93 | } 94 | 95 | void FourierTransformerRadix2::setRealSignalMode(bool willBeUsedForRealSignals) 96 | { 97 | ip[0] = 0; // retriggers twiddle-factor computation 98 | } 99 | 100 | //------------------------------------------------------------------------------------------------- 101 | // signal processing: 102 | 103 | void FourierTransformerRadix2::transformComplexBufferInPlace(Complex *buffer) 104 | { 105 | // retrieve the adresses of the real part of the first array entries in order to treat the 106 | // Complex arrays as arrays of two successive double-numbers: 107 | double* d_buffer = &(buffer[0].re); 108 | 109 | // normalize the FFT-input, if required: 110 | if( normalizationFactor != 1.0 ) 111 | { 112 | for(int n=0; n<2*N; n++) 113 | d_buffer[n] *= normalizationFactor; 114 | } 115 | 116 | // use Ooura's routine: 117 | int sign; 118 | if( direction == FORWARD ) 119 | sign = -1; 120 | else 121 | sign = +1; 122 | cdft(2*N, sign, d_buffer, ip, w); 123 | } 124 | 125 | void FourierTransformerRadix2::transformComplexBuffer(Complex *inBuffer, Complex *outBuffer) 126 | { 127 | // retrieve the adresses of the real part of the first array entries in order to treat the 128 | // Complex arrays as arrays of two successive double-numbers: 129 | double* d_inBuffer = &(inBuffer[0].re); 130 | double* d_outBuffer = &(outBuffer[0].re); 131 | 132 | // copy the input into the output for the in-place routine (thereby normalize, if necesarry): 133 | int n; 134 | if( normalizationFactor != 1.0 ) 135 | { 136 | for(n=0; n<2*N; n++) 137 | d_outBuffer[n] = d_inBuffer[n] * normalizationFactor; 138 | } 139 | else 140 | { 141 | for(n=0; n<2*N; n++) 142 | d_outBuffer[n] = d_inBuffer[n]; 143 | } 144 | 145 | // use Ooura's routine: 146 | int sign; 147 | if( direction == FORWARD ) 148 | sign = -1; 149 | else 150 | sign = +1; 151 | cdft(2*N, sign, d_outBuffer, ip, w); 152 | } 153 | 154 | //------------------------------------------------------------------------------------------------- 155 | // convenience functions for real signal: 156 | 157 | void FourierTransformerRadix2::transformRealSignal(double *inSignal, Complex *outSpectrum) 158 | { 159 | setDirection(FORWARD); 160 | 161 | // retrieve the adress of the real part of the first array entry of the output array in order to 162 | // treat the Complex array as array of two successive double-numbers: 163 | double* d_outBuffer = &(outSpectrum[0].re); 164 | 165 | // copy the input into the output for the in-place routine (thereby normalize, if necesarry): 166 | int n; 167 | if( normalizationFactor != 1.0 ) 168 | { 169 | for(n=0; n // for the NULL macro 6 | 7 | // rosic-indcludes: 8 | #include "rosic_OnePoleFilter.h" 9 | 10 | namespace rosic 11 | { 12 | 13 | /** 14 | 15 | This class is a filter that aims to emulate the filter in the Roland TB 303. It's a variation of 16 | the Moog ladder filter which includes a highpass in the feedback path that reduces the resonance 17 | on low cutoff frequencies. Moreover, it has a highpass and an allpass filter in the input path to 18 | pre-shape the input signal (important for the sonic character of internal and subsequent 19 | nonlinearities). 20 | 21 | ...18 vs. 24 dB? blah? 22 | 23 | */ 24 | 25 | class TeeBeeFilter 26 | { 27 | 28 | public: 29 | 30 | /** Enumeration of the available filter modes. */ 31 | enum modes 32 | { 33 | FLAT = 0, 34 | LP_6, 35 | LP_12, 36 | LP_18, 37 | LP_24, 38 | HP_6, 39 | HP_12, 40 | HP_18, 41 | HP_24, 42 | BP_12_12, 43 | BP_6_18, 44 | BP_18_6, 45 | BP_6_12, 46 | BP_12_6, 47 | BP_6_6, 48 | TB_303, // ala mystran & kunn (page 40 in the kvr-thread) 49 | 50 | NUM_MODES 51 | }; 52 | 53 | //--------------------------------------------------------------------------------------------- 54 | // construction/destruction: 55 | 56 | /** Constructor. */ 57 | TeeBeeFilter(); 58 | 59 | /** Destructor. */ 60 | ~TeeBeeFilter(); 61 | 62 | //--------------------------------------------------------------------------------------------- 63 | // parameter settings: 64 | 65 | /** Sets the sample-rate for this filter. */ 66 | void setSampleRate(double newSampleRate); 67 | 68 | /** Sets the cutoff frequency for this filter - the actual coefficient calculation may be 69 | supressed by passing 'false' as second parameter, in this case, it should be triggered 70 | manually later by calling calculateCoefficients. */ 71 | INLINE void setCutoff(double newCutoff, bool updateCoefficients = true); 72 | 73 | /** Sets the resonance in percent where 100% is self oscillation. */ 74 | INLINE void setResonance(double newResonance, bool updateCoefficients = true); 75 | 76 | /** Sets the input drive in decibels. */ 77 | void setDrive(double newDrive); 78 | 79 | /** Sets the mode of the filter, @see: modes */ 80 | void setMode(int newMode); 81 | 82 | /** Sets the cutoff frequency for the highpass filter in the feedback path. */ 83 | void setFeedbackHighpassCutoff(double newCutoff) { feedbackHighpass.setCutoff(newCutoff); } 84 | 85 | //--------------------------------------------------------------------------------------------- 86 | // inquiry: 87 | 88 | /** Returns the cutoff frequency of this filter. */ 89 | double getCutoff() const { return cutoff; } 90 | 91 | /** Returns the resonance parameter of this filter. */ 92 | double getResonance() const { return 100.0 * resonanceRaw; } 93 | 94 | /** Returns the drive parameter in decibels. */ 95 | double getDrive() const { return drive; } 96 | 97 | /** Returns the slected filter mode. */ 98 | int getMode() const { return mode; } 99 | 100 | /** Returns the cutoff frequency for the highpass filter in the feedback path. */ 101 | double getFeedbackHighpassCutoff() const { return feedbackHighpass.getCutoff(); } 102 | 103 | //--------------------------------------------------------------------------------------------- 104 | // audio processing: 105 | 106 | /** Calculates one output sample at a time. */ 107 | INLINE double getSample(double in); 108 | 109 | //--------------------------------------------------------------------------------------------- 110 | // others: 111 | 112 | /** Causes the filter to re-calculate the coeffiecients via the exact formulas. */ 113 | INLINE void calculateCoefficientsExact(); 114 | 115 | /** Causes the filter to re-calculate the coeffiecients using an approximation that is valid 116 | for normalized radian cutoff frequencies up to pi/4. */ 117 | INLINE void calculateCoefficientsApprox4(); 118 | 119 | /** Implements the waveshaping nonlinearity between the stages. */ 120 | INLINE double shape(double x); 121 | 122 | /** Resets the internal state variables. */ 123 | void reset(); 124 | 125 | //============================================================================================= 126 | 127 | protected: 128 | 129 | double b0, a1; // coefficients for the first order sections 130 | double y1, y2, y3, y4; // output signals of the 4 filter stages 131 | double c0, c1, c2, c3, c4; // coefficients for combining various ouput stages 132 | double k; // feedback factor in the loop 133 | double g; // output gain 134 | double driveFactor; // filter drive as raw factor 135 | double cutoff; // cutoff frequency 136 | double drive; // filter drive in decibels 137 | double resonanceRaw; // resonance parameter (normalized to 0...1) 138 | double resonanceSkewed; // mapped resonance parameter to make it behave more musical 139 | double sampleRate; // the sample rate in Hz 140 | double twoPiOverSampleRate; // 2*PI/sampleRate 141 | int mode; // the selected filter-mode 142 | 143 | OnePoleFilter feedbackHighpass; 144 | 145 | }; 146 | 147 | //----------------------------------------------------------------------------------------------- 148 | // inlined functions: 149 | 150 | INLINE void TeeBeeFilter::setCutoff(double newCutoff, bool updateCoefficients) 151 | { 152 | if( newCutoff != cutoff ) 153 | { 154 | if( newCutoff < 200.0 ) // an absolute floor for the cutoff frequency - tweakable 155 | cutoff = 200.0; 156 | else if( newCutoff > 20000.0 ) 157 | cutoff = 20000.0; 158 | else 159 | cutoff = newCutoff; 160 | 161 | if( updateCoefficients == true ) 162 | calculateCoefficientsApprox4(); 163 | } 164 | } 165 | 166 | INLINE void TeeBeeFilter::setResonance(double newResonance, bool updateCoefficients) 167 | { 168 | resonanceRaw = 0.01 * newResonance; 169 | resonanceSkewed = (1.0-exp(-3.0*resonanceRaw)) / (1.0-exp(-3.0)); 170 | if( updateCoefficients == true ) 171 | calculateCoefficientsApprox4(); 172 | } 173 | 174 | INLINE void TeeBeeFilter::calculateCoefficientsExact() 175 | { 176 | // calculate intermediate variables: 177 | double wc = twoPiOverSampleRate * cutoff; 178 | double s, c; 179 | sinCos(wc, &s, &c); // c = cos(wc); s = sin(wc); 180 | double t = tan(0.25*(wc-PI)); 181 | double r = resonanceSkewed; 182 | 183 | // calculate filter a1-coefficient tuned such the resonance frequency is just right: 184 | double a1_fullRes = t / (s-c*t); 185 | 186 | // calculate filter a1-coefficient as if there were no resonance: 187 | double x = exp(-wc); 188 | double a1_noRes = -x; 189 | 190 | // use a weighted sum between the resonance-tuned and no-resonance coefficient: 191 | a1 = r*a1_fullRes + (1.0-r)*a1_noRes; 192 | 193 | // calculate the b0-coefficient from the condition that each stage should be a leaky 194 | // integrator: 195 | b0 = 1.0+a1; 196 | 197 | // calculate feedback factor by dividing the resonance parameter by the magnitude at the 198 | // resonant frequency: 199 | double gsq = b0*b0 / (1.0 + a1*a1 + 2.0*a1*c); 200 | k = r / (gsq*gsq); 201 | 202 | if( mode == TB_303 ) 203 | k *= (17.0/4.0); 204 | } 205 | 206 | INLINE void TeeBeeFilter::calculateCoefficientsApprox4() 207 | { 208 | // calculate intermediate variables: 209 | double wc = twoPiOverSampleRate * cutoff; 210 | double wc2 = wc*wc; 211 | double r = resonanceSkewed; 212 | double tmp; 213 | 214 | // compute the filter coefficient via a 12th order polynomial approximation (polynomial 215 | // evaluation is done with a Horner-rule alike scheme with nested quadratic factors in the hope 216 | // for potentially better parallelization compared to Horner's rule as is): 217 | const double pa12 = -1.341281325101042e-02; 218 | const double pa11 = 8.168739417977708e-02; 219 | const double pa10 = -2.365036766021623e-01; 220 | const double pa09 = 4.439739664918068e-01; 221 | const double pa08 = -6.297350825423579e-01; 222 | const double pa07 = 7.529691648678890e-01; 223 | const double pa06 = -8.249882473764324e-01; 224 | const double pa05 = 8.736418933533319e-01; 225 | const double pa04 = -9.164580250284832e-01; 226 | const double pa03 = 9.583192455599817e-01; 227 | const double pa02 = -9.999994950291231e-01; 228 | const double pa01 = 9.999999927726119e-01; 229 | const double pa00 = -9.999999999857464e-01; 230 | tmp = wc2*pa12 + pa11*wc + pa10; 231 | tmp = wc2*tmp + pa09*wc + pa08; 232 | tmp = wc2*tmp + pa07*wc + pa06; 233 | tmp = wc2*tmp + pa05*wc + pa04; 234 | tmp = wc2*tmp + pa03*wc + pa02; 235 | a1 = wc2*tmp + pa01*wc + pa00; 236 | b0 = 1.0 + a1; 237 | 238 | // compute the scale factor for the resonance parameter (the factor to obtain k from r) via an 239 | // 8th order polynomial approximation: 240 | const double pr8 = -4.554677015609929e-05; 241 | const double pr7 = -2.022131730719448e-05; 242 | const double pr6 = 2.784706718370008e-03; 243 | const double pr5 = 2.079921151733780e-03; 244 | const double pr4 = -8.333236384240325e-02; 245 | const double pr3 = -1.666668203490468e-01; 246 | const double pr2 = 1.000000012124230e+00; 247 | const double pr1 = 3.999999999650040e+00; 248 | const double pr0 = 4.000000000000113e+00; 249 | tmp = wc2*pr8 + pr7*wc + pr6; 250 | tmp = wc2*tmp + pr5*wc + pr4; 251 | tmp = wc2*tmp + pr3*wc + pr2; 252 | tmp = wc2*tmp + pr1*wc + pr0; // this is now the scale factor 253 | k = r * tmp; 254 | g = 1.0; 255 | 256 | if( mode == TB_303 ) 257 | { 258 | double fx = wc * ONE_OVER_SQRT2/(2*PI); 259 | b0 = (0.00045522346 + 6.1922189 * fx) / (1.0 + 12.358354 * fx + 4.4156345 * (fx * fx)); 260 | k = fx*(fx*(fx*(fx*(fx*(fx+7198.6997)-5837.7917)-476.47308)+614.95611)+213.87126)+16.998792; 261 | g = k * 0.058823529411764705882352941176471; // 17 reciprocal 262 | g = (g - 1.0) * r + 1.0; // r is 0 to 1.0 263 | g = (g * (1.0 + r)); 264 | k = k * r; // k is ready now 265 | } 266 | } 267 | 268 | INLINE double TeeBeeFilter::shape(double x) 269 | { 270 | // return tanhApprox(x); // \todo: find some more suitable nonlinearity here 271 | //return x; // test 272 | 273 | const double r6 = 1.0/6.0; 274 | x = clip(x, -SQRT2, SQRT2); 275 | return x - r6*x*x*x; 276 | 277 | //return clip(x, -1.0, 1.0); 278 | } 279 | 280 | INLINE double TeeBeeFilter::getSample(double in) 281 | { 282 | double y0; 283 | 284 | if( mode == TB_303 ) 285 | { 286 | y0 = in - feedbackHighpass.getSample(k * shape(y4)); 287 | //y0 = in - feedbackHighpass.getSample(k*y4); 288 | //y0 = in - k*shape(y4); 289 | //y0 = in-k*y4; 290 | y1 += 2*b0*(y0-y1+y2); 291 | y2 += b0*(y1-2*y2+y3); 292 | y3 += b0*(y2-2*y3+y4); 293 | y4 += b0*(y3-2*y4); 294 | return 2*g*y4; 295 | //return 3*y4; 296 | } 297 | 298 | // apply drive and feedback to obtain the filter's input signal: 299 | //double y0 = inputFilter.getSample(0.125*driveFactor*in) - feedbackHighpass.getSample(k*y4); 300 | y0 = 0.125*driveFactor*in - feedbackHighpass.getSample(k*y4); 301 | 302 | /* 303 | // cascade of four 1st order sections with nonlinearities: 304 | y1 = shape(b0*y0 - a1*y1); 305 | y2 = shape(b0*y1 - a1*y2); 306 | y3 = shape(b0*y2 - a1*y3); 307 | y4 = shape(b0*y3 - a1*y4); 308 | */ 309 | 310 | // cascade of four 1st order sections with only 1 nonlinearity: 311 | /* 312 | y1 = b0*y0 - a1*y1; 313 | y2 = b0*y1 - a1*y2; 314 | y3 = b0*y2 - a1*y3; 315 | y4 = shape(b0*y3 - a1*y4); 316 | */ 317 | y1 = y0 + a1*(y0-y1); 318 | y2 = y1 + a1*(y1-y2); 319 | y3 = y2 + a1*(y2-y3); 320 | y4 = y3 + a1*(y3-y4); // \todo: performance test both versions of the ladder 321 | //y4 = shape(y3 + a1*(y3-y4)); // \todo: performance test both versions of the ladder 322 | 323 | return 8.0 * (c0*y0 + c1*y1 + c2*y2 + c3*y3 + c4*y4);; 324 | } 325 | 326 | } 327 | 328 | #endif // rosic_TeeBeeFilter_h 329 | -------------------------------------------------------------------------------- /Source/DSPCode/rosic_FunctionTemplates.h: -------------------------------------------------------------------------------- 1 | #ifndef rosic_FunctionTemplates_h 2 | #define rosic_FunctionTemplates_h 3 | 4 | // rosic includes: 5 | //#include "GlobalDefinitions.h" 6 | #include "rosic_RealFunctions.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace rosic 12 | { 13 | // todo write functions for element-wise multiply, divide, negate, 14 | // max, min, absMax, createCopy, filter, impulseResponse, impulseResponseLength, 15 | // fillWith(double value = 0.0), circularShift, resample, 16 | 17 | // maybe introduce a range (start....end) to which the process is to be applied 18 | 19 | /** Returns the absolute value of the input argument for types that define the comparison 20 | operators: '<', '>', the unary operator '-' and a constructor that takes an int and initializes 21 | to zero when 0 is passed. */ 22 | template 23 | T absT(T x); 24 | 25 | /** Adds the elements of 'buffer1' and 'buffer2' - type must define operator '+'. The 'result' 26 | buffer may be the same as 'buffer1' or 'buffer2'. */ 27 | template 28 | void add(T *buffer1, T *buffer2, T *result, int length); 29 | 30 | /** Circularly shifts the content of the buffer by 'numPositions' to the right - for leftward 31 | shifts use negative values for numPositions. If the absolute value of 'numPositions' is greater 32 | than the length of the buffer, it will use numPositions modulo the length - so if the length is 6 33 | and numPositions is 8, it will whift by 2 positions. */ 34 | template 35 | void circularShift(T *buffer, int length, int numPositions); 36 | 37 | /** Restricts the values in the buffer to the range between min and max for types that define the 38 | operators '<' and '>'. */ 39 | template 40 | void clipBuffer(T *buffer, int length, T min, T max); 41 | 42 | /** Copies the data of one array into another one. */ 43 | template 44 | void copyBuffer(T *source, T *destination, int length); 45 | 46 | /** Fills the passed array with all zeros - the type must have a constructor that takes an int 47 | and initializes to the zero element when 0 is passed. */ 48 | template 49 | void fillWithZeros(T *buffer, int length); 50 | 51 | /** Finds and returns the maximum absolute value of the buffer. */ 52 | template 53 | T maxAbs(T *buffer, int length); 54 | 55 | /** Returns the index of maximum value of the buffer (">"-operator must be defined). */ 56 | template 57 | INLINE int maxIndex(T *buffer, int length); 58 | 59 | /** Returns the maximum value of the buffer (">"-operator must be defined). */ 60 | template 61 | INLINE T maxValue(T *buffer, int length); 62 | 63 | /** Returns the index of minimum value of the buffer ("<"-operator must be defined). */ 64 | template 65 | INLINE int minIndex(T *buffer, int length); 66 | 67 | /** Returns the minimum value of the buffer ("<"-operator must be defined). */ 68 | template 69 | INLINE T minValue(T *buffer, int length); 70 | 71 | /** Computes the mean (i.e. the DC-component) from the passed buffer. The type must define operators: 72 | +=, / and a constructor which takes an int and initializes to zero when 0 is passed and a typecast 73 | from int. */ 74 | template 75 | T mean(T *buffer, int length); 76 | 77 | /** Returns the median of the passed buffer. */ 78 | template 79 | T median(T *buffer, int length); 80 | 81 | /** Multiplies the elements of 'buffer1' and 'buffer2' - type must define operator '*'. The 82 | 'result' buffer may be the same as 'buffer1' or 'buffer2'. */ 83 | template 84 | void multiply(T *buffer1, T *buffer2, T *result, int length); 85 | 86 | /** Normalizes the maximum value of the passed array. The type must define: >, *=, / and a 87 | constructor that takes an int and initializes to 0 when 0 is passed. Additionaly, it must be 88 | suitable for absT - that additionaly requires definition of unary '-' and '<'. */ 89 | template 90 | void normalize(T *buffer, int length, T maximum); 91 | 92 | /** Rearranges/permutes and array of type T into bit-reversed order. The 'length' MUST be the 93 | 'numBits' th power of two (this is not checked for). */ 94 | template 95 | INLINE void orderBitReversedOutOfPlace(T *inBuffer, T *outBuffer, int length, int numBits); 96 | 97 | /** Returns the product of the elements in the buffer for types which define the 98 | multiplication operator (the *= version thereof) and a constructor which can take an int 99 | paramater as argument and initializes to the multiplicative neutral element of that class when 1 100 | is passed . */ 101 | template 102 | INLINE T product(T *buffer, int length); 103 | 104 | /** Removes mean (i.e. the DC-component) from the passed buffer. The type must define operators: 105 | +=, -=, / and a constructor which takes an int and initializes to zero when 0 is passed and a 106 | typecast from int. */ 107 | template 108 | void removeMean(T *buffer, int length); 109 | 110 | /** Reverses the order of the elements the passed array. */ 111 | template 112 | void reverse(T *buffer, int length); 113 | 114 | /** The maximum of two objects on which the ">"-operator is defined. */ 115 | template 116 | INLINE T rmax(T in1, T in2); 117 | 118 | /** The maximum of four objects on which the ">"-operator is defined. */ 119 | template 120 | INLINE T rmax(T in1, T in2, T in3, T in4); 121 | 122 | /** The minimum of two objects on which the ">"-operator is defined. */ 123 | template 124 | INLINE T rmin(T in1, T in2); 125 | 126 | /** The minimum of four objects on which the ">"-operator is defined. */ 127 | template 128 | INLINE T rmin(T in1, T in2, T in3, T in4); 129 | 130 | /** Scales the buffer by a constant factor. */ 131 | template 132 | void scale(T *buffer, int length, T scaleFactor); 133 | 134 | /** Subtracts the elements of 'buffer2' from 'buffer1' - type must define operator '-'. The 135 | 'result' buffer may be the same as 'buffer1' or 'buffer2'. */ 136 | template 137 | void subtract(T *buffer1, T *buffer2, T *result, int length); 138 | 139 | /** Returns the sum of the elements in the buffer for types which define the 140 | addition operator (the += version thereof) and a constructor which can take an int 141 | paramater as argument and initializes to the additive neutral element of that class when 0 142 | is passed . */ 143 | template 144 | INLINE T sum(T *buffer, int length); 145 | 146 | /** Swaps two objects of class T. */ 147 | template 148 | INLINE void swap(T &in1, T &in2); 149 | 150 | //=============================================================================================== 151 | // implementation: 152 | 153 | template 154 | T absT(T x) 155 | { 156 | if( x > T(0) ) 157 | return x; 158 | else if( x < T(0) ) 159 | return -x; 160 | else 161 | return T(0); 162 | } 163 | 164 | template 165 | void add(T *buffer1, T *buffer2, T *result, int length) 166 | { 167 | for(int i=0; i 172 | void circularShift(T *buffer, int length, int numPositions) 173 | { 174 | int na = abs(numPositions); 175 | while( na > length ) 176 | na -=length; 177 | T *tmp = new T[na]; 178 | if( numPositions < 0 ) 179 | { 180 | memcpy( tmp, buffer, na*sizeof(T)); 181 | memmove( buffer, &buffer[na], (length-na)*sizeof(T)); 182 | memcpy( &buffer[length-na], tmp, na*sizeof(T)); 183 | } 184 | else if( numPositions > 0 ) 185 | { 186 | memcpy( tmp, &buffer[length-na], na*sizeof(T)); 187 | memmove(&buffer[na], buffer, (length-na)*sizeof(T)); 188 | memcpy( buffer, tmp, na*sizeof(T)); 189 | } 190 | delete[] tmp; 191 | } 192 | 193 | template 194 | void clipBuffer(T *buffer, int length, T min, T max) 195 | { 196 | for(int i=0; i max ) 201 | buffer[i] = max; 202 | } 203 | } 204 | 205 | template 206 | void copyBuffer(T *source, T *destination, int length) 207 | { 208 | for(int i=0; i 213 | void fillWithZeros(T *buffer, int length) 214 | { 215 | for(int i=0; i 220 | T maxAbs(T *buffer, int length) 221 | { 222 | T max = T(0); 223 | for(int i=0; i max) 226 | max = absT(buffer[i]); 227 | } 228 | return max; 229 | } 230 | 231 | template 232 | int maxIndex(T *buffer, int length) 233 | { 234 | T value = buffer[0]; 235 | int index = 0; 236 | for(int i=0; i value ) 239 | { 240 | value = buffer[i]; 241 | index = i; 242 | } 243 | } 244 | return index; 245 | } 246 | 247 | template 248 | T maxValue(T *buffer, int length) 249 | { 250 | return buffer[maxIndex(buffer, length)]; 251 | } 252 | 253 | template 254 | int minIndex(T *buffer, int length) 255 | { 256 | T value = buffer[0]; 257 | int index = 0; 258 | for(int i=0; i 270 | T minValue(T *buffer, int length) 271 | { 272 | return buffer[minIndex(buffer, length)]; 273 | } 274 | 275 | template 276 | T mean(T *buffer, int length) 277 | { 278 | return sum(buffer, length) / (T) length; 279 | } 280 | 281 | template 282 | void multiply(T *buffer1, T *buffer2, T *result, int length) 283 | { 284 | for(int i=0; i 289 | void normalize(T *buffer, int length, T maximum) 290 | { 291 | T max = maxAbs(buffer, length);; 292 | T scale = maximum / max; 293 | for(int i=0; i 298 | INLINE T product(T *buffer, int length) 299 | { 300 | T accu = T(1); // constructor call with 1 should initilize to multiplicative neutral element 301 | for(int n=0; n 307 | void removeMean(T *buffer, int length) 308 | { 309 | T m = mean(buffer, length); 310 | for(int i=0; i 315 | INLINE T rmax(T in1, T in2) 316 | { 317 | if( in1 > in2 ) 318 | return in1; 319 | else 320 | return in2; 321 | } 322 | 323 | template 324 | INLINE T rmax(T in1, T in2, T in3, T in4) 325 | { 326 | return rmax(rmax(in1, in2), rmax(in3, in4)); 327 | } 328 | 329 | template 330 | INLINE T rmin(T in1, T in2) 331 | { 332 | if( in1 < in2 ) 333 | return in1; 334 | else 335 | return in2; 336 | } 337 | 338 | template 339 | INLINE T rmin(T in1, T in2, T in3, T in4) 340 | { 341 | return rmin(rmin(in1, in2), rmin(in3, in4)); 342 | } 343 | 344 | template 345 | void reverse(T *buffer, int length) 346 | { 347 | T tmp; 348 | int lengthMinus1 = length-1; 349 | for(int i=0; i<=(length-2)/2; i++) 350 | { 351 | tmp = buffer[lengthMinus1-i]; 352 | buffer[lengthMinus1-i] = buffer[i]; 353 | buffer[i] = tmp; 354 | } 355 | } 356 | 357 | template 358 | void scale(T *buffer, int length, T scaleFactor) 359 | { 360 | for(int n=0; n 365 | void subtract(T *buffer1, T *buffer2, T *result, int length) 366 | { 367 | for(int i=0; i 372 | INLINE T sum(T *buffer, int length) 373 | { 374 | T accu = T(0); // constructor call with 0 should initilizes to additive neutral element 375 | for(int n=0; n 381 | INLINE void swap(T &in1, T &in2) 382 | { 383 | T tmp = in1; 384 | in1 = in2; 385 | in2 = tmp; 386 | } 387 | 388 | } // end namespace rosic 389 | 390 | #endif // #ifndef rosic_FunctionTemplates_h 391 | --------------------------------------------------------------------------------