added glide, but still needs debugging
This commit is contained in:
130
Acid/Acid.ino
130
Acid/Acid.ino
@ -7,18 +7,17 @@
|
||||
// This code is licenced under GPL v3 or later
|
||||
|
||||
// todo:
|
||||
// add glide handling
|
||||
// make a glide on/off swithc instead of drone, both for MIDI and CV (sample pitch on gate)
|
||||
// debug glide (slides down from lower notes?)
|
||||
// add accent handling
|
||||
// bring back manual triggering (test conflicts with midi)
|
||||
|
||||
#include <Mozzi.h>
|
||||
#include <MIDI.h>
|
||||
#include <Oscil.h>
|
||||
#include <MetaOscil.h>
|
||||
//#include <StateVariable.h>
|
||||
#include <ResonantFilter.h>
|
||||
//#include <ADSR.h>
|
||||
#include <Ead.h>
|
||||
#include <Portamento.h>
|
||||
#include <mozzi_midi.h>
|
||||
#include <IntMap.h>
|
||||
#include <FixMath.h>
|
||||
@ -101,42 +100,57 @@ MetaOscil<SAW_MAX_138_AT_16384_512_NUM_CELLS, MOZZI_AUDIO_RATE, 16> aSaw {&aSaw1
|
||||
|
||||
IntMap kMapNote( 0, 4095, 24 * pitchSubSteps, 84 * pitchSubSteps );
|
||||
IntMap kMapResonance( 0, 1023, 0, 255 );
|
||||
IntMap kMapCutoff( 0, 1023, 20, 127 );
|
||||
IntMap kMapCutoff( 0, 1023, 26, 100 );
|
||||
IntMap kMapAttack( 0, 1023, 3, 100 );
|
||||
IntMap kMapDecay( 0, 1023, 200, 2000 );
|
||||
IntMap kMapEnvMod( 0, 1023, 0, 255 );
|
||||
IntMap kMapEnvMod( 0, 1023, 0, 160 );
|
||||
IntMap kMapDrive( 0, 1023, 0, 400 );
|
||||
|
||||
//ADSR <MOZZI_CONTROL_RATE, MOZZI_CONTROL_RATE> envelope;
|
||||
Ead kEnvelope(MOZZI_CONTROL_RATE);
|
||||
//StateVariable <LOWPASS> lpf;
|
||||
LowPassFilter lpfr;
|
||||
|
||||
Portamento <MOZZI_CONTROL_RATE> glide;
|
||||
|
||||
//Global variables
|
||||
byte gain;
|
||||
bool MIDINotePlaying;
|
||||
bool gateIsHigh = false;
|
||||
float noteFreq;
|
||||
Q16n16 noteFreq;
|
||||
bool envSwitchVal;
|
||||
bool droneSwitchVal;
|
||||
byte MIDIChannel;
|
||||
byte memCode = "a"; //a = MIDI Channel stored in 1023
|
||||
int driveAmount;
|
||||
byte notePlaying;
|
||||
|
||||
// long debugMaxSignal = 0;
|
||||
// long debugMinSignal = 0;
|
||||
|
||||
void MIDINoteOn(byte channel, byte note, byte velocity) {
|
||||
noteFreq = mtof((int) note);
|
||||
kEnvelope.start();
|
||||
//envelope.noteOn();
|
||||
notePlaying = note;
|
||||
noteFreq = Q16n16_mtof((int) note);
|
||||
|
||||
if (!MIDINotePlaying || !droneSwitchVal) {
|
||||
glide.setTime(0);
|
||||
glide.start(note);
|
||||
kEnvelope.start();
|
||||
} else {
|
||||
glide.setTime(GLIDE_TIME);
|
||||
glide.start(note);
|
||||
}
|
||||
MIDINotePlaying = true;
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
|
||||
void MIDINoteOff(byte channel, byte note, byte velocity) {
|
||||
//envelope.noteOff();
|
||||
MIDINotePlaying = false;
|
||||
digitalWrite(LED, HIGH);
|
||||
if (note == notePlaying || !droneSwitchVal) {
|
||||
MIDINotePlaying = false;
|
||||
digitalWrite(LED, HIGH);
|
||||
glide.setTime(0);
|
||||
}
|
||||
}
|
||||
|
||||
long softClip(long input) {
|
||||
int threshold = 2048;
|
||||
int threshold = 24000;
|
||||
if (input < -threshold) {
|
||||
return -threshold + (input + threshold) / 4;
|
||||
} else if (input > threshold) {
|
||||
@ -153,7 +167,7 @@ void setup(){
|
||||
pinMode(DroneSwitch, INPUT_PULLUP);
|
||||
|
||||
//MIDI Channel setup
|
||||
if(!digitalRead(GateIn)) { //&& !digitalRead(DroneSwitch) && !digitalRead(EnvSwitch)) { //MIDI setup mode, first knob you rotate = MIDI channel
|
||||
if(!digitalRead(GateIn)) { //MIDI setup mode, first knob you rotate = MIDI channel
|
||||
int knob1Orig = analogRead(Knob1);
|
||||
int knob2Orig = analogRead(Knob2);
|
||||
int knob3Orig = analogRead(Knob3);
|
||||
@ -161,7 +175,7 @@ void setup(){
|
||||
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
|
||||
int threshhold = 50; //To reduce noise from the input
|
||||
while(true) {
|
||||
if(abs(analogRead(Knob1) - knob1Orig) > threshhold) {
|
||||
MIDIChannel = 1;
|
||||
@ -227,9 +241,6 @@ void setup(){
|
||||
|
||||
startMozzi();
|
||||
|
||||
//envelope.setAttackLevel(255);
|
||||
kEnvelope.setAttack(3);
|
||||
|
||||
digitalWrite(LED, HIGH);
|
||||
}
|
||||
|
||||
@ -247,74 +258,79 @@ void updateControl(){
|
||||
int knobAVal = mozziAnalogRead(KnobA);
|
||||
int knobDRVal = mozziAnalogRead(KnobDR);
|
||||
int knobSVal = mozziAnalogRead(KnobS);
|
||||
bool droneSwitchVal = digitalRead(DroneSwitch);
|
||||
droneSwitchVal = digitalRead(DroneSwitch);
|
||||
envSwitchVal = digitalRead(EnvSwitch);
|
||||
bool gateInVal = !digitalRead(GateIn);
|
||||
int CVInVal = mozziAnalogRead(CVIn);
|
||||
|
||||
//Remap the values and assign to parameter
|
||||
//Remap the values and assign to parameters
|
||||
int cutoff = kMapCutoff(knob1Val);
|
||||
int resonance = kMapResonance(knob2Val);
|
||||
int envMod = kMapEnvMod(knob3Val);
|
||||
driveAmount = kMapDrive(knob4Val);
|
||||
|
||||
//Set pitch and play notes on trigger
|
||||
if (!MIDINotePlaying) {
|
||||
noteFreq = mtof((float) kMapNote(CVInVal << 2) / pitchSubSteps);
|
||||
digitalWrite(LED, !gateInVal);
|
||||
if (gateInVal && !gateIsHigh) {
|
||||
gateIsHigh = true;
|
||||
kEnvelope.start();
|
||||
//envelope.noteOn();
|
||||
} else if (!gateInVal && gateIsHigh) {
|
||||
gateIsHigh = false;
|
||||
//envelope.noteOff();
|
||||
}
|
||||
} /*else if (MIDINotePlaying && !envelope.playing()) {
|
||||
MIDINotePlaying = false;
|
||||
}*/
|
||||
|
||||
//Update Filter settings
|
||||
//lpf.setResonance(resonance);
|
||||
// if (!MIDINotePlaying) {
|
||||
// noteFreq = mtof((float) kMapNote(CVInVal << 2) / pitchSubSteps);
|
||||
// digitalWrite(LED, !gateInVal);
|
||||
// if (gateInVal && !gateIsHigh) {
|
||||
// gateIsHigh = true;
|
||||
// kEnvelope.start();
|
||||
// } else if (!gateInVal && gateIsHigh) {
|
||||
// gateIsHigh = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
//Update Envelope Settings
|
||||
int attackTime = kMapAttack(knobAVal);
|
||||
int decayReleaseTime = kMapDecay(knobDRVal);
|
||||
//int sustainLevel = kMapSustain(knobSVal);
|
||||
kEnvelope.setDecay(decayReleaseTime);
|
||||
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
|
||||
|
||||
//Calculate makeup Gain
|
||||
//makeupGain = (256L * 127) / (127 + driveAmount); // Q8 fixed-point compensation factor
|
||||
|
||||
//Set Oscilator Frequency
|
||||
float oscFreq = noteFreq;
|
||||
aSquare.setFreq(oscFreq);
|
||||
aSaw.setFreq(oscFreq);
|
||||
Q16n16 oscFreq;
|
||||
oscFreq = glide.next();
|
||||
aSquare.setFreq_Q16n16(oscFreq);
|
||||
aSaw.setFreq_Q16n16(oscFreq);
|
||||
|
||||
//envelope.update();
|
||||
|
||||
//int env = envelope.next();
|
||||
int env = kEnvelope.next();
|
||||
|
||||
if(!droneSwitchVal) {
|
||||
//if(!droneSwitchVal) {
|
||||
gain = env;
|
||||
} else {
|
||||
gain = 255;
|
||||
}
|
||||
//lpf.setCentreFreq(constrain(cutoff + (((long) env * envMod) >> 8), 20, 4096));
|
||||
//} else {
|
||||
// gain = 255;
|
||||
//}
|
||||
lpfr.setCutoffFreqAndResonance(constrain(cutoff + (((long)env * envMod * cutoff)>>16), 0, 255), resonance);
|
||||
|
||||
// static int debugCounter = 0;
|
||||
// if (++debugCounter >= 100) { // adjust to taste - print every ~100 control cycles
|
||||
// Serial.print("min: "); Serial.print(debugMinSignal);
|
||||
// Serial.print(" max: "); Serial.println(debugMaxSignal);
|
||||
// debugMaxSignal = 0;
|
||||
// debugMinSignal = 0;
|
||||
// debugCounter = 0;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
AudioOutput updateAudio(){
|
||||
long signal;
|
||||
if(envSwitchVal) {
|
||||
signal = (aSquare.next() * 3) >> 2;// 0.75 gain to ~ match saw level
|
||||
signal = (aSquare.next() * 3) >> 2; // tricky way to set 0.75 gain to ~ match saw level
|
||||
} else {
|
||||
signal = aSaw.next();
|
||||
}
|
||||
signal = lpfr.next(signal); //filter
|
||||
signal = (signal * gain); //envelope
|
||||
//signal = softClip((signal * (127 + driveAmount)) >> 6); //overdrive
|
||||
//signal = softClip((signal * (127 + driveAmount)) >> 9); //overdrive
|
||||
//signal = (signal * makeupGain) >> 7; //makeup gain compensation
|
||||
|
||||
// if (signal > debugMaxSignal) debugMaxSignal = signal;
|
||||
// if (signal < debugMinSignal) debugMinSignal = signal;
|
||||
|
||||
return MonoOutput::fromNBit(17, signal).clip();
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
//Settings
|
||||
const int pitchSubSteps = 16; //set how many steps are there between semitones. set to 1 to quantize to semitones
|
||||
const int driveAmount = 250;
|
||||
const bool oversamplingEnabled = false; //makes V/OCT tracking more precise, but adds a little portamento
|
||||
#define MOZZI_CONTROL_RATE 256
|
||||
#define GLIDE_TIME 150
|
||||
|
||||
//Hardware Definitions
|
||||
#define Knob1 A6 //Intensity
|
||||
|
||||
Reference in New Issue
Block a user