First commit. FLMNG and DubSiren are already here
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*/build/arduino.avr.nano
|
||||||
246
DubSiren/DubSiren.ino
Normal file
246
DubSiren/DubSiren.ino
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
// DubSiren firmware for Sitka Instruments WS-1.0
|
||||||
|
// by Oleksiy Hrachov
|
||||||
|
//
|
||||||
|
// Although the code designed to work on Sitka Instruments WS-1.0 synth, it should
|
||||||
|
// be pretty easy to adapt to run on other arduino/mozzi-based setups
|
||||||
|
//
|
||||||
|
// This code is licenced under GPL v3 or later
|
||||||
|
|
||||||
|
//ToDo:
|
||||||
|
//Transform Flamingo into DubSiren :)
|
||||||
|
//✅ Square oscilator
|
||||||
|
//✅ Square/Sine pitch LFO on switch
|
||||||
|
//✅ Filter
|
||||||
|
//⬜ Delay?
|
||||||
|
|
||||||
|
#include <Mozzi.h>
|
||||||
|
#include <MIDI.h>
|
||||||
|
#include <Oscil.h>
|
||||||
|
#include <MetaOscil.h>
|
||||||
|
#include <tables/sin2048_int8.h>
|
||||||
|
#include <tables/square_no_alias_2048_int8.h>
|
||||||
|
//#include <tables/square_analogue512_int8.h>
|
||||||
|
#include <StateVariable.h>
|
||||||
|
#include <ADSR.h>
|
||||||
|
#include <mozzi_midi.h>
|
||||||
|
#include <IntMap.h>
|
||||||
|
#include <OverSample.h>
|
||||||
|
#include <FixMath.h>
|
||||||
|
|
||||||
|
//Band limited oscilator tables for aliasing-free Meta Oscilator
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_90_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_101_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_122_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_138_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_154_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_174_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_210_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_264_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_327_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_431_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_546_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_744_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_910_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_1170_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_1638_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_2730_at_16384_512_int8.h>
|
||||||
|
#include <tables/BandLimited_SQUARE/512/square_max_8192_at_16384_512_int8.h>
|
||||||
|
Oscil <SQUARE_MAX_90_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq90(SQUARE_MAX_90_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_101_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq101(SQUARE_MAX_101_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_122_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq122(SQUARE_MAX_122_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_138_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq138(SQUARE_MAX_138_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_154_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq154(SQUARE_MAX_154_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_174_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq174(SQUARE_MAX_174_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_210_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq210(SQUARE_MAX_210_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_264_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq264(SQUARE_MAX_264_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_327_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq327(SQUARE_MAX_327_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_431_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq431(SQUARE_MAX_431_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_546_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq546(SQUARE_MAX_546_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_744_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq744(SQUARE_MAX_744_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_910_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq910(SQUARE_MAX_910_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_1170_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq1170(SQUARE_MAX_1170_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_1638_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq1638(SQUARE_MAX_1638_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_2730_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq2730(SQUARE_MAX_2730_AT_16384_512_DATA);
|
||||||
|
Oscil <SQUARE_MAX_8192_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq8192(SQUARE_MAX_8192_AT_16384_512_DATA);
|
||||||
|
MetaOscil<SQUARE_MAX_90_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE, 16> aSquare {&aSq90, &aSq101, &aSq122, &aSq138, &aSq154, &aSq174, &aSq210, &aSq264, &aSq327, &aSq431, &aSq546, &aSq744, &aSq1170, &aSq1638, &aSq2730, &aSq8192};
|
||||||
|
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
const int pitchSubSteps = 32; //set how many steps are there between semitones. set to 1 to quantize to semitones
|
||||||
|
const int driveAmount = 450;
|
||||||
|
#define MIDI_CHANNEL MIDI_CHANNEL_OMNI
|
||||||
|
#define MOZZI_CONTROL_RATE 1024
|
||||||
|
|
||||||
|
//Hardware Definitions
|
||||||
|
#define Knob1 A6 //LFO Frequency
|
||||||
|
#define Knob2 A4 //LFO Intensity
|
||||||
|
#define Knob3 A2 //LPF Resonance
|
||||||
|
#define Knob4 A0 //LPF Cutoff
|
||||||
|
#define KnobA A5 //Attack
|
||||||
|
#define KnobDR A3 //Decay and Release
|
||||||
|
#define KnobS A1 //Sustain
|
||||||
|
#define CVIn A7 //CV input and Pitch knob
|
||||||
|
#define GateIn 10
|
||||||
|
#define EnvSwitch 11
|
||||||
|
#define DroneSwitch 12
|
||||||
|
#define LED 5
|
||||||
|
|
||||||
|
#define MOZZI_ANALOG_READ_RESOLUTION 10
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
|
IntMap kMapNote( 0, 4095, 24 * pitchSubSteps, 84 * pitchSubSteps );
|
||||||
|
IntMap kMapLFOSpeed( 0, 1023, 500, 20000 );
|
||||||
|
IntMap kMapFreqMod( 0, 1023, 0, 1023 );
|
||||||
|
IntMap kMapResonance( 0, 1023, 200, 1 );
|
||||||
|
IntMap kMapCutoff( 0, 1023, 60, 3600 );
|
||||||
|
IntMap kMapAttack( 0, 1023, 0, 80 );
|
||||||
|
IntMap kMapDecayRelease( 0, 1023, 8, 160 );
|
||||||
|
IntMap kMapSustain( 0, 1023, 0, 255 );
|
||||||
|
|
||||||
|
//Oscil<SQUARE_ANALOGUE512_NUM_CELLS, MOZZI_AUDIO_RATE> aSquare(SQUARE_ANALOGUE512_DATA);
|
||||||
|
Oscil<SQUARE_NO_ALIAS_2048_NUM_CELLS, MOZZI_CONTROL_RATE> kSquareLFO(SQUARE_NO_ALIAS_2048_DATA);
|
||||||
|
Oscil<SIN2048_NUM_CELLS, MOZZI_CONTROL_RATE> kSineLFO(SIN2048_DATA);
|
||||||
|
|
||||||
|
ADSR <MOZZI_CONTROL_RATE, MOZZI_CONTROL_RATE> envelope;
|
||||||
|
StateVariable <LOWPASS> lpf;
|
||||||
|
OverSample <unsigned int, 2> kOverSamplePitch;
|
||||||
|
|
||||||
|
//Global variables
|
||||||
|
byte gain;
|
||||||
|
bool MIDINotePlaying;
|
||||||
|
bool gateIsHigh = false;
|
||||||
|
float noteFreq;
|
||||||
|
|
||||||
|
void MIDINoteOn(byte channel, byte note, byte velocity) {
|
||||||
|
noteFreq = mtof((int) note);
|
||||||
|
envelope.noteOn();
|
||||||
|
MIDINotePlaying = true;
|
||||||
|
digitalWrite(LED, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDINoteOff(byte channel, byte note, byte velocity) {
|
||||||
|
envelope.noteOff();
|
||||||
|
digitalWrite(LED, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
long softClip(long input) {
|
||||||
|
int threshold = 2048;
|
||||||
|
if (input < -threshold) {
|
||||||
|
return -threshold + (input + threshold) / 4;
|
||||||
|
} else if (input > threshold) {
|
||||||
|
return threshold + (input - threshold) / 4;
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
pinMode(LED, OUTPUT);
|
||||||
|
pinMode(GateIn, INPUT_PULLUP);
|
||||||
|
pinMode(EnvSwitch, INPUT_PULLUP);
|
||||||
|
pinMode(DroneSwitch, INPUT_PULLUP);
|
||||||
|
|
||||||
|
MIDI.setHandleNoteOn(MIDINoteOn);
|
||||||
|
MIDI.setHandleNoteOff(MIDINoteOff);
|
||||||
|
MIDI.begin(MIDI_CHANNEL);
|
||||||
|
|
||||||
|
aSquare.setCutoffFreqs(90, 101, 122, 138, 154, 174, 210, 264, 327, 431, 546, 744, 1170, 1638, 2730, 8192);
|
||||||
|
|
||||||
|
startMozzi();
|
||||||
|
|
||||||
|
envelope.setAttackLevel(255);
|
||||||
|
|
||||||
|
digitalWrite(LED, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateControl(){
|
||||||
|
//Get Control Values
|
||||||
|
int CVInVal = mozziAnalogRead(CVIn);
|
||||||
|
int knob1Val = mozziAnalogRead(Knob1);
|
||||||
|
int knob2Val = mozziAnalogRead(Knob2);
|
||||||
|
int knob3Val = mozziAnalogRead(Knob3);
|
||||||
|
int knob4Val = mozziAnalogRead(Knob4);
|
||||||
|
int knobAVal = mozziAnalogRead(KnobA);
|
||||||
|
int knobDRVal = mozziAnalogRead(KnobDR);
|
||||||
|
int knobSVal = mozziAnalogRead(KnobS);
|
||||||
|
bool droneSwitchVal = digitalRead(DroneSwitch);
|
||||||
|
bool envSwitchVal = digitalRead(EnvSwitch);
|
||||||
|
bool gateInVal = !digitalRead(GateIn);
|
||||||
|
|
||||||
|
//Remap the values and assign to parameter
|
||||||
|
float LFOSpeed = kMapLFOSpeed(knob1Val) / 100;
|
||||||
|
float expLFOSpeed = (float) LFOSpeed * LFOSpeed / 800000;
|
||||||
|
float freqMod = (float) kMapFreqMod(knob2Val) / 1023;
|
||||||
|
float modSpeed = LFOSpeed;
|
||||||
|
int resonance = kMapResonance(knob3Val);
|
||||||
|
int cutoff = kMapCutoff(knob4Val);
|
||||||
|
|
||||||
|
//Set pitch and play notes on trigger
|
||||||
|
if (!MIDINotePlaying) {
|
||||||
|
int oversampledCVInVal = kOverSamplePitch.next(CVInVal);
|
||||||
|
noteFreq = mtof((float) kMapNote(oversampledCVInVal) / pitchSubSteps);
|
||||||
|
//noteFreq = mtof((float) kMapNote(CVInVal << 2) / pitchSubSteps);
|
||||||
|
digitalWrite(LED, !gateInVal);
|
||||||
|
if (gateInVal && !gateIsHigh) {
|
||||||
|
gateIsHigh = true;
|
||||||
|
envelope.noteOn();
|
||||||
|
} else if (!gateInVal && gateIsHigh) {
|
||||||
|
gateIsHigh = false;
|
||||||
|
envelope.noteOff();
|
||||||
|
}
|
||||||
|
} else if (MIDINotePlaying && !envelope.playing()) {
|
||||||
|
MIDINotePlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update Filter settings
|
||||||
|
lpf.setResonance(resonance);
|
||||||
|
lpf.setCentreFreq(cutoff);
|
||||||
|
|
||||||
|
//Update Envelope Settings
|
||||||
|
int attackTime = kMapAttack(knobAVal);
|
||||||
|
int decayReleaseTime = kMapDecayRelease(knobDRVal);
|
||||||
|
int sustainLevel = kMapSustain(knobSVal);
|
||||||
|
envelope.setDecayLevel(sustainLevel);
|
||||||
|
envelope.setTimes(attackTime, decayReleaseTime, 30000, decayReleaseTime); //30000 is so the note will sustain 30 seconds unless a noteOff comes
|
||||||
|
|
||||||
|
//LFO stuff
|
||||||
|
//Set oscillator frequencies
|
||||||
|
kSquareLFO.setFreq(modSpeed);
|
||||||
|
kSineLFO.setFreq(modSpeed);
|
||||||
|
int LFOValue;
|
||||||
|
if(envSwitchVal) {
|
||||||
|
LFOValue = kSquareLFO.next()-127; //-109 to bring the rangt to ~ 0-192
|
||||||
|
} else {
|
||||||
|
LFOValue = kSineLFO.next()-127;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Oscilator Frequency
|
||||||
|
float oscFreq = noteFreq - noteFreq * LFOValue * freqMod * 3 / 256;
|
||||||
|
//UFix<16,16> oscFreq =
|
||||||
|
aSquare.setFreq(oscFreq);
|
||||||
|
|
||||||
|
envelope.update();
|
||||||
|
|
||||||
|
int env = envelope.next();
|
||||||
|
|
||||||
|
if(!droneSwitchVal) {
|
||||||
|
gain = env;
|
||||||
|
} else {
|
||||||
|
gain = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
MIDI.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioOutput updateAudio(){
|
||||||
|
long signal = aSquare.next();
|
||||||
|
signal = lpf.next(signal); //filter
|
||||||
|
signal = (signal * gain); //envelope
|
||||||
|
//signal = softClip((signal * (127 + driveAmount)) >> 8); //overdrive
|
||||||
|
return MonoOutput::fromNBit(17, signal).clip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
audioHook();
|
||||||
|
}
|
||||||
238
FLMNG/FLMNG.ino
Normal file
238
FLMNG/FLMNG.ino
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
// 2 Operator FM Synth firmware for Sitka Instruments WS-1.0
|
||||||
|
// by Oleksiy Hrachov
|
||||||
|
//
|
||||||
|
// Code is partly based on Knob_LightLevel_x2_FMSynth example from Mozzi Library
|
||||||
|
//
|
||||||
|
// Although the code designed to work on Sitka Instruments WS-1.0 synth, it should
|
||||||
|
// be pretty easy to adapt to run on other arduino/mozzi-based setups
|
||||||
|
//
|
||||||
|
// This code is licenced under GPL v3 or later
|
||||||
|
|
||||||
|
//ToDo:
|
||||||
|
//test how accurate and fast oversampling is
|
||||||
|
//smooth harmonics knob?
|
||||||
|
//rework LFO/Intensity so when LFO rate is 0, intensidy doesn't depend on its phase
|
||||||
|
|
||||||
|
#include <Mozzi.h>
|
||||||
|
#include <MIDI.h>
|
||||||
|
#include <Oscil.h>
|
||||||
|
#include <tables/sin2048_int8.h>
|
||||||
|
#include <tables/square_no_alias_2048_int8.h>
|
||||||
|
#include <tables/saw2048_int8.h>
|
||||||
|
#include <tables/whitenoise8192_int8.h>
|
||||||
|
#include <Smooth.h>
|
||||||
|
#include <ADSR.h>
|
||||||
|
#include <mozzi_midi.h>
|
||||||
|
#include <IntMap.h>
|
||||||
|
#include <OverSample.h>
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
const int pitchSubSteps = 16; //set how many steps are there between semitones. set to 1 to quantize to semitones
|
||||||
|
const int driveAmount = 350;
|
||||||
|
const bool oversamplingEnabled = false; //makes V/OCT tracking more precise, but adds a little portamento
|
||||||
|
#define MIDI_CHANNEL 1 //MIDI_CHANNEL_OMNI
|
||||||
|
#define MOZZI_CONTROL_RATE 1024
|
||||||
|
|
||||||
|
//Hardware Definitions
|
||||||
|
#define Knob1 A6 //Intensity
|
||||||
|
#define Knob2 A4 //Modulator frequency ratio/Harmonics
|
||||||
|
#define Knob3 A2 //LFO Frequency
|
||||||
|
#define Knob4 A0 //LFO Shape
|
||||||
|
#define KnobA A5 //Attack
|
||||||
|
#define KnobDR A3 //Decay and Release
|
||||||
|
#define KnobS A1 //Sustain
|
||||||
|
#define CVIn A7 //CV input and Pitch knob
|
||||||
|
#define GateIn 10
|
||||||
|
#define EnvSwitch 11
|
||||||
|
#define DroneSwitch 12
|
||||||
|
#define LED 5
|
||||||
|
|
||||||
|
#define MOZZI_ANALOG_READ_RESOLUTION 10
|
||||||
|
|
||||||
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||||
|
|
||||||
|
IntMap kMapCarrierNote( 0, 4095, 24 * pitchSubSteps, 84 * pitchSubSteps );
|
||||||
|
IntMap kMapIntensity( 0, 1023, 10, 350 );
|
||||||
|
IntMap kMapHarmonics( 0, 1023, 1, 40 );
|
||||||
|
IntMap kMapLFOSpeed( 0, 1023, 1, 10000 );
|
||||||
|
IntMap kMapAttack( 0, 1023, 0, 80 );
|
||||||
|
IntMap kMapDecayRelease( 0, 1023, 8, 160 );
|
||||||
|
IntMap kMapSustain( 0, 1023, 0, 255 );
|
||||||
|
|
||||||
|
Oscil<SIN2048_NUM_CELLS, MOZZI_AUDIO_RATE> aCarrier(SIN2048_DATA);
|
||||||
|
Oscil<SIN2048_NUM_CELLS, MOZZI_AUDIO_RATE> aModulator(SIN2048_DATA);
|
||||||
|
Oscil<SIN2048_NUM_CELLS, MOZZI_CONTROL_RATE> kSineLFO(SIN2048_DATA);
|
||||||
|
Oscil<SQUARE_NO_ALIAS_2048_NUM_CELLS, MOZZI_CONTROL_RATE> kSquareLFO(SQUARE_NO_ALIAS_2048_DATA);
|
||||||
|
Oscil<SAW2048_NUM_CELLS, MOZZI_CONTROL_RATE> kSawLFO(SAW2048_DATA);
|
||||||
|
Oscil<WHITENOISE8192_NUM_CELLS, MOZZI_CONTROL_RATE> kNoiseLFO(WHITENOISE8192_DATA);
|
||||||
|
ADSR <MOZZI_CONTROL_RATE, MOZZI_CONTROL_RATE> envelope;
|
||||||
|
Smooth <long> aSmoothIntensity(0.95f);
|
||||||
|
OverSample <unsigned int, 2> kOverSamplePitch;
|
||||||
|
|
||||||
|
//Global variables
|
||||||
|
byte gain;
|
||||||
|
bool MIDINotePlaying;
|
||||||
|
bool gateIsHigh = false;
|
||||||
|
float carrierFreq;
|
||||||
|
long FMIntensity; // carries control info from updateControl to updateAudio
|
||||||
|
|
||||||
|
void MIDINoteOn(byte channel, byte note, byte velocity) {
|
||||||
|
carrierFreq = mtof((int) note);
|
||||||
|
envelope.noteOn();
|
||||||
|
MIDINotePlaying = true;
|
||||||
|
digitalWrite(LED, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDINoteOff(byte channel, byte note, byte velocity) {
|
||||||
|
envelope.noteOff();
|
||||||
|
digitalWrite(LED, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
long softClip(long input) {
|
||||||
|
int threshold = 2048;
|
||||||
|
if (input < -threshold) {
|
||||||
|
return -threshold + (input + threshold) / 4;
|
||||||
|
} else if (input > threshold) {
|
||||||
|
return threshold + (input - threshold) / 4;
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
pinMode(LED, OUTPUT);
|
||||||
|
pinMode(GateIn, INPUT_PULLUP);
|
||||||
|
pinMode(EnvSwitch, INPUT_PULLUP);
|
||||||
|
pinMode(DroneSwitch, INPUT_PULLUP);
|
||||||
|
|
||||||
|
MIDI.setHandleNoteOn(MIDINoteOn);
|
||||||
|
MIDI.setHandleNoteOff(MIDINoteOff);
|
||||||
|
MIDI.begin(MIDI_CHANNEL);
|
||||||
|
|
||||||
|
startMozzi();
|
||||||
|
|
||||||
|
envelope.setAttackLevel(255);
|
||||||
|
|
||||||
|
digitalWrite(LED, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateControl(){
|
||||||
|
//Get Control Values
|
||||||
|
int CVInVal = mozziAnalogRead(CVIn);
|
||||||
|
int knob1Val = mozziAnalogRead(Knob1);
|
||||||
|
int knob2Val = mozziAnalogRead(Knob2);
|
||||||
|
int knob3Val = mozziAnalogRead(Knob3);
|
||||||
|
int knob4Val = mozziAnalogRead(Knob4);
|
||||||
|
int knobAVal = mozziAnalogRead(KnobA);
|
||||||
|
int knobDRVal = mozziAnalogRead(KnobDR);
|
||||||
|
int knobSVal = mozziAnalogRead(KnobS);
|
||||||
|
bool droneSwitchVal = digitalRead(DroneSwitch);
|
||||||
|
bool envSwitchVal = digitalRead(EnvSwitch);
|
||||||
|
bool gateInVal = !digitalRead(GateIn);
|
||||||
|
|
||||||
|
//Remap the values and assign to parameter
|
||||||
|
int intensity = kMapIntensity(knob1Val);
|
||||||
|
int harmonics = kMapHarmonics(knob2Val);
|
||||||
|
int LFOSpeed = kMapLFOSpeed(knob3Val);
|
||||||
|
float expLFOSpeed = (float) LFOSpeed * LFOSpeed / 400000;
|
||||||
|
float modSpeed = expLFOSpeed;
|
||||||
|
|
||||||
|
//Set pitch and play notes on trigger
|
||||||
|
if (!MIDINotePlaying) {
|
||||||
|
if (oversamplingEnabled) {
|
||||||
|
int oversampledCVInVal = kOverSamplePitch.next(CVInVal);
|
||||||
|
carrierFreq = mtof((float) kMapCarrierNote(oversampledCVInVal) / pitchSubSteps);
|
||||||
|
} else {
|
||||||
|
carrierFreq = mtof((float) kMapCarrierNote(CVInVal << 2) / pitchSubSteps);
|
||||||
|
}
|
||||||
|
digitalWrite(LED, !gateInVal);
|
||||||
|
if (gateInVal && !gateIsHigh) {
|
||||||
|
gateIsHigh = true;
|
||||||
|
envelope.noteOn();
|
||||||
|
} else if (!gateInVal && gateIsHigh) {
|
||||||
|
gateIsHigh = false;
|
||||||
|
envelope.noteOff();
|
||||||
|
}
|
||||||
|
} else if (MIDINotePlaying && !envelope.playing()) {
|
||||||
|
MIDINotePlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update Envelope Settings
|
||||||
|
int attackTime = kMapAttack(knobAVal);
|
||||||
|
int decayReleaseTime = kMapDecayRelease(knobDRVal);
|
||||||
|
int sustainLevel = kMapSustain(knobSVal);
|
||||||
|
envelope.setDecayLevel(sustainLevel);
|
||||||
|
envelope.setTimes(attackTime, decayReleaseTime, 30000, decayReleaseTime); //30000 is so the note will sustain 30 seconds unless a noteOff comes
|
||||||
|
|
||||||
|
//Calculate the modulation frequency
|
||||||
|
int FMmodFreq = carrierFreq * harmonics;
|
||||||
|
|
||||||
|
//Set oscillator frequencies
|
||||||
|
aCarrier.setFreq(carrierFreq);
|
||||||
|
aModulator.setFreq(FMmodFreq);
|
||||||
|
kSineLFO.setFreq(modSpeed);
|
||||||
|
kSquareLFO.setFreq(modSpeed);
|
||||||
|
kSawLFO.setFreq(modSpeed);
|
||||||
|
kNoiseLFO.setFreq(modSpeed/4096);
|
||||||
|
|
||||||
|
envelope.update();
|
||||||
|
|
||||||
|
int sineLFOLevel;
|
||||||
|
int squareLFOLevel;
|
||||||
|
int sawLFOLevel;
|
||||||
|
int noiseLFOLevel;
|
||||||
|
if (knob4Val < 255) {
|
||||||
|
sineLFOLevel = 255 - knob4Val;
|
||||||
|
squareLFOLevel = knob4Val;
|
||||||
|
sawLFOLevel = 0;
|
||||||
|
noiseLFOLevel = 0;
|
||||||
|
} else if (knob4Val < 511) {
|
||||||
|
sineLFOLevel = 0;
|
||||||
|
squareLFOLevel = 511 - knob4Val;
|
||||||
|
sawLFOLevel = knob4Val - 255;
|
||||||
|
noiseLFOLevel = 0;
|
||||||
|
} else if (knob4Val < 767) {
|
||||||
|
sineLFOLevel = 0;
|
||||||
|
squareLFOLevel = 0;
|
||||||
|
sawLFOLevel = 767 - knob4Val;
|
||||||
|
noiseLFOLevel = knob4Val - 511;
|
||||||
|
} else {
|
||||||
|
sineLFOLevel = 0;
|
||||||
|
squareLFOLevel = 0;
|
||||||
|
sawLFOLevel = 0;
|
||||||
|
noiseLFOLevel = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shapedLFO = (kSineLFO.next() * sineLFOLevel +
|
||||||
|
kSquareLFO.next() * squareLFOLevel +
|
||||||
|
kSawLFO.next() * sawLFOLevel +
|
||||||
|
kNoiseLFO.next() * noiseLFOLevel)>>8;
|
||||||
|
|
||||||
|
int env = envelope.next();
|
||||||
|
int intensityEnv;
|
||||||
|
if(envSwitchVal) {
|
||||||
|
intensityEnv = env*3;
|
||||||
|
} else {
|
||||||
|
intensityEnv = 1;
|
||||||
|
}
|
||||||
|
FMIntensity = ((long)(intensity + intensityEnv) * (shapedLFO+128))>>8; //(shapedLFO+128))>>16; //(kSineLFO.next()+128))>>8;
|
||||||
|
|
||||||
|
if(!droneSwitchVal) {
|
||||||
|
gain = env;
|
||||||
|
} else {
|
||||||
|
gain = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
MIDI.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioOutput updateAudio(){
|
||||||
|
long modulation = aSmoothIntensity.next(FMIntensity) * aModulator.next();
|
||||||
|
long signal = (aCarrier.phMod(modulation) * gain) >> 8; //envelope
|
||||||
|
signal = softClip((signal * (127 + driveAmount)) >> 8); //overdrive
|
||||||
|
return MonoOutput::from8Bit(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
audioHook();
|
||||||
|
}
|
||||||
@ -1,3 +1,9 @@
|
|||||||
# WS-1.0-Firmwares
|
# WS-1.0-Firmwares
|
||||||
|
|
||||||
Collection of firmwares for WS-1.0 Arduino-based Synthesizer
|
Collection of firmwares for WS-1.0 Arduino-based Synthesizer
|
||||||
|
|
||||||
|
## FLMNG
|
||||||
|
2-operator FM synth with LFO mapped to FM intensity
|
||||||
|
|
||||||
|
## DubSiren
|
||||||
|
Simple synth for creating dub-style sirens: square wave oscillator, sine or square wave LFO mapped to oscillator pitch, resonant filter.
|
||||||
|
|||||||
Reference in New Issue
Block a user