Please Help with my MonoSynth emulation...

Status
Not open for further replies.

Synthetech

Active member
Ok so you may have seen my Seenthysizer...

https://forum.pjrc.com/threads/42266-Project-quot-Seenthysizer-quot

inside there you will find info about my ongoing quest to make a really cool Virtual Analog Synth using Teensy 3.5+


(again, here is a link to the Ctrlr app I use to interface/control the Seenthysizer

https://drive.google.com/file/d/0B_IDH8cQH_eNSDhXUkxzcEJTZDQ/view?usp=sharing

because of the Teensy USB interface /Windows bug mentioned elsewhere, you MUST HAVE THE Ctrlr App CLOSED when you start up the Seenthysizer.

So keep the Ctrlr app closed, load the code below into the Teensy 3.+, then start the Ctrlr App.
IF YOU MUST RESTART THE TEENSY, YOU MUST SHUT OFF THE APP FIRST! Otherwise strange things happen! Usually the USB inteface wont work.. then you have to shut it all down and begin again.)




I have busted my butt and brain trying to figure out how to make a good simulation of a MonoSynth for the past 2-3 weeks now..
I wanted to come on here and BEG and PLEAD for help, but I knew I had to keep trying to figure it out for myself.. to LEARN.
Well.. I did figure it out for the most part. It works, 80% of the time..

What's it suppose to do?
Well it's suppose to let you hold one note down, then you press another note..
The first note will shut off and the next note starts.. but wait! Don't let go of the first note!!
So you let go of the SECOND NOTE and then the FIRST NOTE retriggers!
You can do very fast "trills" using this "Mono Mode".
What sounds really cool is using three notes.. hold a middle note down and then alternate between a upper note and a lower note.


What does it do wrong?
Seems every now and then WHEN I AM PLAYING REALLY FAST with 3+ notes.. either my Array get's jacked up or the "currNote" gets set to "0" at the wrong time.
I tried to debug it with Serial.print's in the code, but I guess whatever is happening to "glitch" my method is happening in an area I'm not looking.


I have tried and tried to find a good example of code to use with the Teensy to make this "monosynth" happen.
I found methods for other things.. Java, C++ vst's, etc.
But nothing was even close to what I needed for the Seenthysizer!
So after a few weeks of lots of precious time spent on how NOT TO DO IT, the following code is the best I could come up with.
I am hoping someone who is much more experienced with coding methods can figure out what I may have done wrong or can do to improve the note assignments.


Here's the complete MonoSeenthysizer code-

Code:
/*MonoLead_v1-9_beta
   this is a modification of the Seenthysizer 2.8
   it is using 7 voices for one note..
   all voices are tuned to the same frequency and
   then detuned apart from each other to fatten up
   the sound tremendously!
   Mono Mode with last note retrigger for trill effects!
   This is an attempt to emulate the famous Roland JP-8000
   "SUPERSAW" voice that is much sought after in the dance/trance
   music scene.
   --Enjoy-- More to come as I figure out more..
   -Blaine Perkins
*/

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h>


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformDc     lfoenvelope;    //xy=1526.1395568847656,1195.7141723632812
AudioSynthWaveform       lfo;            //xy=1614.1395568847656,1401.7141723632812
AudioMixer4              mixer1;         //xy=1657.1395568847656,1256.7141723632812
AudioAnalyzePeak         peak1;          //xy=1886.1395568847656,1119.7141723632812
AudioSynthWaveform       voice8b;        //xy=2122.1395568847656,2170.7141723632812
AudioSynthNoiseWhite     voice8n;        //xy=2122.1395568847656,2205.7141723632812
AudioSynthWaveform       voice8a;        //xy=2124.1395568847656,2132.7141723632812
AudioSynthWaveform       voice4a;        //xy=2143.1395568847656,1154.7141723632812
AudioSynthWaveform       voice4b;        //xy=2144.1395568847656,1192.7141723632812
AudioSynthNoiseWhite     voice4n;        //xy=2144.1395568847656,1227.7141723632812
AudioSynthWaveform       voice5b;        //xy=2145.1395568847656,1448.7141723632812
AudioSynthNoiseWhite     voice5n;        //xy=2145.1395568847656,1483.7141723632812
AudioSynthWaveform       voice5a;        //xy=2150.1395568847656,1405.7141723632812
AudioSynthWaveform       voice7b;        //xy=2154.1395568847656,1939.7141723632812
AudioSynthNoiseWhite     voice7n;        //xy=2154.1395568847656,1974.7141723632812
AudioSynthWaveform       voice6b;        //xy=2157.1395568847656,1702.7141723632812
AudioSynthNoiseWhite     voice6n;        //xy=2157.1395568847656,1737.7141723632812
AudioSynthWaveform       voice6a;        //xy=2159.1395568847656,1664.7141723632812
AudioSynthWaveform       voice7a;        //xy=2159.1395568847656,1896.7141723632812
AudioSynthWaveform       voice3b;        //xy=2165.1395568847656,944.7141723632812
AudioSynthNoiseWhite     voice3n;        //xy=2165.1395568847656,979.7141723632812
AudioSynthWaveform       voice3a;        //xy=2170.1395568847656,901.7141723632812
AudioSynthWaveform       voice1b;        //xy=2195.1395568847656,478.71417236328125
AudioSynthNoiseWhite     voice1n;        //xy=2198.1395568847656,522.7141723632812
AudioSynthWaveform       voice2b;        //xy=2198.1395568847656,712.7141723632812
AudioSynthNoiseWhite     voice2n;        //xy=2198.1395568847656,747.7141723632812
AudioSynthWaveform       voice1a;        //xy=2200.1395568847656,435.71417236328125
AudioSynthWaveform       voice2a;        //xy=2200.1395568847656,674.7141723632812
AudioSynthWaveformDc     voice8filterenv; //xy=2250.1395568847656,2316.7141723632812
AudioSynthWaveformDc     voice8env;      //xy=2264.1395568847656,2255.7141723632812
AudioMixer4              voice8mix;      //xy=2267.1395568847656,2190.7141723632812
AudioSynthWaveformDc     voice4filterenv; //xy=2272.1395568847656,1338.7141723632812
AudioSynthWaveformDc     voice5filterenv; //xy=2273.1395568847656,1594.7141723632812
AudioSynthWaveformDc     voice7filterenv; //xy=2282.1395568847656,2085.7141723632812
AudioSynthWaveformDc     voice4env;      //xy=2286.1395568847656,1277.7141723632812
AudioSynthWaveformDc     voice6filterenv; //xy=2285.1395568847656,1848.7141723632812
AudioSynthWaveformDc     voice5env;      //xy=2287.1395568847656,1533.7141723632812
AudioMixer4              voice4mix;      //xy=2289.1395568847656,1212.7141723632812
AudioMixer4              voice5mix;      //xy=2290.1395568847656,1468.7141723632812
AudioSynthWaveformDc     voice3filterenv; //xy=2293.1395568847656,1090.7141723632812
AudioSynthWaveformDc     voice7env;      //xy=2296.1395568847656,2024.7141723632812
AudioSynthWaveformDc     voice6env;      //xy=2299.1395568847656,1787.7141723632812
AudioMixer4              voice7mix;      //xy=2299.1395568847656,1959.7141723632812
AudioMixer4              voice6mix;      //xy=2302.1395568847656,1722.7141723632812
AudioSynthWaveformDc     voice3env;      //xy=2307.1395568847656,1029.7141723632812
AudioMixer4              voice3mix;      //xy=2310.1395568847656,964.7141723632812
AudioSynthWaveformDc     voice1filterenv; //xy=2324.1395568847656,614.7141723632812
AudioSynthWaveformDc     voice2filterenv; //xy=2326.1395568847656,858.7141723632812
AudioMixer4              voice1mix;      //xy=2340.1395568847656,498.71417236328125
AudioSynthWaveformDc     voice2env;      //xy=2340.1395568847656,797.7141723632812
AudioSynthWaveformDc     voice1env;      //xy=2341.1395568847656,563.7141723632812
AudioMixer4              voice2mix;      //xy=2343.1395568847656,732.7141723632812
AudioEffectMultiply      voice8multiply; //xy=2431.1395568847656,2228.7141723632812
AudioMixer4              voice8filtermodmixer; //xy=2441.1395568847656,2344.7141723632812
AudioEffectMultiply      voice4multiply; //xy=2453.1395568847656,1250.7141723632812
AudioEffectMultiply      voice5multiply; //xy=2454.1395568847656,1506.7141723632812
AudioMixer4              voice4filtermodmixer; //xy=2463.1395568847656,1366.7141723632812
AudioEffectMultiply      voice7multiply; //xy=2463.1395568847656,1997.7141723632812
AudioEffectMultiply      voice6multiply; //xy=2466.1395568847656,1760.7141723632812
AudioMixer4              voice5filtermodmixer; //xy=2471.1395568847656,1616.7141723632812
AudioEffectMultiply      voice3multiply; //xy=2474.1395568847656,1002.7141723632812
AudioMixer4              voice6filtermodmixer; //xy=2476.1395568847656,1876.7141723632812
AudioMixer4              voice7filtermodmixer; //xy=2480.1395568847656,2107.7141723632812
AudioMixer4              voice3filtermodmixer; //xy=2491.1395568847656,1112.7141723632812
AudioEffectMultiply      voice1multiply; //xy=2504.1395568847656,536.7141723632812
AudioEffectMultiply      voice2multiply; //xy=2507.1395568847656,770.7141723632812
AudioMixer4              voice2filtermodmixer; //xy=2517.1395568847656,886.7141723632812
AudioMixer4              voice1filtermodmixer; //xy=2521.1395568847656,646.7141723632812
AudioFilterStateVariable voice8filter;   //xy=2614.1395568847656,2251.7141723632812
AudioFilterStateVariable voice5filter;   //xy=2634.1395568847656,1550.7141723632812
AudioFilterStateVariable voice4filter;   //xy=2636.1395568847656,1273.7141723632812
AudioFilterStateVariable voice7filter;   //xy=2643.1395568847656,2041.7141723632812
AudioFilterStateVariable voice6filter;   //xy=2649.1395568847656,1783.7141723632812
AudioFilterStateVariable voice3filter;   //xy=2654.1395568847656,1046.7141723632812
AudioFilterStateVariable voice2filter;   //xy=2690.1395568847656,793.7141723632812
AudioFilterStateVariable voice1filter;   //xy=2707.1395568847656,588.7141723632812
AudioMixer4              last4premix;    //xy=3114.1395568847656,1523.7141723632812
AudioMixer4              first4premix;   //xy=3115.1395568847656,1439.7141723632812
AudioMixer4              mainOutMixer;   //xy=3519.4252014160156,1509.5711517333984
AudioFilterStateVariable delayFilter;    //xy=3564.1395568847656,1633.7141723632812
AudioEffectDelay         delay1;         //xy=3693.1395568847656,1828.7141723632812
AudioOutputUSB           usb1;           //xy=3860.2857666015625,1450.28564453125
AudioOutputI2S           i2s1;           //xy=3861.1395568847656,1514.7141723632812
AudioConnection          patchCord1(lfoenvelope, 0, mixer1, 0);
AudioConnection          patchCord2(lfo, 0, voice1filtermodmixer, 1);
AudioConnection          patchCord3(lfo, 0, voice2filtermodmixer, 1);
AudioConnection          patchCord4(lfo, 0, voice3filtermodmixer, 1);
AudioConnection          patchCord5(lfo, 0, voice4filtermodmixer, 1);
AudioConnection          patchCord6(lfo, 0, voice5filtermodmixer, 1);
AudioConnection          patchCord7(lfo, 0, voice6filtermodmixer, 1);
AudioConnection          patchCord8(lfo, 0, voice7filtermodmixer, 1);
AudioConnection          patchCord9(lfo, 0, voice8filtermodmixer, 1);
AudioConnection          patchCord10(lfo, 0, mixer1, 1);
AudioConnection          patchCord11(mixer1, peak1);
AudioConnection          patchCord12(voice8b, 0, voice8mix, 1);
AudioConnection          patchCord13(voice8n, 0, voice8mix, 2);
AudioConnection          patchCord14(voice8a, 0, voice8mix, 0);
AudioConnection          patchCord15(voice4a, 0, voice4mix, 0);
AudioConnection          patchCord16(voice4b, 0, voice4mix, 1);
AudioConnection          patchCord17(voice4n, 0, voice4mix, 2);
AudioConnection          patchCord18(voice5b, 0, voice5mix, 1);
AudioConnection          patchCord19(voice5n, 0, voice5mix, 2);
AudioConnection          patchCord20(voice5a, 0, voice5mix, 0);
AudioConnection          patchCord21(voice7b, 0, voice7mix, 1);
AudioConnection          patchCord22(voice7n, 0, voice7mix, 2);
AudioConnection          patchCord23(voice6b, 0, voice6mix, 1);
AudioConnection          patchCord24(voice6n, 0, voice6mix, 2);
AudioConnection          patchCord25(voice6a, 0, voice6mix, 0);
AudioConnection          patchCord26(voice7a, 0, voice7mix, 0);
AudioConnection          patchCord27(voice3b, 0, voice3mix, 1);
AudioConnection          patchCord28(voice3n, 0, voice3mix, 2);
AudioConnection          patchCord29(voice3a, 0, voice3mix, 0);
AudioConnection          patchCord30(voice1b, 0, voice1mix, 1);
AudioConnection          patchCord31(voice1n, 0, voice1mix, 2);
AudioConnection          patchCord32(voice2b, 0, voice2mix, 1);
AudioConnection          patchCord33(voice2n, 0, voice2mix, 3);
AudioConnection          patchCord34(voice1a, 0, voice1mix, 0);
AudioConnection          patchCord35(voice2a, 0, voice2mix, 0);
AudioConnection          patchCord36(voice8filterenv, 0, voice8filtermodmixer, 0);
AudioConnection          patchCord37(voice8env, 0, voice8multiply, 1);
AudioConnection          patchCord38(voice8mix, 0, voice8multiply, 0);
AudioConnection          patchCord39(voice4filterenv, 0, voice4filtermodmixer, 0);
AudioConnection          patchCord40(voice5filterenv, 0, voice5filtermodmixer, 0);
AudioConnection          patchCord41(voice7filterenv, 0, voice7filtermodmixer, 0);
AudioConnection          patchCord42(voice4env, 0, voice4multiply, 1);
AudioConnection          patchCord43(voice6filterenv, 0, voice6filtermodmixer, 0);
AudioConnection          patchCord44(voice5env, 0, voice5multiply, 1);
AudioConnection          patchCord45(voice4mix, 0, voice4multiply, 0);
AudioConnection          patchCord46(voice5mix, 0, voice5multiply, 0);
AudioConnection          patchCord47(voice3filterenv, 0, voice3filtermodmixer, 0);
AudioConnection          patchCord48(voice7env, 0, voice7multiply, 1);
AudioConnection          patchCord49(voice6env, 0, voice6multiply, 1);
AudioConnection          patchCord50(voice7mix, 0, voice7multiply, 0);
AudioConnection          patchCord51(voice6mix, 0, voice6multiply, 0);
AudioConnection          patchCord52(voice3env, 0, voice3multiply, 1);
AudioConnection          patchCord53(voice3mix, 0, voice3multiply, 0);
AudioConnection          patchCord54(voice1filterenv, 0, voice1filtermodmixer, 0);
AudioConnection          patchCord55(voice2filterenv, 0, voice2filtermodmixer, 0);
AudioConnection          patchCord56(voice1mix, 0, voice1multiply, 0);
AudioConnection          patchCord57(voice2env, 0, voice2multiply, 1);
AudioConnection          patchCord58(voice1env, 0, voice1multiply, 1);
AudioConnection          patchCord59(voice2mix, 0, voice2multiply, 0);
AudioConnection          patchCord60(voice8multiply, 0, voice8filter, 0);
AudioConnection          patchCord61(voice8filtermodmixer, 0, voice8filter, 1);
AudioConnection          patchCord62(voice4multiply, 0, voice4filter, 0);
AudioConnection          patchCord63(voice5multiply, 0, voice5filter, 0);
AudioConnection          patchCord64(voice4filtermodmixer, 0, voice4filter, 1);
AudioConnection          patchCord65(voice7multiply, 0, voice7filter, 0);
AudioConnection          patchCord66(voice6multiply, 0, voice6filter, 0);
AudioConnection          patchCord67(voice5filtermodmixer, 0, voice5filter, 1);
AudioConnection          patchCord68(voice3multiply, 0, voice3filter, 0);
AudioConnection          patchCord69(voice6filtermodmixer, 0, voice6filter, 1);
AudioConnection          patchCord70(voice7filtermodmixer, 0, voice7filter, 1);
AudioConnection          patchCord71(voice3filtermodmixer, 0, voice3filter, 1);
AudioConnection          patchCord72(voice1multiply, 0, voice1filter, 0);
AudioConnection          patchCord73(voice2multiply, 0, voice2filter, 0);
AudioConnection          patchCord74(voice2filtermodmixer, 0, voice2filter, 1);
AudioConnection          patchCord75(voice1filtermodmixer, 0, voice1filter, 1);
AudioConnection          patchCord76(voice8filter, 0, last4premix, 3);
AudioConnection          patchCord77(voice5filter, 0, last4premix, 0);
AudioConnection          patchCord78(voice4filter, 0, first4premix, 3);
AudioConnection          patchCord79(voice7filter, 0, last4premix, 2);
AudioConnection          patchCord80(voice6filter, 0, last4premix, 1);
AudioConnection          patchCord81(voice3filter, 0, first4premix, 2);
AudioConnection          patchCord82(voice2filter, 0, first4premix, 1);
AudioConnection          patchCord83(voice1filter, 0, first4premix, 0);
AudioConnection          patchCord84(last4premix, 0, mainOutMixer, 1);
AudioConnection          patchCord85(first4premix, 0, mainOutMixer, 0);
AudioConnection          patchCord86(mainOutMixer, 0, i2s1, 0);
AudioConnection          patchCord87(mainOutMixer, 0, i2s1, 1);
AudioConnection          patchCord88(mainOutMixer, delay1);
AudioConnection          patchCord89(mainOutMixer, 0, usb1, 1);
AudioConnection          patchCord90(mainOutMixer, 0, usb1, 0);
AudioConnection          patchCord91(delayFilter, 0, mainOutMixer, 3);
AudioConnection          patchCord92(delay1, 0, delayFilter, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=3598.1395568847656,1283.7141723632812
// GUItool: end automatically generated code






Bounce button0 = Bounce(0, 15);



//a table to store CC values coming in from the usbMIDI interface
//later any value can be recalled for each parameter
float CCvalues[128];
float prevCCvalues[128];

// array for the notes to be assigned to one of eight voices
int voice[4];
int noteFreq[1];

//vars for the state machine cases
const int noteOnWait = 0;
const int ATTACK = 1;
const int ATTACKwait = 2;
const int DECAY = 3;
const int SUSTAIN = 4;
const int RELEASE1 = 5;

//beginning cases for each voice state machines
int state0a = noteOnWait;
int state0b = noteOnWait;
int state0c = noteOnWait;
int state0d = noteOnWait;
int state0e = noteOnWait;
int state0f = noteOnWait;
int state0g = noteOnWait;
int state0h = noteOnWait;
int state0i = noteOnWait;
int state0j = noteOnWait;
int state0k = noteOnWait;
int state0l = noteOnWait;
int state0m = noteOnWait;
int state0n = noteOnWait;
int state0o = noteOnWait;
int state0p = noteOnWait;


//ADSR timing elements
unsigned long int attackMillisA[8];
unsigned long int attackMillisF[8];



//used to track how many voices are active
int noteCount = 0;
//used to track the current note
int currNote = 0;



//some of this from previous code may not be in use
float tempPulseWidth;
float tempPeak;
float tempRMS;


//synth
float mainVolume;

//not used at this time
//int tempLineOutLevel;

float vcoOneLevel;
float vcoTwoLevel;

float deTune;
float deTune1;
float deTune2;
float deTune3;
float deTune5;
float deTune6;
float deTune7;
int waveShapeOneIndex;
int waveShapeTwoIndex;
int lfoWaveShapeIndex;
short waveShapes[4] = {
  WAVEFORM_SINE,
  WAVEFORM_SAWTOOTH,
  WAVEFORM_SQUARE,
  WAVEFORM_PULSE,
};
bool voiceBPulse;
float tempDetuneMod;
float deTuneLfo;
//LFO WaveShapes
short lfoWaveShapes[5] = {
  WAVEFORM_SINE,
  WAVEFORM_SAWTOOTH,
  WAVEFORM_SAWTOOTH_REVERSE,
  WAVEFORM_SQUARE,
  WAVEFORM_SAMPLE_HOLD,
};


//ADSR
int attackTime;
int decayTime;
float sustainLevel;
int releaseTime;
//Filter ADSR
int attackTimeFilter;
int decayTimeFilter;
float sustainLevelFilter;
int releaseTimeFilter;

//LFO ADSR -- not used at this time
// int attackTimeLFO;
// int decayTimeLFO;
// float sustainLevelLFO;
// int releaseTimeLFO;


//function to allocate a new MIDI Note On to the Note Stack array
//will kill current playing note and begin new note On if a prev. note is on
 /*void killNotes()
  {
    currNote = 0;
   
    state0a = noteOnWait;
    voice1env.amplitude(0, 0);
    state0b = noteOnWait;
    voice1filterenv.amplitude(0, 0);
    state0c = noteOnWait;
    voice2env.amplitude(0, 0);
    state0d = noteOnWait;
    voice2filterenv.amplitude(0, 0);
    state0e = noteOnWait;
    voice3env.amplitude(0, 0);
    state0f = noteOnWait;
    voice3filterenv.amplitude(0, 0);
    state0g = noteOnWait;
    voice4env.amplitude(0, 0);
    state0h = noteOnWait;
    voice4filterenv.amplitude(0, 0);
    state0i = noteOnWait;
    voice5env.amplitude(0, 0);
    state0j = noteOnWait;
    voice5filterenv.amplitude(0, 0);
    state0k = noteOnWait;
    voice6env.amplitude(0, 0);
    state0l = noteOnWait;
    voice6filterenv.amplitude(0, 0);
    state0m = noteOnWait;
    voice7env.amplitude(0, 0);
    state0n = noteOnWait;
    voice7filterenv.amplitude(0, 0);
    state0o = noteOnWait;
    voice8env.amplitude(0, 0);
    state0p = noteOnWait;
    voice8filterenv.amplitude(0, 0);
  
  }
  */


//MIDI routines
//triggered when usb port has data
void OnControlChange (byte Channel, byte control, byte value)
{
  MIDIccData(control, value);
}


void OnNoteOn(byte channel, byte note, byte velocity)
{
  MIDInoteOn(note, velocity);
}

void OnNoteOff(byte channel, byte note, byte velocity)
{
  MIDInoteOff(note, velocity);
}





void MIDInoteOn(int note, int vel)
{

  if (noteCount == 5) {
    Serial.println("Voice Limit Exceeded!");
    return;
  }
  if (!noteCount) {
    voice [0] = note;
    currNote = voice[0];
    noteCount++;
    Serial.print("1st Note #  ");
    Serial.println(currNote);
    Serial.println("notecount=  ");
    Serial.println(noteCount);
    
    return;
  }
  //Serial.println(i+1);



  currNote=0;
  for (int i = 0; i < 4; i++) {
    if (!voice[i]) {
      voice[i] = note;
      currNote = voice[i];
      noteCount++;
      Serial.print("Replacement Note #  ");
      Serial.println(currNote);
      Serial.print("Assigned to Voice #  ");
      Serial.println(i + 1);
      Serial.println();
      Serial.println("notecount=  ");
    Serial.println(noteCount);
      break;
    }
  }
}



void MIDIccData(int CCnumber, float CCvalue)
{
  //Serial.print("CC#= ");
  //Serial.print(CCnumber);
  //Serial.print("  Value= ");
  //Serial.println(CCvalue);
  //assign values to the CC lookup table
  CCvalues[CCnumber] = {CCvalue};


}


//shuts notes off, removes them from note Stack and shifts the remainder notes
//towards bottom to keep all active notes down together in array

void MIDInoteOff(int note, int vel)
{


  if (note == currNote && noteCount>1) {
    currNote=0;
    Serial.print("Trying to find note # ");
        Serial.println(note);
    for (int i = 0; i < 4; i++) {
      Serial.print("searching voice-  ");
        Serial.println(i);
      if (note == voice[i]) {
        Serial.print("I FOUND IT! ");
        voice[i] = 0;
        currNote = voice[i - 1];
        noteCount--;
        Serial.print("Current note off # ");
        Serial.println(note);
        Serial.println("Shut Off Current Voice # ");
        Serial.println(i + 1);
        Serial.print("Current note ON # ");
        Serial.println(currNote);
        Serial.println();
        Serial.println("notecount=  ");
    Serial.println(noteCount);
        break;
      }

    }
          return;
  }


  if (noteCount < 2) {
    voice[0] = 0;
    currNote = 0;
    noteCount--;
    if (noteCount < 0) {
      noteCount = 0;
    }
    Serial.print("Last note off # ");
    Serial.println(note);
    Serial.println("Shut Off Voice # 1 ");
    Serial.println();
    Serial.println("notecount=  ");
    Serial.println(noteCount);
    return;
    //Serial.println(i+1);

  }




  if (noteCount > 1) {
    for (int i = 0; i < 4; i++) {
      if (voice[i] == note) {
        voice[i] = 0;
        Serial.print("Drop off note # ");
        Serial.println(note);
        Serial.print("Drop Off Voice # ");
        Serial.println(i + 1);
        for (int c = i + 1; c < 4; c++) {
          voice[i] = voice[c];
          i = i++;
        }
        voice[3] = 0;
        noteCount--;
        Serial.print("-note off # ");
        Serial.println(note);
        Serial.println();
        Serial.println("notecount=  ");
    Serial.println(noteCount);
        break;
      }
    }





  }
}



  //called to immediatly shut voices down when a new note is pressed down
  //allows the new note to retrigger EG

  




  //an exponential formula mapping function
  float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  }

  void setup() {
    AudioMemory(320);
    Serial.begin(9600);
    sgtl5000_1.enable();
    sgtl5000_1.volume(.7);

    usbMIDI.setHandleNoteOff(OnNoteOff);
    usbMIDI.setHandleNoteOn(OnNoteOn) ;
    usbMIDI.setHandleControlChange(OnControlChange);
    pinMode(0, INPUT_PULLUP);



    //mix
    first4premix.gain(0, .25);
    first4premix.gain(1, .25);
    first4premix.gain(2, .25);
    first4premix.gain(3, .25);
    last4premix.gain(0, .25);
    last4premix.gain(1, .25);
    last4premix.gain(2, .25);
    last4premix.gain(3, .25);

    //initiate values to CCvalues array for the default patch
    CCvalues[7] = 119;
    //CCvalues[32] = 15;
    //CCvalues[33] = 8;
    CCvalues[34] = 127;
    CCvalues[35] = 5;
    CCvalues[36] = 127;
    CCvalues[40] = 32;
    CCvalues[41] = 32;
    //CCvalues[42] = 81;
    //CCvalues[43] = 64;
    CCvalues[44] = 83;
    CCvalues[45] = 4;
    //CCvalues[46] = 52;
    //CCvalues[47] = 3;
    CCvalues[49] = 127;
    CCvalues[50] = 90;
    CCvalues[71] = 43;
    CCvalues[74] = 127;
    CCvalues[94] = 17;
    CCvalues[88] = 10;
    CCvalues[89] = 10;


    // initialize the oscillators
    //Voice 1
    //voice1a.begin(.3, 440, WAVEFORM_SQUARE);
    voice1b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 2
    //voice2a.begin(.3, 440, WAVEFORM_SQUARE);
    voice2b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 3
    //voice3a.begin(.3, 440, WAVEFORM_SQUARE);
    voice3b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 4
    //voice4a.begin(.3, 440, WAVEFORM_SQUARE);
    voice4b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 5
    //voice5a.begin(.3, 440, WAVEFORM_SQUARE);
    voice5b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 6
    //voice6a.begin(.3, 440, WAVEFORM_SQUARE);
    voice6b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 7
    //voice7a.begin(.3, 440, WAVEFORM_SQUARE);
    voice7b.begin(.3, 440, WAVEFORM_SAWTOOTH);
    //Voice 8
    //voice8a.begin(.3, 440, WAVEFORM_SQUARE);
    //voice8b.begin(.3, 440, WAVEFORM_SAWTOOTH);

    delayFilter.frequency(3000);
    delayFilter.resonance(1);
    delay1.delay(0, 0);
    mainOutMixer.gain(3, 0);

    //LFO
    lfo.begin(1, 3, WAVEFORM_SINE);
    lfo.frequency(0);
    voice1filtermodmixer.gain(1, 0);
    voice2filtermodmixer.gain(1, 0);
    voice3filtermodmixer.gain(1, 0);
    voice4filtermodmixer.gain(1, 0);
    voice5filtermodmixer.gain(1, 0);
    voice6filtermodmixer.gain(1, 0);
    voice7filtermodmixer.gain(1, 0);
    voice8filtermodmixer.gain(1, 0);


    deTune = 1;
    mainOutMixer.gain(0, .5);
    mainOutMixer.gain(1, .5);
    //lfoenvelope.amplitude(1);
    voiceBPulse = false;







  }



  void loop() {


    usbMIDI.read();

    button0.update();



    //prints the values set in the CC lookup table
    if (button0.fallingEdge()) {
      for (int i = 0; i < 128; i++) {
        if (CCvalues[i]) {
          Serial.print("CC:");
          Serial.print(i);
          Serial.print(" is Value:");
          Serial.print(CCvalues[i]);
          Serial.println();
        }
      }
    }


    //Volume
    mainVolume = CCvalues[7];
    mainVolume = mainVolume / 127;
    sgtl5000_1.volume(mainVolume);

    //not used at this time
    //tempLineOutLevel = CCvalues[7];
    //tempLineOutLevel = map(tempLineOutLevel, 0, 127, 31, 13);
    //sgtl5000_1.lineOutLevel(tempLineOutLevel);



    //start of voice service for loop
    //notes set to frequencies
    for (int i = 0; i < 8; i++) {
      if (i == 0) {
        //voice1a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice1b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune1);
      }
      if (i == 0) {
        //voice2a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice2b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune2);
      }
      if (i == 0) {
        //voice3a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice3b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune3);
      }
      if (i == 0) {
        //voice4a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice4b.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
      }
      if (i == 0) {
        //voice5a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice5b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune5);
      }
      if (i == 0) {
        //voice6a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice6b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune6);
      }
      if (i == 0) {
        //voice7a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        voice7b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune7);
      }
      if (i == 7) {
        //voice8a.frequency(440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333));
        //voice8b.frequency((440.0 * powf(2.0, (float)(currNote - 69) * 0.08333333))* deTune);
      }
      //sevice envelopes for voices
      if (i == 0) {
        switch (state0a) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0a = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice1env.amplitude(1, attackTime);
            state0a = ATTACKwait;
            if (!currNote) {
              state0a = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0a = DECAY;
            }
            if (!currNote) {
              state0a = RELEASE1;
            }

            break;


          case DECAY:
            voice1env.amplitude(sustainLevel, decayTime);
            state0a = SUSTAIN;
            if (!currNote) {
              state0a = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0a = RELEASE1;
            }

            break;


          case RELEASE1:
            voice1env.amplitude(0, releaseTime);
            state0a = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0b) {

          case noteOnWait:
            if (currNote) {
              state0b = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice1filterenv.amplitude(1, attackTimeFilter);
            state0b = ATTACKwait;
            if (!currNote) {
              state0b = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0b = DECAY;
            }
            if (!currNote) {
              state0b = RELEASE1;
            }

            break;


          case DECAY:
            voice1filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0b = SUSTAIN;
            if (!currNote) {
              state0b = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0b = RELEASE1;
            }

            break;


          case RELEASE1:
            voice1filterenv.amplitude(0, releaseTimeFilter);
            state0b = noteOnWait;
            break;
        }
      }




      if (i == 1) {
        switch (state0c) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0c = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice2env.amplitude(1, attackTime);
            state0c = ATTACKwait;
            if (!currNote) {
              state0c = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0c = DECAY;
            }
            if (!currNote) {
              state0c = RELEASE1;
            }

            break;


          case DECAY:
            voice2env.amplitude(sustainLevel, decayTime);
            state0c = SUSTAIN;
            if (!currNote) {
              state0c = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0c = RELEASE1;
            }

            break;


          case RELEASE1:
            voice2env.amplitude(0, releaseTime);
            state0c = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0d) {

          case noteOnWait:
            if (currNote) {
              state0d = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice2filterenv.amplitude(1, attackTimeFilter);
            state0d = ATTACKwait;
            if (!currNote) {
              state0d = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0d = DECAY;
            }
            if (!currNote) {
              state0d = RELEASE1;
            }

            break;


          case DECAY:
            voice2filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0d = SUSTAIN;
            if (!currNote) {
              state0d = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0d = RELEASE1;
            }

            break;


          case RELEASE1:
            voice2filterenv.amplitude(0, releaseTimeFilter);
            state0d = noteOnWait;
            break;
        }
      }

      if (i == 2) {
        switch (state0e) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0e = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice3env.amplitude(1, attackTime);
            state0e = ATTACKwait;
            if (!currNote) {
              state0e = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0e = DECAY;
            }
            if (!currNote) {
              state0e = RELEASE1;
            }

            break;


          case DECAY:
            voice3env.amplitude(sustainLevel, decayTime);
            state0e = SUSTAIN;
            if (!currNote) {
              state0e = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0e = RELEASE1;
            }

            break;


          case RELEASE1:
            voice3env.amplitude(0, releaseTime);
            state0e = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0f) {

          case noteOnWait:
            if (currNote) {
              state0f = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice3filterenv.amplitude(1, attackTimeFilter);
            state0f = ATTACKwait;
            if (!currNote) {
              state0f = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0f = DECAY;
            }
            if (!currNote) {
              state0f = RELEASE1;
            }

            break;


          case DECAY:
            voice3filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0f = SUSTAIN;
            if (!currNote) {
              state0f = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0f = RELEASE1;
            }

            break;


          case RELEASE1:
            voice3filterenv.amplitude(0, releaseTimeFilter);
            state0f = noteOnWait;
            break;
        }
      }



      if (i == 3) {
        switch (state0g) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0g = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice4env.amplitude(1, attackTime);
            state0g = ATTACKwait;
            if (!currNote) {
              state0g = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0g = DECAY;
            }
            if (!currNote) {
              state0g = RELEASE1;
            }

            break;


          case DECAY:
            voice4env.amplitude(sustainLevel, decayTime);
            state0g = SUSTAIN;
            if (!currNote) {
              state0g = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0g = RELEASE1;
            }

            break;


          case RELEASE1:
            voice4env.amplitude(0, releaseTime);
            state0g = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0h) {

          case noteOnWait:
            if (currNote) {
              state0h = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice4filterenv.amplitude(1, attackTimeFilter);
            state0h = ATTACKwait;
            if (!currNote) {
              state0h = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0h = DECAY;
            }
            if (!currNote) {
              state0h = RELEASE1;
            }

            break;


          case DECAY:
            voice4filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0h = SUSTAIN;
            if (!currNote) {
              state0h = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0h = RELEASE1;
            }

            break;


          case RELEASE1:
            voice4filterenv.amplitude(0, releaseTimeFilter);
            state0h = noteOnWait;
            break;
        }
      }



      if (i == 4) {
        switch (state0i) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0i = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice5env.amplitude(1, attackTime);
            state0i = ATTACKwait;
            if (!currNote) {
              state0i = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0i = DECAY;
            }
            if (!currNote) {
              state0i = RELEASE1;
            }

            break;


          case DECAY:
            voice5env.amplitude(sustainLevel, decayTime);
            state0i = SUSTAIN;
            if (!currNote) {
              state0i = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0i = RELEASE1;
            }

            break;


          case RELEASE1:
            voice5env.amplitude(0, releaseTime);
            state0i = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0j) {

          case noteOnWait:
            if (currNote) {
              state0j = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice5filterenv.amplitude(1, attackTimeFilter);
            state0j = ATTACKwait;
            if (!currNote) {
              state0j = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0j = DECAY;
            }
            if (!currNote) {
              state0j = RELEASE1;
            }

            break;


          case DECAY:
            voice5filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0j = SUSTAIN;
            if (!currNote) {
              state0j = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0j = RELEASE1;
            }

            break;


          case RELEASE1:
            voice5filterenv.amplitude(0, releaseTimeFilter);
            state0j = noteOnWait;
            break;
        }
      }



      if (i == 5) {
        switch (state0k) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0k = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice6env.amplitude(1, attackTime);
            state0k = ATTACKwait;
            if (!currNote) {
              state0k = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0k = DECAY;
            }
            if (!currNote) {
              state0k = RELEASE1;
            }

            break;


          case DECAY:
            voice6env.amplitude(sustainLevel, decayTime);
            state0k = SUSTAIN;
            if (!currNote) {
              state0k = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0k = RELEASE1;
            }

            break;


          case RELEASE1:
            voice6env.amplitude(0, releaseTime);
            state0k = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0l) {

          case noteOnWait:
            if (currNote) {
              state0l = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice6filterenv.amplitude(1, attackTimeFilter);
            state0l = ATTACKwait;
            if (!currNote) {
              state0l = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0l = DECAY;
            }
            if (!currNote) {
              state0l = RELEASE1;
            }

            break;


          case DECAY:
            voice6filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0l = SUSTAIN;
            if (!currNote) {
              state0l = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0l = RELEASE1;
            }

            break;


          case RELEASE1:
            voice6filterenv.amplitude(0, releaseTimeFilter);
            state0l = noteOnWait;
            break;
        }
      }


      if (i == 6) {
        switch (state0m) {

          //service the Amp ADSR
          case noteOnWait:
            if (currNote) {
              state0m = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisA[i] = millis();
            voice7env.amplitude(1, attackTime);
            state0m = ATTACKwait;
            if (!currNote) {
              state0m = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisA[i] > attackTime) {
              state0m = DECAY;
            }
            if (!currNote) {
              state0m = RELEASE1;
            }

            break;


          case DECAY:
            voice7env.amplitude(sustainLevel, decayTime);
            state0m = SUSTAIN;
            if (!currNote) {
              state0m = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0m = RELEASE1;
            }

            break;


          case RELEASE1:
            voice7env.amplitude(0, releaseTime);
            state0m = noteOnWait;
            break;
        }


        // service the Filter ADSR
        switch (state0n) {

          case noteOnWait:
            if (currNote) {
              state0n = ATTACK;
            }
            break;

          case ATTACK:
            attackMillisF[i] = millis();
            voice7filterenv.amplitude(1, attackTimeFilter);
            state0n = ATTACKwait;
            if (!currNote) {
              state0n = RELEASE1;
            }
            break;

          case ATTACKwait:
            if (millis() - attackMillisF[i] > attackTimeFilter) {
              state0n = DECAY;
            }
            if (!currNote) {
              state0n = RELEASE1;
            }

            break;


          case DECAY:
            voice7filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
            state0n = SUSTAIN;
            if (!currNote) {
              state0n = RELEASE1;
            }

            break;

          case SUSTAIN:
            if (!currNote) {
              state0n = RELEASE1;
            }

            break;


          case RELEASE1:
            voice7filterenv.amplitude(0, releaseTimeFilter);
            state0n = noteOnWait;
            break;
        }
      }



      /* if (i == 7) {
         switch (state0o) {

           //service the Amp ADSR
           case noteOnWait:
             if (voice[i]) {
               state0o = ATTACK;
             }
             break;

           case ATTACK:
             attackMillisA[i] = millis();
             voice8env.amplitude(1, attackTime);
             state0o = ATTACKwait;
             if (!voice[i]) {
               state0o = RELEASE1;
             }
             break;

           case ATTACKwait:
             if (millis() - attackMillisA[i] > attackTime) {
               state0o = DECAY;
             }
             if (!voice[i]) {
               state0o = RELEASE1;
             }

             break;


           case DECAY:
             voice8env.amplitude(sustainLevel, decayTime);
             state0o = SUSTAIN;
             if (!voice[i]) {
               state0o = RELEASE1;
             }

             break;

           case SUSTAIN:
             if (!voice[i]) {
               state0o = RELEASE1;
             }

             break;


           case RELEASE1:
             voice8env.amplitude(0, releaseTime);
             state0o = noteOnWait;
             break;
         }


         // service the Filter ADSR
         switch (state0p) {

           case noteOnWait:
             if (voice[i]) {
               state0p = ATTACK;
             }
             break;

           case ATTACK:
             attackMillisF[i] = millis();
             voice8filterenv.amplitude(1, attackTimeFilter);
             state0p = ATTACKwait;
             if (!voice[i]) {
               state0p = RELEASE1;
             }
             break;

           case ATTACKwait:
             if (millis() - attackMillisF[i] > attackTimeFilter) {
               state0p = DECAY;
             }
             if (!voice[i]) {
               state0p = RELEASE1;
             }

             break;


           case DECAY:
             voice8filterenv.amplitude(sustainLevelFilter, decayTimeFilter);
             state0p = SUSTAIN;
             if (!voice[i]) {
               state0p = RELEASE1;
             }

             break;

           case SUSTAIN:
             if (!voice[i]) {
               state0p = RELEASE1;
             }

             break;


           case RELEASE1:
             voice8filterenv.amplitude(0, releaseTimeFilter);
             state0p = noteOnWait;
             break;
         }

        }
      */
    }
    //end of voice service for loop












    //assign CC Values to Parameters

    if (CCvalues[40] != prevCCvalues[40]) {
      waveShapeOneIndex = CCvalues[40] / 31;
      if (waveShapeOneIndex < 4) {
        voice1a.begin(waveShapes[waveShapeOneIndex]);
        voice2a.begin(waveShapes[waveShapeOneIndex]);
        voice3a.begin(waveShapes[waveShapeOneIndex]);
        voice4a.begin(waveShapes[waveShapeOneIndex]);
        voice5a.begin(waveShapes[waveShapeOneIndex]);
        voice6a.begin(waveShapes[waveShapeOneIndex]);
        voice7a.begin(waveShapes[waveShapeOneIndex]);
        voice8a.begin(waveShapes[waveShapeOneIndex]);
        prevCCvalues[40] = CCvalues[40];
      }
    }


    //vcoMixBalance
    if (CCvalues[36] != prevCCvalues[36]) {
      vcoOneLevel = (CCvalues[36]) / 127;
      vcoTwoLevel = 1 - (CCvalues[36]) / 127;
      voice1mix.gain(1, vcoOneLevel);
      voice1mix.gain(0, vcoTwoLevel);
      voice2mix.gain(1, vcoOneLevel);
      voice2mix.gain(0, vcoTwoLevel);
      voice3mix.gain(1, vcoOneLevel);
      voice3mix.gain(0, vcoTwoLevel);
      voice4mix.gain(1, vcoOneLevel);
      voice4mix.gain(0, vcoTwoLevel);
      voice5mix.gain(1, vcoOneLevel);
      voice5mix.gain(0, vcoTwoLevel);
      voice6mix.gain(1, vcoOneLevel);
      voice6mix.gain(0, vcoTwoLevel);
      voice7mix.gain(1, vcoOneLevel);
      voice7mix.gain(0, vcoTwoLevel);
      voice8mix.gain(1, vcoOneLevel);
      voice8mix.gain(0, vcoTwoLevel);
      prevCCvalues[36] = CCvalues[36];
    }


    if (CCvalues[41] != prevCCvalues[41]) {
      waveShapeTwoIndex = CCvalues[41] / 31;
      if (waveShapeTwoIndex < 4) {
        if (waveShapeTwoIndex == 3) {
          voiceBPulse = true;
        } else {
          voiceBPulse = false;
        }
        voice1b.begin(waveShapes[waveShapeTwoIndex]);
        voice2b.begin(waveShapes[waveShapeTwoIndex]);
        voice3b.begin(waveShapes[waveShapeTwoIndex]);
        voice4b.begin(waveShapes[waveShapeTwoIndex]);
        voice5b.begin(waveShapes[waveShapeTwoIndex]);
        voice6b.begin(waveShapes[waveShapeTwoIndex]);
        voice7b.begin(waveShapes[waveShapeTwoIndex]);
        voice8b.begin(waveShapes[waveShapeTwoIndex]);
        prevCCvalues[41] = CCvalues[41];
      }
    }
    //0.94498843
    //0.96855780
    //0.99023822
    //0.00995611
    //0.03108269
    //0.05372621

    if (CCvalues[94] != prevCCvalues[94]) {
      //deTune = CCvalues[94];
      deTune1 = mapfloat(CCvalues[94], 0, 127, 1, .94498843);
      deTune2 = mapfloat(CCvalues[94], 0, 127, 1, .96855780);
      deTune3 = mapfloat(CCvalues[94], 0, 127, 1, .99023822);
      deTune5 = mapfloat(CCvalues[94], 0, 127, 1, 1.00995611);
      deTune6 = mapfloat(CCvalues[94], 0, 127, 1, 1.03108269);
      deTune7 = mapfloat(CCvalues[94], 0, 127, 1, 1.05372621);
      prevCCvalues[94] = CCvalues[94];
    }

    //LFO
    if (CCvalues[47] != prevCCvalues[47]) {
      lfo.frequency(CCvalues[47] / 13);
      prevCCvalues[47] = CCvalues[47];
    }
    if (CCvalues[46] != prevCCvalues[46]) {
      lfoWaveShapeIndex = CCvalues[46] / 25.4;
      if (lfoWaveShapeIndex < 5) {
        lfo.begin(lfoWaveShapes[lfoWaveShapeIndex]);
        //Serial.println(lfoWaveShapeIndex);
        prevCCvalues[46] = CCvalues[46];
      }
    }


    //noise
    if (CCvalues[48] != prevCCvalues[48]) {
      voice1n.amplitude(CCvalues[48] / 384.8);
      voice2n.amplitude(CCvalues[48] / 384.8);
      voice3n.amplitude(CCvalues[48] / 384.8);
      voice4n.amplitude(CCvalues[48] / 384.8);
      voice5n.amplitude(CCvalues[48] / 384.8);
      voice6n.amplitude(CCvalues[48] / 384.8);
      voice7n.amplitude(CCvalues[48] / 384.8);
      voice8n.amplitude(CCvalues[48] / 384.8);
      prevCCvalues[48] = CCvalues[48];
    }


    //Filter
    if (CCvalues[74] != prevCCvalues[74]) {
      voice1filter.frequency(CCvalues[74] * 9.33);
      voice2filter.frequency(CCvalues[74] * 9.33);
      voice3filter.frequency(CCvalues[74] * 9.33);
      voice4filter.frequency(CCvalues[74] * 9.33);
      voice5filter.frequency(CCvalues[74] * 9.33);
      voice6filter.frequency(CCvalues[74] * 9.33);
      voice7filter.frequency(CCvalues[74] * 9.33);
      voice8filter.frequency(CCvalues[74] * 9.33);
      prevCCvalues[74] = CCvalues[74];
    }


    //resonance
    if (CCvalues[71] != prevCCvalues[71]) {
      if (CCvalues[71] < 5) {
        CCvalues[71] = 5;
      }
      voice1filter.resonance((CCvalues[71] / 25.4) + .9);
      voice2filter.resonance((CCvalues[71] / 25.4) + .9);
      voice3filter.resonance((CCvalues[71] / 25.4) + .9);
      voice4filter.resonance((CCvalues[71] / 25.4) + .9);
      voice5filter.resonance((CCvalues[71] / 25.4) + .9);
      voice6filter.resonance((CCvalues[71] / 25.4) + .9);
      voice7filter.resonance((CCvalues[71] / 25.4) + .9);
      voice8filter.resonance((CCvalues[71] / 25.4) + .9);
      prevCCvalues[71] = CCvalues[71];
    }


    //filter octaveControl
    voice1filter.octaveControl(3.5);
    voice2filter.octaveControl(3.5);
    voice3filter.octaveControl(3.5);
    voice4filter.octaveControl(3.5);
    voice5filter.octaveControl(3.5);
    voice6filter.octaveControl(3.5);
    voice7filter.octaveControl(3.5);
    voice8filter.octaveControl(3.5);




    //lfoModulation Depth
    if (CCvalues[2] != prevCCvalues[2]) {
      voice1filtermodmixer.gain(1, CCvalues[2] / 127);
      voice2filtermodmixer.gain(1, CCvalues[2] / 127);
      voice3filtermodmixer.gain(1, CCvalues[2] / 127);
      voice4filtermodmixer.gain(1, CCvalues[2] / 127);
      voice5filtermodmixer.gain(1, CCvalues[2] / 127);
      voice6filtermodmixer.gain(1, CCvalues[2] / 127);
      voice7filtermodmixer.gain(1, CCvalues[2] / 127);
      voice8filtermodmixer.gain(1, CCvalues[2] / 127);
      prevCCvalues[2] = CCvalues[2];
    }


    //envelope mod depth
    if (CCvalues[49] != prevCCvalues[49]) {
      voice1filtermodmixer.gain(0, CCvalues[49] / 127);
      voice2filtermodmixer.gain(0, CCvalues[49] / 127);
      voice3filtermodmixer.gain(0, CCvalues[49] / 127);
      voice4filtermodmixer.gain(0, CCvalues[49] / 127);
      voice5filtermodmixer.gain(0, CCvalues[49] / 127);
      voice6filtermodmixer.gain(0, CCvalues[49] / 127);
      voice7filtermodmixer.gain(0, CCvalues[49] / 127);
      voice8filtermodmixer.gain(0, CCvalues[49] / 127);
      prevCCvalues[49] = CCvalues[49];
    }



    //Delay
    //time
    if (CCvalues[88] != prevCCvalues[88]) {
      delay1.delay(0, (CCvalues[88] * 8.05) / 2.4);
      prevCCvalues[88] = CCvalues[88];
    }

    //feedback
    if (CCvalues[89] != prevCCvalues[89]) {
      mainOutMixer.gain(3, CCvalues[89] / 127);
      prevCCvalues[89] = CCvalues[89];
    }


    //pulseWidth
    if (CCvalues[50] != prevCCvalues[50]) {
      tempPulseWidth = 1 - (CCvalues[50] / 127);
      tempDetuneMod = CCvalues[50] / 254;
      prevCCvalues[50] = CCvalues[50];
    }




    //attack Filter
    if (CCvalues[42] != prevCCvalues[42]) {
      attackTimeFilter = (CCvalues[42] * 12.05) * 2;
      prevCCvalues[42] = CCvalues[42];
    }


    //attack Amp
    if (CCvalues[32] != prevCCvalues[32]) {
      attackTime = (CCvalues[32] * 8.05) * 2;
      prevCCvalues[32] = CCvalues[32];
    }



    //decay Filter
    if (CCvalues[43] != prevCCvalues[43]) {
      decayTimeFilter = CCvalues[43] * 12.05;
      prevCCvalues[43] = CCvalues[43];
    }


    //decay Amp
    if (CCvalues[33] != prevCCvalues[33]) {
      decayTime = CCvalues[33] * 8.05;
      prevCCvalues[33] = CCvalues[33];
    }



    //sustain Filter
    if (CCvalues[44] != prevCCvalues[44]) {
      sustainLevelFilter = CCvalues[44] * 4.05;
      sustainLevelFilter = mapfloat(sustainLevelFilter, 0, 127, -1, 1);
      prevCCvalues[44] = CCvalues[44];
    }


    //sustain Amp
    if (CCvalues[34] != prevCCvalues[34]) {
      sustainLevel = CCvalues[34] / 127;
      prevCCvalues[34] = CCvalues[34];
    }


    //release Filter
    if (CCvalues[45] != prevCCvalues[45]) {
      releaseTimeFilter = (CCvalues[45] * 8.05) * 2;
      prevCCvalues[45] = CCvalues[45];
    }

    //Release Amp
    if (CCvalues[35] != prevCCvalues[35]) {
      releaseTime = (CCvalues[35] * 8.05) * 2;
      prevCCvalues[35] = CCvalues[35];
    }



    //LFO Peak
    if (peak1.available()) {
      tempPeak = peak1.read();
    }
    voice1a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice2a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice3a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice4a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice5a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice6a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice7a.pulseWidth((tempPeak / 2) + tempPulseWidth);
    voice8a.pulseWidth((tempPeak / 2) + tempPulseWidth);

    if (voiceBPulse) {
      voice1b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice2b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice3b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice4b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice5b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice6b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice7b.pulseWidth((tempPeak / 2) + tempPulseWidth);
      voice8b.pulseWidth((tempPeak / 2) + tempPulseWidth);
    } else {
      deTuneLfo = ((tempPeak) * tempDetuneMod + 1);
      //Serial.println(deTuneLfo);
    }

    //end loop
  }



The area where the notes are manipulated is here-

Code:
void MIDInoteOn(int note, int vel)
{

  if (noteCount == 5) {
    Serial.println("Voice Limit Exceeded!");
    return;
  }
  if (!noteCount) {
    voice [0] = note;
    currNote = voice[0];
    noteCount++;
    Serial.print("1st Note #  ");
    Serial.println(currNote);
    Serial.println("notecount=  ");
    Serial.println(noteCount);
    
    return;
  }
  //Serial.println(i+1);



  currNote=0;
  for (int i = 0; i < 4; i++) {
    if (!voice[i]) {
      voice[i] = note;
      currNote = voice[i];
      noteCount++;
      Serial.print("Replacement Note #  ");
      Serial.println(currNote);
      Serial.print("Assigned to Voice #  ");
      Serial.println(i + 1);
      Serial.println();
      Serial.println("notecount=  ");
    Serial.println(noteCount);
      break;
    }
  }
}



void MIDIccData(int CCnumber, float CCvalue)
{
  //Serial.print("CC#= ");
  //Serial.print(CCnumber);
  //Serial.print("  Value= ");
  //Serial.println(CCvalue);
  //assign values to the CC lookup table
  CCvalues[CCnumber] = {CCvalue};


}


//shuts notes off, removes them from note Stack and shifts the remainder notes
//towards bottom to keep all active notes down together in array

void MIDInoteOff(int note, int vel)
{


  if (note == currNote && noteCount>1) {
    currNote=0;
    Serial.print("Trying to find note # ");
        Serial.println(note);
    for (int i = 0; i < 4; i++) {
      Serial.print("searching voice-  ");
        Serial.println(i);
      if (note == voice[i]) {
        Serial.print("I FOUND IT! ");
        voice[i] = 0;
        currNote = voice[i - 1];
        noteCount--;
        Serial.print("Current note off # ");
        Serial.println(note);
        Serial.println("Shut Off Current Voice # ");
        Serial.println(i + 1);
        Serial.print("Current note ON # ");
        Serial.println(currNote);
        Serial.println();
        Serial.println("notecount=  ");
    Serial.println(noteCount);
        break;
      }

    }
          return;
  }


  if (noteCount < 2) {
    voice[0] = 0;
    currNote = 0;
    noteCount--;
    if (noteCount < 0) {
      noteCount = 0;
    }
    Serial.print("Last note off # ");
    Serial.println(note);
    Serial.println("Shut Off Voice # 1 ");
    Serial.println();
    Serial.println("notecount=  ");
    Serial.println(noteCount);
    return;
    //Serial.println(i+1);

  }




  if (noteCount > 1) {
    for (int i = 0; i < 4; i++) {
      if (voice[i] == note) {
        voice[i] = 0;
        Serial.print("Drop off note # ");
        Serial.println(note);
        Serial.print("Drop Off Voice # ");
        Serial.println(i + 1);
        for (int c = i + 1; c < 4; c++) {
          voice[i] = voice[c];
          i = i++;
        }
        voice[3] = 0;
        noteCount--;
        Serial.print("-note off # ");
        Serial.println(note);
        Serial.println();
        Serial.println("notecount=  ");
    Serial.println(noteCount);
        break;
      }
    }





  }
}




Hopefully one of you coding gurus can load this up, have a midi keyboard to test it with and by some miracle figure out how to make it not glitch.. ever!

*crossing fingers*.....

/Blaine
 
Last edited:
A array that holds the current state of all notes and a separate variable for the active note...

A new note pushes out previous active but when dropped you scan for the next highest value that is true in the note-on array.


Might even generalize to levels of polyphony by having pressed and active arrays.
 
Last edited:
Thanks for the reply oddson.


What you describe sounds alot like the methods I already wrote.
My method will let you drop a note held down, but not active.
Then a method "splices" the elements in the array together where that note dropped out.

So say you have notes ABCD held down, one at a time in that sequence.
All are held down but only D is playing.
Now let go of B... Instead of A_CD with D still playing, we have ACD.
That way if you let go of D, C will play. If you then let go of C, A will play.

Standard Stack Arrays won't work from what I seen.
JavaScript has a "Splice" command to stitch a broken array together.. But not C.
 
I meant an array of 128 size were the index is the midi number where the pressed state is kept for all notes... but then the problem is having to scan for the next note across a bigger array looking for the next pressed candidate...
 
I have a feeling the problem centers on when currNote=0

Every time it glitches, my debug Serial.prints show currNote was 0 when it should have been a true value.
The glitch is my held down note won't retrigger.

I think it trips up on that somehow.. on currNote=0
I change currNote to 0 so my envelope generators will retrigger.
Seems to do the trick until I play notes very fast.
Maybe I need to just change all the state0a, state0b... Etc to noteOnWait and not make currNote=0 unless it is the LastNote.


I think my note allocation method is working good.
An array for all 128 notes might be better for a poly mode.
 
Last edited:
Found the problem!


It was in here..

Code:
if (noteCount > 1) {
 for (int i = 0; i < 4; i++) {
 if (voice[i] == note) {
 voice[i] = 0; 
Serial.print("Drop off note # ");
 Serial.println(note);
 Serial.print("Drop Off Voice # "); 
Serial.println(i + 1); 
for (int c = i + 1; c < 4; c++) { 
voice[i] = voice[c]; 
i = i++; 
}
 voice[3] = 0; 
noteCount--; 
Serial.print("-note off # "); 
Serial.println(note); 
Serial.println(); 
Serial.println("notecount= "); 
Serial.println(noteCount); 
break; 
} }


The "i= i++;" was suppose to just be ++i;

Just goes to show what a n00b I am at programming in C. :-\

I upped the MAX notes in the voice[] to 8 again like I had before and it all works flawlessly now.
Time to finally move on to Portamento mode...
 
Status
Not open for further replies.
Back
Top