Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 34

Thread: knobby is your midi buddy

  1. #1
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126

    knobby is your midi buddy

    I've built a basic controller that can be applied to basically any control scenario. Knobby is made with 5 LED rotary encoders, an audio board and a teensy 4.1 with two additional memory positions populated. This is with the goal of making a midi controlled synth, but first of course it needs a midi controller. As provided in this example the sketch provides a palette of 6 different channels with 6 different palettes of four knobs for each channel. This allows control of 144 things with visual feedback and no menus or touch screens. Next plan is to add a 19 channel vocoder (that'll use 4 control channels right there) and a few different patchable synths. The design as is could also make a great modular synth midi controller that could even be combined with midi sequencer logic and an 8 channel audio card to provide 144 midi controllers and 8 CV outputs.

    https://www.youtube.com/watch?v=UlIAe0YhFw4
    Attached Files Attached Files

  2. #2
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    Works like gangbusters except I can't get it to send midi over usb. Can anyone tell me what I'm doing wrong here? I've looked at the MIDI library and it doesn't seem to send a MIDI channel number, just a control channel number and a value. Of course, it's easy to do this stuff right in serial, not much overhead there even without the midi library.

    Code:
    /* Knobby midi control palette
    */
    
    #include <Encoder.h>
    #include <MIDI.h>
    
    #if defined(USBCON)
    #include <midi_UsbTransport.h>
    
    static const unsigned sUsbTransportBufferSize = 16;
    typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
    
    UsbTransport sUsbTransport;
    
    MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
    
    #else // No USB available, fallback to Serial
    MIDI_CREATE_DEFAULT_INSTANCE();
    #endif
    
    const int redPin =  2;
    const int greenPin =  3;
    const int bluePin =  4;
    const int mredPin =  5;
    const int mgreenPin =  6;
    const int mbluePin =  7;
    
    Encoder knobby(34, 33);
    Encoder knob0(32, 31);
    Encoder knob1(30, 29);
    Encoder knob2(28, 27);
    Encoder knob3(26, 25);
    
    void setup()   {                
      pinMode(redPin, OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin, OUTPUT);
      pinMode(mredPin, OUTPUT);
      pinMode(mgreenPin, OUTPUT);
      pinMode(mbluePin, OUTPUT);
      knobby.write(1);
      knob0.write(0);
      knob1.write(0);
      knob2.write(0);
      knob3.write(0);
      MIDI.begin();
      Serial.begin(115200);
    }
    
    void knobcolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 1:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 2:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 3:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 0);
        break;
        case 4:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 5:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 255);
        break;
      }
    }
    
    void knobscolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 1:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 2:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 3:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 255);
        break;
        case 4:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 5:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 0);
        break;
      }
    }
    
    long positionKnobby,positionKnob0,positionKnob1,positionKnob2,positionKnob3  = 0;
    long newKnobby,newKnob0,newKnob1,newKnob2,newKnob3 = 0;
    long newpos[144];
    
    int midivals[144];
    
    int midiports[] = {70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93};
                  
    int midichans[] = {0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,
                  0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
                  0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
                  0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,
                  0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,
                  0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5};
    int i;
    int indexer;
    
    void printarray(){
        Serial.print(" ");
        for(int y = 0; y <=143; y++) { 
          Serial.print(abs((newpos[y] / 2)) % 128);
          Serial.print(",");
        }  
        Serial.println();
    }
    
    void midisend(){
        for(int y = 0; y <=143; y++) { 
          if (midivals[y] != abs(newpos[y] / 2) % 128){
            midivals[y] = abs(newpos[y] / 2) % 128;
            Serial.print(midichans[y],HEX);
     //       Serial.print(":");
            Serial.print(midiports[y],HEX);
     //       Serial.print(":");
            Serial.print(midivals[y],HEX);
            Serial.println();
            MIDI.sendProgramChange(midivals[y],midiports[y]);
    
          }
        }  
    }
    
    
    void loop(){
    
      newKnobby = knobby.read();
      if (abs(newKnobby - positionKnobby) >= 1) {
        i = abs(newKnobby / 4);
        int rowNum = i % 36 / 6;
        int chanNum = i % 6;
        indexer = (i % 36);
        knobcolor(rowNum);
        knobscolor(chanNum);
        positionKnobby = newKnobby;
        knob0.write(newpos[indexer * 4]);
        knob1.write(newpos[indexer * 4 + 1]);
        knob2.write(newpos[indexer * 4 + 2]);
        knob3.write(newpos[indexer * 4 + 3]);
      }
    
      newKnob0 = knob0.read();
      if (abs(newKnob0 - positionKnob0) > 1) {
        newpos[indexer * 4] = newKnob0;
     //   printarray();
        positionKnob0 = newKnob0;
      }
    
      newKnob1 = knob1.read();
      if (abs(newKnob1 - positionKnob1) > 1) {
        newpos[indexer * 4 + 1]  = newKnob1;
    //    printarray();
        positionKnob1 = newKnob1;
      }
    
      newKnob2 = knob2.read();
      if (abs(newKnob2 - positionKnob2) > 1) {
        newpos[indexer * 4 + 2] = newKnob2;
    //    printarray();
        positionKnob2 = newKnob2;
      }
    
      newKnob3 = knob3.read();
      if (abs(newKnob3 - positionKnob3) > 1) {
        newpos[indexer * 4 + 3] = newKnob3;
    //    printarray();
        positionKnob3 = newKnob3;
      }
    
      midisend();
      
    }

  3. #3
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    159
    To use Teensy usbMIDI, first in Tools>USB Type, pick a MIDI type which suits.

    There is no need for any CREATE_INSTANCE_etc, just send to or receive from it.

    Look in File>Examples>Teensy>USB_MIDI>TransmitEverything for details.

    Hope that lights the way.

  4. #4
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    Thanks for that link I was looking for it, didn't find it before.

    So now I have all the nonsense out of the setup code and just use one call to usbMIDI.SendControlChange(val,port,chan,wire) but still have no idea if it works. I see no usbmidi device in qtjackctl and sunvox doesn't see my knobs being turned. I suppose I need to install windows on an old laptop to see if it works there.

    Code:
    [287463.810577] usb 1-1.3: Product: Teensy MIDI/Audio
    [287463.810579] usb 1-1.3: Manufacturer: Teensyduino
    [287463.810580] usb 1-1.3: SerialNumber: 7828150
    [287463.810888] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
    [287463.813069] usb 1-1.3: Warning! Unlikely big volume range (=4095), cval->res is probably wrong.
    [287463.813071] usb 1-1.3: [49] FU [PCM Playback Volume] ch = 2, val = 0/4095/1
    [287487.312986] usb 1-1.3: USB disconnect, device number 68
    [287487.486899] usb 1-1.3: new high-speed USB device number 69 using ehci-pci
    [287487.565457] usb 1-1.3: New USB device found, idVendor=16c0, idProduct=0478
    [287487.565460] usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=1
    [287487.565461] usb 1-1.3: SerialNumber: 000BF1DF
    [287487.566966] hid-generic 0003:16C0:0478.00A3: hidraw4: USB HID v1.11 Device [HID 16c0:0478] on usb-0000:00:1a.0-1.3/input0
    [287488.080989] usb 1-1.3: USB disconnect, device number 69
    [287488.306846] usb 1-1.3: new high-speed USB device number 70 using ehci-pci
    [287488.385906] usb 1-1.3: New USB device found, idVendor=16c0, idProduct=048a
    [287488.385910] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
    [287488.385913] usb 1-1.3: Product: Teensy MIDI/Audio
    [287488.385915] usb 1-1.3: Manufacturer: Teensyduino
    [287488.385916] usb 1-1.3: SerialNumber: 7828150
    [287488.386418] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
    [287488.388959] usb 1-1.3: Warning! Unlikely big volume range (=4095), cval->res is probably wrong.
    [287488.388964] usb 1-1.3: [49] FU [PCM Playback Volume] ch = 2, val = 0/4095/1
    [287690.833035] usb 1-1.3: USB disconnect, device number 70
    [287691.005726] usb 1-1.3: new high-speed USB device number 71 using ehci-pci
    [287691.088378] usb 1-1.3: New USB device found, idVendor=16c0, idProduct=0478
    [287691.088380] usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=1
    [287691.088381] usb 1-1.3: SerialNumber: 000BF1DF
    [287691.089592] hid-generic 0003:16C0:0478.00A4: hidraw4: USB HID v1.11 Device [HID 16c0:0478] on usb-0000:00:1a.0-1.3/input0
    [287691.857033] usb 1-1.3: USB disconnect, device number 71
    [287692.028733] usb 1-1.3: new high-speed USB device number 72 using ehci-pci
    [287692.107625] usb 1-1.3: New USB device found, idVendor=16c0, idProduct=048a
    [287692.107628] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
    [287692.107629] usb 1-1.3: Product: Teensy MIDI/Audio
    [287692.107630] usb 1-1.3: Manufacturer: Teensyduino
    [287692.107631] usb 1-1.3: SerialNumber: 7828150
    [287692.107967] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
    [287692.111247] usb 1-1.3: Warning! Unlikely big volume range (=4095), cval->res is probably wrong.
    [287692.111250] usb 1-1.3: [49] FU [PCM Playback Volume] ch = 2, val = 0/4095/1
    [332562.779243] usb 1-1.3: USB disconnect, device number 72
    [332562.952058] usb 1-1.3: new high-speed USB device number 73 using ehci-pci
    [332563.030744] usb 1-1.3: New USB device found, idVendor=16c0, idProduct=0478
    [332563.030747] usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=1
    [332563.030748] usb 1-1.3: SerialNumber: 000BF1DF
    [332563.031911] hid-generic 0003:16C0:0478.00A5: hidraw4: USB HID v1.11 Device [HID 16c0:0478] on usb-0000:00:1a.0-1.3/input0
    [332563.803407] usb 1-1.3: USB disconnect, device number 73
    [332563.975027] usb 1-1.3: new high-speed USB device number 74 using ehci-pci
    [332564.053973] usb 1-1.3: New USB device found, idVendor=16c0, idProduct=048a
    [332564.053989] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
    [332564.053991] usb 1-1.3: Product: Teensy MIDI/Audio
    [332564.053993] usb 1-1.3: Manufacturer: Teensyduino
    [332564.053994] usb 1-1.3: SerialNumber: 7828150
    [332564.054400] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
    [332564.056715] usb 1-1.3: Warning! Unlikely big volume range (=4095), cval->res is probably wrong.
    [332564.056718] usb 1-1.3: [49] FU [PCM Playback Volume] ch = 2, val = 0/4095/1

  5. #5
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    159
    Try inserting a delay(1000); in void setup() to allow time for the host to sort its instantiation.

  6. #6
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    12,360
    If USB needs to be online in setup() try something like this that will wait for up to 4 seconds - but will proceed when it is ready typically 50-200 ms after setup() it entered if USB is activated by host faster:
    Code:
    void setup()   {                
      pinMode(redPin, OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin, OUTPUT);
      pinMode(mredPin, OUTPUT);
      pinMode(mgreenPin, OUTPUT);
      pinMode(mbluePin, OUTPUT);
      Serial.begin(115200);
    	while (!Serial && millis() < 4000 );
      knobby.write(1);
      knob0.write(0);
      knob1.write(0);
      knob2.write(0);
      knob3.write(0);
      MIDI.begin();
    }

  7. #7
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    Thanks for your help. I really feel like I'm flying blind on this - I don't know if it's a usb midi problem, a midi problem, an os problem. I need to find a usb monitor I can run in ubuntu to at least see what's going over usb (if anything). One thing I am noticing is most of the projects that use teensy as a midi controller over usb lack availability of final code. The example MatrixRat pointed me to help make sense, but even trying stuff in the example didn't seem to send anything. Thing is I know I had this working on another project I did about four years ago with a teensy 2 (I believe).


    Code:
    /* Knobby midi control palette
    */
    
    #include <Encoder.h>
    #include <MIDI.h>
    #include <Bounce.h>
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
    
    const int redPin =  2;
    const int greenPin =  3;
    const int bluePin =  4;
    const int mredPin =  37;
    const int mgreenPin =  36;
    const int mbluePin =  33;
    
    Encoder knobby(34, 35);
    Encoder knob0(32, 31);
    Encoder knob1(30, 29);
    Encoder knob2(28, 27);
    Encoder knob3(26, 25);
    
    void setup()   {                
      pinMode(redPin, OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin, OUTPUT);
      pinMode(mredPin, OUTPUT);
      pinMode(mgreenPin, OUTPUT);
      pinMode(mbluePin, OUTPUT);
      knobby.write(1);
      knob0.write(0);
      knob1.write(0);
      knob2.write(0);
      knob3.write(0);
      Serial1.setTX(1);
      Serial1.setRX(0);
      Serial.begin(31250);
        while (!Serial && millis() < 4000 );
      MIDI.begin(MIDI_CHANNEL_OMNI);
      
    }
    
    void knobcolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 1:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 2:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 3:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 0);
        break;
        case 4:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 5:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 255);
        break;
      }
    }
    
    void knobscolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 1:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 2:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 3:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 255);
        break;
        case 4:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 5:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 0);
        break;
      }
    }
    
    long positionKnobby,positionKnob0,positionKnob1,positionKnob2,positionKnob3  = 0;
    long newKnobby,newKnob0,newKnob1,newKnob2,newKnob3 = 0;
    long newpos[144];
    
    int midivals[144];
    
    int midiports[] = {70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93};
                  
    int midichans[] = {0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,
                  0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
                  0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
                  0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,
                  0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,
                  0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5};
    int i;
    int indexer;
    
    void printarray(){
        Serial.print(" ");
        for(int y = 0; y <=143; y++) { 
          Serial.print(abs((newpos[y] / 2)) % 128);
          Serial.print(",");
        }  
        Serial.println();
    }
    
    void midisend(){
        for(int y = 0; y <=143; y++) { 
          if (midivals[y] != abs(newpos[y] / 2) % 128){
            midivals[y] = abs(newpos[y] / 2) % 128;
            Serial.print(midichans[y],HEX);
     //       Serial.print(":");
            Serial.print(midiports[y],HEX);
     //       Serial.print(":");
            Serial.print(midivals[y],HEX);
            Serial.println();
            usbMIDI.sendControlChange(midivals[y],midiports[y],midichans[y] & 0x0f,0);
    
          }
        }  
    }
    
    
    void loop(){
    
      newKnobby = knobby.read();
      if (abs(newKnobby - positionKnobby) >= 1) {
        i = abs(newKnobby / 4);
        int rowNum = i % 36 / 6;
        int chanNum = i % 6;
        indexer = (i % 36);
        knobcolor(rowNum);
        knobscolor(chanNum);
        positionKnobby = newKnobby;
        knob0.write(newpos[indexer * 4]);
        knob1.write(newpos[indexer * 4 + 1]);
        knob2.write(newpos[indexer * 4 + 2]);
        knob3.write(newpos[indexer * 4 + 3]);
      }
    
      newKnob0 = knob0.read();
      if (abs(newKnob0 - positionKnob0) > 1) {
        newpos[indexer * 4] = newKnob0;
     //   printarray();
        positionKnob0 = newKnob0;
      }
    
      newKnob1 = knob1.read();
      if (abs(newKnob1 - positionKnob1) > 1) {
        newpos[indexer * 4 + 1]  = newKnob1;
    //    printarray();
        positionKnob1 = newKnob1;
      }
    
      newKnob2 = knob2.read();
      if (abs(newKnob2 - positionKnob2) > 1) {
        newpos[indexer * 4 + 2] = newKnob2;
    //    printarray();
        positionKnob2 = newKnob2;
      }
    
      newKnob3 = knob3.read();
      if (abs(newKnob3 - positionKnob3) > 1) {
        newpos[indexer * 4 + 3] = newKnob3;
    //    printarray();
        positionKnob3 = newKnob3;
      }
    
      midisend();
      
    }

  8. #8
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    159
    What version of the IDE and Teensyduino are you using?

    I've had no hands on with the Linux - Midi equation so can't offer any suggestions other than rule it in or out by testing on Windows with a really basic sketch that just sends a single usbMIDI message every 100Ms. If it works then plug it in to Linux.

  9. #9
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    I downloaded 1.53 but for some reason the loader still says it's 1.52.

    My goal with this is to have four midi outputs via usb, and four or eight front panel midi outputs. The goal is to have control over many parameters in many places all from five knobs in one location. I've also never messed with multiple usb serial outputs at once, I'm actually contemplating buying a tiny korg to start an army for testing.

  10. #10
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    12,360
    Quote Originally Posted by boxxofrobots View Post
    I downloaded 1.53 but for some reason the loader still says it's 1.52.
    ...
    There is another copy of an old Teensy.exe Loader 1.52 running from somewhere. If Teensy Installer 1.53 ran to completion it should have left a version reporting that when used. On Windows running install with Loader open stops for failure to over write the file - expect that would happen on linux as well if it was running during install and not just skip writing that file.

    Check for multiple installs ?

  11. #11
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    I don't get it. I downloaded the loader from this page

    https://www.pjrc.com/teensy/loader_linux.html

    After deleting the existing files, and it still reports it's version 1.52 when I run the file. I'm stumped. Where do I get 1.53 for linux64?

  12. #12
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    12,360
    Downloading the loader directly may not be replacing the version installed with TeensyDuino if 1.53 installed.

    Also the LOADER itself doesn't change that often - so what is posted as 'loader for linux' may indeed by an older version without any adverse side effects.

    However the version # likely updated with each FULL release of TeensyDuino Installer. Installing that TD 1.53 should then show that version # - if not there is a spare copy taking precedence in execution.

    One loader change was to push the OS time/date to set RTC on T_4.x's - maybe in 1.52, otherwise unless it has new bootloader update or some issue in use it is generally uncahnging.

  13. #13
    great tons of info

  14. #14
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    Thanks to neroroxx great midi tester tool I was able to confirm this thing is now sending valid midi messages very reliably. Don't yet have an incoming midi handler, that's coming.

    With five RGB rotary encoders, knobby allows you to control 144 midi controls, any knob mapped to any USB MIDI port and channel you like. By changing the left knob you change the color of the row of four, which can be any of six colors. Six times six times four = 144 knobs spread across an RGB palette. In this version there's the beginning of a monophonic synth and a sequencer, to be added. About 50 controls used so far, with 24 more dedicated to a planned 3x8 sequencer. Another six mixer channels (by 4) to be added as well as a wavetable synth and a percussion section, a vocoder, and ability to harmonize with an external source (8MB of memory, whee! So far I'm using 1%). It will support an 8x8 analog interface to allow cv tracking or audio for 16 parameters as well as 8 optoisolated midi ports (ie an 8x8 cv>midi>cv convertor). I have all the bits working individually, I'm just mapping them in one at a time.

    https://youtu.be/uNARHQ3IWLY






    Code:
    /* Knobby midi control palette
    By BOXXOFROBOTS (aka Bradley Sanders)
    This code is gpl3. If you use it enjoy it. If you sell it, pay me. 
    */
    
    #include <Encoder.h>
    #include <MIDI.h>
    #include <Bounce.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    #define _WAVEFORM_SINE 0
    #define _WAVEFORM_SAWTOOTH 1
    #define _WAVEFORM_SAWTOOTH_REVERSE 2
    #define _WAVEFORM_TRIANGLE_VARIABLE 3
    #define _WAVEFORM_PULSE 4
    #define _WAVEFORM_SAMPLE_HOLD 5             
    
    #define LFO1_SHAPE 24
    #define LFO1_SPEED 25
    #define LFO1_PULSEWIDTH 26
    #define LFO1_PHASE 27
    
    #define LFO2_SHAPE 28
    #define LFO2_SPEED 29
    #define LFO2_PULSEWIDTH 30
    #define LFO2_PHASE 31
    
    #define OSC1_SHAPE 32
    #define OSC1_FREQUENCY 33
    #define OSC1_SHAPEMOD 34
    #define OSC1_FREQMOD 35
    
    #define OSC2_SHAPE 36
    #define OSC2_FREQUENCY 37
    #define OSC2_SHAPEMOD 38
    #define OSC2_FREQMOD 39
    
    #define FILTER1_FREQUENCY 48
    #define FILTER1_RESONANCE 49
    #define FILTER1_RANGE 50
    #define FILTER1_CHORUS 51
    
    #define CRUSHER1_BITS 52
    #define CRUSHER1_SAMPLERATE 53
    #define FREEVERB1_SIZE 54
    #define FREEVERB1_DAMPING 55
    
    #define ADSR1_ATTACK 56
    #define ADSR1_DECAY 57
    #define ADSR1_SUSTAIN 58
    #define ADSR1_RELEASE 59
    
    #define MAX_LFO_PHASE 360
    #define MAX_LFO_SPEED 8
    #define MAX_FILTER_Q 5
    #define MIN_FILTER_Q 0.707
    #define MAX_OSC_TRACKING 10
    #define MAX_FILTER_TRACKING 7
    
    #define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES)
    
    // GUItool: begin automatically generated code
    AudioSynthWaveform       waveform1;      //xy=97,508
    AudioMixer4              mixer6;         //xy=127,88
    AudioMixer4              mixer7;         //xy=128,222
    AudioSynthWaveform       waveform2;      //xy=131,694
    AudioSynthWaveformDc     cvbus;            //xy=260,154
    AudioFilterBiquad        biquad3;        //xy=280,698
    AudioSynthWaveformDc     dc2;            //xy=315,434
    AudioFilterBiquad        biquad2;        //xy=322,548
    AudioSynthWaveformDc     dc3;            //xy=347,349
    AudioMixer4              mixer9;         //xy=435,225
    AudioEffectMultiply      multiply3;      //xy=471,407
    AudioSynthWaveformDc     dc1;            //xy=482,771
    AudioMixer4              mixer8;         //xy=495,89
    AudioEffectMultiply      multiply2;      //xy=495,332
    AudioFilterBiquad        biquad5;        //xy=579,222
    AudioFilterBiquad        biquad4;        //xy=630,90
    AudioEffectEnvelope      envelope1;      //xy=637,771
    AudioSynthWaveformModulated waveformMod2;   //xy=691,380
    AudioSynthWaveformModulated waveformMod1;   //xy=701,299
    AudioSynthNoisePink      pink1;          //xy=716,434
    AudioEffectRectifier          fade1;          //xy=778,157
    AudioMixer4              mixer4;         //xy=847,588
    AudioMixer4              mixer3;         //xy=892,376
    AudioFilterBiquad        biquad1;        //xy=956,106
    AudioMixer4              mixer5;         //xy=994,718
    AudioMixer4              mixer10;        //xy=1021,594
    AudioEffectBitcrusher    bitcrusher1;    //xy=1064,381
    AudioAnalyzePeak         peak1;          //xy=1163,150
    AudioFilterBiquad        biquad6;        //xy=1180,565
    AudioEffectChorus        chorus1;        //xy=1217,326
    AudioFilterStateVariable filter1;        //xy=1263,394
    AudioEffectMultiply      multiply1;      //xy=1419,451
    AudioInputI2S            i2s1;           //xy=1575,192
    AudioEffectFreeverbStereo freeverbs1;     //xy=1688,512
    AudioAnalyzeNoteFrequency notefreq1;      //xy=1785,152
    AudioMixer4              mixer2;         //xy=2091,295
    AudioMixer4              mixer1;         //xy=2098,455
    AudioOutputI2S           i2s2;           //xy=2432,444
    AudioOutputUSB           usb1;           //xy=2439,300
    AudioConnection          patchCord1(waveform1, biquad2);
    AudioConnection          patchCord2(mixer6, 0, multiply2, 0);
    AudioConnection          patchCord3(mixer6, 0, mixer8, 0);
    AudioConnection          patchCord4(mixer7, 0, multiply3, 0);
    AudioConnection          patchCord5(mixer7, 0, mixer9, 0);
    AudioConnection          patchCord6(waveform2, biquad3);
    AudioConnection          patchCord7(cvbus, 0, mixer9, 1);
    AudioConnection          patchCord8(cvbus, 0, mixer8, 1);
    AudioConnection          patchCord9(cvbus, 0, mixer10, 1);
    AudioConnection          patchCord10(biquad3, 0, mixer5, 1);
    AudioConnection          patchCord11(biquad3, 0, mixer4, 1);
    AudioConnection          patchCord12(biquad3, 0, mixer6, 1);
    AudioConnection          patchCord13(biquad3, 0, mixer7, 1);
    AudioConnection          patchCord14(dc2, 0, multiply3, 1);
    AudioConnection          patchCord15(biquad2, 0, mixer5, 0);
    AudioConnection          patchCord16(biquad2, 0, mixer4, 0);
    AudioConnection          patchCord17(biquad2, 0, mixer7, 0);
    AudioConnection          patchCord18(biquad2, 0, mixer6, 0);
    AudioConnection          patchCord19(dc3, 0, multiply2, 1);
    AudioConnection          patchCord20(mixer9, biquad5);
    AudioConnection          patchCord21(multiply3, 0, waveformMod2, 1);
    AudioConnection          patchCord22(dc1, envelope1);
    AudioConnection          patchCord23(mixer8, biquad4);
    AudioConnection          patchCord24(multiply2, 0, waveformMod1, 1);
    AudioConnection          patchCord25(biquad5, 0, waveformMod2, 0);
    AudioConnection          patchCord26(biquad4, 0, waveformMod1, 0);
    AudioConnection          patchCord27(envelope1, 0, mixer5, 3);
    AudioConnection          patchCord28(envelope1, 0, mixer4, 3);
    AudioConnection          patchCord29(envelope1, 0, mixer6, 3);
    AudioConnection          patchCord30(envelope1, 0, mixer7, 3);
    AudioConnection          patchCord31(waveformMod2, 0, mixer3, 1);
    AudioConnection          patchCord32(waveformMod1, 0, mixer3, 0);
    AudioConnection          patchCord33(pink1, 0, mixer3, 2);
    AudioConnection          patchCord34(fade1, biquad1);
    AudioConnection          patchCord35(mixer4, 0, mixer10, 0);
    AudioConnection          patchCord36(mixer3, bitcrusher1);
    AudioConnection          patchCord37(biquad1, 0, mixer4, 2);
    AudioConnection          patchCord38(biquad1, 0, mixer5, 2);
    AudioConnection          patchCord39(biquad1, peak1);
    AudioConnection          patchCord40(biquad1, 0, mixer6, 2);
    AudioConnection          patchCord41(biquad1, 0, mixer7, 2);
    AudioConnection          patchCord42(mixer5, 0, multiply1, 1);
    AudioConnection          patchCord43(mixer10, biquad6);
    AudioConnection          patchCord44(bitcrusher1, chorus1);
    AudioConnection          patchCord45(biquad6, 0, filter1, 1);
    AudioConnection          patchCord46(chorus1, 0, filter1, 0);
    AudioConnection          patchCord47(filter1, 0, multiply1, 0);
    AudioConnection          patchCord48(multiply1, 0, mixer2, 1);
    AudioConnection          patchCord49(multiply1, 0, mixer1, 1);
    AudioConnection          patchCord50(multiply1, freeverbs1);
    AudioConnection          patchCord51(i2s1, 0, mixer2, 0);
    AudioConnection          patchCord52(i2s1, 0, mixer3, 3);
    AudioConnection          patchCord53(i2s1, 0, fade1, 0);
    AudioConnection          patchCord54(i2s1, 0, notefreq1, 0);
    AudioConnection          patchCord55(i2s1, 1, mixer1, 0);
    AudioConnection          patchCord56(freeverbs1, 0, mixer2, 3);
    AudioConnection          patchCord57(freeverbs1, 1, mixer1, 3);
    AudioConnection          patchCord58(mixer2, 0, i2s2, 0);
    AudioConnection          patchCord59(mixer2, 0, usb1, 0);
    AudioConnection          patchCord60(mixer1, 0, i2s2, 1);
    AudioConnection          patchCord61(mixer1, 0, usb1, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=2063,702
    // GUItool: end automatically generated code
    
    
    
    /*
    // Number of samples in each delay line
    #define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES)
    // Allocate the delay lines for left and right channels
    short delayline[CHORUS_DELAY_LENGTH];
    int n_chorus = 1;
    */
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, MIDI2);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial3, MIDI3);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial4, MIDI4);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial5, MIDI5);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial6, MIDI6);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial7, MIDI7);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial8, MIDI8);
    
    
    short delayline[CHORUS_DELAY_LENGTH];
    int n_chorus = 3;
    const int myInput = AUDIO_INPUT_MIC;
    
    const int redPin =  2;
    const int greenPin =  3;
    const int bluePin =  4;
    const int mredPin =  37;
    const int mgreenPin =  36;
    const int mbluePin =  33;
    
    Encoder knobby(34, 35);
    Encoder knob0(32, 31);
    Encoder knob1(30, 29);
    Encoder knob2(28, 27);
    Encoder knob3(26, 25);
    
    long positionKnobby,positionKnob0,positionKnob1,positio  nKnob2,positionKnob3  = 0;
    long newKnobby,newKnob0,newKnob1,newKnob2,newKnob3 = 0;
    
    long newpos[144] = {0,268,4,88,88,72,0,0,128,0,0,0,100,188,0,0,168,0,  0,0,108,0,0,0,56,508,168,52,68,324,160,120,128,212  ,4,4,68,28,4,0,0,0,0,0,0,0,0,0,348,188,188,4,96,50  4,8};
    
     
    int lastval[144] = {128,128,128,128,128,128,128,128,128,128,128,128,1  28,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128};
                                 
    int midivals[144];
    
    int midiquant[144] = {128,128,128,128,128,128,128,128,128,128,128,128,1  28,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,12  8,128,128,128,128,128,128,128,128,128,128,128};
    
    int midiports[] = {70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,8  6,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86  ,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86  ,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86  ,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86  ,87,88,89,90,91,92,93,
                      70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86  ,87,88,89,90,91,92,93};
                  
    int midichans[] = {0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf  ,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf  ,0xbf,0xbf,0xbf,0xbf,
                  0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,  0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,  0xb1,0xb1,0xb1,0xb1,
                  0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,  0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,  0xb2,0xb2,0xb2,0xb2,
                  0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,  0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,  0xb3,0xb3,0xb3,0xb3,
                  0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,  0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,  0xb4,0xb4,0xb4,0xb4,
                  0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,  0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,  0xb5,0xb5,0xb5,0xb5};
    int i;
    int indexer;
    
    const float inc = (float)1/127;
    
    PROGMEM const float noteFreqs[128] = {8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602,
                                  21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27,
                                  61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563,
                                  164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995,
                                  415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767,
                                  1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461,
                                  2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032,
                                  5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85};
    
    void setup()   {                
      pinMode(redPin, OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin, OUTPUT);
      pinMode(mredPin, OUTPUT);
      pinMode(mgreenPin, OUTPUT);
      pinMode(mbluePin, OUTPUT);
      knobby.write(576);
      knob0.write(1);
      knob1.write(1);
      knob2.write(1);
      knob3.write(1);
      
      Serial1.setTX(1);
      Serial1.setRX(0);
      Serial1.begin(31250);
        while (!Serial1 && millis() < 4000 );
      MIDI1.begin(MIDI_CHANNEL_OMNI);
    /*
      Serial2.setTX(8);
      Serial2.setRX(7);
      Serial2.begin(31250);
        while (!Serial2 && millis() < 4000 );
      MIDI2.begin(MIDI_CHANNEL_OMNI);
    
      Serial3.setTX(14);
      Serial3.setRX(15);
      Serial3.begin(31250);
        while (!Serial3 && millis() < 4000 );
      MIDI3.begin(MIDI_CHANNEL_OMNI);
    
      Serial4.setTX(17);
      Serial4.setRX(16);
      Serial4.begin(31250);
        while (!Serial4 && millis() < 4000 );
      MIDI4.begin(MIDI_CHANNEL_OMNI);
    
      Serial5.setTX(20);
      Serial5.setRX(21);
      Serial5.begin(31250);
        while (!Serial5 && millis() < 4000 );
      MIDI5.begin(MIDI_CHANNEL_OMNI);
    
      Serial6.setTX(24);
      Serial6.setRX(25);
      Serial6.begin(31250);
        while (!Serial6 && millis() < 4000 );
      MIDI6.begin(MIDI_CHANNEL_OMNI);
    
      Serial7.setTX(29);
      Serial7.setRX(28);
      Serial7.begin(31250);
        while (!Serial7 && millis() < 4000 );
      MIDI7.begin(MIDI_CHANNEL_OMNI);
    
      Serial8.setTX(35);
      Serial8.setRX(34);
      Serial8.begin(31250);
        while (!Serial8 && millis() < 4000 );
      MIDI8.begin(MIDI_CHANNEL_OMNI);
      
    */
    
      AudioMemory(120);                  // allocate some memory for audio library
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.99);  
      sgtl5000_1.micGain(36);
      
      pink1.amplitude(0.99); 
      dc1.amplitude(1.0);
      
      biquad1.setLowpass(0, 60, 0.53);
      biquad1.setLowpass(1, 90, 0.707);
      biquad1.setLowpass(2, 60, 0.53);
      biquad1.setLowpass(3, 80, 0.707);
    
      biquad2.setLowpass(0, 60, 0.53);
      biquad2.setLowpass(1, 90, 0.707);
      biquad2.setLowpass(2, 60, 0.53);
      biquad2.setLowpass(3, 80, 0.707);
      
      biquad3.setLowpass(0, 60, 0.53);
      biquad3.setLowpass(1, 90, 0.707);
      biquad3.setLowpass(2, 60, 0.53);
      biquad3.setLowpass(3, 80, 0.707);
    
      biquad4.setLowpass(0, 60, 0.53);
      biquad4.setLowpass(1, 90, 0.707);
      biquad4.setLowpass(2, 60, 0.53);
      biquad4.setLowpass(3, 80, 0.707);
    
      biquad5.setLowpass(0, 60, 0.53);
      biquad5.setLowpass(1, 90, 0.707);
      biquad5.setLowpass(2, 60, 0.53);
      biquad5.setLowpass(3, 80, 0.707);
    
      biquad6.setLowpass(0, 60, 0.53);
      biquad6.setLowpass(1, 90, 0.707);
      biquad6.setLowpass(2, 60, 0.53);
      biquad6.setLowpass(3, 80, 0.707);
    
      mixer8.gain(0,1);
      mixer8.gain(1,1);
      mixer8.gain(2,0);
      mixer8.gain(3,0);
      
      mixer9.gain(0,1);
      mixer9.gain(1,1);
      mixer9.gain(2,0);
      mixer9.gain(3,0);
      
      mixer10.gain(0,1);
      mixer10.gain(1,1);
      mixer10.gain(2,0);
      mixer10.gain(3,0);
    
      cvbus.amplitude(0);
      notefreq1.begin(.85);
      chorus1.begin(delayline,CHORUS_DELAY_LENGTH,n_chor  us);
    
    }
    
    void knobcolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 1:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 2:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 3:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 0);
        break;
        case 4:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 5:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 255);
        break;
      }
    }
    
    void knobscolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 1:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 2:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 3:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 255);
        break;
        case 4:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 5:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 0);
        break;
      }
    }
    
                             
    void printarray(){
        Serial.println();
        for(int y = 0; y <=143; y++) { 
          Serial.print(newpos[y]);
          Serial.print(",");
          if ((y >= 1) & (y % 16 ==  0)){
            Serial.println();
          }
        }  
        Serial.println();
    }
    
    void midisend(){
        for(int y = 0; y <=143; y++) { 
          if (abs(midivals[y]) != abs(newpos[y] / 4) % midiquant[y]){
            if (midiquant[y] == 128){
              midivals[y] = abs(newpos[y] / 4) % 128;
            }
            if (midiquant[y] == 8192){
              midivals[y] = newpos[y] / 4 % 8192;
            }
            Serial.print(midichans[y],HEX);
            Serial.print(":");
            Serial.print(midiports[y]);
            Serial.print(":");
            Serial.print(midivals[y]);
            Serial.println();
            usbMIDI.sendControlChange(midiports[y],midivals[y],midichans[y] & 0x0f,0);
            printarray();
          }
        }  
    }
    
    unsigned long lastMicros = micros();
    
    void sequencer(){
        unsigned long currentMicros = micros();
        //Serial.println(currentMicros);
    }
    
    void playportstest(){
    
      //mixer scans
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y] != midivals[y]){
          mixer1.gain(y, (float)midivals[y] * inc);
          mixer2.gain(y, (float)midivals[y] * inc);
          lastval[y] = midivals[y];
          Serial.print("val: ");
          Serial.println((float)midivals[y] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+4] != midivals[y+4]){
          mixer3.gain(y, (float)midivals[y+4] * inc);
          lastval[y+4] = midivals[y+4];
          Serial.print("mixer3val: ");
          Serial.println((float)midivals[y+4] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+8] != midivals[y+8]){
          mixer4.gain(y, (float)midivals[y+8] * inc);
          lastval[y+8] = midivals[y+8];
          Serial.print("mixer4val: ");
          Serial.println((float)midivals[y+8] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+12] != midivals[y+12]){
          mixer5.gain(y, (float)midivals[y+12] * inc);
          lastval[y+12] = midivals[y+12];
          Serial.print("mixer5val: ");
          Serial.println((float)midivals[y+12] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+16] != midivals[y+16]){
          mixer6.gain(y, (float)midivals[y+16] * inc);
          lastval[y+16] = midivals[y+16];
          Serial.print("mixer6val: ");
          Serial.println((float)midivals[y+16] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+20] != midivals[y+20]){
          mixer7.gain(y, (float)midivals[y+20] * inc);
          lastval[y+20] = midivals[y+20];
          Serial.print("mixer7val: ");
          Serial.println((float)midivals[y+20] * inc);  
        }
      }
    
      //now other stuff. this defines how the various midi channels are assigned to the synth functions.
      
      //  lfo1  =============================
        if (lastval[LFO1_SHAPE] != midivals[LFO1_SHAPE]){
          lastval[LFO1_SHAPE] = midivals[LFO1_SHAPE];
          int shape = midivals[LFO1_SHAPE] % 6;
          
          float xSpeed = midivals[LFO1_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo1speed = (7 * xSpeed);
            
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
      
            case _WAVEFORM_SAMPLE_HOLD:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SAMPLE_HOLD);
              Serial.print("WAVEFORM_SAMPLE_HOLD ");
            break;
          }        
          Serial.print("lfo1.frequency: ");
          Serial.println(lfo1speed);  
        }
    
        if (lastval[LFO1_SPEED] != midivals[LFO1_SPEED]){
          lastval[LFO1_SPEED] = midivals[LFO1_SPEED];
          float xSpeed = midivals[LFO1_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo1speed = (MAX_LFO_SPEED * xSpeed);
          waveform1.frequency(lfo1speed);
          Serial.print("lfo1.frequency: ");
          Serial.println(lfo1speed);  
        }
        if (lastval[LFO1_PULSEWIDTH] != midivals[LFO1_PULSEWIDTH]){
          lastval[LFO1_PULSEWIDTH] = midivals[LFO1_PULSEWIDTH];
          waveform1.pulseWidth(midivals[LFO1_PULSEWIDTH]/2);
          Serial.print("lfo1.pulse width: ");
          Serial.println(midivals[LFO1_PULSEWIDTH]/2);  
        }
        if (lastval[LFO1_PHASE] != midivals[LFO1_PHASE]){
          lastval[LFO1_PHASE] = midivals[LFO1_PHASE];
          waveform1.phase((float)midivals[LFO1_PHASE] * inc * MAX_LFO_PHASE);
          Serial.print("lfo1.phase: ");
          Serial.println((float)midivals[LFO1_PHASE] * inc * MAX_LFO_PHASE);  
        }
        
      //  lfo2  =============================
        if (lastval[LFO2_SHAPE] != midivals[LFO2_SHAPE]){
          lastval[LFO2_SHAPE] = midivals[LFO2_SHAPE];
          int shape = midivals[LFO2_SHAPE] % 6;
          
          float xSpeed = midivals[LFO2_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo2speed = (7 * xSpeed);
            
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
      
            case _WAVEFORM_SAMPLE_HOLD:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SAMPLE_HOLD);
              Serial.print("WAVEFORM_SAMPLE_HOLD ");
            break;
          }        
          Serial.print("lfo2.frequency: ");
          Serial.println(lfo2speed);  
        }
    
        if (lastval[LFO2_SPEED] != midivals[LFO2_SPEED]){
          lastval[LFO2_SPEED] = midivals[LFO2_SPEED];
          float xSpeed = midivals[LFO2_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo2speed = (MAX_LFO_SPEED * xSpeed);
          waveform2.frequency(lfo2speed);      
          Serial.print("lfo2.frequency: ");
          Serial.println(lfo2speed);  
        }
        if (lastval[LFO2_PULSEWIDTH] != midivals[LFO2_PULSEWIDTH]){
          lastval[LFO2_PULSEWIDTH] = midivals[LFO2_PULSEWIDTH];
          waveform2.pulseWidth((float)midivals[LFO2_PULSEWIDTH] * inc);
          Serial.print("lfo2.pulse width: ");
          Serial.println((float)midivals[LFO2_PULSEWIDTH] * inc);  
        }
        if (lastval[LFO2_PHASE] != midivals[LFO2_PHASE]){
          lastval[LFO2_PHASE] = midivals[LFO2_PHASE];
          waveform2.phase((float)midivals[LFO2_PHASE] * inc * MAX_LFO_PHASE);
          Serial.print("lfo2.phase: ");
          Serial.println((float)midivals[LFO2_PHASE] * inc * MAX_LFO_PHASE);  
        }
        
      //  osc1  =============================
        if (lastval[OSC1_SHAPE] != midivals[OSC1_SHAPE]){
          lastval[OSC1_SHAPE] = midivals[OSC1_SHAPE];
          int shape = midivals[OSC1_SHAPE] % 5;
          Serial.print("osc1: ");
    
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
          }        
          Serial.print("osc1.frequency: ");
          Serial.println(noteFreqs[midivals[OSC1_FREQUENCY]]);  
        }
    
        if (lastval[OSC1_FREQUENCY] != midivals[OSC1_FREQUENCY]){
          lastval[OSC1_FREQUENCY] = midivals[OSC1_FREQUENCY];
          waveformMod1.frequency(noteFreqs[midivals[OSC1_FREQUENCY]]);
          Serial.print("osc1.frequency: ");
          Serial.println(noteFreqs[midivals[OSC1_FREQUENCY]]);  
        }
        if (lastval[OSC1_SHAPEMOD] != midivals[OSC1_SHAPEMOD]){
          lastval[OSC1_SHAPEMOD] = midivals[OSC1_SHAPEMOD];
          dc3.amplitude((float)midivals[OSC1_SHAPEMOD] * inc);
          Serial.print("osc1 wavemod: ");
          Serial.println((float)midivals[OSC1_SHAPEMOD] * inc);  
        }
        if (lastval[OSC1_FREQMOD] != midivals[OSC1_FREQMOD]){
          lastval[OSC1_FREQMOD] = midivals[OSC1_FREQMOD];
          waveformMod1.frequencyModulation((float)midivals[OSC1_FREQMOD] * inc * MAX_OSC_TRACKING);
          Serial.print("osc1.FM: ");
          Serial.println((float)midivals[OSC1_FREQMOD] * inc * MAX_OSC_TRACKING);  
        }
        
      //  osc2  =============================
        if (lastval[OSC2_SHAPE] != midivals[OSC2_SHAPE]){
          lastval[OSC2_SHAPE] = midivals[OSC2_SHAPE];
          int shape = midivals[OSC2_SHAPE] % 5;
          Serial.print("osc2: ");
    
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
          }        
          Serial.print("osc2.frequency: ");
          Serial.println(noteFreqs[midivals[OSC2_FREQUENCY]]);  
        }
    
        if (lastval[OSC2_FREQUENCY] != midivals[OSC2_FREQUENCY]){
          lastval[OSC2_FREQUENCY] = midivals[OSC2_FREQUENCY];
          waveformMod2.frequency(noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]]);
          Serial.print("osc2.frequency: ");
          Serial.println(noteFreqs[midivals[OSC2_FREQUENCY] + midivals[OSC1_FREQUENCY]]);  
        }
        if (lastval[OSC2_SHAPEMOD] != midivals[OSC2_SHAPEMOD]){
          lastval[OSC2_SHAPEMOD] = midivals[OSC2_SHAPEMOD];
          dc2.amplitude((float)midivals[OSC2_SHAPEMOD] * inc);
          Serial.print("osc2 wavemod: ");
          Serial.println((float)midivals[OSC2_SHAPEMOD] * inc);  
        }
        if (lastval[OSC2_FREQMOD] != midivals[OSC2_FREQMOD]){
          lastval[OSC2_FREQMOD] = midivals[OSC2_FREQMOD];
          waveformMod2.frequencyModulation((float)midivals[OSC2_FREQMOD] * inc * MAX_OSC_TRACKING);
          Serial.print("osc2.FM: ");
          Serial.println((float)midivals[OSC2_FREQMOD] * inc * MAX_OSC_TRACKING);  
        }
        
    // filter
        if (lastval[FILTER1_FREQUENCY] != midivals[FILTER1_FREQUENCY]){
          lastval[FILTER1_FREQUENCY] = midivals[FILTER1_FREQUENCY];
          filter1.frequency(noteFreqs[midivals[FILTER1_FREQUENCY]]);
          Serial.print("filter.frequency: ");
          Serial.println(noteFreqs[midivals[FILTER1_FREQUENCY]]);  
        }
        if (lastval[FILTER1_RESONANCE] != midivals[FILTER1_RESONANCE]){
          lastval[FILTER1_RESONANCE] = midivals[FILTER1_RESONANCE];
          filter1.resonance((float)midivals[FILTER1_RESONANCE] * inc * MAX_FILTER_Q + MIN_FILTER_Q);
          Serial.print("filter.Q: ");
          Serial.println((float)midivals[FILTER1_RESONANCE] * inc * MAX_FILTER_Q + MIN_FILTER_Q);  
        }
        if (lastval[FILTER1_RANGE] != midivals[FILTER1_RANGE]){
          lastval[FILTER1_RANGE] = midivals[FILTER1_RANGE];
          filter1.octaveControl((float)midivals[FILTER1_RANGE] * inc * MAX_FILTER_TRACKING);
          Serial.print("filter.range: ");
          Serial.println((float)midivals[FILTER1_RANGE] * inc * MAX_FILTER_TRACKING );  
        }
        if (lastval[FILTER1_CHORUS] != midivals[FILTER1_CHORUS]){
          lastval[FILTER1_CHORUS] = midivals[FILTER1_CHORUS];
          chorus1.voices(midivals[FILTER1_CHORUS] + 1);
          Serial.print("chorus.size: ");
          Serial.println(midivals[FILTER1_CHORUS] + 1 );  
        }
    
    //expressive controls
    
        if (lastval[CRUSHER1_BITS] != midivals[CRUSHER1_BITS]){
          lastval[CRUSHER1_BITS] = midivals[CRUSHER1_BITS];
          bitcrusher1.bits((midivals[CRUSHER1_BITS] % 16) + 1);
          Serial.print("bitcrusher.bits: ");
          Serial.println((midivals[CRUSHER1_BITS] % 16) + 1);  
        }
        if (lastval[CRUSHER1_SAMPLERATE] != midivals[CRUSHER1_SAMPLERATE]){
          lastval[CRUSHER1_SAMPLERATE] = midivals[CRUSHER1_SAMPLERATE];
          bitcrusher1.sampleRate((float)midivals[CRUSHER1_SAMPLERATE] * inc * 44444);
          Serial.print("bitcruncher:samplerate: ");
          Serial.println((float)midivals[CRUSHER1_SAMPLERATE] * inc * 44444 );  
        }
        if (lastval[FREEVERB1_SIZE] != midivals[FREEVERB1_SIZE]){
          lastval[FREEVERB1_SIZE] = midivals[FREEVERB1_SIZE];
          freeverbs1.roomsize((float)midivals[FREEVERB1_SIZE] * inc);
          Serial.print("freeverbs:roomsize: ");
          Serial.println((float)midivals[FREEVERB1_SIZE] * inc);  
        }
        if (lastval[FREEVERB1_DAMPING] != midivals[FREEVERB1_DAMPING]){
          lastval[FREEVERB1_DAMPING] = midivals[FREEVERB1_DAMPING];
          freeverbs1.damping((float)midivals[FREEVERB1_DAMPING] * inc);
          Serial.print("freeverbs:damping: ");
          Serial.println((float)midivals[FREEVERB1_DAMPING] * inc);  
        }
    
    //adsr
    
        if (lastval[ADSR1_ATTACK] != midivals[ADSR1_ATTACK]){
          lastval[ADSR1_ATTACK] = midivals[ADSR1_ATTACK];
          envelope1.attack((3000 * ((float)midivals[ADSR1_ATTACK] * inc)) + 10.5);//TEST Attack min limit to 10.5ms
          Serial.print("attack1: ");
          Serial.println((3000 * ((float)midivals[ADSR1_ATTACK] * inc)) + 10.5);  
        }
        
        if (lastval[ADSR1_DECAY] != midivals[ADSR1_DECAY]){
          lastval[ADSR1_DECAY] = midivals[ADSR1_DECAY];
          envelope1.decay(3000 * ((float)midivals[ADSR1_DECAY] * inc));
          Serial.print("decay1: ");
          Serial.println((3000 * ((float)midivals[ADSR1_DECAY] * inc)));  
        }
    
        if (lastval[ADSR1_SUSTAIN] != midivals[ADSR1_SUSTAIN]){
          lastval[ADSR1_SUSTAIN] = midivals[ADSR1_SUSTAIN];
          envelope1.sustain((float)midivals[ADSR1_SUSTAIN] * inc);
          Serial.print("sustain1: ");
          Serial.println((float)midivals[ADSR1_SUSTAIN] * inc);  
        }
    
        if (lastval[ADSR1_RELEASE] != midivals[ADSR1_RELEASE]){
          lastval[ADSR1_RELEASE] = midivals[ADSR1_RELEASE];
          envelope1.release((3000 * (midivals[ADSR1_RELEASE] * inc)) + .5);
          Serial.print("release1: ");
          Serial.println((3000 * (midivals[ADSR1_RELEASE] * inc)) + .5);  
        }
    
    
    /*
     peak1;          //xy=1148,150
    */
    }
    void loop(){
    
      newKnobby = knobby.read();
      if (abs(newKnobby - positionKnobby) >= 1) {
        i = abs(newKnobby / 4);
        int rowNum = i % 36 / 6;
        int chanNum = i % 6;
        indexer = (i % 36);
        knobcolor(rowNum);
        knobscolor(chanNum);
        positionKnobby = newKnobby;
        knob0.write(newpos[indexer * 4]);
        knob1.write(newpos[indexer * 4 + 1]);
        knob2.write(newpos[indexer * 4 + 2]);
        knob3.write(newpos[indexer * 4 + 3]);
      }
    
      newKnob0 = knob0.read();
      if (abs(newKnob0 - positionKnob0) >= 1) {
        newpos[indexer * 4] = newKnob0;
     //   printarray();
        positionKnob0 = newKnob0;
      }
    
      newKnob1 = knob1.read();
      if (abs(newKnob1 - positionKnob1) >= 1) {
        newpos[indexer * 4 + 1]  = newKnob1;
    //    printarray();
        positionKnob1 = newKnob1;
      }
    
      newKnob2 = knob2.read();
      if (abs(newKnob2 - positionKnob2) >= 1) {
        newpos[indexer * 4 + 2] = newKnob2;
    //    printarray();
        positionKnob2 = newKnob2;
      }
    
      newKnob3 = knob3.read();
      if (abs(newKnob3 - positionKnob3) >= 1) {
        newpos[indexer * 4 + 3] = newKnob3;
    //    printarray();
        positionKnob3 = newKnob3;
      }
      midisend();
      playportstest();
      sequencer();
    }
    Attached Files Attached Files

  15. #15
    Junior Member
    Join Date
    Jun 2020
    Posts
    1
    Interesting project. Now I am curious :-)

    Could you tell...which encoders do you use? I see three resistors for each, but which one? (1k ?) Do you use a muxer?

  16. #16
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    The encoders are the PEL12T (like 4 bucks each) and the wiring is right in the code, they attach directly to the teensy with no caps or resistors and work great. The resistors are not critical, anything around half a K but all the same value. Three 2n7000 fets drive the 4 rgb all in common right now, in the final version there will be a 16 channel pwm driver running the leds so they can individually flash and change in brightness. Not worried about that until I start working on the midi code for the sequencer. Right now I'm working on integrating the new voices.

    Click image for larger version. 

Name:	Screenshot from 2020-09-04 08-21-51.jpg 
Views:	20 
Size:	109.7 KB 
ID:	21620

  17. #17
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    OK, here's the thing. This project is getting very long, but it's not a lot of modules just of a lot of repeated code and it sort of needs to be that way. How can I put a module in another file and include it in my source without making the included file a freaking object and building constructors and stuff. I just want another page to be included like I include another bash script in a bash script. I'm experienced well in python and many languages, but my c skills have remained primitive it seems. Can anyone offer suggestions on how I might make this thing more manageable before it turns into one page 3000 lines long?

    edit: BTW if you load the sketch on a 4.1 with an audio shield it is a full fledged synth playing a scale, even without the knobs.

    3 LFOs
    4 ADSR generators
    4 8 step sequencers
    3 oscillators (12 planned)
    8 filters
    If you add the five knobs, you get access to the synth and 256 fully routable midi controls.


    Code:
    /* Knobby midi control palette
    */
    
    #include <Encoder.h>
    #include <MIDI.h>
    #include <Bounce.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    
    
    #define _WAVEFORM_SINE 0
    #define _WAVEFORM_SAWTOOTH 1
    #define _WAVEFORM_SAWTOOTH_REVERSE 2
    #define _WAVEFORM_TRIANGLE_VARIABLE 3
    #define _WAVEFORM_PULSE 4
    #define _WAVEFORM_SAMPLE_HOLD 5             
    
    #define LFO1_SHAPE 64
    #define LFO1_SPEED 65
    #define LFO1_PULSEWIDTH 66
    #define LFO1_PHASE 67
    
    #define LFO2_SHAPE 68
    #define LFO2_SPEED 69
    #define LFO2_PULSEWIDTH 70
    #define LFO2_PHASE 71
    
    #define LFO3_SHAPE 72
    #define LFO3_SPEED 73
    #define LFO3_PULSEWIDTH 74
    #define LFO3_PHASE 75
    
    #define SEQ_MASTER_BPM 76
    #define SEQ1_BPM 77
    #define SEQ2_BPM 78
    #define SEQ3_BPM 79
    
    #define OSC1_SHAPE 80
    #define OSC1_FREQUENCY 81
    #define OSC1_SHAPEMOD 82
    #define OSC1_FREQMOD 83
    
    #define OSC2_SHAPE 84
    #define OSC2_FREQUENCY 85
    #define OSC2_SHAPEMOD 86
    #define OSC2_FREQMOD 87
    
    #define OSC3_SHAPE 88
    #define OSC3_FREQUENCY 89
    #define OSC3_SHAPEMOD 90
    #define OSC3_FREQMOD 91
    
    #define OSC4_SHAPE 92
    #define OSC4_FREQUENCY 93
    #define OSC4_SHAPEMOD 94
    #define VOICE2_CRUNCH 95
    
    #define OSC5_SHAPE 96
    #define OSC5_FREQUENCY 97
    #define OSC5_SHAPEMOD 98
    #define VOICE3_CRUNCH 99
    
    #define OSC6_INTEN 92
    #define OSC6_FREQUENCY 93
    #define OSC6_SHAPEMOD 94
    #define VOICE4_CRUNCH 95
    
    #define DRUM1_FREQ 96
    #define DRUM1_SUSTAIN 97
    #define DRUM1_PITCHMOD 98
    #define DRUM1_CRUNCH 99
    
    #define DRUM2_FREQ 100
    #define DRUM2_SUSTAIN 101
    #define DRUM2_PITCHMOD 102
    #define DRUM2_CRUNCH 103
    
    #define FILTER1_FREQUENCY 128
    #define FILTER1_RESONANCE 129
    #define FILTER1_RANGE 130
    #define FILTER1_CHORUS 131
    
    #define FILTER2_FREQUENCY 132
    #define FILTER2_RESONANCE 133
    #define FILTER2_TYPE 134
    #define FILTER2_MOD_DEPTH 135
    
    #define FILTER3_FREQUENCY 136
    #define FILTER3_RESONANCE 137
    #define FILTER3_TYPE 138
    #define FILTER3_MOD_DEPTH 139
    
    #define FILTER4_FREQUENCY 140
    #define FILTER4_RESONANCE 141
    #define FILTER4_TYPE 142
    #define FILTER4_MOD_DEPTH 143
    
    #define FREEVERB1_SIZE 60
    #define FREEVERB1_DAMPING 61
    #define CRUSHER1_BITS 62
    #define CRUSHER1_SAMPLERATE 63
    
    #define ADSR1_ATTACK 160
    #define ADSR1_DECAY 161
    #define ADSR1_SUSTAIN 162
    #define ADSR1_RELEASE 163
    
    #define ADSR2_ATTACK 164
    #define ADSR2_DECAY 165
    #define ADSR2_SUSTAIN 166
    #define ADSR2_RELEASE 167
    
    #define ADSR3_ATTACK 168
    #define ADSR3_DECAY 169
    #define ADSR3_SUSTAIN 170
    #define ADSR3_RELEASE 171
    
    #define ADSR4_ATTACK 172
    #define ADSR4_DECAY 173
    #define ADSR4_SUSTAIN 174
    #define ADSR4_RELEASE 175
    
    #define MAX_LFO_PHASE 360
    #define MAX_LFO_SPEED 64
    #define MAX_FILTER_Q 5
    #define MIN_FILTER_Q 0.707
    #define MAX_OSC_TRACKING 10
    #define MAX_FILTER_TRACKING 7
    
    #define CV_LP_HI 90
    #define CV_LP_MID 80
    #define CV_LP_LO 60
    #define CV_LP_HIQ 0.707
    #define CV_LP_LOQ 0.53
    
    #define SEQ1_ENTRY 224
    #define SEQ2_ENTRY 232
    #define SEQ3_ENTRY 240
    #define SEQ4_ENTRY 248
    
    
    #define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES)
    
    // GUItool: begin automatically generated code
    AudioSynthWaveform       waveform1;      //xy=97,508
    AudioMixer4              mixer6;         //xy=127,88
    AudioMixer4              mixer7;         //xy=128,222
    AudioSynthWaveform       waveform2;      //xy=131,694
    AudioSynthWaveformDc     cvbus;            //xy=260,154
    AudioFilterBiquad        biquad3;        //xy=280,698
    AudioSynthWaveformDc     dc2;            //xy=315,434
    AudioFilterBiquad        biquad2;        //xy=322,548
    AudioSynthWaveformDc     dc3;            //xy=347,349
    AudioMixer4              mixer9;         //xy=435,225
    AudioEffectMultiply      multiply3;      //xy=471,407
    AudioSynthWaveformDc     dc1;            //xy=482,771
    AudioMixer4              mixer8;         //xy=495,89
    AudioEffectMultiply      multiply2;      //xy=495,332
    AudioFilterBiquad        biquad5;        //xy=579,222
    AudioFilterBiquad        biquad4;        //xy=630,90
    AudioEffectEnvelope      envelope1;      //xy=637,771
    AudioSynthWaveformModulated waveformMod2;   //xy=691,380
    AudioSynthWaveformModulated waveformMod1;   //xy=701,299
    AudioSynthNoisePink      pink1;          //xy=716,434
    AudioEffectRectifier          fade1;          //xy=778,157
    AudioMixer4              mixer4;         //xy=847,588
    AudioMixer4              mixer3;         //xy=892,376
    AudioFilterBiquad        biquad1;        //xy=956,106
    AudioMixer4              mixer5;         //xy=994,718
    AudioMixer4              mixer10;        //xy=1021,594
    AudioEffectBitcrusher    bitcrusher1;    //xy=1064,381
    AudioAnalyzePeak         peak1;          //xy=1163,150
    AudioFilterBiquad        biquad6;        //xy=1180,565
    AudioEffectChorus        chorus1;        //xy=1217,326
    AudioFilterStateVariable filter1;        //xy=1263,394
    AudioEffectMultiply      multiply1;      //xy=1419,451
    AudioInputI2S            i2s1;           //xy=1575,192
    AudioEffectFreeverbStereo freeverbs1;     //xy=1688,512
    AudioAnalyzeNoteFrequency notefreq1;      //xy=1785,152
    AudioMixer4              mixer2;         //xy=2091,295
    AudioMixer4              mixer1;         //xy=2098,455
    AudioOutputI2S           i2s2;           //xy=2432,444
    AudioOutputUSB           usb1;           //xy=2439,300
    AudioConnection          patchCord1(waveform1, biquad2);
    AudioConnection          patchCord2(mixer6, 0, multiply2, 0);
    AudioConnection          patchCord3(mixer6, 0, mixer8, 0);
    AudioConnection          patchCord4(mixer7, 0, multiply3, 0);
    AudioConnection          patchCord5(mixer7, 0, mixer9, 0);
    AudioConnection          patchCord6(waveform2, biquad3);
    AudioConnection          patchCord7(cvbus, 0, mixer9, 1);
    AudioConnection          patchCord8(cvbus, 0, mixer8, 1);
    AudioConnection          patchCord9(cvbus, 0, mixer10, 1);
    AudioConnection          patchCord10(biquad3, 0, mixer5, 1);
    AudioConnection          patchCord11(biquad3, 0, mixer4, 1);
    AudioConnection          patchCord12(biquad3, 0, mixer6, 1);
    AudioConnection          patchCord13(biquad3, 0, mixer7, 1);
    AudioConnection          patchCord14(dc2, 0, multiply3, 1);
    AudioConnection          patchCord15(biquad2, 0, mixer5, 0);
    AudioConnection          patchCord16(biquad2, 0, mixer4, 0);
    AudioConnection          patchCord17(biquad2, 0, mixer7, 0);
    AudioConnection          patchCord18(biquad2, 0, mixer6, 0);
    AudioConnection          patchCord19(dc3, 0, multiply2, 1);
    AudioConnection          patchCord20(mixer9, biquad5);
    AudioConnection          patchCord21(multiply3, 0, waveformMod2, 1);
    AudioConnection          patchCord22(dc1, envelope1);
    AudioConnection          patchCord23(mixer8, biquad4);
    AudioConnection          patchCord24(multiply2, 0, waveformMod1, 1);
    AudioConnection          patchCord25(biquad5, 0, waveformMod2, 0);
    AudioConnection          patchCord26(biquad4, 0, waveformMod1, 0);
    AudioConnection          patchCord27(envelope1, 0, mixer5, 3);
    AudioConnection          patchCord28(envelope1, 0, mixer4, 3);
    AudioConnection          patchCord29(envelope1, 0, mixer6, 3);
    AudioConnection          patchCord30(envelope1, 0, mixer7, 3);
    AudioConnection          patchCord31(waveformMod2, 0, mixer3, 1);
    AudioConnection          patchCord32(waveformMod1, 0, mixer3, 0);
    AudioConnection          patchCord33(pink1, 0, mixer3, 2);
    AudioConnection          patchCord34(fade1, biquad1);
    AudioConnection          patchCord35(mixer4, 0, mixer10, 0);
    AudioConnection          patchCord36(mixer3, bitcrusher1);
    AudioConnection          patchCord37(biquad1, 0, mixer4, 2);
    AudioConnection          patchCord38(biquad1, 0, mixer5, 2);
    AudioConnection          patchCord39(biquad1, peak1);
    AudioConnection          patchCord40(biquad1, 0, mixer6, 2);
    AudioConnection          patchCord41(biquad1, 0, mixer7, 2);
    AudioConnection          patchCord42(mixer5, 0, multiply1, 1);
    AudioConnection          patchCord43(mixer10, biquad6);
    AudioConnection          patchCord44(bitcrusher1, chorus1);
    AudioConnection          patchCord45(biquad6, 0, filter1, 1);
    AudioConnection          patchCord46(chorus1, 0, filter1, 0);
    AudioConnection          patchCord47(filter1, 0, multiply1, 0);
    AudioConnection          patchCord48(multiply1, 0, mixer2, 1);
    AudioConnection          patchCord49(multiply1, 0, mixer1, 1);
    AudioConnection          patchCord50(multiply1, freeverbs1);
    AudioConnection          patchCord51(i2s1, 0, mixer2, 0);
    AudioConnection          patchCord52(i2s1, 0, mixer3, 3);
    AudioConnection          patchCord53(i2s1, 0, fade1, 0);
    AudioConnection          patchCord54(i2s1, 0, notefreq1, 0);
    AudioConnection          patchCord55(i2s1, 1, mixer1, 0);
    AudioConnection          patchCord56(freeverbs1, 0, mixer2, 3);
    AudioConnection          patchCord57(freeverbs1, 1, mixer1, 3);
    AudioConnection          patchCord58(mixer2, 0, i2s2, 0);
    AudioConnection          patchCord59(mixer2, 0, usb1, 0);
    AudioConnection          patchCord60(mixer1, 0, i2s2, 1);
    AudioConnection          patchCord61(mixer1, 0, usb1, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=2063,702
    // GUItool: end automatically generated code
    
    
    
    /*
    // Number of samples in each delay line
    #define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES)
    // Allocate the delay lines for left and right channels
    short delayline[CHORUS_DELAY_LENGTH];
    int n_chorus = 1;
    */
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, MIDI2);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial3, MIDI3);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial4, MIDI4);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial5, MIDI5);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial6, MIDI6);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial7, MIDI7);
    //MIDI_CREATE_INSTANCE(HardwareSerial, Serial8, MIDI8);
    
    
    short delayline[CHORUS_DELAY_LENGTH];
    int n_chorus = 3;
    const int myInput = AUDIO_INPUT_MIC;
    
    const int redPin =  2;
    const int greenPin =  3;
    const int bluePin =  4;
    const int mredPin =  37;
    const int mgreenPin =  36;
    const int mbluePin =  33;
    
    Encoder knobby(34, 35);
    Encoder knob0(32, 31);
    Encoder knob1(30, 29);
    Encoder knob2(28, 27);
    Encoder knob3(26, 25);
    
    long positionKnobby,positionKnob0,positionKnob1,positionKnob2,positionKnob3  = 0;
    long newKnobby,newKnob0,newKnob1,newKnob2,newKnob3 = 0;
    
    long newpos[256] = {0,228,4,280,128,152,0,0,0,0,512,0,1,0,0,508,-1,
                        0,0,0,0,4,0,4,68,518,168,56,84,332,160,124,156,
                        464,4,8,100,492,308,92,12,187,264,36,32,113,224,300,320,
                        456,1020,4,200,1024,288,72,16,4,0,4,96,140,63,508,-8,
                        135,0,4,0,-16,0,0,8,8,0,0,1168,12,8,-1,4,
                        -1,0,508,-8,6,0,508,0,0,0,0,0,0,0,0,8,
                        12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,24,0,0,0,416,
                        84,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
                        40,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,
                        140,132,164,148,172,260,289,116,112,144,164,84,108,232,104,180,
                        240,184,168,84,104,88,80,128,144,128,144,132,144,128,128};
    
     
    int lastval[256] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                        128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128};
                                 
    int midivals[256];
    
    int midiquant[256] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
                          128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128};
    
    int midiports[256] = {60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,
                          60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91};
                  
    int midichans[256] = {0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
                          0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
                          0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,
                          0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,
                          0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,
                          0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,
                          0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,
                          0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8};
    int i;
    int indexer;
    
    const float inc = (float)1/127;
    
    PROGMEM const float noteFreqs[128] = {8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602,
                                  21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27,
                                  61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563,
                                  164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995,
                                  415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767,
                                  1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461,
                                  2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032,
                                  5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85};
    
    void setup()   {                
      pinMode(redPin, OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin, OUTPUT);
      pinMode(mredPin, OUTPUT);
      pinMode(mgreenPin, OUTPUT);
      pinMode(mbluePin, OUTPUT);
      knobby.write(768);
      knob0.write(1);
      knob1.write(1);
      knob2.write(1);
      knob3.write(1);
      
      Serial1.setTX(1);
      Serial1.setRX(0);
      Serial1.begin(31250);
        while (!Serial1 && millis() < 4000 );
      MIDI1.begin(MIDI_CHANNEL_OMNI);
    /*
      Serial2.setTX(8);
      Serial2.setRX(7);
      Serial2.begin(31250);
        while (!Serial2 && millis() < 4000 );
      MIDI2.begin(MIDI_CHANNEL_OMNI);
    
      Serial3.setTX(14);
      Serial3.setRX(15);
      Serial3.begin(31250);
        while (!Serial3 && millis() < 4000 );
      MIDI3.begin(MIDI_CHANNEL_OMNI);
    
      Serial4.setTX(17);
      Serial4.setRX(16);
      Serial4.begin(31250);
        while (!Serial4 && millis() < 4000 );
      MIDI4.begin(MIDI_CHANNEL_OMNI);
    
      Serial5.setTX(20);
      Serial5.setRX(21);
      Serial5.begin(31250);
        while (!Serial5 && millis() < 4000 );
      MIDI5.begin(MIDI_CHANNEL_OMNI);
    
      Serial6.setTX(24);
      Serial6.setRX(25);
      Serial6.begin(31250);
        while (!Serial6 && millis() < 4000 );
      MIDI6.begin(MIDI_CHANNEL_OMNI);
    
      Serial7.setTX(29);
      Serial7.setRX(28);
      Serial7.begin(31250);
        while (!Serial7 && millis() < 4000 );
      MIDI7.begin(MIDI_CHANNEL_OMNI);
    
      Serial8.setTX(35);
      Serial8.setRX(34);
      Serial8.begin(31250);
        while (!Serial8 && millis() < 4000 );
      MIDI8.begin(MIDI_CHANNEL_OMNI);
      
    */
    
      AudioMemory(120);                  // allocate some memory for audio library
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.99);  
      sgtl5000_1.micGain(36);
      
      pink1.amplitude(0.99); 
      dc1.amplitude(1.0);
      
      biquad1.setLowpass(0, CV_LP_LO, CV_LP_LOQ);
      biquad1.setLowpass(1, CV_LP_HI, CV_LP_HIQ);
      biquad1.setLowpass(2, CV_LP_LO, CV_LP_LOQ);
      biquad1.setLowpass(3, CV_LP_MID, CV_LP_HIQ);
    
      biquad2.setLowpass(0, CV_LP_LO, CV_LP_LOQ);
      biquad2.setLowpass(1, CV_LP_HI, CV_LP_HIQ);
      biquad2.setLowpass(2, CV_LP_LO, CV_LP_LOQ);
      biquad2.setLowpass(3, CV_LP_MID, CV_LP_HIQ);
      
      biquad3.setLowpass(0, CV_LP_LO, CV_LP_LOQ);
      biquad3.setLowpass(1, CV_LP_HI, CV_LP_HIQ);
      biquad3.setLowpass(2, CV_LP_LO, CV_LP_LOQ);
      biquad3.setLowpass(3, CV_LP_MID, CV_LP_HIQ);
    
      biquad4.setLowpass(0, CV_LP_LO, CV_LP_LOQ);
      biquad4.setLowpass(1, CV_LP_HI, CV_LP_HIQ);
      biquad4.setLowpass(2, CV_LP_LO, CV_LP_LOQ);
      biquad4.setLowpass(3, CV_LP_MID, CV_LP_HIQ);
    
      biquad5.setLowpass(0, CV_LP_LO, CV_LP_LOQ);
      biquad5.setLowpass(1, CV_LP_HI, CV_LP_HIQ);
      biquad5.setLowpass(2, CV_LP_LO, CV_LP_LOQ);
      biquad5.setLowpass(3, CV_LP_MID, CV_LP_HIQ);
    
      biquad6.setLowpass(0, CV_LP_LO, CV_LP_LOQ);
      biquad6.setLowpass(1, CV_LP_HI, CV_LP_HIQ);
      biquad6.setLowpass(2, CV_LP_LO, CV_LP_LOQ);
      biquad6.setLowpass(3, CV_LP_MID, CV_LP_HIQ);
    
      mixer8.gain(0,1);
      mixer8.gain(1,1);
      mixer8.gain(2,0);
      mixer8.gain(3,0);
      
      mixer9.gain(0,1);
      mixer9.gain(1,1);
      mixer9.gain(2,0);
      mixer9.gain(3,0);
      
      mixer10.gain(0,1);
      mixer10.gain(1,1);
      mixer10.gain(2,0);
      mixer10.gain(3,0);
    
      cvbus.amplitude(0);
      notefreq1.begin(.85);
      chorus1.begin(delayline,CHORUS_DELAY_LENGTH,n_chorus);
    
    }
    
    void knobcolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 2:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 3:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 1:
          analogWrite(mredPin, 192);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 255);
        break;
        case 4:
          analogWrite(mredPin, 255);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 0);
        break;
        case 5:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 0);
          analogWrite(mgreenPin, 0);
        break;
        case 6:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 0);
        break;
        case 7:
          analogWrite(mredPin, 0);
          analogWrite(mbluePin, 255);
          analogWrite(mgreenPin, 255);
        break;
      }
    }
    
    void knobscolor(int colornum){
      switch(colornum) {
        case 0:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 2:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 3:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 1:
          analogWrite(redPin, 63);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 0);
        break;
        case 4:
          analogWrite(redPin, 0);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 255);
        break;
        case 5:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 255);
          analogWrite(greenPin, 255);
        break;
        case 6:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 255);
        break;
        case 7:
          analogWrite(redPin, 255);
          analogWrite(bluePin, 0);
          analogWrite(greenPin, 0);
        break;
      }
    }
    
                             
    void printarray(){
        Serial.println();
        for(int y = 0; y <=255; y++) { 
          Serial.print(newpos[y]);
          Serial.print(",");
          if ((y >= 1) & (y % 16 ==  0)){
            Serial.println();
          }
        }  
        Serial.println();
    }
    
    
    void midisend(){
        for(int y = 0; y <=255; y++) { 
          if (abs(midivals[y]) != abs(newpos[y] / 4) % midiquant[y]){
            if (midiquant[y] == 128){
              midivals[y] = abs(newpos[y] / 4) % 128;
            }
            if (midiquant[y] == 8192){
              midivals[y] = newpos[y] / 4 % 8192;
            }
            Serial.print(y);
            Serial.print("--");
            Serial.print(midichans[y],HEX);
            Serial.print(":");
            Serial.print(midiports[y]);
            Serial.print(":");
            Serial.print(midivals[y]);
            Serial.println();
            usbMIDI.sendControlChange(midiports[y],midivals[y],midichans[y] & 0x0f,0);
            printarray();
          }
        }  
    }
    
    unsigned long lastMicros = micros();
    unsigned long note1 = 0;
    unsigned long note2 = 0;
    unsigned long note3 = 0;
    unsigned long note4 = 0;
    
    void sequencer(){
        unsigned long currentMicros = micros();
        int bpm = midivals[SEQ_MASTER_BPM] + 1;
        bpm = bpm * 4;
        
    //    if (currentMicros - lastMicros >= round((60000/(midivals[SEQ_MASTER_BPM] + 1) * 4))*1000){
        if (currentMicros - lastMicros >= round((60000/bpm)*1000)){
          lastMicros = currentMicros;
          note1 = (note1 + 1) % 8;
          cvbus.amplitude((float)midivals[SEQ1_ENTRY + note1] * inc);
          envelope1.noteOn();
          Serial.println(bpm);
          Serial.println(currentMicros);
        }
    }
    
    void playportstest(){
    
      //mixer scans
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y] != midivals[y]){
          mixer1.gain(y, (float)midivals[y] * inc);
          mixer2.gain(y, (float)midivals[y] * inc);
          lastval[y] = midivals[y];
          Serial.print("val: ");
          Serial.println((float)midivals[y] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+4] != midivals[y+4]){
          mixer3.gain(y, (float)midivals[y+4] * inc);
          lastval[y+4] = midivals[y+4];
          Serial.print("mixer3val: ");
          Serial.println((float)midivals[y+4] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+8] != midivals[y+8]){
          mixer4.gain(y, (float)midivals[y+8] * inc);
          lastval[y+8] = midivals[y+8];
          Serial.print("mixer4val: ");
          Serial.println((float)midivals[y+8] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+12] != midivals[y+12]){
          mixer5.gain(y, (float)midivals[y+12] * inc);
          lastval[y+12] = midivals[y+12];
          Serial.print("mixer5val: ");
          Serial.println((float)midivals[y+12] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+16] != midivals[y+16]){
          mixer6.gain(y, (float)midivals[y+16] * inc);
          lastval[y+16] = midivals[y+16];
          Serial.print("mixer6val: ");
          Serial.println((float)midivals[y+16] * inc);  
        }
      }
    
      for(int y = 0; y <=3; y++) { 
      
        if (lastval[y+20] != midivals[y+20]){
          mixer7.gain(y, (float)midivals[y+20] * inc);
          lastval[y+20] = midivals[y+20];
          Serial.print("mixer7val: ");
          Serial.println((float)midivals[y+20] * inc);  
        }
      }
    
      //now other stuff. this defines how the various midi channels are assigned to the synth functions.
      
      //  lfo1  =============================
        if (lastval[LFO1_SHAPE] != midivals[LFO1_SHAPE]){
          lastval[LFO1_SHAPE] = midivals[LFO1_SHAPE];
          int shape = midivals[LFO1_SHAPE] % 6;
          
          float xSpeed = midivals[LFO1_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo1speed = (7 * xSpeed);
            
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
      
            case _WAVEFORM_SAMPLE_HOLD:
              waveform1.begin(1.0, lfo1speed, WAVEFORM_SAMPLE_HOLD);
              Serial.print("WAVEFORM_SAMPLE_HOLD ");
            break;
          }        
          Serial.print("lfo1.frequency: ");
          Serial.println(lfo1speed);  
        }
    
        if (lastval[LFO1_SPEED] != midivals[LFO1_SPEED]){
          lastval[LFO1_SPEED] = midivals[LFO1_SPEED];
          float xSpeed = midivals[LFO1_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo1speed = (MAX_LFO_SPEED * xSpeed);
          waveform1.frequency(lfo1speed);
          Serial.print("lfo1.frequency: ");
          Serial.println(lfo1speed);  
        }
        if (lastval[LFO1_PULSEWIDTH] != midivals[LFO1_PULSEWIDTH]){
          lastval[LFO1_PULSEWIDTH] = midivals[LFO1_PULSEWIDTH];
          waveform1.pulseWidth(midivals[LFO1_PULSEWIDTH]/2);
          Serial.print("lfo1.pulse width: ");
          Serial.println(midivals[LFO1_PULSEWIDTH]/2);  
        }
        if (lastval[LFO1_PHASE] != midivals[LFO1_PHASE]){
          lastval[LFO1_PHASE] = midivals[LFO1_PHASE];
          waveform1.phase((float)midivals[LFO1_PHASE] * inc * MAX_LFO_PHASE);
          Serial.print("lfo1.phase: ");
          Serial.println((float)midivals[LFO1_PHASE] * inc * MAX_LFO_PHASE);  
        }
        
      //  lfo2  =============================
        if (lastval[LFO2_SHAPE] != midivals[LFO2_SHAPE]){
          lastval[LFO2_SHAPE] = midivals[LFO2_SHAPE];
          int shape = midivals[LFO2_SHAPE] % 6;
          
          float xSpeed = midivals[LFO2_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo2speed = (7 * xSpeed);
            
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
      
            case _WAVEFORM_SAMPLE_HOLD:
              waveform2.begin(1.0, lfo2speed, WAVEFORM_SAMPLE_HOLD);
              Serial.print("WAVEFORM_SAMPLE_HOLD ");
            break;
          }        
          Serial.print("lfo2.frequency: ");
          Serial.println(lfo2speed);  
        }
    
        if (lastval[LFO2_SPEED] != midivals[LFO2_SPEED]){
          lastval[LFO2_SPEED] = midivals[LFO2_SPEED];
          float xSpeed = midivals[LFO2_SPEED] * inc;
          xSpeed = pow(100, (xSpeed - 1));
          float lfo2speed = (MAX_LFO_SPEED * xSpeed);
          waveform2.frequency(lfo2speed);      
          Serial.print("lfo2.frequency: ");
          Serial.println(lfo2speed);  
        }
        if (lastval[LFO2_PULSEWIDTH] != midivals[LFO2_PULSEWIDTH]){
          lastval[LFO2_PULSEWIDTH] = midivals[LFO2_PULSEWIDTH];
          waveform2.pulseWidth((float)midivals[LFO2_PULSEWIDTH] * inc);
          Serial.print("lfo2.pulse width: ");
          Serial.println((float)midivals[LFO2_PULSEWIDTH] * inc);  
        }
        if (lastval[LFO2_PHASE] != midivals[LFO2_PHASE]){
          lastval[LFO2_PHASE] = midivals[LFO2_PHASE];
          waveform2.phase((float)midivals[LFO2_PHASE] * inc * MAX_LFO_PHASE);
          Serial.print("lfo2.phase: ");
          Serial.println((float)midivals[LFO2_PHASE] * inc * MAX_LFO_PHASE);  
        }
        
      //  osc1  =============================
        if (lastval[OSC1_SHAPE] != midivals[OSC1_SHAPE]){
          lastval[OSC1_SHAPE] = midivals[OSC1_SHAPE];
          int shape = midivals[OSC1_SHAPE] % 5;
          Serial.print("osc1: ");
    
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveformMod1.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY]], WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
          }        
          Serial.print("osc1.frequency: ");
          Serial.println(noteFreqs[midivals[OSC1_FREQUENCY]]);  
        }
    
        if (lastval[OSC1_FREQUENCY] != midivals[OSC1_FREQUENCY]){
          lastval[OSC1_FREQUENCY] = midivals[OSC1_FREQUENCY];
          waveformMod1.frequency(noteFreqs[midivals[OSC1_FREQUENCY]]);
          waveformMod2.frequency(noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]]);
          Serial.print("osc1.frequency: ");
          Serial.println(noteFreqs[midivals[OSC1_FREQUENCY]]);  
        }
        if (lastval[OSC1_SHAPEMOD] != midivals[OSC1_SHAPEMOD]){
          lastval[OSC1_SHAPEMOD] = midivals[OSC1_SHAPEMOD];
          dc3.amplitude((float)midivals[OSC1_SHAPEMOD] * inc);
          Serial.print("osc1 wavemod: ");
          Serial.println((float)midivals[OSC1_SHAPEMOD] * inc);  
        }
        if (lastval[OSC1_FREQMOD] != midivals[OSC1_FREQMOD]){
          lastval[OSC1_FREQMOD] = midivals[OSC1_FREQMOD];
          waveformMod1.frequencyModulation((float)midivals[OSC1_FREQMOD] * inc * MAX_OSC_TRACKING);
          Serial.print("osc1.FM: ");
          Serial.println((float)midivals[OSC1_FREQMOD] * inc * MAX_OSC_TRACKING);  
        }
        
      //  osc2  =============================
        if (lastval[OSC2_SHAPE] != midivals[OSC2_SHAPE]){
          lastval[OSC2_SHAPE] = midivals[OSC2_SHAPE];
          int shape = midivals[OSC2_SHAPE] % 5;
          Serial.print("osc2: ");
    
          switch(shape){
          
            case _WAVEFORM_SINE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_SINE);
              Serial.print("WAVEFORM_SINE ");
            break;
      
            case _WAVEFORM_SAWTOOTH:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_SAWTOOTH);
              Serial.print("WAVEFORM_SAWTOOTH ");
            break;
      
            case _WAVEFORM_SAWTOOTH_REVERSE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_SAWTOOTH_REVERSE);
              Serial.print("WAVEFORM_SAWTOOTH_REVERSE ");
            break;
      
            case _WAVEFORM_PULSE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_PULSE);
              Serial.print("WAVEFORM_PULSE ");
            break;
      
            case _WAVEFORM_TRIANGLE_VARIABLE:
              waveformMod2.begin(1.0, noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]], WAVEFORM_TRIANGLE_VARIABLE);
              Serial.print("WAVEFORM_TRIANGLE_VARIABLE ");
            break;
          }        
          Serial.print("osc2.frequency: ");
          Serial.println(noteFreqs[midivals[OSC2_FREQUENCY]]);  
        }
    
        if (lastval[OSC2_FREQUENCY] != midivals[OSC2_FREQUENCY]){
          lastval[OSC2_FREQUENCY] = midivals[OSC2_FREQUENCY];
          waveformMod2.frequency(noteFreqs[midivals[OSC1_FREQUENCY] + midivals[OSC2_FREQUENCY]]);
          Serial.print("osc2.frequency: ");
          Serial.println(noteFreqs[midivals[OSC2_FREQUENCY] + midivals[OSC1_FREQUENCY]]);  
        }
        if (lastval[OSC2_SHAPEMOD] != midivals[OSC2_SHAPEMOD]){
          lastval[OSC2_SHAPEMOD] = midivals[OSC2_SHAPEMOD];
          dc2.amplitude((float)midivals[OSC2_SHAPEMOD] * inc);
          Serial.print("osc2 wavemod: ");
          Serial.println((float)midivals[OSC2_SHAPEMOD] * inc);  
        }
        if (lastval[OSC2_FREQMOD] != midivals[OSC2_FREQMOD]){
          lastval[OSC2_FREQMOD] = midivals[OSC2_FREQMOD];
          waveformMod2.frequencyModulation((float)midivals[OSC2_FREQMOD] * inc * MAX_OSC_TRACKING);
          Serial.print("osc2.FM: ");
          Serial.println((float)midivals[OSC2_FREQMOD] * inc * MAX_OSC_TRACKING);  
        }
        
    // filter
        if (lastval[FILTER1_FREQUENCY] != midivals[FILTER1_FREQUENCY]){
          lastval[FILTER1_FREQUENCY] = midivals[FILTER1_FREQUENCY];
          filter1.frequency(noteFreqs[midivals[FILTER1_FREQUENCY]]);
          Serial.print("filter.frequency: ");
          Serial.println(noteFreqs[midivals[FILTER1_FREQUENCY]]);  
        }
        if (lastval[FILTER1_RESONANCE] != midivals[FILTER1_RESONANCE]){
          lastval[FILTER1_RESONANCE] = midivals[FILTER1_RESONANCE];
          filter1.resonance((float)midivals[FILTER1_RESONANCE] * inc * MAX_FILTER_Q + MIN_FILTER_Q);
          Serial.print("filter.Q: ");
          Serial.println((float)midivals[FILTER1_RESONANCE] * inc * MAX_FILTER_Q + MIN_FILTER_Q);  
        }
        if (lastval[FILTER1_RANGE] != midivals[FILTER1_RANGE]){
          lastval[FILTER1_RANGE] = midivals[FILTER1_RANGE];
          filter1.octaveControl((float)midivals[FILTER1_RANGE] * inc * MAX_FILTER_TRACKING);
          Serial.print("filter.range: ");
          Serial.println((float)midivals[FILTER1_RANGE] * inc * MAX_FILTER_TRACKING );  
        }
        if (lastval[FILTER1_CHORUS] != midivals[FILTER1_CHORUS]){
          lastval[FILTER1_CHORUS] = midivals[FILTER1_CHORUS];
          chorus1.voices(midivals[FILTER1_CHORUS] + 1);
          Serial.print("chorus.size: ");
          Serial.println(midivals[FILTER1_CHORUS] + 1 );  
        }
    
    //expressive controls
    
        if (lastval[CRUSHER1_BITS] != midivals[CRUSHER1_BITS]){
          lastval[CRUSHER1_BITS] = midivals[CRUSHER1_BITS];
          bitcrusher1.bits((midivals[CRUSHER1_BITS] % 16) + 1);
          Serial.print("bitcrusher.bits: ");
          Serial.println((midivals[CRUSHER1_BITS] % 16) + 1);  
        }
        if (lastval[CRUSHER1_SAMPLERATE] != midivals[CRUSHER1_SAMPLERATE]){
          lastval[CRUSHER1_SAMPLERATE] = midivals[CRUSHER1_SAMPLERATE];
          bitcrusher1.sampleRate((float)midivals[CRUSHER1_SAMPLERATE] * inc * 44444);
          Serial.print("bitcruncher:samplerate: ");
          Serial.println((float)midivals[CRUSHER1_SAMPLERATE] * inc * 44444 );  
        }
        if (lastval[FREEVERB1_SIZE] != midivals[FREEVERB1_SIZE]){
          lastval[FREEVERB1_SIZE] = midivals[FREEVERB1_SIZE];
          freeverbs1.roomsize((float)midivals[FREEVERB1_SIZE] * inc);
          Serial.print("freeverbs:roomsize: ");
          Serial.println((float)midivals[FREEVERB1_SIZE] * inc);  
        }
        if (lastval[FREEVERB1_DAMPING] != midivals[FREEVERB1_DAMPING]){
          lastval[FREEVERB1_DAMPING] = midivals[FREEVERB1_DAMPING];
          freeverbs1.damping((float)midivals[FREEVERB1_DAMPING] * inc);
          Serial.print("freeverbs:damping: ");
          Serial.println((float)midivals[FREEVERB1_DAMPING] * inc);  
        }
    
    //adsr
    
        if (lastval[ADSR1_ATTACK] != midivals[ADSR1_ATTACK]){
          lastval[ADSR1_ATTACK] = midivals[ADSR1_ATTACK];
          envelope1.attack((3000 * ((float)midivals[ADSR1_ATTACK] * inc)) + 10.5);//TEST Attack min limit to 10.5ms
          Serial.print("attack1: ");
          Serial.println((3000 * ((float)midivals[ADSR1_ATTACK] * inc)) + 10.5);  
        }
        
        if (lastval[ADSR1_DECAY] != midivals[ADSR1_DECAY]){
          lastval[ADSR1_DECAY] = midivals[ADSR1_DECAY];
          envelope1.decay(3000 * ((float)midivals[ADSR1_DECAY] * inc));
          Serial.print("decay1: ");
          Serial.println((3000 * ((float)midivals[ADSR1_DECAY] * inc)));  
        }
    
        if (lastval[ADSR1_SUSTAIN] != midivals[ADSR1_SUSTAIN]){
          lastval[ADSR1_SUSTAIN] = midivals[ADSR1_SUSTAIN];
          envelope1.sustain((float)midivals[ADSR1_SUSTAIN] * inc);
          Serial.print("sustain1: ");
          Serial.println((float)midivals[ADSR1_SUSTAIN] * inc);  
        }
    
        if (lastval[ADSR1_RELEASE] != midivals[ADSR1_RELEASE]){
          lastval[ADSR1_RELEASE] = midivals[ADSR1_RELEASE];
          envelope1.release((3000 * (midivals[ADSR1_RELEASE] * inc)) + .5);
          Serial.print("release1: ");
          Serial.println((3000 * (midivals[ADSR1_RELEASE] * inc)) + .5);  
        }
    
        if (lastval[ADSR2_ATTACK] != midivals[ADSR2_ATTACK]){
          lastval[ADSR2_ATTACK] = midivals[ADSR2_ATTACK];
          envelope1.attack((3000 * ((float)midivals[ADSR2_ATTACK] * inc)) + 10.5);//TEST Attack min limit to 10.5ms
          Serial.print("attack2: ");
          Serial.println((3000 * ((float)midivals[ADSR2_ATTACK] * inc)) + 10.5);  
        }
        
        if (lastval[ADSR2_DECAY] != midivals[ADSR2_DECAY]){
          lastval[ADSR2_DECAY] = midivals[ADSR2_DECAY];
          envelope1.decay(3000 * ((float)midivals[ADSR2_DECAY] * inc));
          Serial.print("decay2: ");
          Serial.println((3000 * ((float)midivals[ADSR2_DECAY] * inc)));  
        }
    
        if (lastval[ADSR2_SUSTAIN] != midivals[ADSR2_SUSTAIN]){
          lastval[ADSR2_SUSTAIN] = midivals[ADSR2_SUSTAIN];
          envelope1.sustain((float)midivals[ADSR2_SUSTAIN] * inc);
          Serial.print("sustain2: ");
          Serial.println((float)midivals[ADSR2_SUSTAIN] * inc);  
        }
    
        if (lastval[ADSR2_RELEASE] != midivals[ADSR2_RELEASE]){
          lastval[ADSR2_RELEASE] = midivals[ADSR2_RELEASE];
          envelope1.release((3000 * (midivals[ADSR2_RELEASE] * inc)) + .5);
          Serial.print("release2: ");
          Serial.println((3000 * (midivals[ADSR2_RELEASE] * inc)) + .5);  
        }
    
        if (lastval[ADSR3_ATTACK] != midivals[ADSR3_ATTACK]){
          lastval[ADSR3_ATTACK] = midivals[ADSR3_ATTACK];
          envelope1.attack((3000 * ((float)midivals[ADSR3_ATTACK] * inc)) + 10.5);//TEST Attack min limit to 10.5ms
          Serial.print("attack3: ");
          Serial.println((3000 * ((float)midivals[ADSR3_ATTACK] * inc)) + 10.5);  
        }
        
        if (lastval[ADSR3_DECAY] != midivals[ADSR3_DECAY]){
          lastval[ADSR3_DECAY] = midivals[ADSR3_DECAY];
          envelope1.decay(3000 * ((float)midivals[ADSR3_DECAY] * inc));
          Serial.print("decay3: ");
          Serial.println((3000 * ((float)midivals[ADSR3_DECAY] * inc)));  
        }
    
        if (lastval[ADSR3_SUSTAIN] != midivals[ADSR3_SUSTAIN]){
          lastval[ADSR3_SUSTAIN] = midivals[ADSR3_SUSTAIN];
          envelope1.sustain((float)midivals[ADSR3_SUSTAIN] * inc);
          Serial.print("sustain3: ");
          Serial.println((float)midivals[ADSR3_SUSTAIN] * inc);  
        }
    
        if (lastval[ADSR3_RELEASE] != midivals[ADSR3_RELEASE]){
          lastval[ADSR3_RELEASE] = midivals[ADSR3_RELEASE];
          envelope1.release((3000 * (midivals[ADSR3_RELEASE] * inc)) + .5);
          Serial.print("release3: ");
          Serial.println((3000 * (midivals[ADSR3_RELEASE] * inc)) + .5);  
        }
    
        if (lastval[ADSR4_ATTACK] != midivals[ADSR4_ATTACK]){
          lastval[ADSR4_ATTACK] = midivals[ADSR4_ATTACK];
          envelope1.attack((3000 * ((float)midivals[ADSR4_ATTACK] * inc)) + 10.5);//TEST Attack min limit to 10.5ms
          Serial.print("attack4: ");
          Serial.println((3000 * ((float)midivals[ADSR4_ATTACK] * inc)) + 10.5);  
        }
        
        if (lastval[ADSR4_DECAY] != midivals[ADSR4_DECAY]){
          lastval[ADSR4_DECAY] = midivals[ADSR4_DECAY];
          envelope1.decay(3000 * ((float)midivals[ADSR4_DECAY] * inc));
          Serial.print("decay4: ");
          Serial.println((3000 * ((float)midivals[ADSR4_DECAY] * inc)));  
        }
    
        if (lastval[ADSR4_SUSTAIN] != midivals[ADSR4_SUSTAIN]){
          lastval[ADSR4_SUSTAIN] = midivals[ADSR4_SUSTAIN];
          envelope1.sustain((float)midivals[ADSR4_SUSTAIN] * inc);
          Serial.print("sustain4: ");
          Serial.println((float)midivals[ADSR4_SUSTAIN] * inc);  
        }
    
        if (lastval[ADSR4_RELEASE] != midivals[ADSR4_RELEASE]){
          lastval[ADSR4_RELEASE] = midivals[ADSR4_RELEASE];
          envelope1.release((3000 * (midivals[ADSR4_RELEASE] * inc)) + .5);
          Serial.print("release4: ");
          Serial.println((3000 * (midivals[ADSR4_RELEASE] * inc)) + .5);  
        }
    
        
        
        
        if (lastval[SEQ_MASTER_BPM] != midivals[SEQ_MASTER_BPM]){
          lastval[SEQ_MASTER_BPM] = midivals[SEQ_MASTER_BPM];
          Serial.print("seq_master_bpm: ");
          Serial.println(midivals[SEQ_MASTER_BPM] * 4);  
        }
    
    
    
    /*
     peak1;          //xy=1148,150
    */
    }
    void loop(){
    
      newKnobby = knobby.read();
      if (abs(newKnobby - positionKnobby) >= 1) {
        i = abs(newKnobby / 4);
        int rowNum = i % 64 / 8;
        int chanNum = i % 8;
        indexer = (i % 64);
        knobcolor(rowNum);
        knobscolor(chanNum);
        positionKnobby = newKnobby;
        knob0.write(newpos[indexer * 4]);
        knob1.write(newpos[indexer * 4 + 1]);
        knob2.write(newpos[indexer * 4 + 2]);
        knob3.write(newpos[indexer * 4 + 3]);
        Serial.print(newKnobby);
        Serial.println();
      }
    
      newKnob0 = knob0.read();
      if (abs(newKnob0 - positionKnob0) >= 1) {
        newpos[indexer * 4] = newKnob0;
     //   printarray();
        positionKnob0 = newKnob0;
      }
    
      newKnob1 = knob1.read();
      if (abs(newKnob1 - positionKnob1) >= 1) {
        newpos[indexer * 4 + 1]  = newKnob1;
    //    printarray();
        positionKnob1 = newKnob1;
      }
    
      newKnob2 = knob2.read();
      if (abs(newKnob2 - positionKnob2) >= 1) {
        newpos[indexer * 4 + 2] = newKnob2;
    //    printarray();
        positionKnob2 = newKnob2;
      }
    
      newKnob3 = knob3.read();
      if (abs(newKnob3 - positionKnob3) >= 1) {
        newpos[indexer * 4 + 3] = newKnob3;
    //    printarray();
        positionKnob3 = newKnob3;
      }
      midisend();
      playportstest();
      sequencer();
    }
    Last edited by boxxofrobots; 09-07-2020 at 07:45 PM.

  18. #18
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    159
    Cool project. Thumbs up to the idea of using color as feedback.

  19. #19
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    Updated with system messaging primitives to support a .96" OLED. Major revision planned, welcome to my git
    Attached Files Attached Files

  20. #20
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    vocoder added
    Attached Files Attached Files

  21. #21
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126

    Another stupid question

    Why does this not work? I am simply trying to make an array of unsigned long into to hold an array of sequencer timings.

    Code:
    unsigned long lastMicros[4];
    unsigned long note1 = 0;
    unsigned long note2 = 0;
    unsigned long note3 = 0;
    unsigned long note4 = 0;
    
    void sequencer(){
        unsigned long currentMicros = micros();
        int bpm = midivals[SEQ_MASTER_BPM] + 1;
        bpm = bpm * 4;
        if (currentMicros[0] - lastMicros >= round((60000/bpm)*1000)){
          lastMicros[0] = currentMicros;
          note1 = (note1 + 1) % 8;
          if (midivals[SEQ1_ENTRY + note1] != 0){
            cvbus1.amplitude((float)midivals[SEQ1_ENTRY + note1] * inc);
            envelope1.noteOn();
            envelope2.noteOn();
          }
        }
    }

    invalid types 'long unsigned int[int]' for array subscript

    Why is the int 0 invalid?

    Thanks

  22. #22
    Senior Member
    Join Date
    Apr 2020
    Location
    DFW area in Texas
    Posts
    128
    Quote Originally Posted by boxxofrobots View Post
    Why does this not work? I am simply trying to make an array of unsigned long into to hold an array of sequencer timings.

    Code:
    unsigned long lastMicros[4];
    unsigned long note1 = 0;
    unsigned long note2 = 0;
    unsigned long note3 = 0;
    unsigned long note4 = 0;
    
    void sequencer(){
        unsigned long currentMicros = micros();
        int bpm = midivals[SEQ_MASTER_BPM] + 1;
        bpm = bpm * 4;
        if (currentMicros[0] - lastMicros >= round((60000/bpm)*1000)){
          lastMicros[0] = currentMicros;
          note1 = (note1 + 1) % 8;
          if (midivals[SEQ1_ENTRY + note1] != 0){
            cvbus1.amplitude((float)midivals[SEQ1_ENTRY + note1] * inc);
            envelope1.noteOn();
            envelope2.noteOn();
          }
        }
    }

    invalid types 'long unsigned int[int]' for array subscript

    Why is the int 0 invalid?

    Thanks
    With lastMicros defined as an array of unsigned longs, & currentMicros defined as an unsigned long, the following statement probably does not reflect your intent:

    if (currentMicros[0] - lastMicros >= round((60000/bpm)*1000)){

    As written, this statement says take the first member of the array "currentMicros" (which isn't defined an array) & subtract the address of the first entry in the "lastMicros" array (the array name without an index is the same as asking for the address of the array itself, independent of the variable type stored in the array).

    If I had to guess, you most likely meant the following instead:

    if (currentMicros - lastMicros[0] >= round((60000/bpm)*1000)){

    Hope that helps . . .

    Mark J Culross
    KD5RXT

  23. #23
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126
    Thanks. Obviously I have no one to go to on stuff like this. Lockdown sucks sometimes. I cheaped out (because there will only be four anyway) and just used vars and got it working. Now with 3 LFOs, 2 sequencers, 5 VCOs, 2 VCFs and four envelope gens and about 20 4 channel mixers. Playing the world's most obnoxious patches.
    Attached Files Attached Files

  24. #24
    Senior Member
    Join Date
    Apr 2020
    Location
    Tucson
    Posts
    126

    Giorgio's Pendereke Nightmare Shattered like Glass

    So you don't need the knobs to build it and play the patch, all that's needed is the teensy 4.1 with the audio board. I can post an mp3 on soundcloud, but thought it fun to post the patch here and see if anyone bothers to play it. This is generative synthesis with 3 lfos, 2 sequencers, 5 oscillators, two filters and four env generators. It'll play forever and never really repeat itself, just carry on the theme as long as you can stand it. Does anyone know a good Euclidian sequencer sketch?
    Attached Files Attached Files

  25. #25
    Senior Member
    Join Date
    Jul 2020
    Posts
    174
    Quote Originally Posted by boxxofrobots View Post
    OK, here's the thing. This project is getting very long, but it's not a lot of modules just of a lot of repeated code and it sort of needs to be that way. How can I put a module in another file and include it in my source without making the included file a freaking object and building constructors and stuff. I just want another page to be included like I include another bash script in a bash script. I'm experienced well in python and many languages, but my c skills have remained primitive it seems. Can anyone offer suggestions on how I might make this thing more manageable before it turns into one page 3000 lines long?
    You asked this a while back, but if anyone is still wondering:

    Arduino is weird. It will automatically build all C++ and header files in the same directory as the .ino "for free." If you want to organize your code into subdirectories, well, let me save you a few hours of scratching your head and learning to hate error messages containing the word "vtable". For arcane reasons, if you want to build a .cpp file that isn't in the same directory, you have to put it under src/. You can have as many levels of nesting as you like as long as the files are under that directory.

    Other build systems let you add files to a project explicitly, but the Arduino toolchain is not that advanced.

    If you don't want to put stuff under src/, you can still include stuff (like #include "path/to/file.h"), which many people support by putting all the code into header files.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •