Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MIDI.h>
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
// GUItool: begin automatically generated code
AudioSynthWaveformModulated Osc1; //xy=129,88
AudioSynthWaveformModulated Osc2; //xy=129,175
AudioEffectChorus chorus1; //xy=128,452
AudioSynthWaveformModulated Osc3; //xy=133,256
AudioEffectEnvelope envelope1; //xy=136,496
AudioSynthWaveformModulated LFO_Osc2Freq; //xy=295,313
AudioSynthWaveformModulated LFO_DelayTime; //xy=300,393
AudioMixer4 Premix; //xy=319,159
AudioSynthWaveformModulated LFO_Volume; //xy=336,435
AudioSynthWaveformModulated LFO_Filter; //xy=340,351
AudioFilterStateVariable LowPassFilter; //xy=479,212
AudioEffectDelay Delay; //xy=589,340
AudioEffectFreeverb Verb; //xy=723,35
AudioOutputI2S i2s1; //xy=771,134
AudioMixer4 MasterR; //xy=776,345
AudioMixer4 MasterL; //xy=777,272
AudioConnection patchCord1(Osc1, 0, Premix, 0);
AudioConnection patchCord2(Osc2, 0, Premix, 1);
AudioConnection patchCord3(Osc3, 0, Premix, 2);
AudioConnection patchCord4(Premix, 0, LowPassFilter, 0);
AudioConnection patchCord5(LowPassFilter, 0, MasterL, 0);
AudioConnection patchCord6(LowPassFilter, 0, MasterR, 0);
AudioConnection patchCord7(LowPassFilter, 0, Verb, 0);
AudioConnection patchCord8(Verb, 0, MasterL, 1);
AudioConnection patchCord9(Verb, 0, MasterR, 1);
AudioConnection patchCord10(MasterR, 0, i2s1, 1);
AudioConnection patchCord11(MasterL, 0, i2s1, 0);
AudioControlSGTL5000 sgtl5000_1; //xy=771,409
// GUItool: end automatically generated code
//variables that hold the values/states of the knobs and switches
int attackVal;
int decayVal;
int sustainVal;
int releaseVal;
int resoVal;
int cutoffVal;
int osc2FreqVal;
int osc2LevelVal;
int osc3FreqVal;
int osc3LevelVal;
int osc1Shape1Val;
int osc1Shape2Val;
int osc2Shape1Val;
int osc2Shape2Val;
int osc3Shape1Val;
int osc3Shape2Val;
int osc3Octave1Val;
int osc3Octave2Val;
int lfoRateVal;
int lfoDepthVal;
int lfoShape1Val;
int lfoShape2Val;
int lfoDest1Val;
int lfoDest2Val;
int lfoDest3Val;
int volumeVal;
int delayLengthVal;
int delayMixVal;
int reverbMixVal;
//Pin assignments
int attackPin = 21;
int decayPin = 20;
int sustainPin = 17;
int releasePin = 16;
int resoPin = 31;
int cutoffPin = 32;
int osc1ShapePin1 = 1;
int osc1ShapePin2 = 2;
int osc2ShapePin1 = 27;
int osc2ShapePin2 = 28;
int osc3ShapePin1 = 8;
int osc3ShapePin2 = 5;
int osc2FreqPin = A14;
int osc2LevelPin = A18;
int osc3FreqPin = A20;
int osc3LevelPin = A17;
int osc3OctavePin1 = 30;
int osc3OctavePin2 = 29;
int lfoRatePin = A15;
int lfoDepthPin = A19;
int lfoShapePin1 = 3;
int lfoShapePin2 = 4;
int lfoDestPin1 = 25;
int lfoDestPin2 = 24;
int lfoDestPin3 = 26;
int volumePin = A1;
int delayLengthPin = A22;
int delayMixPin = A16;
int reverbMixPin = A21;
//oscillator and audio library object values
int osc1current_waveform = 0;
float osc1Pitch = 261.63;
int osc2current_waveform = 0;
float osc2Pitch = 130.86;
int osc3current_waveform = 0;
float osc3Pitch = 65.44;
float osc1Volume = 1.00;
float osc2Volume = 1.00;
float osc3Volume = 1.00;
float osc3Octave = 1.00;
float filterFreq = 6500.0;
float resAmount = 0.700;
float verbMix = 0.00;
float hertz = 1.000;
//midi code variables
unsigned long t=0;
int ledPin = 13;
// array for the notes to be assigned to one of eight voices
int voice[8];
//used to track how many voices are active
//when limit is reached, msg prints Voice Limit Exceeded!
int noteCount=0;
void setup() {
Serial.begin(38400);
pinMode (osc1ShapePin1, INPUT_PULLUP);
pinMode (osc1ShapePin2, INPUT_PULLUP);
pinMode (osc2ShapePin1, INPUT_PULLUP);
pinMode (osc2ShapePin2, INPUT_PULLUP);
pinMode (osc3ShapePin1, INPUT_PULLUP);
pinMode (osc3ShapePin2, INPUT_PULLUP);
pinMode (osc3OctavePin1, INPUT_PULLUP);
pinMode (osc3OctavePin2, INPUT_PULLUP);
pinMode (lfoShapePin1, INPUT_PULLUP);
pinMode (lfoShapePin2, INPUT_PULLUP);
pinMode (lfoDestPin1, INPUT_PULLUP);
pinMode (lfoDestPin2, INPUT_PULLUP);
pinMode (lfoDestPin3, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
AudioMemory(120);
sgtl5000_1.enable();
sgtl5000_1.volume(0.4);
LowPassFilter.frequency(filterFreq);
Verb.roomsize(0.75);
Verb.damping(0.45);
MIDI.setHandleNoteOn(OnNoteOn);
MIDI.setHandleNoteOff(OnNoteOff);
MIDI.begin(MIDI_CHANNEL_OMNI);
}
void loop() {
getReadings();
setWaveForms();
setWaveFreqs();
startWaves();
applyFilter();
reverbMix();
midiDetect();
}
void getReadings(){
attackVal = analogRead(attackPin);
decayVal = analogRead(decayPin);
sustainVal = analogRead(sustainPin);
releaseVal = analogRead(releasePin);
resoVal = analogRead(resoPin);
cutoffVal = analogRead(cutoffPin);
osc1Shape1Val = digitalRead(osc1ShapePin1);
osc1Shape2Val = digitalRead(osc1ShapePin2);
osc2Shape1Val = digitalRead(osc2ShapePin1);
osc2Shape2Val = digitalRead(osc2ShapePin2);
osc3Shape1Val = digitalRead(osc3ShapePin1);
osc3Shape2Val = digitalRead(osc3ShapePin2);
osc3Octave1Val = digitalRead(osc3OctavePin1);
osc3Octave2Val = digitalRead(osc3OctavePin2);
osc2FreqVal = analogRead(osc2FreqPin);
osc2LevelVal = analogRead(osc2LevelPin);
osc3FreqVal = analogRead(osc3FreqPin);
osc3LevelVal = analogRead(osc3LevelPin);
lfoRateVal = analogRead(lfoRatePin);
lfoDepthVal = analogRead(lfoDepthPin);
lfoShape1Val = digitalRead(lfoShapePin1);
lfoShape2Val = digitalRead(lfoShapePin2);
lfoDest1Val = digitalRead(lfoDestPin1);
lfoDest2Val = digitalRead(lfoDestPin2);
lfoDest3Val = digitalRead(lfoDestPin3);
volumeVal = analogRead(volumePin);
delayLengthVal = analogRead(delayLengthPin);
delayMixVal = analogRead(delayMixPin);
reverbMixVal = analogRead(reverbMixPin);
}
void setWaveForms(){
if (osc1Shape1Val == 0){
osc1current_waveform = WAVEFORM_SQUARE;
}
else if (osc1Shape2Val == 0){
osc1current_waveform = WAVEFORM_SAWTOOTH;
}
else {
osc1current_waveform = WAVEFORM_SINE;
}
if (osc2Shape1Val == 0){
osc2current_waveform = WAVEFORM_SQUARE;
}
else if (osc2Shape2Val == 0){
osc2current_waveform = WAVEFORM_SAWTOOTH;
}
else {
osc2current_waveform = WAVEFORM_TRIANGLE;
}
if (osc3Shape1Val == 0){
osc3current_waveform = WAVEFORM_SQUARE;
}
else if (osc3Shape2Val == 0){
osc3current_waveform = WAVEFORM_SAWTOOTH;
}
else {
osc3current_waveform = WAVEFORM_TRIANGLE;
}
}
void setWaveFreqs(){
osc1Pitch = hertz;
osc2Pitch = (osc1Pitch * 3.00);
if (osc3Octave1Val == 0){
osc3Octave = 0.50;
}
else if (osc3Octave2Val == 0){
osc3Octave = 2.00;
}
else {
osc3Octave = 1.00;
}
osc3Pitch = (osc1Pitch / osc3Octave);
}
void startWaves(){
osc2Volume = ((osc2FreqVal / 1023.00) * osc1Volume);
osc3Volume = ((osc3LevelVal / 1023.00) * osc1Volume);
Osc1.begin(osc1Volume, osc1Pitch, osc1current_waveform);
Osc2.begin(osc2Volume, osc2Pitch, osc2current_waveform);
Osc3.begin(osc3Volume, osc3Pitch, osc3current_waveform);
}
void applyFilter(){
filterFreq = expf((float)cutoffVal / 145.00) * 10.00 + 00.00;
LowPassFilter.frequency(filterFreq);
resAmount = (.690 + (resoVal / 235.000));
LowPassFilter.resonance(resAmount);
}
void reverbMix(){
verbMix = (reverbMixVal / 1023.00);
MasterL.gain(0, 1.0);
MasterR.gain(0, 1.0);
MasterL.gain(1, verbMix);
MasterR.gain(1, verbMix);
}
void handleNoteOn(byte channel, byte pitch, byte velocity)
{
}
void handleNoteOff(byte channel, byte pitch, byte velocity)
{
// Do something when the note is released.
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
}
void midiDetect(){
int type, note, velocity, channel, d1, d2;
if (MIDI.read()) { // Is there a MIDI message incoming ?
byte type = MIDI.getType();
switch (type) {
case midi::NoteOn:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
hertz = (pow (2.0, ((float)(note-69)/12.0)))*440;
Serial.println(String("Note On: ch=") + channel + ", note=" + note + ", velocity=" + velocity + ", hertz=" + hertz);
} else {
Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
}
break;
case midi::NoteOff:
note = MIDI.getData1();
velocity = MIDI.getData2();
channel = MIDI.getChannel();
Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
break;
default:
d1 = MIDI.getData1();
d2 = MIDI.getData2();
Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
}
t = millis();
}
if (millis() - t > 10000) {
t += 10000;
Serial.println("(inactivity)");
}
}
void MIDInoteOn(int note, int vel)
{
if(noteCount==8){
Serial.println("Voice Limit Exceeded!");
}
for (int i=0; i<8;i++){
if(!voice[i]){
voice[i]=note;
Serial.print("New Note # ");
Serial.println(note);
Serial.println(vel);
Serial.print("Assigned to Voice # ");
Serial.println(i+1);
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
noteCount++;
if(voice[i]){return;
}
}
}
}
//functin called when a Note Off msg is received. Will scan the voice array to locate
//the note to be shut off. Thus returning the element to zero value. which frees up that
//voice for use of a new note.
void MIDInoteOff(int note, int vel)
{
for(int i=0; i<8; i++){
if(voice[i]==note){
voice[i]=0;
Serial.print("-note off # ");
Serial.println(note);
Serial.print("Shut Off Voice # ");
Serial.println(i+1);
noteCount--;
if(noteCount<0){noteCount=0;
}
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
}
}
}
void OnNoteOn(byte channel, byte note, byte velocity)
{
MIDInoteOn(note, velocity);
}
void OnNoteOff(byte channel, byte note, byte velocity)
{
MIDInoteOff(note, velocity);
digitalWrite(ledPin, LOW);
Serial.print("-note off # ");
Serial.println(note);
}