Compare commits

...

3 Commits

5 changed files with 216 additions and 59 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
*/build/arduino.avr.nano */build/arduino.avr.nano
.DS_Store

View File

@ -19,13 +19,14 @@
#include <MetaOscil.h> #include <MetaOscil.h>
#include <tables/sin2048_int8.h> #include <tables/sin2048_int8.h>
#include <tables/square_no_alias_2048_int8.h> #include <tables/square_no_alias_2048_int8.h>
//#include <tables/square_analogue512_int8.h>
#include <StateVariable.h> #include <StateVariable.h>
#include <ADSR.h> #include <ADSR.h>
#include <mozzi_midi.h> #include <mozzi_midi.h>
#include <IntMap.h> #include <IntMap.h>
#include <OverSample.h> #include <OverSample.h>
#include <FixMath.h> #include <FixMath.h>
#include <EEPROM.h>
#include "config.h"
//Band limited oscilator tables for aliasing-free Meta Oscilator //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_90_at_16384_512_int8.h>
@ -64,31 +65,6 @@ Oscil <SQUARE_MAX_2730_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq2730(SQUARE_
Oscil <SQUARE_MAX_8192_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSq8192(SQUARE_MAX_8192_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}; 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 kMapNote( 0, 4095, 24 * pitchSubSteps, 84 * pitchSubSteps );
IntMap kMapLFOSpeed( 0, 1023, 500, 20000 ); IntMap kMapLFOSpeed( 0, 1023, 500, 20000 );
IntMap kMapFreqMod( 0, 1023, 0, 1023 ); IntMap kMapFreqMod( 0, 1023, 0, 1023 );
@ -111,6 +87,8 @@ byte gain;
bool MIDINotePlaying; bool MIDINotePlaying;
bool gateIsHigh = false; bool gateIsHigh = false;
float noteFreq; float noteFreq;
byte MIDIChannel;
byte memCode = "a";
void MIDINoteOn(byte channel, byte note, byte velocity) { void MIDINoteOn(byte channel, byte note, byte velocity) {
noteFreq = mtof((int) note); noteFreq = mtof((int) note);
@ -141,9 +119,83 @@ void setup(){
pinMode(EnvSwitch, INPUT_PULLUP); pinMode(EnvSwitch, INPUT_PULLUP);
pinMode(DroneSwitch, INPUT_PULLUP); pinMode(DroneSwitch, INPUT_PULLUP);
//MIDI Channel setup
if(!digitalRead(GateIn)) { //&& !digitalRead(DroneSwitch) && !digitalRead(EnvSwitch)) { //MIDI setup mode, first knob you rotate = MIDI channel
int knob1Orig = analogRead(Knob1);
int knob2Orig = analogRead(Knob2);
int knob3Orig = analogRead(Knob3);
int knob4Orig = analogRead(Knob4);
int knobAOrig = analogRead(KnobA);
int knobDROrig = analogRead(KnobDR);
int knobSOrig = analogRead(KnobS);
int threshhold = 50; //To reduce noise from the input, needs testing and fine-tuning
while(true) {
if(abs(analogRead(Knob1) - knob1Orig) > threshhold) {
MIDIChannel = 1;
break;
} else if (abs(analogRead(Knob2) - knob2Orig) > threshhold) {
MIDIChannel = 2;
break;
} else if (abs(analogRead(Knob3) - knob3Orig) > threshhold) {
MIDIChannel = 3;
break;
} else if (abs(analogRead(Knob4) - knob4Orig) > threshhold) {
MIDIChannel = 4;
break;
} else if (abs(analogRead(KnobA) - knobAOrig) > threshhold) {
MIDIChannel = 5;
break;
} else if (abs(analogRead(KnobDR) - knobDROrig) > threshhold) {
MIDIChannel = 6;
break;
} else if (abs(analogRead(KnobS) - knobSOrig) > threshhold) {
MIDIChannel = 7;
break;
}
digitalWrite(LED, HIGH); //slow blinking to indicate the setup mode
delay(500);
digitalWrite(LED, LOW);
delay(500);
}
EEPROM.write(0, MIDIChannel);
EEPROM.write(1023, memCode);
digitalWrite(LED, LOW);
delay(150);
for(int i = 0; i < MIDIChannel; i ++) { //fast blink to indicate saved MIDI channel
digitalWrite(LED, HIGH);
delay(150);
digitalWrite(LED, LOW);
delay(150);
}
delay(500);
} else if (EEPROM.read(1023) == memCode) {
MIDIChannel = EEPROM.read(0);
} else { //Save default MIDI Channel to EEPROM if it wasn't set
MIDIChannel = 1; //channel 1 by default
EEPROM.write(0, MIDIChannel);
EEPROM.write(1023, memCode);
}
disconnectDigitalIn(Knob1);
disconnectDigitalIn(Knob2);
disconnectDigitalIn(Knob3);
disconnectDigitalIn(Knob4);
disconnectDigitalIn(KnobA);
disconnectDigitalIn(KnobDR);
disconnectDigitalIn(KnobS);
disconnectDigitalIn(CVIn);
MIDI.setHandleNoteOn(MIDINoteOn); MIDI.setHandleNoteOn(MIDINoteOn);
MIDI.setHandleNoteOff(MIDINoteOff); MIDI.setHandleNoteOff(MIDINoteOff);
MIDI.begin(MIDI_CHANNEL);
MIDI.setHandleClock(nullptr);
MIDI.setHandleStart(nullptr);
MIDI.setHandleStop(nullptr);
MIDI.setHandleContinue(nullptr);
MIDI.setHandleControlChange(nullptr);
MIDI.begin(MIDIChannel);
MIDI.turnThruOff();
aSquare.setCutoffFreqs(90, 101, 122, 138, 154, 174, 210, 264, 327, 431, 546, 744, 1170, 1638, 2730, 8192); aSquare.setCutoffFreqs(90, 101, 122, 138, 154, 174, 210, 264, 327, 431, 546, 744, 1170, 1638, 2730, 8192);

22
DubSiren/config.h Normal file
View File

@ -0,0 +1,22 @@
//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 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();

View File

@ -4,14 +4,16 @@
// Code is partly based on Knob_LightLevel_x2_FMSynth example from Mozzi Library // 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 // 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 // be pretty easy to adapt to run on other arduino/mozzi-based setups.
// Edit config.h to match your setup.
// //
// This code is licenced under GPL v3 or later // This code is licenced under GPL v3 or later
//ToDo: //ToDo:
//test how accurate and fast oversampling is //optimize MIDI input (maybe neohwserial and this parser might help https://github.com/eclab/grains/tree/main/midi)
//smooth harmonics knob? //add ramp LFO
//rework LFO/Intensity so when LFO rate is 0, intensidy doesn't depend on its phase //add uneven rations (like 3:2, 3:5)
//rework LFO/Intensity so when LFO rate is 0, intensity doesn't depend on its phase
#include <Mozzi.h> #include <Mozzi.h>
#include <MIDI.h> #include <MIDI.h>
@ -25,31 +27,8 @@
#include <mozzi_midi.h> #include <mozzi_midi.h>
#include <IntMap.h> #include <IntMap.h>
#include <OverSample.h> #include <OverSample.h>
#include <EEPROM.h>
//Settings #include "config.h"
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 kMapCarrierNote( 0, 4095, 24 * pitchSubSteps, 84 * pitchSubSteps );
IntMap kMapIntensity( 0, 1023, 10, 350 ); IntMap kMapIntensity( 0, 1023, 10, 350 );
@ -75,6 +54,8 @@ bool MIDINotePlaying;
bool gateIsHigh = false; bool gateIsHigh = false;
float carrierFreq; float carrierFreq;
long FMIntensity; // carries control info from updateControl to updateAudio long FMIntensity; // carries control info from updateControl to updateAudio
byte MIDIChannel;
byte memCode = "a";
void MIDINoteOn(byte channel, byte note, byte velocity) { void MIDINoteOn(byte channel, byte note, byte velocity) {
carrierFreq = mtof((int) note); carrierFreq = mtof((int) note);
@ -105,9 +86,83 @@ void setup(){
pinMode(EnvSwitch, INPUT_PULLUP); pinMode(EnvSwitch, INPUT_PULLUP);
pinMode(DroneSwitch, INPUT_PULLUP); pinMode(DroneSwitch, INPUT_PULLUP);
//MIDI Channel setup
if(!digitalRead(GateIn)) { //&& !digitalRead(DroneSwitch) && !digitalRead(EnvSwitch)) { //MIDI setup mode, first knob you rotate = MIDI channel
int knob1Orig = analogRead(Knob1);
int knob2Orig = analogRead(Knob2);
int knob3Orig = analogRead(Knob3);
int knob4Orig = analogRead(Knob4);
int knobAOrig = analogRead(KnobA);
int knobDROrig = analogRead(KnobDR);
int knobSOrig = analogRead(KnobS);
int threshhold = 50; //To reduce noise from the input, needs testing and fine-tuning
while(true) {
if(abs(analogRead(Knob1) - knob1Orig) > threshhold) {
MIDIChannel = 1;
break;
} else if (abs(analogRead(Knob2) - knob2Orig) > threshhold) {
MIDIChannel = 2;
break;
} else if (abs(analogRead(Knob3) - knob3Orig) > threshhold) {
MIDIChannel = 3;
break;
} else if (abs(analogRead(Knob4) - knob4Orig) > threshhold) {
MIDIChannel = 4;
break;
} else if (abs(analogRead(KnobA) - knobAOrig) > threshhold) {
MIDIChannel = 5;
break;
} else if (abs(analogRead(KnobDR) - knobDROrig) > threshhold) {
MIDIChannel = 6;
break;
} else if (abs(analogRead(KnobS) - knobSOrig) > threshhold) {
MIDIChannel = 7;
break;
}
digitalWrite(LED, HIGH); //slow blinking to indicate the setup mode
delay(500);
digitalWrite(LED, LOW);
delay(500);
}
EEPROM.write(0, MIDIChannel);
EEPROM.write(1023, memCode);
digitalWrite(LED, LOW);
delay(150);
for(int i = 0; i < MIDIChannel; i ++) { //fast blink to indicate saved MIDI channel
digitalWrite(LED, HIGH);
delay(150);
digitalWrite(LED, LOW);
delay(150);
}
delay(500);
} else if (EEPROM.read(1023) == memCode) {
MIDIChannel = EEPROM.read(0);
} else { //Save default MIDI Channel to EEPROM if it wasn't set
MIDIChannel = 1; //channel 1 by default
EEPROM.write(0, MIDIChannel);
EEPROM.write(1023, memCode);
}
disconnectDigitalIn(Knob1);
disconnectDigitalIn(Knob2);
disconnectDigitalIn(Knob3);
disconnectDigitalIn(Knob4);
disconnectDigitalIn(KnobA);
disconnectDigitalIn(KnobDR);
disconnectDigitalIn(KnobS);
disconnectDigitalIn(CVIn);
MIDI.setHandleNoteOn(MIDINoteOn); MIDI.setHandleNoteOn(MIDINoteOn);
MIDI.setHandleNoteOff(MIDINoteOff); MIDI.setHandleNoteOff(MIDINoteOff);
MIDI.begin(MIDI_CHANNEL);
MIDI.setHandleClock(nullptr);
MIDI.setHandleStart(nullptr);
MIDI.setHandleStop(nullptr);
MIDI.setHandleContinue(nullptr);
MIDI.setHandleControlChange(nullptr);
MIDI.begin(MIDIChannel);
MIDI.turnThruOff();
startMozzi(); startMozzi();
@ -117,6 +172,11 @@ void setup(){
} }
void updateControl(){ void updateControl(){
for(int i=0; i<10; i++) { // Hacky way to drain the buffer faster
MIDI.read();
}
//Get Control Values //Get Control Values
int CVInVal = mozziAnalogRead(CVIn); int CVInVal = mozziAnalogRead(CVIn);
int knob1Val = mozziAnalogRead(Knob1); int knob1Val = mozziAnalogRead(Knob1);
@ -223,7 +283,6 @@ void updateControl(){
gain = 255; gain = 255;
} }
MIDI.read();
} }
AudioOutput updateAudio(){ AudioOutput updateAudio(){

23
FLMNG/config.h Normal file
View File

@ -0,0 +1,23 @@
//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 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();