Project "Seenthysizer"

Status
Not open for further replies.

Synthetech

Active member
Well after a few weeks of learning to program through trial and error and lots of research, I have a working MIDI controlled synthesizer
made with a Teensy 3.5 and the Audio Library.

I present the "Seenthysizer"!
(v1.0)


https://www.youtube.com/watch?v=fVdPEy9sTUk




It's a start.. most definately not finished!
I will post code after some cleaning up and sorting a few bugs.

If my 3.5 can do all this with only 13% of it's memory used so far, I can only imagine what else it can do when it is at say.. 50%!

/Blaine



EDIT 2-21-17

Here is a version of the code that seems to work well enough to share.
I have only used it on a Teensy 3.5. It may work fine on 3.2 or earlier, I am not certain since I don't have those boards to test it with.
If you have earlier boards than mine to try on, please post your results.

The controller (Ctrlr) software is found here-

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

FIRST load up the code and/or power up the Teensy with code already on it.
THEN open up the Ctrlr app so it can locate the Teensy MIDI interface.

If you ever restart the Teensy, you MUST RESTART THE CONTROLLER.. every time.

If you have sluggish controls, try closing the Ctrlr App, restart Teensy, open Ctrlr back up.

Here you go!


HTML:
/*Project Seenthysizer v2.8
 *a modified Teensy 3.2+ Audio Proect originally written by otemrellik 
 *this MIDI controlled version written by:
 *Blaine Perkins
 *
 *Includes support for Teensy Audio Board, USB Audio and USB MIDI
*/


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.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[8];
int noteFreq[8];

//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
//when limit is reached, msg prints Voice Limit Exceeded!
int noteCount = 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;
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;



//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);
}



//function to allocate a new MIDI Note On to an available voice number
//scans for elements that are zero value. then assigns the note number to it

void MIDInoteOn(int note, int vel)
{

  if (noteCount == 8) {
    //Serial.println("Voice Limit Exceeded!");
//may use the noteCount to enable a "note stealing" routine later on
  }

  for (int i = 0; i < 8; i++) {
    if (!voice[i]) {
      voice[i] = note;
      noteFreq[i] = voice[i];
      Serial.print("New Note #  ");
      Serial.println(note);
      //float freq = 440.0 * powf(2.0, (float)(note - 69) * 0.08333333);
      //Serial.print("Frequency= ");
      //Serial.println(freq);
      //Serial.print("Velocity= ");
      //Serial.println(vel);
      Serial.print("Assigned to Voice #  ");
      Serial.println(i + 1);
      Serial.println();
      noteCount++;

      if (voice[i]) {
        return;
      }
    }
  }
}

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};


}


//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;
      }
    }
  }
}


//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] = 127;
  CCvalues[32] = 15;
  CCvalues[33] = 8;
  CCvalues[34] = 127;
  CCvalues[35] = 106;
  CCvalues[36] = 63;
  CCvalues[40] = 32;
  CCvalues[41] = 96;
  CCvalues[42] = 81;
  CCvalues[43] = 64;
  CCvalues[44] = 16;
  CCvalues[45] = 89;
  CCvalues[46] = 52;
  CCvalues[47] = 3;
  CCvalues[49] = 127;
  CCvalues[50] = 72;
  CCvalues[71] = 100;
  CCvalues[74] = 37;
  CCvalues[94] = 70;


// 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)(noteFreq [i] - 69) * 0.08333333));
      voice1b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 1) {
      voice2a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice2b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 2) {
      voice3a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice3b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 3) {
      voice4a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice4b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 4) {
      voice5a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice5b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 5) {
      voice6a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice6b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 6) {
      voice7a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice7b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 7) {
      voice8a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice8b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
//sevice envelopes for voices
    if (i == 0) {
      switch (state0a) {

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0b) {

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

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

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

          break;


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

          break;

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

          break;


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




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

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0d) {

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

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

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

          break;


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

          break;

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

          break;


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

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

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0f) {

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

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

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

          break;


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

          break;

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

          break;


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



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

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0h) {

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

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

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

          break;


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

          break;

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

          break;


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



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

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0j) {

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

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

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

          break;


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

          break;

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

          break;


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



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

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0l) {

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

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

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

          break;


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

          break;

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

          break;


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


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

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

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

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

          break;


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

          break;

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

          break;


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


      // service the Filter ADSR
      switch (state0n) {

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[i]) {
            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];
    }
  }


  if (CCvalues[94] != prevCCvalues[94]) {
    deTune = CCvalues[94];
    deTune = mapfloat(deTune, 0, 127, .875, 1.125);
    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
}





PS- There were some erroneous statements of the specs of 3.5 in my vid.. it's been a long few weeks! Corrections were made in the description and a mention of where to get the specs.
I simply just dont have time to redo the entire vid again.
 
Last edited:
That is COOL!

I want to play with it! Are you going to release the source? I'd really like to see how you handle data transfer between the PC software and the Teensy :)
 
I made the GUI using Ctrlr

http://ctrlr.org/

Here is a link to the exe file on my Google Drive

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



It is a custom MIDI controller.
I made each knob/control output a Control Change number/value.
The Seenthy simply grabs the CC data from the USB MIDI interface and changes parameters with the new values.


I will try to post up the code soon.. I just need to clean house so it wont look so gaudy and have more commentry in it too.
It has some issues.. mainly formulations to convert MIDI CC values to the Audio Objects values.
I need REALLY badly GOOD exponential conversions for the filter and ADSRs :(
 
So you're using CCs for your own purposes.... could be a breath controller to control an attack duration?
Clever! When you control both ends of the midi stream, you can do whatever you want.
 
Superb work! I look forwards to giving it a go.

I was particularly amused at the youtube automatic transcribed subtitles during the LFO modulated sound demo at the beginning 'oh no oh no oh no oh no'
 
I updated the OP with the code that seems to work decently now.

It still needs alot of tweaking, but this should be good enough to play with and not be aggravating.
 
I'm happy to report that I've got this all to work!

Thank you, this'll provide many hours of fun.

Note: Changing I2S object to dacs object (for Teensy 3.6 DACs) works nicely.
 
Code:
  for (int i = 0; i < 8; i++) {
    if (i == 0) {
      voice1a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice1b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 1) {
      voice2a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice2b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 2) {
      voice3a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice3b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 3) {
      voice4a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice4b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 4) {
      voice5a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice5b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 5) {
      voice6a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice6b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 6) {
      voice7a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice7b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 7) {
      voice8a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice8b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
What does that do that this doesn't?
Code:
   for (int i = 0; i < 8; i++) {
     voice1a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
     voice1b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
Edit... oh I see it now... there must be a way to do this with arrays... edit 2 -- I guess there isn't if you are making objects with the audio tool there's no simple way to make the assignment work by looping with an increment variable.
 
Last edited:
I'm happy to report that I've got this all to work!

Thank you, this'll provide many hours of fun.

Note: Changing I2S object to dacs object (for Teensy 3.6 DACs) works nicely.

Thanks for the report. Have fun!
I plan to make it much more interesting later on.
That GUI is scriptable with LUA... I have made some very slick GUIs for synths using it.


Code:
  for (int i = 0; i < 8; i++) {
    if (i == 0) {
      voice1a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice1b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 1) {
      voice2a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice2b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 2) {
      voice3a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice3b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 3) {
      voice4a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice4b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 4) {
      voice5a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice5b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 5) {
      voice6a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice6b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 6) {
      voice7a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice7b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
    if (i == 7) {
      voice8a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice8b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
What does that do that this doesn't?
Code:
   for (int i = 0; i < 8; i++) {
     voice1a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
     voice1b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
Edit... oh I see it now... there must be a way to do this with arrays... edit 2 -- I guess there isn't if you are making objects with the audio tool there's no simple way to make the assignment work by looping with an increment variable.

Lol... yea, I thought the same thing at first.
It might be possible to do a string array to fill in the header element of the object.
It was faster to just do it that way and move on at the time.
 
Supersaw!

Did some more tinkering around tonight and managed to butcher my own code up to "Stack" the voices.

I managed to get 7 voices to play for one note, then detuned 6 of them from a central note to FATTEN up the sound.
The idea was to emulate the much sought after "SUPERSAW" sound of the famous Roland JP-8000 synth that is heard in many trance/techno/dance tracks.

Give it a try and lemme know what you think!

Sorry for the hacked up code, but you can see what I did to change from the Seenthysizer 2.8 to this experimental version.

The "detune" control is where you notice a huge change.. turn it all the way to the left to hear no DETUNE effect, then gradually turn it up ever so slowly to hear the voices begin to "swirl" around the harmonics.
Only the OscR/Oscillator 2 voice is active. Turn the Osc1-OscR Knob all the way to the OscR side.

Be sure to turn the Volume down below Max.. otherwise you will get distortion.


HTML:
/*SuperSaw2.1
 * 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 only.
 * 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[1];
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
//when limit is reached, msg prints Voice Limit Exceeded!
int noteCount = 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;



//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);
}



//function to allocate a new MIDI Note On to an available voice number
//scans for elements that are zero value. then assigns the note number to it

void MIDInoteOn(int note, int vel)
{

  if (noteCount == 8) {
    //Serial.println("Voice Limit Exceeded!");
//may use the noteCount to enable a "note stealing" routine later on
  }

  //for (int i = 0; i < 8; i++) {
    //if (!voice[0]) {
      voice[0] = note;
      noteFreq[0] = voice[0];
      //Serial.print("New Note #  ");
      //Serial.println(note);
      //float freq = 440.0 * powf(2.0, (float)(note - 69) * 0.08333333);
      //Serial.print("Frequency= ");
      //Serial.println(freq);
      //Serial.print("Velocity= ");
      //Serial.println(vel);
      //Serial.print("Assigned to Voice #  ");
      //Serial.println(i + 1);
      //Serial.println();
      noteCount++;

      //if (voice[0]) {
        return;
      //}
    //}
  }
//}

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};


}


//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[0] == note) {
      voice[0] = 0;
      //Serial.print("-note off # ");
      //Serial.println(note);
      //Serial.print("Shut Off Voice # ");
      //Serial.println(i + 1);
      noteCount--;
      if (noteCount < 0) {
        noteCount = 0;
      }
    }
  //}
}


//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] = 107;
  CCvalues[89] = 74;


// 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)(noteFreq [i] - 69) * 0.08333333));
      voice1b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune1);
    }
    if (i == 0) {
      //voice2a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice2b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune2);
    }
    if (i == 0) {
      //voice3a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice3b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune3);
    }
    if (i == 0) {
      //voice4a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice4b.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
    }
    if (i == 0) {
      //voice5a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice5b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune5);
    }
    if (i == 0) {
      //voice6a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice6b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune6);
    }
    if (i == 0) {
      //voice7a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      voice7b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune7);
    }
    if (i == 7) {
      //voice8a.frequency(440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333));
      //voice8b.frequency((440.0 * powf(2.0, (float)(noteFreq [i] - 69) * 0.08333333))* deTune);
    }
//sevice envelopes for voices
    if (i == 0) {
      switch (state0a) {

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0a = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0b) {

        case noteOnWait:
          if (voice[0]) {
            state0b = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0b = RELEASE1;
          }

          break;


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




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

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0c = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0d) {

        case noteOnWait:
          if (voice[0]) {
            state0d = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0d = RELEASE1;
          }

          break;


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

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

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0e = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0f) {

        case noteOnWait:
          if (voice[0]) {
            state0f = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0f = RELEASE1;
          }

          break;


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



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

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0g = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0h) {

        case noteOnWait:
          if (voice[0]) {
            state0h = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0h = RELEASE1;
          }

          break;


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



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

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0i = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0j) {

        case noteOnWait:
          if (voice[0]) {
            state0j = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0j = RELEASE1;
          }

          break;


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



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

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0k = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0l) {

        case noteOnWait:
          if (voice[0]) {
            state0l = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0l = RELEASE1;
          }

          break;


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


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

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

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            state0m = RELEASE1;
          }

          break;


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


      // service the Filter ADSR
      switch (state0n) {

        case noteOnWait:
          if (voice[0]) {
            state0n = ATTACK;
          }
          break;

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

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

          break;


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

          break;

        case SUSTAIN:
          if (!voice[0]) {
            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];
    }
  }


  if (CCvalues[94] != prevCCvalues[94]) {
    //deTune = CCvalues[94];
    deTune1 = mapfloat(CCvalues[94], 0, 127, 1, .88997686);
    deTune2 = mapfloat(CCvalues[94], 0, 127, 1, .93711560);
    deTune3 = mapfloat(CCvalues[94], 0, 127, 1, .98047643);
    deTune5 = mapfloat(CCvalues[94], 0, 127, 1, 1.01991221);
    deTune6 = mapfloat(CCvalues[94], 0, 127, 1, 1.06216538);
    deTune7 = mapfloat(CCvalues[94], 0, 127, 1, 1.10745242);
    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
}
 
I made the GUI using Ctrlr
It is a custom MIDI controller.
I made each knob/control output a Control Change number/value.
The Seenthy simply grabs the CC data from the USB MIDI interface and changes parameters with the new values.

Nice project!

Would it be possible to post a list of the used CC numbers and data? So I may write a GUI useable on my Mac ... ;-)

P.S.: Way better - Ctrlt runs on macOS already, so then the panel file would help a lot ... THX!
 
Last edited:
Here's a link to the .bpanelz file

It's called "Seenthysizer v1.0"

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

Let me know if it works for you.. I am curious about having the bpanelz file opening up on a mac.



The list for the Control Changes is:

HTML:
-Master Volume 7

-vcoMixBalance 36

-deTune 94

-waveShapeOneIndex 40
-waveShapeTwoIndex 41

-lfoWaveShapeIndex 46
-lfo frequency 47
-noiseVolume 48

//Filter
-Filter Cutoff 74
-Resonance 71
-lfoModDepth. 2
-envDepth 49


//Amp ADSR-
-Attack 32
-Decay 33
-Sustain 34
-Release 35

//Filter ADSR

-fAttack 42
-fDecay 43
-fSustain 44
-fRelease 45






-pulseWidth 50


//Delay Effect
Delay depth 90
Delay Time 88
Delay Feedback 89
 
Thank you for the file, works like a charm! See? :cool: :)

Screenshot 2017-03-02 18.05.11.png
 
Status
Not open for further replies.
Back
Top