Compare commits

..

No commits in common. "2ea0409fe7a9d2ded38dda6ae8a5f58b9dd78452" and "b70ab64dc147402ea29a047d63b7a9e3c9fe1a85" have entirely different histories.

10 changed files with 74 additions and 80 deletions

View File

@ -138,10 +138,6 @@ void Assigner::noteOn(uint8_t note) {
// limit highest note to C7, one octave above the Solina's maximum range // limit highest note to C7, one octave above the Solina's maximum range
while(note>96) note -= 12; while(note>96) note -= 12;
// limit lowest note to C2, too
while(note<36) note += 12;
// I'm not sure these are correct; these string ensembles don't have MIDI
// so it's all a bit of a guess
voices[v].startNote(note); voices[v].startNote(note);

View File

@ -20,6 +20,7 @@
#define _ASSIGNER_HPP #define _ASSIGNER_HPP
#include "DistrhoPlugin.hpp" #include "DistrhoPlugin.hpp"
#include "generator.hpp" #include "generator.hpp"
class Assigner { class Assigner {
@ -30,12 +31,12 @@ class Assigner {
private: private:
void noteOn(uint8_t note); // incoming note on (or off, if velocity = 0) void noteOn(uint8_t note); // incoming note on (or off, if velocity = 0)
void noteOff(uint8_t note); // incoming note off void noteOff(uint8_t note); // incoming note off
void dumpTables();
uint8_t voiceTbl[NUM_VOICES]; // voices in order of use uint8_t voiceTbl[NUM_VOICES]; // voices in order of use
uint8_t noteTbl[NUM_VOICES]; // note played by voice uint8_t noteTbl[NUM_VOICES]; // note played by voice
Voice *voices; // used to gain access to generator voices
Voice *voices;
void dumpTables();
}; };
#endif #endif

View File

@ -23,11 +23,12 @@
#include <cstdio> #include <cstdio>
extern double sampleRate; Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, programs, or states
extern uint32_t bufferSize;
Chorus::Chorus() { // no parameters, programs, or states bufferSize = xbufferSize;
sampleRate = xsampleRate;
lpfIn = new float[bufferSize];
lpfOut1 = new float[bufferSize]; lpfOut1 = new float[bufferSize];
lpfOut2 = new float[bufferSize]; lpfOut2 = new float[bufferSize];
ram = new float[DELAYSIZE]; // probably needs to be calculated based on sample rate ram = new float[DELAYSIZE]; // probably needs to be calculated based on sample rate
@ -35,29 +36,32 @@ Chorus::Chorus() { // no parameters, programs, or states
fastPhase = 0; fastPhase = 0;
slowPhase = 0; slowPhase = 0;
postFilter1l = new SVF(POSTCUTOFF, .546); preFilter = new SVF();
postFilter2l = new SVF(POSTCUTOFF, 1.324); postFilter1 = new SVF();
postFilter1r = new SVF(POSTCUTOFF, .546); postFilter2 = new SVF();
postFilter2r = new SVF(POSTCUTOFF, 1.324);
// lfo values taken from a rough simulation // lfo values taken from a rough simulation
fastOmega = 6.283 * 5.7 / sampleRate; // approximate, can be adjusted fastOmega = 6.283 * 6.8 / sampleRate; // approximate, can be adjusted
slowOmega = 6.283 * 0.7 / sampleRate; // again approximate slowOmega = 6.283 * 0.7 / sampleRate; // again approximate
// zero out the delay buffer // zero out the delay buffer
memset(ram, 0, sizeof(float) * DELAYSIZE); memset(ram, 0, sizeof(float) * DELAYSIZE);
memset(lpfIn, 0, sizeof(float) * bufferSize);
memset(lpfOut1, 0, sizeof(float) * bufferSize); memset(lpfOut1, 0, sizeof(float) * bufferSize);
memset(lpfOut2, 0, sizeof(float) * bufferSize); memset(lpfOut2, 0, sizeof(float) * bufferSize);
preFilter->setCutoff(12600, 1.3, sampleRate);
postFilter1->setCutoff(11653, 6.6, sampleRate);
postFilter2->setCutoff(5883, 1.1, sampleRate);
} }
Chorus::~Chorus() { Chorus::~Chorus() {
delete lpfIn;
delete lpfOut1; delete lpfOut1;
delete lpfOut2; delete lpfOut2;
delete ram; delete ram;
delete postFilter1l; delete preFilter;
delete postFilter2l; delete postFilter1;
delete postFilter1r; delete postFilter2;
delete postFilter2r;
} }
void Chorus::run(const float *input, float **outputs, uint32_t frames) { void Chorus::run(const float *input, float **outputs, uint32_t frames) {
@ -68,6 +72,9 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
float lfoMod, dly1, frac; float lfoMod, dly1, frac;
uint16_t tap, delay; uint16_t tap, delay;
// filter the input
preFilter->runSVF(input, lpfIn, frames);
for (uint32_t i = 0; i < frames; i++) { for (uint32_t i = 0; i < frames; i++) {
// run a step of LFO // run a step of LFO
fastPhase += fastOmega; fastPhase += fastOmega;
@ -75,13 +82,22 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
slowPhase += slowOmega; slowPhase += slowOmega;
if (slowPhase > 6.283) slowPhase -= 6.283; if (slowPhase > 6.283) slowPhase -= 6.283;
ram[delayptr] = input[i]; ram[delayptr] = lpfIn[i];
#define BASE 0.05 // lowpass filter
#define AMT 0.00175
// now we need to calculate the delay
// I don't know how long the Solina's delay lines are so I'm guessing 2-4ms for now
// normalised mod depths, from a quick simulation of the LFO block:
// 0deg 0.203 slow 0.635 fast
// 120deg 0.248 slow 0.745 fast
// 240deg 0.252 slow 0.609 fast
#define BASE 0.005
#define AMT 0.0015
// 0 degree delay line // 0 degree delay line
lfoMod = 0.203 * sin(fastPhase) + 0.835 * sin(slowPhase); lfoMod = 0.203 * sin(fastPhase) + 0.635 * sin(slowPhase);
dly1 = (BASE + (AMT * lfoMod)) * sampleRate; dly1 = (BASE + (AMT * lfoMod)) * sampleRate;
delay = (int)dly1; delay = (int)dly1;
frac = dly1 - delay; frac = dly1 - delay;
@ -103,7 +119,7 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
out120 = ((s1 - s0) * frac) + s0; out120 = ((s1 - s0) * frac) + s0;
// 240 degree delay line // 240 degree delay line
lfoMod = 0.252 * sin(fastPhase + 4.18) + 0.809 * sin(slowPhase + 4.18); lfoMod = 0.252 * sin(fastPhase + 4.18) + 0.609 * sin(slowPhase + 4.18);
dly1 = (BASE + (AMT * lfoMod)) * sampleRate; dly1 = (BASE + (AMT * lfoMod)) * sampleRate;
delay = (int)dly1; delay = (int)dly1;
frac = dly1 - delay; frac = dly1 - delay;
@ -113,15 +129,13 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
s0 = ram[tap & 0x3ff]; s0 = ram[tap & 0x3ff];
out240 = ((s1 - s0) * frac) + s0; out240 = ((s1 - s0) * frac) + s0;
lpfOut1[i] = (out0 + (out120 * 0.66) + (out240 * 0.33)); lpfOut1[i] = (out0 + out120 + out240) / 3;
lpfOut2[i] = (out0 + (out120 * 0.33) + (out240 * 0.66));
delayptr++; delayptr++;
delayptr &= 0x3ff; delayptr &= 0x3ff;
} }
postFilter1l->runSVF(lpfOut1, lpfOut1, frames); postFilter1->runSVF(lpfOut1, lpfOut2, frames);
postFilter2l->runSVF(lpfOut1, outputs[0], frames); postFilter2->runSVF(lpfOut2, outputs[0], frames);
postFilter1r->runSVF(lpfOut2, lpfOut2, frames); memcpy (outputs[1], outputs[0], frames * sizeof(float)); // only mono output for now
postFilter2r->runSVF(lpfOut2, outputs[1], frames);
} }

View File

@ -24,15 +24,15 @@
// total size of delay line buffer // total size of delay line buffer
#define DELAYSIZE 1028 #define DELAYSIZE 1028
#define POSTCUTOFF 10000
class Chorus { class Chorus {
public: public:
Chorus(); Chorus(uint32_t xbufferSize, double xsampleRate);
~Chorus(); ~Chorus();
void run(const float *input, float **outputs, uint32_t frames); void run(const float *input, float **outputs, uint32_t frames);
double sampleRate;
private: private:
uint32_t bufferSize;
double fastPhase, fastOmega; double fastPhase, fastOmega;
double slowPhase, slowOmega; double slowPhase, slowOmega;
double fastLfo, slowLfo; double fastLfo, slowLfo;
@ -43,6 +43,6 @@ class Chorus {
float *lpfIn; float *lpfIn;
float *lpfOut1, *lpfOut2; float *lpfOut1, *lpfOut2;
SVF *postFilter1l, *postFilter2l, *postFilter1r, *postFilter2r; SVF *preFilter, *postFilter1, *postFilter2;
}; };
#endif #endif

View File

@ -23,29 +23,24 @@
#include <cstdio> #include <cstdio>
#include "DistrhoPluginInfo.h" #include "DistrhoPluginInfo.h"
#include "svf.hpp"
extern double sampleRate; // some unit-local globals
extern uint32_t bufferSize;
// unit-local global float sampleRate = 0;
static float envTc[2];
Generator::Generator() { float envTc[2];
Generator::Generator(uint32_t bufferSize, double xSampleRate) {
sampleRate = xSampleRate;
output = new float[bufferSize]; output = new float[bufferSize];
// create the phase increments for each semitone // create the phase increments for each semitone
for (uint8_t i = 0; i < 12; i++) { for (uint8_t i = 0; i < 12; i++) {
phase[i] = 0; phase[i] = 0;
uint32_t f; uint32_t f;
f = (1 << 31) * (32.703 * powf(2, 0.083334 * i) / sampleRate); f = (1 << 31) * (65.406 * powf(2, 0.083334 * (i + 12)) / sampleRate);
omega[i] = f; omega[i] = f;
} }
// output filters
// trumpet 4200 2.5
// horn 1500 2.5
tr2 = SVF(9500.0f, 0.707f);
setEnvelope(0.5, 0.5);
} }
Generator::~Generator() { Generator::~Generator() {
@ -55,7 +50,7 @@ Generator::~Generator() {
void Generator::runBlock(uint32_t frames) { void Generator::runBlock(uint32_t frames) {
Voice *v; Voice *v;
uint32_t i; uint32_t i;
uint8_t k, p, d; uint8_t k, p, key, n1, n2, d;
float n; float n;
memset(output, 0, frames * sizeof(float)); memset(output, 0, frames * sizeof(float));
@ -68,7 +63,7 @@ void Generator::runBlock(uint32_t frames) {
for (k = 0; k < NUM_VOICES; k++) { for (k = 0; k < NUM_VOICES; k++) {
v = &voices[k]; v = &voices[k];
d = (phase[v->semi] & (0x20000000 >> v->oct)) != 0; d = (phase[v->semi] & (0x40000000 >> v->oct)) != 0;
n = d ? 0.25 : -0.25; n = d ? 0.25 : -0.25;
v->vc34 = ((n - v->vc34) * v->c34) + v->vc34; v->vc34 = ((n - v->vc34) * v->c34) + v->vc34;
n -= v->vc34; n -= v->vc34;
@ -76,7 +71,7 @@ void Generator::runBlock(uint32_t frames) {
v->vc78 = ((n - v->vc78) * v->c78) + v->vc78; v->vc78 = ((n - v->vc78) * v->c78) + v->vc78;
v->vc107 = ((v->vc78 - v->vc107) * v->c107) + v->vc107; v->vc107 = ((v->vc78 - v->vc107) * v->c107) + v->vc107;
d = (phase[v->semi] & (0x40000000 >> v->oct)) != 0; d = (phase[v->semi] & (0x80000000 >> v->oct)) != 0;
n = d ? 0.25 : -0.25; n = d ? 0.25 : -0.25;
v->vc33 = ((n - v->vc33) * v->c33) + v->vc33; v->vc33 = ((n - v->vc33) * v->c33) + v->vc33;
n -= v->vc33; n -= v->vc33;
@ -92,7 +87,6 @@ void Generator::runBlock(uint32_t frames) {
output[i] += 0.25 * (v4 + v8) * v->vca; output[i] += 0.25 * (v4 + v8) * v->vca;
} }
} }
tr2.runSVF(output, output, frames);
} }
void Voice::startNote(uint8_t key) { void Voice::startNote(uint8_t key) {

View File

@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include "DistrhoPluginInfo.h" #include "DistrhoPluginInfo.h"
#include "svf.hpp"
class Generator; class Generator;
@ -47,9 +46,7 @@ class Voice {
class Generator { class Generator {
public: public:
// Generator(uint32_t bufferSize, double xSampleRate); Generator(uint32_t bufferSize, double xSampleRate);
Generator();
~Generator(); ~Generator();
void setEnvelope(float attack, float sustain); void setEnvelope(float attack, float sustain);
void runBlock(uint32_t frames); void runBlock(uint32_t frames);
@ -59,7 +56,6 @@ class Generator {
private: private:
uint32_t phase[12]; uint32_t phase[12];
uint32_t omega[12]; uint32_t omega[12];
SVF tr2;
}; };
#endif #endif

View File

@ -18,20 +18,14 @@
#include "sonnenlicht.hpp" #include "sonnenlicht.hpp"
double sampleRate;
uint32_t bufferSize;
START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO
Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0) { Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0), fSampleRate(getSampleRate()) {
// genny = new Generator(getBufferSize(), fSampleRate); genny = new Generator(getBufferSize(), fSampleRate);
sampleRate = getSampleRate();
bufferSize = getBufferSize();
genny = new Generator();
assigner = new Assigner(genny->voices); assigner = new Assigner(genny->voices);
chorus = new Chorus();
chorus = new Chorus(getBufferSize(), fSampleRate);
} }
Sonnenlicht::~Sonnenlicht() { Sonnenlicht::~Sonnenlicht() {
@ -63,6 +57,7 @@ void Sonnenlicht::run(const float**, float** outputs, uint32_t frames,
genny->runBlock(frames); genny->runBlock(frames);
if (prog.enableChorus) { if (prog.enableChorus) {
chorus->run(genny->output, outputs, frames); chorus->run(genny->output, outputs, frames);
} else { } else {
memcpy(outputs[0], genny->output, frames * sizeof(float)); memcpy(outputs[0], genny->output, frames * sizeof(float));

View File

@ -77,7 +77,7 @@ class Sonnenlicht : public Plugin {
const MidiEvent *midiEvents, uint32_t midiEventCount) override; const MidiEvent *midiEvents, uint32_t midiEventCount) override;
private: private:
//double fSampleRate; double fSampleRate;
Program prog; Program prog;
Assigner *assigner; Assigner *assigner;

View File

@ -22,14 +22,16 @@
#include <cstdio> #include <cstdio>
SVF::SVF(float cutoff, float Q) { SVF::SVF() {
// zero out all values // zero out all values
z1 = 0; z1 = 0;
z2 = 0; z2 = 0;
setCutoff(cutoff, Q); c1 = 0;
c2 = 0;
d0 = 0;
} }
void SVF::setCutoff(float cutoff, float Q) { void SVF::setCutoff(float cutoff, float Q, float sampleRate) {
float F = cutoff / sampleRate; float F = cutoff / sampleRate;
float w = 2 * tan(3.14159 * F); float w = 2 * tan(3.14159 * F);
float a = w / Q; float a = w / Q;
@ -43,7 +45,6 @@ void SVF::setCutoff(float cutoff, float Q) {
void SVF::runSVF(const float *input, float *output, uint32_t frames) { void SVF::runSVF(const float *input, float *output, uint32_t frames) {
float x; float x;
for (uint32_t i = 0; i < frames; i++) { for (uint32_t i = 0; i < frames; i++) {
// lowpass filter // lowpass filter
x = input[i] - z1 - z2; x = input[i] - z1 - z2;

View File

@ -21,13 +21,10 @@
#include <stdint.h> #include <stdint.h>
extern double sampleRate;
class SVF { class SVF {
public: public:
SVF(float cutoff=1000, float Q=0.707); SVF();
void setCutoff(float cutoff, float Q); void setCutoff(float cutoff, float Q, float sampleRate);
void runSVF(const float *input, float *output, uint32_t frames); void runSVF(const float *input, float *output, uint32_t frames);
protected: protected: