If you would like this code and want me to share the folder where it includes user-defined files in the program, please email me at contact@djlita.com <3

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h>
#include <Adafruit_NeoPixel.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1325.h>
#include <RotaryEncoder.h>
#include <Mux.h>
#include "effect_tapedelay10tap.h"
#include <MIDI.h>

#define SCENE_INSTEAD_OF_VOLUME

using namespace admux;

// WAV files converted to code by wav2sketch

#include "AudioSampleRivertoseakittablamid.h"
#include "AudioSampleRivertoseakittablalow.h"
#include "AudioSampleRivertoseakittablahigh.h"
#include "AudioSampleRivertoseakitriqshake.h"
#include "AudioSampleRivertoseakitriqhit.h"
#include "AudioSampleRivertoseakitoud.h"
#include "AudioSampleRivertoseakitdaf.h"
#include "AudioSampleRivertoseakitchant.h"

//MIDI hardware connections
#define MIDI_ENABLED false
#define MIDI_OUT_PIN 29
#define MIDI_IN_PIN 28

// If using software SPI, define CLK and MOSI
#define OLED_CLK 27
#define OLED_MOSI 11

// These are neede for both hardware & softare SPI
#define OLED_CS 38
#define OLED_RESET 10
#define OLED_DC 9
Adafruit_SSD1325 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

/* settings for our little animation later */
#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH 16

#define rotaryVolumePinA 41
#define rotaryVolumePinB 32
RotaryEncoder *encoderVolume = nullptr;

#define rotaryTempoPinA 34
#define rotaryTempoPinB 33
RotaryEncoder *encoderTempo = nullptr;

#define rotary1PinA 16
#define rotary1PinB 17
RotaryEncoder *encoder1 = nullptr;

#define rotary2PinA 30
#define rotary2PinB 31
RotaryEncoder *encoder2 = nullptr;

#define rotary3PinA 25
#define rotary3PinB 26
RotaryEncoder *encoder3 = nullptr;

#define rotary4PinA 4
#define rotary4PinB 5
RotaryEncoder *encoder4 = nullptr;

#define DELAY_MAX_LEN 22050  // buffer for samples @44100 samples per second, 22050 = 0.5s

int16_t sample_delay_line[DELAY_MAX_LEN] = {};

const int muxA = 37;  // S0 pin // resuing these pins for the second multiplexer
const int muxB = 36;  // S1 pin
const int muxC = 35;  // S2 pin

const int mux1Common = 40;
const int mux2Common = 24;
const int mux3Common = 39;

Mux mux1(Pin(mux1Common, INPUT, PinType::Digital), Pinset(muxA, muxB, muxC));
Mux mux2(Pin(mux2Common, INPUT, PinType::Digital), Pinset(muxA, muxB, muxC));
Mux mux3(Pin(mux3Common, INPUT, PinType::Digital), Pinset(muxA, muxB, muxC));

int mux1Vals[8] = { 0 };
int lastMux1Vals[8] = { 0 };

int mux2Vals[8] = { 0 };
int lastMux2Vals[8] = { 0 };

int mux3Vals[8] = { 0 };
int lastMux3Vals[8] = { 0 };

float notesOn[127] = { 0.0 };

int numMuxReads = 20;  // how many times to read mux in a row (to allow signal to propogate)

const int octaveButtonPin = 12;
int octaveButtonState = 1;

const int keyboardSequenceMuteButtonPin = 34;
int keyboardSequenceMuteButtonState = 1;

float keyboardNotes[8] = { 38.02, 39.53, 40.96, 43.00, 45.04, 46.55, 47.98, 50.02 }; // HERE
int currentKeyPressed = -1;

int previousSamples[10];
int previousSamplesIndex;

typedef enum {
  DrumKeyModeInstrumentSelect,
  DrumKeyModeSequenceEdit,
  DrumKeyModeFreePlay
} DrumKeyMode;

typedef enum {
  LitaColorChannel0,
  LitaColorChannel1,
  LitaColorChannel2,
  LitaColorChannel3,
  LitaColorChannel4,
  LitaColorChannel5,
  LitaColorChannel6,
  LitaColorChannel7,
  LitaColorSequence,
  LitaColorMute,
  StepActive
} LitaColor;

typedef enum {
  DrumMIDINote0 = 36,
  DrumMIDINote1 = 37,
  DrumMIDINote2 = 38,
  DrumMIDINote3 = 39,
  DrumMIDINote4 = 40,
  DrumMIDINote5 = 41,
  DrumMIDINote6 = 42,
  DrumMIDINote7 = 43
} DrumMIDINotes;

enum EncoderStates {
  ADSR,
  Effects
} CurrentEncoderState;

float delaySend = 0.0;

// Create the Audio components.  These should be created in the order data flows, inputs/sources -> processing -> outputs

// GUItool: begin automatically generated code

AudioPlayMemory playMem2;                  //xy=204,701
AudioPlayMemory playMem3;                  //xy=204,748
AudioPlayMemory playMem5;                  //xy=204,837
AudioPlayMemory playMem4;                  //xy=205,793
AudioPlayMemory playMem6;                  //xy=205,881
AudioPlayMemory playMem1;                  //xy=206,658
AudioPlayMemory playMem7;                  //xy=206,928
AudioPlayMemory playMem8;                  //xy=209,977
AudioSynthWaveformModulated waveformMod1;  //xy=358,1130
AudioEffectEnvelope envelope1;             //xy=513,1083
AudioMixer4 mixer1;                        //xy=553,847
AudioMixer4 mixer2;                        //xy=555,935
AudioFilterStateVariable filter1;          //xy=665,1083
AudioMixer4 delaysend1_4;                  //xy=735,372
AudioMixer4 delaysend5_8;                  //xy=735,454
AudioMixer4 reverbSend1to4;                //xy=749,538
AudioMixer4 reverbSend5to8;                //xy=749,606
AudioMixer4 mixer6;                        //xy=923,348
AudioMixer4 mixer4;                        //xy=934,558
AudioMixer4 mixer3;                        //xy=1022,890
AudioEffectFreeverb mainReverb;            //xy=1095,605
AudioEffectTapeDelay10tap delay1;          //xy=1271.0000190734863,545.0000057220459
AudioMixer4 mixer7;                        //xy=1494.0000190734863,901.0000152587891
AudioOutputI2S i2s1;                       //xy=1644.0000228881836,587.0000076293945
AudioConnection patchCord1(playMem2, 0, mixer1, 1);
AudioConnection patchCord2(playMem2, 0, reverbSend1to4, 1);
AudioConnection patchCord3(playMem2, 0, delaysend1_4, 1);
AudioConnection patchCord4(playMem3, 0, mixer1, 2);
AudioConnection patchCord5(playMem3, 0, reverbSend1to4, 2);
AudioConnection patchCord6(playMem3, 0, delaysend1_4, 2);
AudioConnection patchCord7(playMem5, 0, mixer2, 0);
AudioConnection patchCord8(playMem5, 0, reverbSend5to8, 0);
AudioConnection patchCord9(playMem5, 0, delaysend5_8, 0);
AudioConnection patchCord10(playMem4, 0, mixer1, 3);
AudioConnection patchCord11(playMem4, 0, reverbSend1to4, 3);
AudioConnection patchCord12(playMem4, 0, delaysend1_4, 3);
AudioConnection patchCord13(playMem6, 0, mixer2, 1);
AudioConnection patchCord14(playMem6, 0, reverbSend5to8, 1);
AudioConnection patchCord15(playMem6, 0, delaysend5_8, 1);
AudioConnection patchCord16(playMem1, 0, mixer1, 0);
AudioConnection patchCord17(playMem1, 0, reverbSend1to4, 0);
AudioConnection patchCord18(playMem1, 0, delaysend1_4, 0);
AudioConnection patchCord19(playMem7, 0, mixer2, 2);
AudioConnection patchCord20(playMem7, 0, reverbSend5to8, 2);
AudioConnection patchCord21(playMem7, 0, delaysend5_8, 2);
AudioConnection patchCord22(playMem8, 0, mixer2, 3);
AudioConnection patchCord23(playMem8, 0, reverbSend5to8, 3);
AudioConnection patchCord24(playMem8, 0, delaysend5_8, 3);
AudioConnection patchCord25(waveformMod1, envelope1);
AudioConnection patchCord26(envelope1, 0, filter1, 0);
AudioConnection patchCord27(mixer1, 0, mixer3, 0);
AudioConnection patchCord28(mixer2, 0, mixer3, 3);
AudioConnection patchCord29(filter1, 0, mixer3, 1);
AudioConnection patchCord30(delaysend1_4, 0, mixer6, 0);
AudioConnection patchCord31(delaysend5_8, 0, mixer6, 1);
AudioConnection patchCord32(reverbSend1to4, 0, mixer4, 0);
AudioConnection patchCord33(reverbSend5to8, 0, mixer4, 1);
AudioConnection patchCord34(mixer6, delay1);
AudioConnection patchCord35(mixer4, mainReverb);
AudioConnection patchCord36(mixer3, 0, mixer7, 0);
AudioConnection patchCord37(mainReverb, 0, mixer3, 2);
AudioConnection patchCord38(delay1, 0, mixer7, 1);
AudioConnection patchCord39(delay1, 0, mixer6, 3);
AudioConnection patchCord40(mixer7, 0, i2s1, 0);
AudioConnection patchCord41(mixer7, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1;  //xy=1304,154

// GUItool: end automatically generated code

//Bounce clearDrumPartButton = 0;// Bounce(35, 5);

int bpm = 120;
int ms_per_step = 125;

//int tempoPotPin = A17;
//int synthNotes[8] = { 60, 62, 64, 65, 67, 69, 71, 72 };
//int drumNotes[8] = { 36, 39, 36, 39, 36, 39, 36, 39 };

//keep track of note for synth -- better to put this in a struct
int currentNote = 55;  //a440
int keyboardOctave = 3;

//Convert any MIDI note number to it's frequency
float freqFromMidiNote(float note) {
  return 440.0f * powf(2, (float (note) - 69.0f) / 12.0f); // efpitch/G3-55 // 55.0/12.0 with return 195.998f 
}

//melody sequencemelodyNotes
int melodyNotes[32] = { 60, 62, 63, 72, 70, 65, 67, 70, 60, 62, 63, 72, 70, 65, 67, 70, 60, 62, 63, 72, 70, 65, 67, 70, 60, 62, 63, 72, 70, 65, 67, 70 };  // corresponds to midi note c major scale
int filterCutoffs[8] = { 50, 50, 50, 50, 50, 50, 50, 50 };                                                                                                // corresponds to midi note c major scale

//int melodyNotes[8] = { 48, 50, 52, 54, 56,58, 60, 62 };  // corresponds to midi note c major scale

//Drum sequence arrays

int kickNotes[8] = { 1, 0, 0, 0, 1, 0, 0, 0 };
int clapNotes[8] = { 0, 0, 0, 0, 1, 0, 0, 0 };
int openhihatNotes[8] = { 0, 0, 1, 0, 0, 1, 0, 0 };
int closedhihatNotes[8] = { 0, 0, 0, 1, 0, 0, 0, 1 };
int snareNotes[8] = { 0, 0, 0, 0, 1, 0, 0, 0 };
int cowbellNotes[8] = { 1, 0, 0, 0, 0, 1, 0, 0 };
int cymbalNotes[8] = { 0, 0, 0, 1, 0, 0, 0, 1 };
int tomNotes[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

int mutes[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

//int programMode = 0; // 0 is change beats; 1 is change effects

float drumVolumes[8] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
float drumProbabilities[8] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };

float reverbSends[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
float delaySends[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

int whichReverbVoice = 0;

int instrumentchangeflag = 0;

int channelselectbutton;
int lastchannelselectbutton = LOW;

int mutechangeflag = 0;
int clearchangeflag = 0;

int channelmutebutton;
int lastchannelmutebutton = LOW;

int keyboardSequenceMute = 1;

int adsrButton;
int lastadsrButton;

#define defaultAttack 0
#define defaultDecay 100
#define defaultSustain 0.5
#define defaultRelease 20

int attack = defaultAttack;
int decay = defaultDecay;
float sustain = defaultSustain;
int release = defaultRelease;

double normalizedCutoff = 0.9;  // used and then squared before scaling to get logarithmic curve
int cutoff = 10000;
float resonance = 0.7;

float globalGain = 4.0;

int lastPos1 = 0;
int lastPos2 = 0;
int lastPos3 = 0;
int lastPos4 = 0;

int lastPosDelay = 0;

int velocity = 100;

int channel = 0;

int playing = 0;
int lastStartStopButtonState = LOW;

unsigned long lastStepTime = 0;
unsigned long lastStepTime_previous = 0;

int currentStep = 0;
int currentStepMelody = 0;

int displayStep = 0;

int totalSteps = 8;
int totalStepsMelody = 32;

int lastButtonState = LOW;  // state of the button last time you checked

int current_waveform = WAVEFORM_SINE;

//MIDI <https://www.pjrc.com/teensy/td_libs_MIDI.html>

#include <SoftwareSerial.h>
MIDI_CREATE_INSTANCE(HardwareSerial, Serial7, MIDI);

Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(64, 3, NEO_GRB);

void loadScene(int scene) {

  Serial.print("load scene ");
  Serial.println(scene);

  int numpatterns = 7;
  if (scene < 0) {
    while (scene < 0) {
      scene += numpatterns;
    }
  }
  scene = scene % numpatterns;

  switch (scene) {
    case 0:
      kickNotes[0] = 1;
      kickNotes[1] = 0;
      kickNotes[2] = 0;
      kickNotes[3] = 0;
      kickNotes[4] = 1;
      kickNotes[5] = 0;
      kickNotes[6] = 0;
      kickNotes[7] = 0;

      clapNotes[0] = 0;
      clapNotes[1] = 0;
      clapNotes[2] = 0;
      clapNotes[3] = 0;
      clapNotes[4] = 0;
      clapNotes[5] = 0;
      clapNotes[6] = 0;
      clapNotes[7] = 0;

      openhihatNotes[0] = 0;
      openhihatNotes[1] = 0;
      openhihatNotes[2] = 0;
      openhihatNotes[3] = 0;
      openhihatNotes[4] = 0;
      openhihatNotes[5] = 0;
      openhihatNotes[6] = 0;
      openhihatNotes[7] = 0;

      closedhihatNotes[0] = 0;
      closedhihatNotes[1] = 0;
      closedhihatNotes[2] = 0;
      closedhihatNotes[3] = 0;
      closedhihatNotes[4] = 0;
      closedhihatNotes[5] = 0;
      closedhihatNotes[6] = 0;
      closedhihatNotes[7] = 0;

      snareNotes[0] = 0;
      snareNotes[1] = 0;
      snareNotes[2] = 0;
      snareNotes[3] = 0;
      snareNotes[4] = 0;
      snareNotes[5] = 0;
      snareNotes[6] = 0;
      snareNotes[7] = 0;

      cowbellNotes[0] = 0;
      cowbellNotes[1] = 0;
      cowbellNotes[2] = 0;
      cowbellNotes[3] = 0;
      cowbellNotes[4] = 0;
      cowbellNotes[5] = 0;
      cowbellNotes[6] = 0;
      cowbellNotes[7] = 0;

      cymbalNotes[0] = 0;
      cymbalNotes[1] = 0;
      cymbalNotes[2] = 0;
      cymbalNotes[3] = 0;
      cymbalNotes[4] = 0;
      cymbalNotes[5] = 0;
      cymbalNotes[6] = 0;
      cymbalNotes[7] = 0;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;

    case 1:
      kickNotes[0] = 1;
      kickNotes[1] = 0;
      kickNotes[2] = 0;
      kickNotes[3] = 1;
      kickNotes[4] = 0;
      kickNotes[5] = 0;
      kickNotes[6] = 1;
      kickNotes[7] = 0;

      clapNotes[0] = 0;
      clapNotes[1] = 0;
      clapNotes[2] = 0;
      clapNotes[3] = 0;
      clapNotes[4] = 1;
      clapNotes[5] = 0;
      clapNotes[6] = 0;
      clapNotes[7] = 0;

      openhihatNotes[0] = 0;
      openhihatNotes[1] = 0;
      openhihatNotes[2] = 0;
      openhihatNotes[3] = 0;
      openhihatNotes[4] = 0;
      openhihatNotes[5] = 0;
      openhihatNotes[6] = 0;
      openhihatNotes[7] = 1;

      closedhihatNotes[0] = 0;
      closedhihatNotes[1] = 0;
      closedhihatNotes[2] = 0;
      closedhihatNotes[3] = 0;
      closedhihatNotes[4] = 0;
      closedhihatNotes[5] = 0;
      closedhihatNotes[6] = 0;
      closedhihatNotes[7] = 0;

      snareNotes[0] = 0;
      snareNotes[1] = 1;
      snareNotes[2] = 0;
      snareNotes[3] = 1;
      snareNotes[4] = 0;
      snareNotes[5] = 0;
      snareNotes[6] = 0;
      snareNotes[7] = 0;

      cowbellNotes[0] = 0;
      cowbellNotes[1] = 0;
      cowbellNotes[2] = 1;
      cowbellNotes[3] = 0;
      cowbellNotes[4] = 0;
      cowbellNotes[5] = 0;
      cowbellNotes[6] = 1;
      cowbellNotes[7] = 0;

      cymbalNotes[0] = 1;
      cymbalNotes[1] = 0;
      cymbalNotes[2] = 0;
      cymbalNotes[3] = 0;
      cymbalNotes[4] = 0;
      cymbalNotes[5] = 0;
      cymbalNotes[6] = 0;
      cymbalNotes[7] = 0;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;

    case 2:
      kickNotes[0] = 1;
      kickNotes[1] = 0;
      kickNotes[2] = 0;
      kickNotes[3] = 1;
      kickNotes[4] = 0;
      kickNotes[5] = 0;
      kickNotes[6] = 1;
      kickNotes[7] = 1;

      clapNotes[0] = 1;
      clapNotes[1] = 0;
      clapNotes[2] = 0;
      clapNotes[3] = 0;
      clapNotes[4] = 1;
      clapNotes[5] = 0;
      clapNotes[6] = 0;
      clapNotes[7] = 0;

      openhihatNotes[0] = 0;
      openhihatNotes[1] = 0;
      openhihatNotes[2] = 1;
      openhihatNotes[3] = 0;
      openhihatNotes[4] = 0;
      openhihatNotes[5] = 0;
      openhihatNotes[6] = 1;
      openhihatNotes[7] = 0;

      closedhihatNotes[0] = 1;
      closedhihatNotes[1] = 0;
      closedhihatNotes[2] = 0;
      closedhihatNotes[3] = 0;
      closedhihatNotes[4] = 1;
      closedhihatNotes[5] = 0;
      closedhihatNotes[6] = 0;
      closedhihatNotes[7] = 0;

      snareNotes[0] = 0;
      snareNotes[1] = 1;
      snareNotes[2] = 0;
      snareNotes[3] = 1;
      snareNotes[4] = 1;
      snareNotes[5] = 1;
      snareNotes[6] = 0;
      snareNotes[7] = 0;

      cowbellNotes[0] = 0;
      cowbellNotes[1] = 0;
      cowbellNotes[2] = 0;
      cowbellNotes[3] = 1;
      cowbellNotes[4] = 0;
      cowbellNotes[5] = 0;
      cowbellNotes[6] = 0;
      cowbellNotes[7] = 1;

      cymbalNotes[0] = 1;
      cymbalNotes[1] = 0;
      cymbalNotes[2] = 0;
      cymbalNotes[3] = 0;
      cymbalNotes[4] = 1;
      cymbalNotes[5] = 0;
      cymbalNotes[6] = 0;
      cymbalNotes[7] = 0;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;

    case 3:
      kickNotes[0] = 1;
      kickNotes[1] = 1;
      kickNotes[2] = 0;
      kickNotes[3] = 1;
      kickNotes[4] = 1;
      kickNotes[5] = 0;
      kickNotes[6] = 0;
      kickNotes[7] = 1;

      clapNotes[0] = 0;
      clapNotes[1] = 0;
      clapNotes[2] = 0;
      clapNotes[3] = 0;
      clapNotes[4] = 1;
      clapNotes[5] = 0;
      clapNotes[6] = 0;
      clapNotes[7] = 0;

      openhihatNotes[0] = 1;
      openhihatNotes[1] = 0;
      openhihatNotes[2] = 0;
      openhihatNotes[3] = 0;
      openhihatNotes[4] = 1;
      openhihatNotes[5] = 0;
      openhihatNotes[6] = 0;
      openhihatNotes[7] = 0;

      closedhihatNotes[0] = 1;
      closedhihatNotes[1] = 1;
      closedhihatNotes[2] = 1;
      closedhihatNotes[3] = 1;
      closedhihatNotes[4] = 1;
      closedhihatNotes[5] = 1;
      closedhihatNotes[6] = 1;
      closedhihatNotes[7] = 1;

      snareNotes[0] = 0;
      snareNotes[1] = 0;
      snareNotes[2] = 0;
      snareNotes[3] = 0;
      snareNotes[4] = 1;
      snareNotes[5] = 0;
      snareNotes[6] = 0;
      snareNotes[7] = 0;

      cowbellNotes[0] = 0;
      cowbellNotes[1] = 0;
      cowbellNotes[2] = 1;
      cowbellNotes[3] = 0;
      cowbellNotes[4] = 0;
      cowbellNotes[5] = 0;
      cowbellNotes[6] = 1;
      cowbellNotes[7] = 0;

      cymbalNotes[0] = 0;
      cymbalNotes[1] = 0;
      cymbalNotes[2] = 0;
      cymbalNotes[3] = 0;
      cymbalNotes[4] = 0;
      cymbalNotes[5] = 0;
      cymbalNotes[6] = 0;
      cymbalNotes[7] = 0;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;

    case 4:
      kickNotes[0] = 1;
      kickNotes[1] = 1;
      kickNotes[2] = 1;
      kickNotes[3] = 0;
      kickNotes[4] = 0;
      kickNotes[5] = 0;
      kickNotes[6] = 0;
      kickNotes[7] = 0;

      clapNotes[0] = 0;
      clapNotes[1] = 0;
      clapNotes[2] = 0;
      clapNotes[3] = 0;
      clapNotes[4] = 1;
      clapNotes[5] = 1;
      clapNotes[6] = 1;
      clapNotes[7] = 0;

      openhihatNotes[0] = 0;
      openhihatNotes[1] = 0;
      openhihatNotes[2] = 0;
      openhihatNotes[3] = 1;
      openhihatNotes[4] = 1;
      openhihatNotes[5] = 0;
      openhihatNotes[6] = 1;
      openhihatNotes[7] = 0;

      closedhihatNotes[0] = 0;
      closedhihatNotes[1] = 0;
      closedhihatNotes[2] = 1;
      closedhihatNotes[3] = 0;
      closedhihatNotes[4] = 0;
      closedhihatNotes[5] = 0;
      closedhihatNotes[6] = 1;
      closedhihatNotes[7] = 0;

      snareNotes[0] = 0;
      snareNotes[1] = 0;
      snareNotes[2] = 0;
      snareNotes[3] = 0;
      snareNotes[4] = 0;
      snareNotes[5] = 0;
      snareNotes[6] = 0;
      snareNotes[7] = 0;

      cowbellNotes[0] = 1;
      cowbellNotes[1] = 0;
      cowbellNotes[2] = 0;
      cowbellNotes[3] = 0;
      cowbellNotes[4] = 1;
      cowbellNotes[5] = 0;
      cowbellNotes[6] = 1;
      cowbellNotes[7] = 0;

      cymbalNotes[0] = 1;
      cymbalNotes[1] = 1;
      cymbalNotes[2] = 1;
      cymbalNotes[3] = 1;
      cymbalNotes[4] = 1;
      cymbalNotes[5] = 1;
      cymbalNotes[6] = 1;
      cymbalNotes[7] = 1;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;
      /////////////////////////////////////
    case 5:
      kickNotes[0] = 1;
      kickNotes[1] = 0;
      kickNotes[2] = 1;
      kickNotes[3] = 0;
      kickNotes[4] = 0;
      kickNotes[5] = 1;
      kickNotes[6] = 1;
      kickNotes[7] = 0;

      clapNotes[0] = 0;
      clapNotes[1] = 0;
      clapNotes[2] = 0;
      clapNotes[3] = 1;
      clapNotes[4] = 1;
      clapNotes[5] = 0;
      clapNotes[6] = 0;
      clapNotes[7] = 0;

      openhihatNotes[0] = 1;
      openhihatNotes[1] = 0;
      openhihatNotes[2] = 0;
      openhihatNotes[3] = 1;
      openhihatNotes[4] = 1;
      openhihatNotes[5] = 0;
      openhihatNotes[6] = 0;
      openhihatNotes[7] = 0;

      closedhihatNotes[0] = 1;
      closedhihatNotes[1] = 1;
      closedhihatNotes[2] = 1;
      closedhihatNotes[3] = 1;
      closedhihatNotes[4] = 1;
      closedhihatNotes[5] = 1;
      closedhihatNotes[6] = 1;
      closedhihatNotes[7] = 1;

      snareNotes[0] = 0;
      snareNotes[1] = 0;
      snareNotes[2] = 0;
      snareNotes[3] = 0;
      snareNotes[4] = 1;
      snareNotes[5] = 0;
      snareNotes[6] = 0;
      snareNotes[7] = 0;

      cowbellNotes[0] = 1;
      cowbellNotes[1] = 0;
      cowbellNotes[2] = 1;
      cowbellNotes[3] = 0;
      cowbellNotes[4] = 1;
      cowbellNotes[5] = 0;
      cowbellNotes[6] = 0;
      cowbellNotes[7] = 0;

      cymbalNotes[0] = 0;
      cymbalNotes[1] = 0;
      cymbalNotes[2] = 0;
      cymbalNotes[3] = 1;
      cymbalNotes[4] = 0;
      cymbalNotes[5] = 0;
      cymbalNotes[6] = 0;
      cymbalNotes[7] = 1;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;
      //////////////////////////////
      /////////////////////////////////////
    case 6:
      kickNotes[0] = 1;
      kickNotes[1] = 1;
      kickNotes[2] = 1;
      kickNotes[3] = 1;
      kickNotes[4] = 1;
      kickNotes[5] = 1;
      kickNotes[6] = 1;
      kickNotes[7] = 1;

      clapNotes[0] = 1;
      clapNotes[1] = 1;
      clapNotes[2] = 1;
      clapNotes[3] = 1;
      clapNotes[4] = 1;
      clapNotes[5] = 1;
      clapNotes[6] = 1;
      clapNotes[7] = 1;

      openhihatNotes[0] = 1;
      openhihatNotes[1] = 1;
      openhihatNotes[2] = 1;
      openhihatNotes[3] = 1;
      openhihatNotes[4] = 1;
      openhihatNotes[5] = 1;
      openhihatNotes[6] = 1;
      openhihatNotes[7] = 1;

      closedhihatNotes[0] = 1;
      closedhihatNotes[1] = 1;
      closedhihatNotes[2] = 1;
      closedhihatNotes[3] = 1;
      closedhihatNotes[4] = 1;
      closedhihatNotes[5] = 1;
      closedhihatNotes[6] = 1;
      closedhihatNotes[7] = 1;

      snareNotes[0] = 1;
      snareNotes[1] = 1;
      snareNotes[2] = 1;
      snareNotes[3] = 1;
      snareNotes[4] = 1;
      snareNotes[5] = 1;
      snareNotes[6] = 1;
      snareNotes[7] = 1;

      cowbellNotes[0] = 1;
      cowbellNotes[1] = 1;
      cowbellNotes[2] = 1;
      cowbellNotes[3] = 1;
      cowbellNotes[4] = 1;
      cowbellNotes[5] = 1;
      cowbellNotes[6] = 1;
      cowbellNotes[7] = 1;

      cymbalNotes[0] = 1;
      cymbalNotes[1] = 1;
      cymbalNotes[2] = 1;
      cymbalNotes[3] = 1;
      cymbalNotes[4] = 1;
      cymbalNotes[5] = 1;
      cymbalNotes[6] = 1;
      cymbalNotes[7] = 1;

      tomNotes[0] = 0;
      tomNotes[1] = 0;
      tomNotes[2] = 0;
      tomNotes[3] = 0;
      tomNotes[4] = 0;
      tomNotes[5] = 0;
      tomNotes[6] = 0;
      tomNotes[7] = 0;

      mutes[0] = 0;
      mutes[1] = 0;
      mutes[2] = 0;
      mutes[3] = 0;
      mutes[4] = 0;
      mutes[5] = 0;
      mutes[6] = 0;
      mutes[7] = 0;
      break;
      //////////////////////////////
  }
}

// This interrupt routine will be called on any change of one of the input signals
void checkPositionTempo() {
  //Serial.println("checkPosition tempo");
  encoderTempo->tick();  // just call tick() to check the state.
}

void checkPositionVolume() {
  //Serial.println("checkPosition volume");
  encoderVolume->tick();  // just call tick() to check the state.
}

void checkPositionRotary1() {
  //Serial.println("checkPosition rotary 1");
  encoder1->tick();  // just call tick() to check the state.
}

void checkPositionRotary2() {
  //Serial.println("checkPosition rotary 2");
  encoder2->tick();  // just call tick() to check the state.
}

void checkPositionRotary3() {
  //Serial.println("checkPosition rotary 3");
  encoder3->tick();  // just call tick() to check the state.
}

void checkPositionRotary4() {
  //Serial.println("checkPosition rotary 4");
  encoder4->tick();  // just call tick() to check the state.
}

void setup() {
  AudioMemory(150 * (128 / AUDIO_BLOCK_SAMPLES));
  Serial.begin(9600);

  if (MIDI_ENABLED) {
    MIDI.begin();  // Initialize MIDI with Omni channel (responds to all MIDI channels)
  }
  display.begin();

  neopixel.begin();
  neopixel.clear();
  neopixel.show();

  // always need this for synth
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  waveformMod1.begin(0.8, 261, WAVEFORM_SINE);

  envelope1.noteOff();
  envelope1.attack(attack);
  envelope1.decay(decay);
  envelope1.sustain(sustain);
  envelope1.release(release);

  waveformMod1.frequency(440);
  waveformMod1.amplitude(1.0);

  waveformMod1.begin(1.0, 440, WAVEFORM_SINE);
  //current_waveform = WAVEFORM_TRIANGLE;
  waveformMod1.begin(current_waveform);

  //mainReverb.reverbTime(5.0);
  mainReverb.roomsize(0.97);
  mainReverb.damping(0.5);

  //delay
  delay1.begin(sample_delay_line, DELAY_MAX_LEN);
  delay1.delayfade(0, 500, 3.0);

  //make pin 2 an input:
  pinMode(16, INPUT);
  pinMode(17, INPUT);
  pinMode(25, INPUT);
  pinMode(26, INPUT);
  pinMode(22, INPUT);
  //pinMode(28, INPUT);
  //pinMode(29, INPUT);
  pinMode(30, INPUT);
  pinMode(31, INPUT);
  pinMode(32, INPUT);

  // Set up multiplexers
  pinMode(muxA, OUTPUT);
  pinMode(muxB, OUTPUT);
  pinMode(muxC, OUTPUT);

  pinMode(mux1Common, INPUT_PULLUP);
  pinMode(mux2Common, INPUT_PULLUP);
  pinMode(mux3Common, INPUT_PULLUP);

  //setting the mixer levels
  mixer1.gain(0, 2.0 * globalGain);  //daf aka kick
  mixer1.gain(1, 1.0 * globalGain);  //tabla low
  mixer1.gain(2, 1.5 * globalGain);  //tabla mid
  mixer1.gain(3, 1.8 * globalGain);  //tabla high
  mixer2.gain(0, 0.5 * globalGain);  // riq hit
  mixer2.gain(1, 0.5 * globalGain);  // riq shake
  mixer2.gain(2, 0.5 * globalGain);  //oud
  mixer2.gain(3, 0.4 * globalGain);  //chant

  mixer3.gain(0, 2.0);                 //drums
  mixer3.gain(1, globalGain * 0.125);  //dry synth
  mixer3.gain(2, globalGain * 2);      //synth reverb
  mixer3.gain(3, 2.0);                 //drums pt 2

  mixer6.gain(2, 0.6);
  mixer6.gain(3, 0.6);
  mixer6.gain(0, 1);
  mixer6.gain(1, 1);

  mixer7.gain(1, 10);

  delaysend1_4.gain(0, 0);
  delaysend1_4.gain(1, 0);
  delaysend1_4.gain(2, 0);
  delaysend1_4.gain(3, 0);
  delaysend5_8.gain(0, 0);
  delaysend5_8.gain(1, 0);
  delaysend5_8.gain(2, 0);
  delaysend5_8.gain(3, 0);

  //setting the reverb send levels
  reverbSend1to4.gain(0, 0.0);  //kick
  reverbSend1to4.gain(1, 0.0);  //clap
  reverbSend1to4.gain(2, 0.0);  //open hh
  reverbSend1to4.gain(3, 0.0);  //closed hh
  reverbSend5to8.gain(0, 0.0);  //snare
  reverbSend5to8.gain(1, 0.0);  //cowbell
  reverbSend5to8.gain(2, 0.0);  //ride
  reverbSend5to8.gain(3, 0.0);  //tom

  filter1.frequency(400);
  filter1.resonance(3);

  encoderTempo = new RotaryEncoder(rotaryTempoPinA, rotaryTempoPinB, RotaryEncoder::LatchMode::TWO03);

  encoderVolume = new RotaryEncoder(rotaryVolumePinA, rotaryVolumePinB, RotaryEncoder::LatchMode::TWO03);
  encoderVolume->setPosition(-50);

  encoder1 = new RotaryEncoder(rotary1PinA, rotary1PinB, RotaryEncoder::LatchMode::TWO03);
  encoder2 = new RotaryEncoder(rotary2PinA, rotary2PinB, RotaryEncoder::LatchMode::TWO03);
  encoder3 = new RotaryEncoder(rotary3PinA, rotary3PinB, RotaryEncoder::LatchMode::TWO03);
  encoder4 = new RotaryEncoder(rotary4PinA, rotary4PinB, RotaryEncoder::LatchMode::TWO03);

  attachInterrupt(digitalPinToInterrupt(rotaryTempoPinA), checkPositionTempo, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotaryTempoPinB), checkPositionTempo, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotaryVolumePinA), checkPositionVolume, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotaryVolumePinB), checkPositionVolume, CHANGE);

  attachInterrupt(digitalPinToInterrupt(rotary1PinA), checkPositionRotary1, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary1PinB), checkPositionRotary1, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary2PinA), checkPositionRotary2, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary2PinB), checkPositionRotary2, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary3PinA), checkPositionRotary3, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary3PinB), checkPositionRotary3, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary4PinA), checkPositionRotary4, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotary4PinB), checkPositionRotary4, CHANGE);

  CurrentEncoderState = ADSR;

  Serial.println("Welcome to DRUM-U-LITA");
}

unsigned long t = 0;

void updateMidiIn() {
  int type, velocity, channel, d1, d2;
  float note;
  if (MIDI.read()) {  // Is there a MIDI message incoming ?
    byte type = MIDI.getType();
    switch (type) {
      case midi::NoteOn:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();

        switch (int(note)) {
          case 24:
            {
              triggerSample(0);
            }
            break;
          case 26:
            {
              triggerSample(1);
            }
            break;
          case 28:
            {
              triggerSample(2);
            }
            break;
          case 29:
            {
              triggerSample(3);
            }
            break;
          case 31:
            {
              triggerSample(4);
            }
            break;
          case 33:
            {
              triggerSample(5);
            }
            break;
          case 35:
            {
              triggerSample(6);
            }
            break;
          case 36:
            {
              triggerSample(7);
            }
            break;

          default:
            break;
        }

        if (velocity > 0) {
          if (note > 36.0f) {
            triggerNoteOn(note);
          }
          Serial.println(String("Note On:  ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        } else {

          if (note > 36.0f) {
            triggerNoteOff(note);
          }
          Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
        }
        break;
      case midi::NoteOff:
        note = MIDI.getData1();

        if (note > 36.0f) {
          triggerNoteOff(note);
        }
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        break;
      default:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
    }
  }
}
void triggerNoteOn(float note){

}
void triggerNoteOff(float note){

}

void loop() {
  if (MIDI_ENABLED) {
    updateMidiIn();
  }
  updateDisplay();
  updateTempo();
  updateVolume();
  updateReverb();
  updateDrumMix();
  updateDrumProbabilities();
  updateSequencer();
  updateAdsrButton();
  updateEnvelope();
  updateTopRow();
  updateSideButtons();
  updateBottomRow();
  updateDelay();
}

// MIDI -- sends over USB and Hardware port.

void sendMIDITrigger(float note) {

  //   // usbMIDI.sendNoteOn(note, 127, 1);
  //   // usbMIDI.sendNoteOff(note, 0, 1);

  //   MIDI.sendNoteOn(note, 127, 1);
  //   MIDI.sendNoteOff(note, 0, 1);
}

void cycleOctave() {
  Serial.print("cycle octave ");
  Serial.println(keyboardOctave);

  keyboardOctave++;
  keyboardOctave %= 7;
}

void updateSideButtons() {

  for (int chan = 0; chan < 8; chan++) {
    mux2.channel(chan);  // set mux channel

    for (int i = 0; i < numMuxReads; i++) {  // reading same mux several times to allow address signal to propogate through, don't know why this mux is reacting slower than the others
      mux2Vals[chan] = mux2.read(chan);
    }

    if (mux2Vals[chan] != lastMux2Vals[chan]) {

      if (chan == 7) {

        //programMode = !mux2Vals[chan];
      }
      Serial.print("Mux 2 Pressed Channel:  ");
      Serial.print(chan);
      Serial.print(" ");
      Serial.println(mux2Vals[chan]);

      //Start / Stop button top left misc button
      if (chan == 5 && mux2Vals[chan] == HIGH) {
        startStop();
      }

      //Channel Select button top left misc button
      if (chan == 0 && mux2Vals[chan] == HIGH) {
        instrumentchangeflag = !instrumentchangeflag;
        mutechangeflag = 0;
        clearchangeflag = 0;
      }

      //Channel Select button top left misc button
      if (chan == 2 && mux2Vals[chan] == HIGH) {
        mutechangeflag = !mutechangeflag;
        instrumentchangeflag = 0;
        clearchangeflag = 0;
      }

      //Clear part button
      if (chan == 3 && mux2Vals[chan] == HIGH) {
        clearchangeflag = !clearchangeflag;
        instrumentchangeflag = 0;
        mutechangeflag = 0;
      }

      //Waveform select
      if (chan == 1 && mux2Vals[chan] == HIGH) {
        current_waveform++;
        if (current_waveform == 4) {  // we are skipping over waveform arbituary
          current_waveform = 5;
        }
        current_waveform %= 13;
        waveformMod1.begin(current_waveform);
        Serial.println(current_waveform);
      }

      //Mute Keys button
      if (chan == 4 && mux2Vals[chan] == HIGH) {

        if (clearchangeflag == true) {

          for (int i = 0; i < 32; i++) {
            melodyNotes[i] = 0;
          }
          clearchangeflag = false;

        } else {

          if (keyboardSequenceMute == 1) {
            keyboardSequenceMute = 0;
          } else {
            keyboardSequenceMute = 1;
            for (int i = 0; i < 8; i++) {
              triggerNoteOff(melodyNotes[i]);  // going to eventually replace whole thing to playSDwave.play(filename)
            }
          }
        }
      }

      //Octave button
      if (chan == 6 && mux2Vals[chan] == HIGH) {
        cycleOctave();
      }

      //Encoder mode button
      if (chan == 7 && mux2Vals[chan] == HIGH) {
        if (CurrentEncoderState == ADSR) {
          CurrentEncoderState = Effects;
        } else if (CurrentEncoderState == Effects) {
          CurrentEncoderState = ADSR;
        }
      }
    }
    lastMux2Vals[chan] = mux2Vals[chan];
  }
}

void startStop() {

  if (playing) {
    envelope1.noteOff();
    playing = 0;
    displayStep = -1;

  } else {
    currentStep = 0;
    currentStepMelody = 0;
    displayStep = 0;
    lastStepTime = 0;
    lastStepTime_previous = 0;
    playing = 1;
  }
}

void updateTopRow() {
  int *notesArray = kickNotes;

  // assign array based on channel
  if (channel == 1) {
    notesArray = clapNotes;
  }
  if (channel == 2) {
    notesArray = openhihatNotes;
  }
  if (channel == 3) {
    notesArray = closedhihatNotes;
  }
  if (channel == 4) {
    notesArray = snareNotes;
  }
  if (channel == 5) {
    notesArray = cowbellNotes;
  }
  if (channel == 6) {
    notesArray = cymbalNotes;
  }
  if (channel == 7) {
    notesArray = tomNotes;
  }

  for (int chan = 0; chan < 8; chan++) {
    //hack for 12/8/2023 PCB
    // int drumStep = drumStepL - 1;
    // if (drumStep < 0) {
    //   drumStep += 8;
    // }

    mux3.channel(chan);

    for (int i = 0; i < numMuxReads; i++) {
      mux3Vals[chan] = mux3.read(chan);
    }

    //   check if the current button state is different than the last state:
    if (mux3Vals[chan] != lastMux3Vals[chan] /* && programMode==0*/) {
      Serial.print("Mux 3 Pressed Channel:  ");
      Serial.print(chan);
      Serial.print(" ");
      Serial.println(mux3Vals[chan]);

      // do stuff if it is different here
      if (mux3Vals[chan] == LOW) {

        if (mutechangeflag == 1) {
          if (mutes[chan] == 0) {
            mutes[chan] = 1;
          } else {
            mutes[chan] = 0;
          }
          mutechangeflag = 0;
        } else if (instrumentchangeflag == 1) {
          channel = chan;
          // triggerSample(channel);
          Serial.print("inst change: ");
          Serial.println(channel);
          instrumentchangeflag = 0;
        } else if (clearchangeflag == 1) {
          clearchangeflag = 0;
          channel = chan;
          clearActiveDrumChannel();
        } else {
          if (notesArray[chan] == 1) {
            notesArray[chan] = 0;
          } else if (notesArray[chan] == 0) {
            notesArray[chan] = 1;
          }
          Serial.print(notesArray[0]);
          Serial.print(notesArray[1]);
          Serial.print(notesArray[2]);
          Serial.print(notesArray[3]);
          Serial.print(notesArray[4]);
          Serial.print(notesArray[5]);
          Serial.print(notesArray[6]);
          Serial.println(notesArray[7]);
        }

        whichReverbVoice = chan;
      }
      // save button state for next comparison:
      lastMux3Vals[chan] = mux3Vals[chan];
    }
    // delay(1);
  }
}

void clearflags() {
  instrumentchangeflag = 0;
  mutechangeflag = 0;
  clearchangeflag = 0;
}

void updateBottomRow() {
  for (int chan = 0; chan < 8; chan++) {
    mux1.channel(chan);

    for (int i = 0; i < numMuxReads; i++) {
      mux1Vals[chan] = mux1.read(chan);
    }

    // rewrte this part
    if (lastMux1Vals[chan] != mux1Vals[chan]) {
      Serial.print("Mux 1 Pressed Channel:  ");
      Serial.print(chan);
      Serial.print(" ");
      Serial.println(mux1Vals[chan]);

      if (mux1Vals[chan] == 1) {
        triggerNoteOff(currentNote);
      }
      if (mux1Vals[chan] == 0) {
        currentKeyPressed = chan;
        currentNote = keyboardNotes[currentKeyPressed] + (keyboardOctave * 12);
        triggerNoteOn(currentNote);

        if (melodyNotes[currentStepMelody] != currentNote) {
          melodyNotes[currentStepMelody] = currentNote;
          //filterCutoffs[currentStep] = release;

        } else {
          melodyNotes[currentStepMelody] = 0;
        }
      }
    }
    lastMux1Vals[chan] = mux1Vals[chan];
  }
}

void updateEnvelope() {

  // static int counter_print = 0;

  if (CurrentEncoderState == ADSR) {

    int newPos1 = encoder1->getPosition();
    if (newPos1 != lastPos1) {
      int dir = (int)encoder1->getDirection();
      if (dir == 1) {
        attack = attack - 5;
      } else {
        attack = attack + 5;
      }

      if (attack <= 0) {
        attack = 0;
      }
      if (attack >= 1000) {
        attack = 1000;
      }
      Serial.print("attack: ");
      Serial.println(attack);
    }
    lastPos1 = newPos1;
  }

  if (CurrentEncoderState == ADSR) {

    int newPos2 = encoder2->getPosition();
    // Serial.println(newPos2);
    if (newPos2 != lastPos2) {
      int dir = (int)encoder2->getDirection();
      if (dir == 1) {
        decay = decay + 5;
      } else {
        decay = decay - 5;
      }
      if (decay <= 0) {
        decay = 0;
      }

      if (decay >= 1000) {
        decay = 1000;
      }

      Serial.print("Decay: ");
      Serial.println(decay);
    }
    lastPos2 = newPos2;
  }

  //apply 2 all encoders
  if (CurrentEncoderState == ADSR) {

    int newPos3 = encoder3->getPosition();
    if (newPos3 != lastPos3) {
      Serial.println("c");
      int dir = (int)encoder3->getDirection();
      if (dir == 1) {
        normalizedCutoff += 0.02;
      } else {
        normalizedCutoff -= 0.02;
      }

      if (normalizedCutoff <= 0.02) {
        normalizedCutoff = 0.02;
      }
      if (normalizedCutoff >= 0.9) {
        normalizedCutoff = 0.9;
      }
      Serial.print("Normalized Cutoff: ");
      Serial.println(normalizedCutoff);
    }

    lastPos3 = newPos3;
  }

  if (CurrentEncoderState == ADSR) {

    int newPos4 = encoder4->getPosition();
    if (newPos4 != lastPos4) {
      Serial.println("r");
      int dir = (int)encoder4->getDirection();
      if (dir == 1) {
        resonance = resonance + 0.05;
      } else {
        resonance = resonance - 0.05;
      }
      if (resonance <= 0.7) {
        resonance = 0.7;
      }
      if (resonance >= 5) {
        resonance = 5;
      }
      Serial.print("res: ");
      Serial.println(resonance);
    }
    lastPos4 = newPos4;
  }

  envelope1.attack(attack);
  envelope1.hold(0);
  envelope1.decay(decay);
  envelope1.sustain(0);
  envelope1.release(0);

  cutoff = normalizedCutoff * normalizedCutoff * normalizedCutoff * 20000;
  filter1.frequency(cutoff);
  filter1.resonance(resonance);
}

void triggerNoteOn(int note) {
  waveformMod1.frequency(freqFromMidiNote(note));
  envelope1.noteOn();
}
void triggerNoteOff(int note) {
  envelope1.noteOff();
}

void updateAdsrButton() {

  lastadsrButton = adsrButton;
  adsrButton = 0;  //digitalRead(37);
  // Serial.println(adsrButton);

  if (adsrButton != lastadsrButton) {
    if (adsrButton == HIGH) {
      current_waveform++;
      if (current_waveform == 4) {  // we are skipping over waveform arbituary
        current_waveform = 5;
      }
      current_waveform %= 13;
      waveformMod1.begin(current_waveform);
      Serial.println(current_waveform);

      // if(currentNote > 80){
      //   currentNote = 60;
      // }
      // currentNote+=2;

      // triggerNoteOn(currentNote);

      Serial.println("envelope start");
    }
    if (adsrButton == LOW) {
      Serial.println("envelope off");
      triggerNoteOff(currentNote);
    }
  }
}

// void onNoteOn(int buttonNum) {
//   Serial.println("button pressed");
//   //envelope1.noteOn();
// }

// void onNoteOff(int buttonNum) {
//   Serial.println("button released");
//   //envelope1.noteOff();
//}

void updateVolume() {

  static int pos = 0;
  static int lastTime = millis();
  int delta_time = millis() - lastTime;
  if (delta_time > 100) {
    int newPos = encoderVolume->getPosition();
    if (pos != newPos) {

      Serial.print("pos:");
      Serial.print(newPos);
      Serial.print(" dir:");
      Serial.println((int)(encoderVolume->getDirection()));

      Serial.print("Millis - lasttime :");

      if (newPos > pos) {
        pos++;
      } else {
        pos--;
      }
      encoderVolume->setPosition(pos);

#ifdef SCENE_INSTEAD_OF_VOLUME
      loadScene(pos);
#else
      sgtl5000_1.volume(newVolume);

#endif

      lastTime = millis();

    }  // if
  } else {
    encoderVolume->setPosition(pos);
  }

  float newVolume = (float)(-1 * pos) / 100.0;
  if (newVolume > 1.0) {
    newVolume = 1.0;
  }
  if (newVolume < 0.0) {
    newVolume = 0.0;
  }
}

void updateTempo() {
  //tempo = map(analogRead(A17), 0, 1023, 50, 1000);

  static int pos = 0;
  static int lastTime = millis();

  if (millis() - lastTime > 100) {
    int newPos = encoderTempo->getPosition();
    if (pos != newPos) {
      lastTime = millis();
      Serial.print("pos:");
      Serial.print(newPos);
      Serial.print(" dir:");
      Serial.println((int)(encoderTempo->getDirection()));
      pos = newPos;
      encoderTempo->setPosition(pos);

    }  // if

    bpm = 120 + pos;
    if (bpm >= 360) {
      bpm = 360;
      pos = 240;
      encoderTempo->setPosition(pos);
    }
    if (bpm <= 5) {
      bpm = 5;
      pos = 5 - 120;
      encoderTempo->setPosition(pos);
    }

    //calculating milliseconds per step from BPM
    ms_per_step = (int)(60000.0 / (float)(bpm * 4));

    delay1.delayfade(0, ms_per_step * 2, 3.0);

  } else {
    encoderTempo->setPosition(pos);
  }
}

//effects area

void updateDrumMix() {

  if (CurrentEncoderState == Effects) {

    static int pos = 0;
    int newPos = encoder1->getPosition();
    if (pos != newPos) {  // ENCODER HAS CHANGED
      int dir = (int)encoder1->getDirection();
      drumVolumes[channel] += (float)(-1 * dir) / 50.0;

      Serial.println("Drum volume changed");

      if (drumVolumes[channel] > 2.0) {
        drumVolumes[channel] = 2.0;
      }

      if (drumVolumes[channel] < 0.0) {
        drumVolumes[channel] = 0.0;
      }

      //drumVolumes[channel] = newVolume;

      //setting the mixer levels
      mixer1.gain(0, 2.0 * drumVolumes[0] * globalGain);  //daf aka kick
      mixer1.gain(1, 1.0 * drumVolumes[1] * globalGain);  //tabla low
      mixer1.gain(2, 1.5 * drumVolumes[2] * globalGain);  //tabla mid
      mixer1.gain(3, 1.8 * drumVolumes[3] * globalGain);  //tabla high
      mixer2.gain(0, 0.5 * drumVolumes[4] * globalGain);  // riq hit
      mixer2.gain(1, 0.5 * drumVolumes[5] * globalGain);  // riq shake
      mixer2.gain(2, 0.5 * drumVolumes[6] * globalGain);  //oud
      mixer2.gain(3, 0.4 * drumVolumes[7] * globalGain);  //chant

      pos = newPos;
    }
  }
}

void updateDrumProbabilities() {

  if (CurrentEncoderState == Effects) {

    static int pos = 0;
    int newPos = encoder2->getPosition();
    if (pos != newPos) {  // ENCODER HAS CHANGED

      Serial.println("Drum probability changed");
      int dir = (int)encoder2->getDirection();
      drumProbabilities[channel] += (dir / 50.0);

      if (drumProbabilities[channel] > 1.0) {
        drumProbabilities[channel] = 1.0;
      }

      if (drumProbabilities[channel] < 0.0) {
        drumProbabilities[channel] = 0.0;
      }

      pos = newPos;
    }
  }
}

// Reverb Zone

void updateReverb() {

  if (CurrentEncoderState == Effects) {

    static int pos = 0;
    int newPos = encoder4->getPosition();
    if (pos != newPos) {  // ENCODER HAS CHANGED

      Serial.println("Reverb changed");
      int dir = (int)encoder4->getDirection();
      reverbSends[channel] += (float)(dir) / 20.0;
      if (reverbSends[channel] > 1.0) {
        reverbSends[channel] = 1.0;
      }
      if (reverbSends[channel] < 0.0) {
        reverbSends[channel] = 0.0;
      }

      //setting the reverb send levels
      reverbSend1to4.gain(0, reverbSends[0]);  //kick
      reverbSend1to4.gain(1, reverbSends[1]);  //clap
      reverbSend1to4.gain(2, reverbSends[2]);  //open hh
      reverbSend1to4.gain(3, reverbSends[3]);  //closed hh
      reverbSend5to8.gain(0, reverbSends[4]);  //snare
      reverbSend5to8.gain(1, reverbSends[5]);  //cowbell
      reverbSend5to8.gain(2, reverbSends[6]);  //ride
      reverbSend5to8.gain(3, reverbSends[7]);  //tom

      pos = newPos;
    }
  }
}

// Delay Zone

void updateDelay() {

  if (CurrentEncoderState == Effects) {
    int newPos = encoder3->getPosition();
    if (lastPosDelay != newPos) {
      int dir = (int)encoder3->getDirection();
      Serial.print(lastPosDelay);
      Serial.print(" ");
      Serial.print(newPos);
      if (newPos > lastPosDelay) {
        Serial.println("inc");
        delaySends[channel] += 0.1;
      } else {
        Serial.println("dec");
        delaySends[channel] -= 0.1;
      }

      if (delaySends[channel] <= 0) {
        delaySends[channel] = 0;
      }
      if (delaySends[channel] >= 1) {
        delaySends[channel] = 1;
      }
      lastPosDelay = newPos;
      Serial.println(delaySends[channel]);

      delaysend1_4.gain(0, delaySends[0]);
      delaysend1_4.gain(1, delaySends[1]);
      delaysend1_4.gain(2, delaySends[2]);
      delaysend1_4.gain(3, delaySends[3]);
      delaysend5_8.gain(0, delaySends[4]);
      delaysend5_8.gain(1, delaySends[5]);
      delaysend5_8.gain(2, delaySends[6]);
      delaysend5_8.gain(3, delaySends[7]);
    }
  }
}

void clearActiveDrumChannel() {

  int *notesArray = kickNotes;

  // assign array based on channel
  if (channel == 1) {
    notesArray = clapNotes;
  }
  if (channel == 2) {
    notesArray = openhihatNotes;
  }
  if (channel == 3) {
    notesArray = closedhihatNotes;
  }
  if (channel == 4) {
    notesArray = snareNotes;
  }
  if (channel == 5) {
    notesArray = cowbellNotes;
  }
  if (channel == 6) {
    notesArray = cymbalNotes;
  }
  if (channel == 7) {
    notesArray = tomNotes;
  }

  for (int i = 0; i < 8; i++) {
    notesArray[i] = 0;
  }
}

//Updates the sequence of selected channel when step button is pushed
void onButtonChangeNote(int pin, int step) {
}

void triggerSample(int channel) {

  if (mutes[channel] > 0) {
    return;
  }

  switch (channel) {

    case 0:
      sendMIDITrigger(DrumMIDINote0);
      playMem1.play(AudioSampleRivertoseakitdaf);
      break;

    case 1:
      sendMIDITrigger(DrumMIDINote1);
      playMem2.play(AudioSampleRivertoseakittablalow);
      break;

    case 2:
      sendMIDITrigger(DrumMIDINote2);
      playMem3.play(AudioSampleRivertoseakittablamid);
      break;

    case 3:
      sendMIDITrigger(DrumMIDINote3);
      playMem4.play(AudioSampleRivertoseakittablahigh);
      break;

    case 4:
      sendMIDITrigger(DrumMIDINote4);
      playMem5.play(AudioSampleRivertoseakitriqhit);
      break;

    case 5:
      sendMIDITrigger(DrumMIDINote5);
      playMem6.play(AudioSampleRivertoseakitriqshake);
      break;

    case 6:
      sendMIDITrigger(DrumMIDINote6);
      playMem7.play(AudioSampleRivertoseakitoud);
      break;

    case 7:
      sendMIDITrigger(DrumMIDINote7);
      playMem8.play(AudioSampleRivertoseakitchant);
      break;
  }
}

bool checkProbability(float probability) {
  float randomNum = (float)random(0, 100) / (float)100.0;

  if (randomNum < probability) {
    return true;
  } else {
    return false;
  }
}

void updateSequencer() {

  if (!playing) {
    return;
  }

  if (MIDI_ENABLED) {
    if (millis() > lastStepTime + (ms_per_step / 2)) {
      for (int i = 0; i < 128; i++) {
        if (notesOn[i] > 0) {
          MIDI.sendNoteOff(i, 100, 1);
          //delay(100);
          notesOn[i] = 0;
          //delay(100);
        }
      }
    }
  }

  if (millis() > lastStepTime + ms_per_step) {

    lastStepTime = millis();

    //Playing back melody sequence with MIDI OUT

    if (keyboardSequenceMute == 0 && melodyNotes[currentStepMelody] > 0) {
      //Serial.println("hi");
      triggerNoteOff(melodyNotes[currentStepMelody]);  // going to eventually replace whole thing to playSDwave.play(filename)
      triggerNoteOn(melodyNotes[currentStepMelody]);   // going to eventually replace whole thing to playSDwave.play(filename)
      // MIDI.sendNoteOff(melodyNotes[currentStep], 100, 1);
      int lastNote = random(32, 100);

      if (MIDI_ENABLED) {
        MIDI.sendNoteOn(melodyNotes[currentStepMelody], 100, 1);
        Serial.println(melodyNotes[currentStepMelody]);
        notesOn[melodyNotes[currentStepMelody]] = 1;
      }
    }

    if (kickNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[0])) {
        triggerSample(0);
      }
    }
    if (clapNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[1])) {
        triggerSample(1);
      }
    }
    if (openhihatNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[2])) {
        triggerSample(2);
      }
    }
    if (closedhihatNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[3])) {
        triggerSample(3);
      }
    }
    if (snareNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[4])) {
        triggerSample(4);
      }
    }
    if (cowbellNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[5])) {
        triggerSample(5);
      }
    }
    if (cymbalNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[6])) {
        triggerSample(6);
      }
    }
    if (tomNotes[currentStep] > 0) {
      if (checkProbability(drumProbabilities[7])) {
        triggerSample(7);
      }
    }

    displayStep = currentStep;
    currentStep++;
    currentStepMelody++;

    if (currentStep >= totalSteps) {
      currentStep = 0;
    }

    if (currentStepMelody >= totalStepsMelody) {
      currentStepMelody = 0;
    }

    updateLeds();
  }
}

void updateLed(int num, int on, LitaColor color) {

  int red = 0;
  int green = 0;
  int white = 0;
  int blue = 0;

  switch (color) {
    //pink
    case LitaColorChannel0:
      red = 255;
      green = 0;
      blue = 255;
      break;

    case LitaColorChannel1:
      //blue
      red = 0;
      green = 255;
      blue = 255;
      break;

    case LitaColorChannel2:
      //blue
      red = 64;
      green = 128;
      blue = 255;
      break;

    case LitaColorChannel3:

      //yellow
      red = 255;
      green = 128;
      blue = 255;
      break;

    //yellow
    case LitaColorChannel4:
      red = 128;
      green = 0;
      blue = 255;
      break;

    case LitaColorChannel5:
      red = 0;
      green = 255;
      blue = 64;
      break;

    case LitaColorChannel6:
      red = 64;
      green = 255;
      blue = 64;
      break;

    case LitaColorChannel7:
      red = 64;
      green = 255;
      blue = 64;
      break;

    case LitaColorSequence:
      red = 255;
      green = 255;
      blue = 240;
      break;

    case LitaColorMute:
      red = 155;
      green = 0;
      blue = 0;
      break;

    case StepActive:
      red = 0;
      green = 255;
      blue = 0;
      break;
  }

  //brightness of lights -- high number is darker
  int dimFactor = 6;

  // neopixel.setPixelColor(num, 0, 0, 0);  //red
  // neopixel.show();

  if (on) {
    neopixel.setPixelColor(num, red / dimFactor, green / dimFactor, blue / dimFactor);  //red
  } else {
    neopixel.setPixelColor(num, 0, 0, 0);
  }
}

void updateLeds() {

  for (int i = 0; i < totalSteps; i++) {

    // if (channel == 0) {
    if (kickNotes[i] == 1) {
      updateLed(i, 1, StepActive);
    } else {
      updateLed(i, 0, StepActive);
    }
    // }

    // if (channel == 1) {
    if (clapNotes[i] == 1) {
      updateLed(i + 8, 1, StepActive);
    } else {
      updateLed(i + 8, 0, StepActive);
    }
    // }

    // if (channel == 2) {
    if (openhihatNotes[i] == 1) {
      updateLed(i + 16, 1, StepActive);
    } else {
      updateLed(i + 16, 0, StepActive);
    }
    //}

    // if (channel == 3) {
    if (closedhihatNotes[i] == 1) {
      updateLed(i + 24, 1, StepActive);
    } else {
      updateLed(i + 24, 0, StepActive);
    }
    //}

    //if (channel == 4) {
    if (snareNotes[i] == 1) {
      updateLed(i + 32, 1, StepActive);
    } else {
      updateLed(i + 32, 0, StepActive);
    }
    //}

    //if (channel == 5) {
    if (cowbellNotes[i] == 1) {
      updateLed(i + 40, 1, StepActive);
    } else {
      updateLed(i + 40, 0, StepActive);
    }
    //}

    //if (channel == 6) {
    if (cymbalNotes[i] == 1) {
      updateLed(i + 48, 1, StepActive);
    } else {
      updateLed(i + 48, 0, StepActive);
    }
    //}

    //if (channel == 7) {
    if (tomNotes[i] == 1) {
      updateLed(i + 56, 1, StepActive);
    } else {
      updateLed(i + 56, 0, StepActive);
    }
    //}
  }

  //Mutes
  for (int i = 0; i < 8; i++) {
    if (mutes[i] > 0) {
      updateLed(i * 8, 1, LitaColorMute);
      updateLed(i * 8 + 1, 1, LitaColorMute);
      updateLed(i * 8 + 2, 1, LitaColorMute);
      updateLed(i * 8 + 3, 1, LitaColorMute);
      updateLed(i * 8 + 4, 1, LitaColorMute);
      updateLed(i * 8 + 5, 1, LitaColorMute);
      updateLed(i * 8 + 6, 1, LitaColorMute);
      updateLed(i * 8 + 7, 1, LitaColorMute);
    }
  }

  //Vertical Bar
  int myDisplayStep = displayStep;
  if (displayStep >= 0) {
    while (myDisplayStep < 64) {
      updateLed(myDisplayStep, 1, LitaColorSequence);
      myDisplayStep += 8;
    }
  }

  neopixel.show();
}

void updateDisplay() {

  display.clearDisplay();  // clears the screen and buffer

  display.setRotation(0);
  display.clearDisplay();

  // text display tests

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  //display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print(bpm);
  display.setTextSize(1);
  display.println("BPM");

  display.setTextSize(0.5);

  display.print("Attack:");
  display.println((float)attack / 1000.0);
  display.print("DrumVol:");
  display.println((float)drumVolumes[channel]);

  display.print("Decay:");
  display.print((float)decay / 1000.0);
  display.print(" Prob:");
  display.println();

  display.print("CO:");
  display.print((float)cutoff);

  display.print(" Del:");
  display.println((float)delaySends[channel]);

  display.print("Res:");
  display.print((float)resonance);
  display.print(" Rev:");
  display.println((float)reverbSends[channel]);

  display.print("Synth ");
  if (keyboardSequenceMute == 1) {
    display.println("Off");
  } else if (keyboardSequenceMute == 0) {
    display.println("On");
  }
  //display.println(keyboardSequenceMute);

  if (mutechangeflag == 1) {
    display.println("Choose track to mute");
  } else if (instrumentchangeflag == 1) {
    display.println("Choose track to edit");
  } else if (clearchangeflag == 1) {
    display.println("Choose chan to clear");

  } else {

    display.print("Editing: ");

    switch (channel) {
      case 0:
        display.print("Tabla Mid");  //kick
        break;
      case 1:
        display.print("Tabla Low");  //clap
        break;
      case 2:
        display.print("Tabla High");  //Open High
        break;
      case 3:
        display.print("Riq Shake");  //Clsed HH
        break;
      case 4:
        display.print("Riq Hit");  //snare
        break;
      case 5:
        display.print("Oud");  //Cowbell
        break;
      case 6:
        display.print("Daf");  //cymbal
        break;
      case 7:
        display.print("Chant");  //Tom
        break;
    }
  }

  display.setCursor(75, 0);
  display.print("Oct:");
  display.println(keyboardOctave);

  display.setCursor(75, 10);

  display.print("Wav:");

  switch (current_waveform) {
    case 0:
      display.print("Sin");
      break;
    case 1:
      display.print("Saw");
      break;
    case 2:
      display.print("Sq");
      break;
    case 3:
      display.print("Tri");
      break;
    case 4:
      display.print("Arb");
      break;
    case 5:
      display.print("Pls");
      break;
    case 6:
      display.print("RSw");
      break;
    case 7:
      display.print("S&H");
      break;
    case 8:
      display.print("VTri");
      break;
    case 9:
      display.print("BSaw");
      break;
    case 10:
      display.print("BRSw");
      break;
    case 11:
      display.print("BSq");
      break;
    case 12:
      display.print("BPls");
      break;
  }
  display.println();
  display.display();
}