Switched from ADSR to EAD, tweaked filter, added MIDI config part
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
*/build/arduino.avr.nano
|
*/build/arduino.avr.nano
|
||||||
|
.DS_Store
|
||||||
|
|||||||
128
Acid/Acid.ino
128
Acid/Acid.ino
@ -6,15 +6,23 @@
|
|||||||
//
|
//
|
||||||
// This code is licenced under GPL v3 or later
|
// This code is licenced under GPL v3 or later
|
||||||
|
|
||||||
|
// todo:
|
||||||
|
// add glide handling
|
||||||
|
// add accent handling
|
||||||
|
// test StateVariable vs Resonant filters
|
||||||
|
// exponential envelope https://sensorium.github.io/Mozzi/doc/html/07_8_envelopes_2_ead__envelope_2_ead__envelope_8ino-example.html
|
||||||
|
|
||||||
#include <Mozzi.h>
|
#include <Mozzi.h>
|
||||||
#include <MIDI.h>
|
#include <MIDI.h>
|
||||||
#include <Oscil.h>
|
#include <Oscil.h>
|
||||||
#include <MetaOscil.h>
|
#include <MetaOscil.h>
|
||||||
#include <StateVariable.h>
|
#include <StateVariable.h>
|
||||||
#include <ADSR.h>
|
//#include <ADSR.h>
|
||||||
|
#include <Ead.h>
|
||||||
#include <mozzi_midi.h>
|
#include <mozzi_midi.h>
|
||||||
#include <IntMap.h>
|
#include <IntMap.h>
|
||||||
#include <FixMath.h>
|
#include <FixMath.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
//Band limited SQUARE oscilator tables
|
//Band limited SQUARE oscilator tables
|
||||||
@ -91,34 +99,39 @@ Oscil <SAW_MAX_4096_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSaw4096(SAW_MAX_4
|
|||||||
Oscil <SAW_MAX_8192_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSaw8192(SAW_MAX_8192_AT_16384_512_DATA);
|
Oscil <SAW_MAX_8192_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE> aSaw8192(SAW_MAX_8192_AT_16384_512_DATA);
|
||||||
MetaOscil<SAW_MAX_138_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE, 16> aSaw {&aSaw138, &aSaw154, &aSaw182, &aSaw240, &aSaw292, &aSaw341, &aSaw390, &aSaw431, &aSaw512, &aSaw630, &aSaw744, &aSaw1170, &aSaw1638, &aSaw2730, &aSaw4096, &aSaw8192};
|
MetaOscil<SAW_MAX_138_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE, 16> aSaw {&aSaw138, &aSaw154, &aSaw182, &aSaw240, &aSaw292, &aSaw341, &aSaw390, &aSaw431, &aSaw512, &aSaw630, &aSaw744, &aSaw1170, &aSaw1638, &aSaw2730, &aSaw4096, &aSaw8192};
|
||||||
|
|
||||||
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 );
|
||||||
IntMap kMapResonance( 0, 1023, 200, 1 );
|
IntMap kMapResonance( 0, 1023, 200, 1 );
|
||||||
IntMap kMapCutoff( 0, 1023, 60, 3600 );
|
IntMap kMapCutoff( 0, 1023, 1, 20 );
|
||||||
IntMap kMapAttack( 0, 1023, 0, 80 );
|
IntMap kMapAttack( 0, 1023, 3, 100 );
|
||||||
IntMap kMapDecayRelease( 0, 1023, 8, 160 );
|
IntMap kMapDecayRelease( 0, 1023, 200, 2000 );
|
||||||
IntMap kMapSustain( 0, 1023, 0, 255 );
|
IntMap kMapSustain( 0, 1023, 0, 255 );
|
||||||
|
|
||||||
ADSR <MOZZI_CONTROL_RATE, MOZZI_CONTROL_RATE> envelope;
|
//ADSR <MOZZI_CONTROL_RATE, MOZZI_CONTROL_RATE> envelope;
|
||||||
|
Ead kEnvelope(MOZZI_CONTROL_RATE);
|
||||||
StateVariable <LOWPASS> lpf;
|
StateVariable <LOWPASS> lpf;
|
||||||
|
|
||||||
|
|
||||||
//Global variables
|
//Global variables
|
||||||
byte gain;
|
byte gain;
|
||||||
bool MIDINotePlaying;
|
bool MIDINotePlaying;
|
||||||
bool gateIsHigh = false;
|
bool gateIsHigh = false;
|
||||||
float noteFreq;
|
float noteFreq;
|
||||||
bool envSwitchVal;
|
bool envSwitchVal;
|
||||||
|
byte MIDIChannel;
|
||||||
|
byte memCode = "a"; //a = MIDI Channel stored in 1023
|
||||||
|
|
||||||
void MIDINoteOn(byte channel, byte note, byte velocity) {
|
void MIDINoteOn(byte channel, byte note, byte velocity) {
|
||||||
noteFreq = mtof((int) note);
|
noteFreq = mtof((int) note);
|
||||||
envelope.noteOn();
|
kEnvelope.start();
|
||||||
|
//envelope.noteOn();
|
||||||
MIDINotePlaying = true;
|
MIDINotePlaying = true;
|
||||||
digitalWrite(LED, LOW);
|
digitalWrite(LED, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MIDINoteOff(byte channel, byte note, byte velocity) {
|
void MIDINoteOff(byte channel, byte note, byte velocity) {
|
||||||
envelope.noteOff();
|
//envelope.noteOff();
|
||||||
digitalWrite(LED, HIGH);
|
digitalWrite(LED, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,16 +152,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.begin(MIDIChannel);
|
||||||
|
|
||||||
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);
|
||||||
aSaw.setCutoffFreqs(138, 154, 182, 240, 292, 341, 390, 431, 512, 630, 744, 1170, 1638, 2730, 4096, 8192);
|
aSaw.setCutoffFreqs(138, 154, 182, 240, 292, 341, 390, 431, 512, 630, 744, 1170, 1638, 2730, 4096, 8192);
|
||||||
|
|
||||||
startMozzi();
|
startMozzi();
|
||||||
|
|
||||||
envelope.setAttackLevel(255);
|
//envelope.setAttackLevel(255);
|
||||||
|
kEnvelope.setAttack(3);
|
||||||
|
|
||||||
digitalWrite(LED, HIGH);
|
digitalWrite(LED, HIGH);
|
||||||
}
|
}
|
||||||
@ -182,14 +262,15 @@ void updateControl(){
|
|||||||
digitalWrite(LED, !gateInVal);
|
digitalWrite(LED, !gateInVal);
|
||||||
if (gateInVal && !gateIsHigh) {
|
if (gateInVal && !gateIsHigh) {
|
||||||
gateIsHigh = true;
|
gateIsHigh = true;
|
||||||
envelope.noteOn();
|
kEnvelope.start();
|
||||||
|
//envelope.noteOn();
|
||||||
} else if (!gateInVal && gateIsHigh) {
|
} else if (!gateInVal && gateIsHigh) {
|
||||||
gateIsHigh = false;
|
gateIsHigh = false;
|
||||||
envelope.noteOff();
|
//envelope.noteOff();
|
||||||
}
|
}
|
||||||
} else if (MIDINotePlaying && !envelope.playing()) {
|
} /*else if (MIDINotePlaying && !envelope.playing()) {
|
||||||
MIDINotePlaying = false;
|
MIDINotePlaying = false;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//Update Filter settings
|
//Update Filter settings
|
||||||
lpf.setResonance(resonance);
|
lpf.setResonance(resonance);
|
||||||
@ -199,37 +280,40 @@ void updateControl(){
|
|||||||
int attackTime = kMapAttack(knobAVal);
|
int attackTime = kMapAttack(knobAVal);
|
||||||
int decayReleaseTime = kMapDecayRelease(knobDRVal);
|
int decayReleaseTime = kMapDecayRelease(knobDRVal);
|
||||||
int sustainLevel = kMapSustain(knobSVal);
|
int sustainLevel = kMapSustain(knobSVal);
|
||||||
envelope.setDecayLevel(sustainLevel);
|
kEnvelope.setDecay(decayReleaseTime);
|
||||||
envelope.setTimes(attackTime, decayReleaseTime, 30000, decayReleaseTime); //30000 is so the note will sustain 30 seconds unless a noteOff comes
|
kEnvelope.setAttack(attackTime);
|
||||||
|
//envelope.setDecayLevel(sustainLevel);
|
||||||
|
//envelope.setTimes(attackTime, decayReleaseTime, 30000, decayReleaseTime); //30000 is so the note will sustain 30 seconds unless a noteOff comes
|
||||||
|
|
||||||
//Set Oscilator Frequency
|
//Set Oscilator Frequency
|
||||||
float oscFreq = noteFreq;
|
float oscFreq = noteFreq;
|
||||||
aSquare.setFreq(oscFreq);
|
aSquare.setFreq(oscFreq);
|
||||||
aSaw.setFreq(oscFreq);
|
aSaw.setFreq(oscFreq);
|
||||||
|
|
||||||
envelope.update();
|
//envelope.update();
|
||||||
|
|
||||||
int env = envelope.next();
|
//int env = envelope.next();
|
||||||
|
int env = kEnvelope.next();
|
||||||
|
|
||||||
if(!droneSwitchVal) {
|
if(!droneSwitchVal) {
|
||||||
gain = env;
|
gain = env;
|
||||||
} else {
|
} else {
|
||||||
gain = 255;
|
gain = 255;
|
||||||
}
|
}
|
||||||
lpf.setCentreFreq(60 + env * 14);
|
lpf.setCentreFreq(env * cutoff);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutput updateAudio(){
|
AudioOutput updateAudio(){
|
||||||
long signal;
|
long signal;
|
||||||
if(envSwitchVal) {
|
if(envSwitchVal) {
|
||||||
signal = aSquare.next() * 0.3;
|
signal = aSquare.next() * 0.5;
|
||||||
} else {
|
} else {
|
||||||
signal = aSaw.next() * 1.2;
|
signal = aSaw.next() * 1;
|
||||||
}
|
}
|
||||||
signal = lpf.next(signal); //filter
|
signal = lpf.next(signal); //filter
|
||||||
signal = (signal * gain); //envelope
|
signal = (signal * gain); //envelope
|
||||||
//signal = softClip((signal * (127 + driveAmount)) >> 8); //overdrive
|
signal = softClip((signal * (127 + driveAmount)) >> 6); //overdrive
|
||||||
return MonoOutput::fromNBit(17, signal).clip();
|
return MonoOutput::fromNBit(17, signal).clip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
//Settings
|
//Settings
|
||||||
const int pitchSubSteps = 16; //set how many steps are there between semitones. set to 1 to quantize to semitones
|
const int pitchSubSteps = 16; //set how many steps are there between semitones. set to 1 to quantize to semitones
|
||||||
const int driveAmount = 350;
|
const int driveAmount = 250;
|
||||||
const bool oversamplingEnabled = false; //makes V/OCT tracking more precise, but adds a little portamento
|
const bool oversamplingEnabled = false; //makes V/OCT tracking more precise, but adds a little portamento
|
||||||
#define MIDI_CHANNEL 2 //MIDI_CHANNEL_OMNI
|
|
||||||
#define MOZZI_CONTROL_RATE 256
|
#define MOZZI_CONTROL_RATE 256
|
||||||
|
|
||||||
//Hardware Definitions
|
//Hardware Definitions
|
||||||
|
|||||||
Reference in New Issue
Block a user