diff --git a/code/daisy-looper/README.md b/code/daisy-looper/README.md
deleted file mode 100644
index bacab1a29c72756576855193ee23afec135b449e..0000000000000000000000000000000000000000
--- a/code/daisy-looper/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# daisy-looper
-
-
-
-# What does the looper do?
-
-*daisy-looper* is a software that can be installed on the [daisyy hardware](../../README.md) developed in the course *Synthesizer DIY* that took place during winter semester 2023/2024 at HFBK Hamburg. The looper allows you to record audio present at the input and [overdub](https://en.wikipedia.org/wiki/Overdubbing) into up to 5 different virtual "tapes" called *buffers*. The recorded sounds stored in each buffer will be displayed as a waveform and can be played back at different speeds (including reverse speed). 
-
diff --git a/code/daisy-looper/button_grid.h b/code/daisy-looper/button_grid.h
deleted file mode 100644
index 96395e3a441d14019b08c57eaf5f938a884df272..0000000000000000000000000000000000000000
--- a/code/daisy-looper/button_grid.h
+++ /dev/null
@@ -1,187 +0,0 @@
-#ifndef Buttongrid_h
-#define Buttongrid_h
-
-#include "Adafruit_SH110X.h"
-#include "Adafruit_GFX.h"
-#include "potentiometers.h"
-#include "buttons.h"
-#include "ui.h"
-
-
-extern Potentiometer pot_1, pot_2, pot_3, pot_4, pot_5, pot_6, pot_7;
-extern Button button_1, button_2, button_3, button_4, button_5, button_6;
-extern Adafruit_SH1106G display;
-
-// Represents the different types of GridButtons in the UI
-enum ButtonType {
-  BUTTON_TYPE_SIMPLE,       // Simple Button that can be pressed
-  BUTTON_TYPE_TOGGLE,       // Toggles between two values (name needs to have a break "\n")
-  BUTTON_TYPE_MULTITOGGLE,  // Toggles between two or more values (name needs to have a break "\n")
-  BUTTON_TYPE_ENUM,         // Toggles between a group of buttons
-  BUTTON_TYPE_LAST
-};
-
-// A Gridbutton is a single button within the Ui-Button Grid
-// The name can have multiple lines, delimited by "\n" which
-// will be used to represent different states for buttons of
-// the type BUTTON_TYPE_TOGGLE or BUTTON_TYPE_MULTITOGGLE
-// is_home tells us if this is the home button (and thus should
-// be rendered inverted)
-class GridButton {
-  public:
-    const char* name;
-    const char* description;
-    GridButton(const char* name, Button *button, bool is_home=false, ButtonType type=BUTTON_TYPE_SIMPLE, int default_value=0, const char* description="")
-     : 
-      name(name),
-      button(button),
-      is_home(is_home),
-      type(type),
-      active(default_value),
-      description(description)
-    {
-      // Count the number of lines in the name
-      for(int i = 0; name[i] != '\0'; i++) {
-          if(name[i] == '\n')
-              ++lines;
-      }
-    }
-    Button *button;
-    ButtonType type;
-    bool is_home;
-    bool should_render_description = false;
-    int active;
-    int lines = 0;
-    
-    // Go to the next option
-    void next() {
-      active++;
-      if (active > lines) {
-        active = 0;
-      }
-    }
-
-    void renderDescription() {
-      if (should_render_description) {
-        display.setTextWrap(true);
-        display.clearDisplay();
-        display.setCursor(0,0);
-        display.setTextColor(SH110X_WHITE);
-        display.print(description);
-        display.setTextWrap(false);
-      }
-    }
-};
-
-// The ButtonGrid is a grid of 2×3 = 6 buttons
-class ButtonGrid {
-  public:
-    ButtonGrid(int home_mode, const GridButton (&grid_buttons)[6]) 
-    : grid_buttons_{
-        grid_buttons[0], 
-        grid_buttons[1], 
-        grid_buttons[2], 
-        grid_buttons[3], 
-        grid_buttons[4], 
-        grid_buttons[5]
-      },
-      ui_mode(home_mode)
-    {}
-    GridButton grid_buttons_[6];
-    int ui_mode;
-
-    void setup() {
-      for (int n=0; n<6; n++) {
-        if (!grid_buttons_[n].is_home) {
-          // Not a home button, display help on long hold and hide on release
-          // grid_buttons_[n].button->onLongHold([this, n](){
-          //   grid_buttons_[n].should_render_description = true;
-          // });
-          // grid_buttons_[n].button->onReleased([this, n](){
-          //   grid_buttons_[n].should_render_description = false;
-          // });
-        }
-      }
-    }
-
-    int homeButtonIndex() {
-      for (int i=0; i<6; i++) {
-        if (grid_buttons_[i].is_home) {
-          return i;
-        }
-      }
-      return -1;
-    }
-
-    void hideAllDescriptions() {
-      for (int i=0; i<6; i++) {
-        grid_buttons_[i].should_render_description = false;
-      }
-    }
-
-    void render(int button_enum) {
-      int width = display.width();
-      int height = display.height();
-      int box_width = int(width/3.0f);
-      int box_height= int(height/2.0f);
-      int i = 0;
-      // Draw boxes (2 rows, 3 columns)
-      for (int box_y=0; box_y<2; box_y++) {
-        for (int box_x=0; box_x<3; box_x++) {
-          // Get the current buttons name
-          const char* name = grid_buttons_[i].name;
-
-          // Prepare colors
-          uint16_t bg_color = SH110X_BLACK;
-          uint16_t text_color = SH110X_WHITE;
-
-          // Home-Buttons have a inverted color scheme
-          if (grid_buttons_[i].is_home) {
-            bg_color = SH110X_WHITE;
-            text_color = SH110X_BLACK;
-          }
-
-          // Position variables
-          uint16_t x = box_x * box_width;
-          uint16_t y = box_y * box_height;
-          uint16_t xc = x + box_width/2;
-          uint16_t yc = y + box_height/2;
-
-          // Fill Background
-          display.fillRect(x, y, box_width, box_height, bg_color);
-
-          // Render the different button types
-          if (grid_buttons_[i].type == BUTTON_TYPE_TOGGLE) {
-            centeredTextMarkMulti(name, xc, yc, text_color, grid_buttons_[i].active, 12);
-          } else if (grid_buttons_[i].type == BUTTON_TYPE_MULTITOGGLE) {
-            button_multi(name, xc, yc, text_color, grid_buttons_[i].active, grid_buttons_[i].lines);
-          } else if (grid_buttons_[i].type == BUTTON_TYPE_ENUM) {
-            bool active = i == button_enum;
-            centeredTextMark(name, xc, yc, text_color, active);
-          } else {
-            centeredText(name, xc, yc, text_color);
-          }
-          // Increase ounter for the index of the button
-          i++;
-        }
-      }
-      
-      // Draw divider lines
-      display.drawFastVLine(box_width, 0, height, SH110X_WHITE);
-      display.drawFastVLine(box_width*2, 0, height, SH110X_WHITE);
-      display.drawFastHLine(0, box_height, width, SH110X_WHITE);
-
-      // Render Descriptions on top (hence another loop)
-      i = 0;
-      // Draw boxes (2 rows, 3 columns)
-      for (int box_y=0; box_y<2; box_y++) {
-        for (int box_x=0; box_x<3; box_x++) {
-          grid_buttons_[i].renderDescription();
-          i++;
-        }
-      }
-    }
-};
-
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/buttons.h b/code/daisy-looper/buttons.h
deleted file mode 100644
index 4ab6d9935deb016e332dd482f1080f93688a2b17..0000000000000000000000000000000000000000
--- a/code/daisy-looper/buttons.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#include "wiring_constants.h"
-#ifndef Buttons_h
-#define Buttons_h
-
-#include "Arduino.h"
-#include "Adafruit_SH110X.h"
-#include "Adafruit_GFX.h"
-extern Adafruit_SH1106G display;
-
-#define DURATION_SHORT_PRESS 800
-#define DURATION_VERY_LONG_PRESS 2000
-
-
-
-
-
-class Button {
-  int pin;
-  bool has_been_pressed;
-  unsigned long press_start;
-  unsigned long release_start;
-  std::function<void()> onPressFunction;
-  std::function<void()> onHoldFunction;
-  std::function<void()> onLongHoldFunction;
-  std::function<void()> onVeryLongHoldFunction;
-  std::function<void()> onLongPressFunction;
-  std::function<void()> onVeryLongPressFunction;
-  std::function<void()> onReleasedFunction;
-
-  public:
-    Button(int pin);
-    void init();
-    void read();
-    unsigned long pressed_since();
-    unsigned long released_since();
-
-    void onPress(std::function<void()> f);
-    void onHold(std::function<void()> f);
-    void onLongHold(std::function<void()> f);
-    void onVeryLongHold(std::function<void()> f);
-    void onLongPress(std::function<void()> f);
-    void onVeryLongPress(std::function<void()> f);
-    void onReleased(std::function<void()> f);
-
-    void reset();
-};
-
-Button::Button(int pin) {
-  this->pin = pin;
-}
-
-void Button::init() {
-  pinMode(this->pin, INPUT_PULLUP);
-  this->has_been_pressed = false;
-  this->press_start = 0;
-  this->release_start = 0;
-}
-
-void Button::read() {
-  int is_pressed = !digitalRead(this->pin);
-  
-  if (is_pressed && this->press_start == 0) {
-    this->press_start = millis();
-  }
-  if (!is_pressed && this->has_been_pressed && this->release_start == 0) {
-    this->release_start = millis();
-  }
-
-  unsigned long pressed_since = this->pressed_since();
-  unsigned long released_since = this->released_since();
-  
-  if (is_pressed) {
-    // Fire the callback function all the time while this is being pressed
-    if (this->onHoldFunction) { this->onHoldFunction(); }
-
-    if (this->pressed_since() > 1000) {
-      if (this->onLongHoldFunction) { this->onLongHoldFunction(); }
-    }
-    if (this->pressed_since() > 5000) {
-      if (this->onVeryLongHoldFunction) { this->onVeryLongHoldFunction(); }
-    }
-    // Serial.print("Pressed since ");
-    // Serial.println(pressed_since);
-    if ( released_since > 100) {
-      this->has_been_pressed = false;
-    }
-  } else {
-    // Not pressed.
-    if (!this->has_been_pressed) {
-      if (pressed_since > 0 && pressed_since < DURATION_SHORT_PRESS) {
-        if (this->onPressFunction) { this->onPressFunction(); }
-        // Serial.print("Short Press (released after ");
-        // Serial.print(pressed_since);
-        // Serial.print(", released since ");
-        // Serial.print(released_since);
-      } else if (pressed_since > 0 &&  pressed_since < DURATION_VERY_LONG_PRESS) {
-        if (this->onLongPressFunction) { this->onLongPressFunction(); }
-        // Serial.print("Long Press (released after ");
-        // Serial.print(pressed_since);
-        // Serial.println(")");
-      } else if (pressed_since > 0 && pressed_since >= DURATION_VERY_LONG_PRESS) {
-        if (this->onVeryLongPressFunction) { this->onVeryLongPressFunction(); }
-        // Serial.print("Very Long Press (released after ");
-        // Serial.print(pressed_since);
-        // Serial.println(")");
-      }
-      this->press_start = 0;
-      this->has_been_pressed = true;
-      this->release_start = millis();
-      if (this->onReleasedFunction) { this->onReleasedFunction(); }
-    }
-  }
-}
-
-unsigned long Button::pressed_since() {
-  if ( this->press_start == 0) {
-    return 0;
-  }
-  return millis() - this->press_start;
-}
-
-unsigned long Button::released_since() {
-  if ( this->release_start == 0) {
-    return 0;
-  }
-  return millis() - this->release_start;
-}
-
-void Button::onPress(std::function<void()> f) {
-  this->onPressFunction = f;
-}
-
-void Button::onHold(std::function<void()> f) {
-  this->onHoldFunction = f;
-}
-
-void Button::onLongHold(std::function<void()> f) {
-  this->onLongHoldFunction = f;
-}
-
-void Button::onVeryLongHold(std::function<void()> f) {
-  this->onVeryLongHoldFunction = f;
-}
-
-void Button::onLongPress(std::function<void()> f) {
-  this->onLongPressFunction = f;
-}
-
-void Button::onVeryLongPress(std::function<void()> f) {
-  this->onVeryLongPressFunction = f;
-}
-
-void Button::onReleased(std::function<void()> f) {
-  this->onReleasedFunction = f;
-}
-
-void Button::reset() {
-  this->onPressFunction = NULL;
-  this->onHoldFunction = NULL;
-  this->onLongPressFunction = NULL;
-  this->onVeryLongPressFunction = NULL;
-}
-
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/daisy-looper.ino b/code/daisy-looper/daisy-looper.ino
deleted file mode 100644
index b19ec1885feda0039f732ee8acb37ce07b295706..0000000000000000000000000000000000000000
--- a/code/daisy-looper/daisy-looper.ino
+++ /dev/null
@@ -1,467 +0,0 @@
-#include "DaisyDuino.h"
-#include <Wire.h>
-#include <Adafruit_GFX.h>
-#include <Adafruit_SH110X.h>
-#include <MIDI.h>
-
-#include "leds.h"
-#include "potentiometers.h"
-#include "buttons.h"
-#include "looper.h"
-#include "env_follower.h"
-#include "helpers.h"
-#include "luts.h"
-#include "ui.h"
-#include "lfo.h"
-
-MIDI_CREATE_DEFAULT_INSTANCE();
-#define BUFFER_LENGTH_SECONDS 5
-
-#define DEBUGMODE
-
-static const size_t buffer_length = 48000 * BUFFER_LENGTH_SECONDS;
-static float DSY_SDRAM_BSS buffer[buffer_length];
-static float DSY_SDRAM_BSS buffer_b[buffer_length];
-static float DSY_SDRAM_BSS buffer_c[buffer_length];
-static float DSY_SDRAM_BSS buffer_d[buffer_length];
-static float DSY_SDRAM_BSS buffer_e[buffer_length];
-
-
-// Create instances of audio stuff
-atoav::Looper looper_a, looper_b, looper_c, looper_d, looper_e;
-static atoav::EnvelopeFollower input_envelope_follower;
-DSY_SDRAM_BSS ReverbSc reverb;
-static Compressor compressor;
-Oscillator lfo;
-static SampleHold sample_and_hold;
-static WhiteNoise noise;
-static Metro tick;
-static Easer easer;
-
-// Initialize Buttons  
-Button button_1 = Button(D7);
-Button button_2 = Button(D8);
-Button button_3 = Button(D9);
-Button button_4 = Button(D10);
-Button button_5 = Button(D13);
-Button button_6 = Button(D27);
-
-// Initialize Potentiometers
-Potentiometer pot_1 = Potentiometer(A0);
-Potentiometer pot_2 = Potentiometer(A1);
-Potentiometer pot_3 = Potentiometer(A3);
-Potentiometer pot_4 = Potentiometer(A2);
-Potentiometer pot_5 = Potentiometer(A4);
-Potentiometer pot_6 = Potentiometer(A5);
-Potentiometer pot_7 = Potentiometer(A6);
-
-// RGB LED               R    G    B
-RGBLed rgb_led = RGBLed(A10, A11, A9);
-
-
-// OLED Display
-#define SCREEN_WIDTH 128 // OLED display width, in pixels
-#define SCREEN_HEIGHT 64 // OLED display height, in pixels
-#define OLED_RESET -1   //   QT-PY / XIAO
-Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
-
-// User Interface
-Ui ui;
-
-// Daisy
-DaisyHardware hw;
-
-// Variables for the Audio-Callback
-size_t num_channels;
-float blocksize;
-float drywetmix = 0.0f;
-float volume = 1.0f;
-float reverbmix = 0.0f;
-float lfo_amount = 0.0f;
-float pitch_val = 0.5f;
-float midi_pitch_offset = 0.0f;
-
-float reverb_tone = 15000.0f;
-float reverb_decay = 0.95f;
-float lfo_speed = 8.0f;
-int lfo_kind = 0;
-float rand_pitch_mod = 0.0f;
-
-//float pressure = 0.0f;
-
-// Actual audio-processing is orchestrated here
-void AudioCallback(float **in, float **out, size_t size) {
-  float output1, output2 = 0.0f;
-  float out1, out2;
-  reverb.SetFeedback(reverb_decay);
-  reverb.SetLpFreq(reverb_tone);
-  lfo.SetFreq(lfo_speed);
-  tick.SetFreq(lfo_speed);
-  
-  // Iterate through the samples in the buffer
-  for (size_t i = 0; i < size; i++) {
-    float lfo_value = 0.0f;
-    switch (lfo_kind) {
-      case LfoKind::LFO_KIND_TRI:
-        lfo.SetWaveform(Oscillator::WAVE_TRI);
-        lfo_value = lfo.Process();
-        break;
-      case LfoKind::LFO_KIND_SQR:
-        lfo.SetWaveform(Oscillator::WAVE_SQUARE);
-        lfo_value = lfo.Process();
-        break;
-      default:
-        break;
-    }
-    
-    tick.SetFreq(0.25f+lfo_speed*49.75f);
-    uint8_t trig = tick.Process();
-    float noise_value = noise.Process();
-
-    switch (lfo_kind) {
-      case LfoKind::LFO_KIND_RAND:
-        easer.setFactor(0.01);
-        break;
-      case LfoKind::LFO_KIND_JUMP:
-        easer.setFactor(1.0);
-        break;
-    }
-
-    float rand = easer.Process(
-      sample_and_hold.Process(
-        trig, 
-        noise_value * 5.0f, 
-        sample_and_hold.MODE_SAMPLE_HOLD
-    ));
-
-    if (ui.rec_source == REC_SOURCE_NOISE) {
-     ui.activeLooper()->Record(noise_value * 0.5f);
-    }
-    // When the metro ticks, trigger the envelope to start.
-    float random_amount = lfo_amount * 2.0;
-    
-    if (trig) {
-      // Random LFO
-      switch (lfo_kind) {
-        case LfoKind::LFO_KIND_RAND:
-          rand_pitch_mod = rand * random_amount * 5.0f;
-          break;
-        case LfoKind::LFO_KIND_JUMP:
-          // Chance
-          if (drand(0.0f, 1.0f) < lfo_amount) {
-            ui.activeLooper()->addToPlayhead(rand * random_amount * 8000.0f);
-          }
-          break;
-        default:
-          break;
-      }
-    }
-
-    // Add the LFO to the signal if it is active
-    switch (lfo_kind) {
-      case LfoKind::LFO_KIND_TRI:
-      case LfoKind::LFO_KIND_SQR:
-        ui.activeLooper()->setPlaybackSpeed(pitch_val + lfo_value * lfo_amount + midi_pitch_offset);
-        break;
-      case LfoKind::LFO_KIND_RAND:
-        ui.activeLooper()->setPlaybackSpeed(pitch_val + rand_pitch_mod + midi_pitch_offset);
-        break;
-      default:
-        ui.activeLooper()->setPlaybackSpeed(pitch_val + midi_pitch_offset);
-        break;
-    }
-    
-
-    float looper_out;
-    
-    if (ui.rec_source == REC_SOURCE_PRE) {
-     ui.activeLooper()->Record(in[1][i]);
-    }
-
-    if (ui.rec_source == REC_SOURCE_LAST_BUF) {
-      // FIXME: This might process the previous looper twice later below, add check...
-      ui.activeLooper()->Record(ui.previousLooper()->Process());
-    }
-    
-    // Process the input envelope
-    input_envelope_follower.Process(in[1][i]);
-
-    // Process the Looper
-    switch (ui.buffer_summing_mode) {
-      case BUFFER_SUM_MODE_SOLO:
-        // Only play active looper
-        looper_out = ui.activeLooper()->Process();
-        break;
-      case BUFFER_SUM_MODE_SUM:
-        // Sum all loopers
-        looper_out = looper_a.Process();
-        looper_out += looper_b.Process();
-        looper_out += looper_c.Process();
-        looper_out += looper_d.Process();
-        looper_out += looper_e.Process();
-        looper_out = looper_out;
-        break;
-      case BUFFER_SUM_MODE_RING:
-        // Sum all loopers and ringmodulate with input
-        looper_out = looper_a.Process();
-        looper_out += looper_b.Process();
-        looper_out += looper_c.Process();
-        looper_out += looper_d.Process();
-        looper_out += looper_e.Process();
-        float deadbanded_input;
-        if (in[1][i] < 0.0f) {
-          deadbanded_input = min(0.0f, in[1][i] + 0.05f);
-        } else {
-          deadbanded_input = max(0.0f, in[1][i] - 0.05f);
-        }
-        looper_out *= deadbanded_input*2.0f;
-        looper_out = looper_out;
-        break;
-    }
-
-    // looper_out = pressure * looper_out;
-    looper_out = saturate(volume * looper_out);
-
-    // Mix the dry/Wet of the looper
-    output1 = output2 = drywetmix * looper_out + in[1][i] * (1.0f - drywetmix);
-
-    // Compress the signal
-    compressor.Process(output1);
-
-    // Process reverb
-    reverb.Process(output1, output1, &out1, &out2);
-
-    // Short decays are silent, so increase level here
-    float dec_fac = 1.0f + (1.0f - reverb_decay) * 2.0f;
-    out1 = out1 * dec_fac;
-    out2 = out2 * dec_fac;
-
-    // Mix reverb with the dry signal depending on the amount dialed
-    output1 = output1 * (1.0f - reverbmix) + out1 * reverbmix;
-    output2 = output1 * (1.0f - reverbmix) + out2 * reverbmix;
-
-    // Record the output if needed
-    if (ui.rec_source == REC_SOURCE_OUT) {
-     ui.activeLooper()->Record(output1);
-    }
-    
-    out[0][i] = output1;
-    out[1][i] = output2;
-  }
-}
-
-// TODO: Add Voice Stealing/Multiple Playheads?
-// TODO: Is USB Midi possible? https://github.com/electro-smith/DaisyExamples/blob/master/seed/USB_MIDI/USB_MIDI.cpp
-
-void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) {
-  #ifdef DEBUGMODE
-  Serial.print("[MIDI ON] chn<");
-  Serial.print((int) inChannel);
-  Serial.print("> note<");
-  Serial.print((int) inNote);
-  Serial.print("> velocity<");
-  Serial.print((int) inVelocity);
-  Serial.println(">");
-  #endif
-  // Note Off can come in as Note On w/ 0 Velocity
-  if (inVelocity == 0.0f) {
-    midi_pitch_offset = 0.0f;
-  } 
-  else {
-    midi_pitch_offset = (int(inNote)-36.0)/12.0f;
-  }
-}
-
-
-
-void handleNoteOff(byte inChannel, byte inNote, byte inVelocity) {
-  #ifdef DEBUGMODE
-  Serial.print("[MIDI OFF] chn<");
-  Serial.print((int) inChannel);
-  Serial.print("> note<");
-  Serial.print((int) inNote);
-  Serial.print("> velocity<");
-  Serial.print((int) inVelocity);
-  Serial.println(">");
-  #endif
-  midi_pitch_offset = 0.0f;
-}
-
-// void handleAftertouch(byte channel, byte channel_pressure) {
-//   #ifdef DEBUGMODE
-//   Serial.print("[MIDI AFTER] chn<");
-//   Serial.print((int) channel);
-//   Serial.print("> pressure<");
-//   Serial.print((int) channel_pressure);
-//   Serial.println(">");
-//   #endif
-//   pressure = float(channel_pressure)/127.0f;
-// }
-
-
-
-void setup() {
-  float sample_rate;
-  // Initialize for Daisy pod at 48kHz
-  hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
-  DAISY.SetAudioBlockSize(64);
-  num_channels = hw.num_channels;
-  sample_rate = DAISY.get_samplerate();
-  blocksize = 64.0f;
-
-  // Create a Tick and a noise source for the Sample and Hold
-  tick.SetFreq(1.0f+lfo_amount*99.0f);
-  tick.Init(10, sample_rate);
-  noise.Init();
-  
-  // Initialize Looper with the buffer
-  looper_a.Init(buffer, buffer_length);
-  looper_b.Init(buffer_b, buffer_length);
-  looper_c.Init(buffer_c, buffer_length);
-  looper_d.Init(buffer_d, buffer_length);
-  looper_e.Init(buffer_e, buffer_length);
-
-  // Initialize Envelope Follower for the Level LED
-  input_envelope_follower.Init(sample_rate);
-  input_envelope_follower.SetAttack(100.0);
-  input_envelope_follower.SetDecay(1000.0);
-
-  // Initialize Reverb
-  reverb.Init(sample_rate);
-  reverb.SetFeedback(reverb_decay);
-  reverb.SetLpFreq(reverb_tone);
-
-  // Initialize Compressor
-  compressor.SetThreshold(-64.0f);
-  compressor.SetRatio(2.0f);
-  compressor.SetAttack(0.005f);
-  compressor.SetRelease(0.1250);
-
-  // Initialize the LFO for modulations
-  lfo.Init(sample_rate);
-  lfo.SetWaveform(Oscillator::WAVE_TRI);
-  lfo.SetAmp(1);
-  lfo.SetFreq(lfo_speed);
-
-  // Easer for the random jumps
-  easer.setFactor(0.001);
-
-  // Start serial communications
-  Serial.begin(250000);
-
-  // Initialize Display
-  display.begin(0x3C, true);
-  delay(50);
-  ui.Render();
-  
-  // Initialize the LED
-  rgb_led.init();
-
-  // Set the analog read and write resolution to 12 bits
-  analogReadResolution(12);
-
-  // Setup MIDI handlers
-  MIDI.setHandleNoteOn(handleNoteOn);
-  MIDI.setHandleNoteOff(handleNoteOff);
-  // MIDI.setHandleAfterTouchChannel(handleAftertouch);
-  
-  MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages
-
-  // Set Knob names and display functions
-  pot_1.name = "Start";
-  pot_2.name = "Length";
-  pot_3.setDisplayMode("Speed", 1000.0f, POT_DISPLAY_MODE_PERCENT);
-  pot_4.setDisplayMode("Mix", 100.0f, POT_DISPLAY_MODE_PERCENT);
-  pot_5.setDisplayMode("LFO", 100.0f, POT_DISPLAY_MODE_PERCENT);
-  pot_6.setDisplayMode("Volume", 400.0f, POT_DISPLAY_MODE_PERCENT);
-  pot_7.setDisplayMode("Reverb", 100.0f, POT_DISPLAY_MODE_PERCENT);
-
-  // Set Knob Scaling Modes
-  // pot_3.setBipolar();
-  pot_3.setPitch();
-
-  // Initialize Buttons (callbacks are assigned in the Ui class)
-  button_1.init();
-  button_2.init();
-  button_3.init();
-  button_4.init();
-  button_5.init();
-  button_6.init();
-
-  // Start the audio Callback
-  DAISY.begin(AudioCallback);
-}
-
-void loop() {
-  // Read the values from the potentiometers
-  float p1 = pot_1.read();
-  float p2 = pot_2.read();
-  float p3 = pot_3.read();
-  float p4 = pot_4.read();
-  float p5 = pot_5.read();
-  float p6 = pot_6.read();
-  float p7 = pot_7.read();
-
-  // Update the UI
-  ui.update();
-
-  // Read the buttons
-  button_1.read();
-  button_2.read();
-  button_3.read();
-  button_4.read();
-  button_5.read();
-  button_6.read();
-
-  // Set loop-start and loop-length with the potentiometers
-  ui.setLoop(p1, p2);
-  
-  // Tune the pitch to the ten-fold of the potentiometer 3,
-  // a bipolar pot, so it returns values from -1.0 to +1.0
-  // Pitch should go 10 octaves up/down (10*1.0 = 1000%)
-  if (!isnan(p3)) {pitch_val = 10.0f * p3; }
-
-  // Set other parameters (from 0.0 to 1.0)
-  if (!isnan(p4)) { drywetmix = p4; }
-
-  switch (ui.fx_mode) {
-    case FX_MODE_ALL:
-      if (!isnan(p5)) {  lfo_amount = p5; }
-      if (!isnan(p6)) {  volume = p6 * 4.0f; }
-      if (!isnan(p7)) {  reverbmix = p7; }
-      break;
-    case FX_MODE_REVERB:
-      if (!isnan(p5)) {  reverb_tone = 50.0f + p5 * 20000.0f; }
-      // TODO: Short Reverb Decay times are too silent?
-      if (!isnan(p6)) {  reverb_decay = 0.05f + p6 * 0.94f; }
-      if (!isnan(p7)) {  reverbmix = p7; }
-      break;
-    case FX_MODE_LFO:
-      if (!isnan(p5)) {  lfo_kind = p5; }
-      if (!isnan(p6)) {  lfo_speed = (p6 * p6 *p6) * 100.0f; }
-      if (!isnan(p7)) {  lfo_amount = p7; }
-      break;
-    case FX_MODE_GRAIN:
-      if (!isnan(p5)) {  ui.activeLooper()->grain_count = 1+int(p5); }
-      if (!isnan(p6)) {  ui.activeLooper()->grain_spread = p6*10.0f; }
-      if (!isnan(p7)) {  ui.activeLooper()->grain_variation = p7; }
-      break;
-  }
-
-  // Render the UI (frame rate limited by UI_MAX_FPS in ui.h)
-  // double start = millis();
-  ui.Render();
-  // Serial.print("ui Render took ");
-  // Serial.print(millis()-start);
-  // Serial.println("ms");
-
-  // Set the Color and brightness of the RGB LED in 8 bits
-  rgb_led.setAudioLevelIndicator(input_envelope_follower.getValue());
-
-  // MIDI
-  MIDI.read();
-}
-
-
-
-
diff --git a/code/daisy-looper/env_follower.h b/code/daisy-looper/env_follower.h
deleted file mode 100644
index b3a123969be9a41e91c5ed3ab17b8b5f3265ad5d..0000000000000000000000000000000000000000
--- a/code/daisy-looper/env_follower.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "wiring_constants.h"
-#ifndef Env_follower_h
-#define Env_follower_h
-#include "Arduino.h"
-
-namespace atoav {
-
-class SmoothingFilter {
-  public:
-      void Init(float smoothing_time_ms, float sample_rate) {
-        a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
-        b = 1.0f - a;
-        z = 0.0f;
-      }
-
-      inline float Process(float in) {
-        z = (in * b) + (z * a);
-        return z;
-      }
-
-      void setSmoothing(float smoothing_time_ms, float sample_rate) {
-        a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
-        b = 1.0f - a;
-      }
-
-  private:
-    float a;
-    float b;
-    float z;
-};
-
-
-class EnvelopeFollower {
-  public:
-    void Init(float sample_rate) {
-      sample_rate = sample_rate;
-      attack = 200.0f;
-      decay = 4000.0f;
-      smoothing = 50.0f;
-      value  = 0.0f;
-      smoothing_filter.Init(smoothing, sample_rate);
-    }
-
-    void SetAttack(float attack_ms) {
-      attack = pow(0.01, 1.0 / (attack_ms * sample_rate * 0.001));
-    }
-
-    void SetDecay(float decay_ms) {
-      decay = pow(0.01, 1.0 / (decay_ms * sample_rate * 0.001));
-    }
-
-    void SetSmoothing(float smoothing_ms) {
-      smoothing_filter.setSmoothing(smoothing_ms, sample_rate);
-    }
-
-    float Process(float in) {
-      abs_value = smoothing_filter.Process(abs(in));
-      if (abs_value > value) {
-        value = attack * (value - abs_value) + abs_value;
-      } else {
-        value = decay * (value - abs_value) + abs_value;
-      }
-      return value;
-    }
-
-    float value;
-
-    float getValue() {
-      if (value == 0.0f || value == -0.0f) {
-        return value;
-      }
-      return max(0.0f, (3.0f + log10(value)) / 3.0f);
-      // return value;
-    }
-
-
-  private:
-    float sample_rate;
-    float attack;
-    float decay;
-    float smoothing;
-    float abs_value = 0.0f;
-    SmoothingFilter smoothing_filter;
-};
-};
-
-
-
-
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/helpers.h b/code/daisy-looper/helpers.h
deleted file mode 100644
index 2f6601ac9522345ecb78328232270987587998ba..0000000000000000000000000000000000000000
--- a/code/daisy-looper/helpers.h
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef Helpers_h
-#define Helpers_h
-
-#include "Adafruit_SH110X.h"
-#include "Adafruit_GFX.h"
-extern Adafruit_SH1106G display;
-
-
-
-int centeredText(const char *buf, int x, int y, int color, int lineheight=8) {
-  int16_t x1, y1;
-  uint16_t w, h;
-  char *line_pointer = strchr(buf, '\n');
-  display.setTextColor(color);
-  if (!line_pointer) {
-    display.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-    display.setCursor(x - (w / 2), y - (h / 2));
-    display.print(buf);
-  }else {
-    char *tmp = strdup(buf);
-    char* d = strtok(tmp, "\n");
-    int line = 0;
-    while (d != NULL) {
-        display.getTextBounds(d, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-        display.setCursor(x - (w / 2), y - (h / 2)-lineheight/2 + (line*lineheight));
-        display.print(d);
-        d = strtok(NULL, ",");
-        line++;
-    }
-    free(tmp);
-  }
-  return w;
-}
-
-int centeredTextMark(const char *buf, int x, int y, int color, int underline_line=0, int lineheight=8) {
-  int16_t x1, y1;
-  uint16_t w, h;
-  char *line_pointer = strchr(buf, '\n');
-  display.setTextColor(color);
-  if (!line_pointer) {
-    display.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-    int x_start = x - (w / 2);
-    int y_start = y - (h / 2);
-    display.setCursor(x_start, y_start);
-    if (underline_line == 1) {
-        display.drawFastHLine(x_start-2, y_start+lineheight, w+4, color);
-      }
-    display.print(buf);
-  }else {
-    char *tmp = strdup(buf);
-    char* d = strtok(tmp, "\n");
-    int line = 0;
-    while (d != NULL) {
-        display.getTextBounds(d, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-        int x_start = x - (w / 2);
-        int y_start = y - (h / 2)-lineheight/2 + (line*lineheight);
-        display.setCursor(x_start, y_start);
-        display.print(d);
-        d = strtok(NULL, ",");
-        if (underline_line == 1) {
-          display.drawFastHLine(x_start-2, y_start+lineheight, w+4, color);
-        }
-        line++;
-    }
-    free(tmp);
-  }
-  return w;
-}
-
-
-int centeredTextMarkMulti(const char *buf, int x, int y, int color, int underline_line=0, int lineheight=8) {
-  int16_t x1, y1;
-  uint16_t w, h;
-  char *line_pointer = strchr(buf, '\n');
-  display.setTextColor(color);
-  if (!line_pointer) {
-    display.getTextBounds(buf, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-    int x_start = x - (w / 2);
-    int y_start = y - (h / 2);
-    display.setCursor(x_start, y_start);
-    if (underline_line == 1) {
-        display.drawFastHLine(x_start-2, y_start, w+4, color);
-      }
-    display.print(buf);
-  }else {
-    char *tmp = strdup(buf);
-    char* d = strtok(tmp, "\n");
-    int line = 0;
-    while (d != NULL) {
-        display.getTextBounds(d, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-        int x_start = x - (w / 2);
-        int y_start = y - (h / 2)-lineheight/2 + (line*lineheight);
-        display.setCursor(x_start, y_start);
-        display.print(d);
-        d = strtok(NULL, ",");
-        if (line == underline_line) {
-          display.drawFastHLine(x_start-2, y_start+lineheight-3, w+4, color);
-        }
-        line++;
-    }
-    free(tmp);
-  }
-  return w;
-}
-
-int button_multi(const char *buf, int x, int y, int color, int underline_line=0, int lines=0) {
-  int16_t x1, y1;
-  uint16_t w, h;
-  display.setTextColor(color);
-  char *tmp = strdup(buf);
-  int line = 0;
-  char* pch = NULL;
-  pch = strtok(tmp, "\n");
-
-  int radius = 2;
-  int cell_width = 128/3;
-  int left_x = x - (cell_width/2);
-  int margin = 10;
-  int circle_start_x  = left_x + margin;
-  int spacing = (cell_width - margin - margin) / lines;
-
-  while (pch != NULL){
-    // Draw Option-Circles
-    display.drawCircle(circle_start_x + line*spacing, y+7, radius, SH110X_WHITE);
-    // Only display the active text
-    if (line == underline_line) {
-      display.getTextBounds(pch, 0, 0, &x1, &y1, &w, &h); //calc width of new string
-      int x_start = x - (w / 2);
-      int y_start = y - (h / 2)-7;
-      display.setCursor(x_start, y_start);
-      display.print(pch);
-      // On the active option, draw a filled circle
-      display.fillCircle(circle_start_x + line*spacing, y+7, radius, SH110X_WHITE);
-    }
-    line++;
-    pch = strtok(NULL, "\n");
-  }
-  free(tmp);
-  return w;
-}
-
-float saturate(float x) {
-  if (x < -3.0f) {
-    return -1.0f;
-  } else if (x > 3.0f) {
-    return 1.0f;
-  } else {
-    return x * (27.0f + x * x ) / (27.0f + 9.0f * x * x);
-  }
-}
-
-
-double drand(double minf, double maxf){
-  return minf + random(1UL << 31) * (maxf - minf) / (1UL << 31);  // use 1ULL<<63 for max double values)
-}
-
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/leds.h b/code/daisy-looper/leds.h
deleted file mode 100644
index 5c4a8168eed032f26197954220287731a493f39f..0000000000000000000000000000000000000000
--- a/code/daisy-looper/leds.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef Leds_h
-#define Leds_h
-#include "Arduino.h"
-#include "luts.h"
-
-
-// Lookup Curves LED Red b
-float red_lut_x[] = {170.0, 173.5, 177.0, 180.5, 184.0, 187.5, 191.0, 194.5, 198.0, 201.5, 205.0, 208.5, 212.0, 215.5, 219.0, 222.5, 240.0, 240.75, 241.5, 242.25, 243.0, 243.75, 244.5, 245.25, 246.0, 246.75, 247.5, 248.25, 249.0, 249.75, 250.5, 251.25, 255};
-float red_lut_y[] = {0.0, 0.0037500000000000007, 0.030000000000000006, 0.10125000000000003, 0.24000000000000005, 0.46875, 0.8100000000000003, 1.2862500000000003, 1.9200000000000004, 2.7337500000000006, 3.75, 4.991250000000002, 6.480000000000002, 8.238750000000001, 10.290000000000003, 12.65625, 30.0, 31.1503125, 32.4525, 34.0584375, 36.12, 38.7890625, 42.2175, 46.5571875, 51.96, 58.5778125, 66.5625, 76.06593750000002, 87.24000000000001, 100.23656250000002, 115.20750000000002, 132.3046875, 255};
-size_t red_lut_len = 33;
-
-// Lookup Curves LED Green b
-float green_lut_x[] = {10.0, 18.5, 27.0, 35.5, 44.0, 52.5, 61.00000000000001, 69.5, 78.0, 86.5, 95.0, 103.50000000000001, 112.00000000000001, 120.5, 129.0, 137.5, 180.0, 183.5, 187.0, 190.5, 194.0, 197.5, 201.0, 204.5, 208.0, 211.5, 215.0, 218.5, 222.0, 225.5, 229.0, 232.5, 250};
-float green_lut_y[] = {0.0, 0.0075000000000000015, 0.06000000000000001, 0.20250000000000007, 0.4800000000000001, 0.9375, 1.6200000000000006, 2.5725000000000007, 3.8400000000000007, 5.467500000000001, 7.5, 9.982500000000003, 12.960000000000004, 16.477500000000003, 20.580000000000005, 25.3125, 60.0, 56.43, 52.92, 49.47, 46.08, 42.75, 39.48, 36.269999999999996, 33.120000000000005, 30.029999999999998, 27.000000000000007, 24.03, 21.119999999999997, 18.269999999999996, 15.480000000000004, 12.750000000000007, 0};
-size_t green_lut_len = 33;
-
-// Lookup Curves LED Blue b
-float blue_lut_x[] = {0.0, 2.0, 4.0, 6.000000000000001, 8.0, 10.0, 12.000000000000002, 14.000000000000002, 16.0, 18.0, 20.0, 22.0, 24.000000000000004, 26.0, 28.000000000000004, 30.0, 40.0, 46.5, 53.0, 59.5, 66.0, 72.5, 79.0, 85.5, 92.0, 98.5, 105.0, 111.5, 118.00000000000001, 124.5, 131.0, 137.5, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0, 170.0};
-float blue_lut_y[] = {0.0, 0.10099999999999998, 0.20799999999999996, 0.327, 0.46399999999999997, 0.6249999999999999, 0.8160000000000001, 1.0430000000000001, 1.312, 1.629, 1.9999999999999998, 2.4310000000000005, 2.928000000000001, 3.497, 4.144000000000001, 4.875, 10.0, 9.025, 8.1, 7.225, 6.4, 5.625, 4.9, 4.225, 3.5999999999999996, 3.0250000000000004, 2.5, 2.0249999999999986, 1.5999999999999996, 1.2250000000000014, 0.9000000000000004, 0.625, 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, 0.0, 0.0, 0.0};
-size_t blue_lut_len = 48;
-
-
-
-
-
-class RGBLed {
-  int pin_red;
-  int pin_green;
-  int pin_blue;
-  float level = 0.0f;
-  Easer easer;
-
-  public:
-    RGBLed(int pin_red, int pin_green, int pin_blue);
-    void init();
-    void off();
-    void setColor(int r, int g, int b);
-    void setAudioLevelIndicator(float envelope_value);
-};
-
-RGBLed::RGBLed(int pin_red, int pin_green, int pin_blue) {
-  this->pin_red = pin_red;
-  this->pin_green = pin_green;
-  this->pin_blue = pin_blue;
-  this->easer.setFactor(0.7);
-}
-
-void RGBLed::init() {
-  pinMode(this->pin_red, OUTPUT);
-  pinMode(this->pin_green, OUTPUT);
-  pinMode(this->pin_blue, OUTPUT);
-}
-
-void RGBLed::off() {
-  digitalWrite(this->pin_red, LOW);
-  digitalWrite(this->pin_green, LOW);
-  digitalWrite(this->pin_blue, LOW);
-}
-
-void RGBLed::setColor(int r, int g, int b) {
-  r = min(255, max(0, r));
-  g = min(255, max(0, g));
-  b = min(255, max(0, b));
-  analogWrite(this->pin_red, r);
-  analogWrite(this->pin_green, g);
-  analogWrite(this->pin_blue, b);
-}
-
-void RGBLed::setAudioLevelIndicator(float envelope_value) {
-  level = easer.Process(envelope_value);
-  int brightness = int(min(255.0f, max(0.0f, level * 255)));
-  int red = get_from_xy_table(red_lut_x, red_lut_y, brightness, red_lut_len);
-  int green = get_from_xy_table(green_lut_x, green_lut_y, brightness, green_lut_len);
-  int blue = get_from_xy_table(blue_lut_x, blue_lut_y, brightness, blue_lut_len);
-  this->setColor(red, green, blue);
-}
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/lfo.h b/code/daisy-looper/lfo.h
deleted file mode 100644
index a91cdb6d496e4ed4b3da4cecc5eeaeb31ca85869..0000000000000000000000000000000000000000
--- a/code/daisy-looper/lfo.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-enum LfoKind {
-	LFO_KIND_TRI,
-	LFO_KIND_SQR,
-	LFO_KIND_RAND,
-	LFO_KIND_JUMP,
-	LFO_KIND_NONE,
-};
\ No newline at end of file
diff --git a/code/daisy-looper/looper.h b/code/daisy-looper/looper.h
deleted file mode 100644
index 594ae1a14efdbb6f58c40446bedd2e89cee50300..0000000000000000000000000000000000000000
--- a/code/daisy-looper/looper.h
+++ /dev/null
@@ -1,468 +0,0 @@
-#pragma once
-
-#include "luts.h"
-
-namespace atoav {
-
-enum RecPitchMode {
-  REC_PITCH_MODE_NORMAL,
-  REC_PITCH_MODE_UNPITCHED,
-  REC_PITCH_MODE_LAST,
-};
-
-enum RecStartMode {
-  REC_START_MODE_BUFFER,
-  REC_START_MODE_LOOP,
-  REC_START_MODE_PLAYHEAD,
-  REC_START_MODE_LAST,
-};
-
-enum PlaybackState {
-  PLAYBACK_STATE_STOPPED,
-  PLAYBACK_STATE_LOOP,
-  PLAYBACK_STATE_MULTILOOP,
-  PLAYBACK_STATE_MIDI,
-  PLAYBACK_STATE_LAST,
-};
-
-enum RecordingState {
-  REC_STATE_EMPTY,
-  REC_STATE_RECORDING,
-  REC_STATE_OVERDUBBING,
-  REC_STATE_ERASING,
-  REC_STATE_NONE,
-  REC_STATE_LAST,
-};
-
-// =================================================
-// =                   H E A D                     =
-// =================================================
-
-class Head {
-  public:
-    Head();
-    void activate();
-    void deactivate();
-    bool isActive();
-    void setPosition(float value);
-    void reset();
-    void setIncrement(float value);
-    void incrementBy(float value);
-    void slowDown();
-    void reverse();
-    void speedUp();
-    void update();
-    float read();
-    float increment = 1.0f;
-    float variation = 0.0f;
-    float variation_amount = 0.0f;
-    float speed_multiplier = 1.0f;
-  private:
-    bool active = true;
-    float position = 0.0f;
-};
-
-Head::Head() {
-  variation = random(-0.1f, 0.1f);
-}
-void Head::activate() {
-  this->active = true;
-}
-void Head::deactivate() {
-  this->active = false;
-}
-bool Head::isActive() {
-  return active;
-}
-void Head::reset() {
-  this->position = 0.0f;
-}
-void Head::setPosition(float value) {
-  this->position = value * speed_multiplier;
-}
-void Head::setIncrement(float value) {
-  this->increment = value;
-}
-void Head::incrementBy(float value) {
-  this->position += value;
-}
-void Head::slowDown() {
-  this->speed_multiplier = max(0.0f, this->speed_multiplier - 0.0025f);
-}
-void Head::reverse() {
-  this->speed_multiplier = -abs(this->speed_multiplier );
-}
-void Head::speedUp() {
-  this->speed_multiplier = 1.0f;
-}
-void Head::update() {
-  this->position += (this->increment + (variation * variation_amount)) * speed_multiplier;
-}
-float Head::read() {
-  return this->position;
-}
-
-
-// =================================================
-// =                 L O O P E R                   =
-// =================================================
-
-class Looper {
-	public:
-		Looper();
-    void Init(float *buf, size_t buf_size);
-    void SetRecord();
-    void SetOverdub();
-    void SetErase();
-    void SetStopWriting();
-    bool isWriting();
-    void ResetRecHead();
-    void SetLoop(float loop_start_time, float loop_length_time);
-    void Record(float in);
-    float Process();
-    float* getBuffer();
-    size_t getBufferLength();
-    void setRecPitchMode(RecPitchMode mode);
-    void setRecStartMode(RecStartMode mode);
-    float GetPlayhead();
-    float* GetPlayheads();
-    uint8_t GetPlayheadCount();
-    float GetRecHead();
-    bool toggleRecMode();
-    void setRecModeFull();
-    void setRecModeLoop();
-    void setRecModeFullShot();
-    void setRecModeLoopShot();
-    void setPlaybackSpeed(float increment);
-    void addToPlayhead(float value);
-    void slowDown();
-    void reverse();
-    void restart();
-    void speedUp();
-    float loop_start_f = 0.0f;
-    float loop_length_f = 1.0f;
-    uint8_t grain_count = 8;
-    float grain_spread = 2.0f;
-    float grain_variation = 0.0f;
-    RecPitchMode rec_pitch_mode = REC_PITCH_MODE_NORMAL;
-    RecStartMode rec_start_mode = REC_START_MODE_BUFFER;
-    PlaybackState playback_state = PLAYBACK_STATE_LOOP;
-    RecordingState recording_state = REC_STATE_EMPTY;
-
-  private:
-    static const size_t kFadeLength = 200;
-    static const size_t kMinLoopLength = 2 * kFadeLength;
-
-    float* buffer;
-    size_t buffer_length = 0;
-
-    Head playheads[9];
-    Head rec_head;
-
-    size_t loop_start = 0;
-    size_t loop_length = 48000;
-
-    bool stop_after_recording = false;
-    bool stay_within_loop = true;
-
-};
-
-
-Looper::Looper() {}
-
-void Looper::Init(float *buf, size_t buf_size) {
-  buffer = buf;
-  buffer_length = buf_size;
-  memset(buffer, 0, sizeof(float) * buffer_length);
-}
-
-void Looper::SetRecord() {
-  recording_state = REC_STATE_RECORDING;
-  ResetRecHead();
-  rec_head.activate();
-}
-
-void Looper::SetOverdub() {
-  recording_state = REC_STATE_OVERDUBBING;
-  ResetRecHead();
-  rec_head.activate();
-}
-
-void Looper::SetErase() {
-  recording_state = REC_STATE_ERASING;
-  ResetRecHead();
-  rec_head.activate();
-}
-
-void Looper::SetStopWriting() {
-  recording_state = REC_STATE_NONE;
-  rec_head.deactivate();
-}
-
-bool Looper::isWriting() {
-  return recording_state == REC_STATE_RECORDING 
-    || recording_state == REC_STATE_OVERDUBBING 
-    || recording_state == REC_STATE_ERASING; 
-}
-
-void Looper::ResetRecHead() {
-  if (isWriting()) {
-    switch (rec_start_mode) {
-      case REC_START_MODE_LOOP:
-        rec_head.setPosition(loop_start % buffer_length);
-        break;
-      case REC_START_MODE_BUFFER:
-        rec_head.setPosition(0.0f);
-        break;
-      case REC_START_MODE_PLAYHEAD:
-        rec_head.setPosition(fmod(loop_start + playheads[0].read(), float(buffer_length)));
-        break;
-    }
-  }
-}
-
-void Looper::SetLoop(float loop_start_time, float loop_length_time) {
-  if (!isnan(loop_start_time)) {
-    loop_start_f = loop_start_time;
-    loop_start = static_cast<size_t>(loop_start_time * (buffer_length - 1));
-  }
-  if (!isnan(loop_length_time)) {
-    loop_length_f = loop_length_time;
-    loop_length = max(kMinLoopLength, static_cast<size_t>(loop_length_time * buffer_length));
-  }
-}
-
-void Looper::Record(float in) {
-  // Overwrite/Add/Erase the buffer depending on the mode
-  switch (recording_state) {
-    case REC_STATE_RECORDING:
-      buffer[int(rec_head.read())] = in;
-      break;
-    case REC_STATE_OVERDUBBING:
-      buffer[int(rec_head.read())] += in;
-      break;
-    case REC_STATE_ERASING:
-      buffer[int(rec_head.read())] = 0.0f;
-      break;
-  }
-
-  // Advance the recording head if needed
-  if (isWriting()) {
-    // Set Recording head increment depending on the mode
-    switch (rec_pitch_mode) {
-      case REC_PITCH_MODE_NORMAL: 
-        rec_head.setIncrement(1.0f); 
-        break;
-      case REC_PITCH_MODE_UNPITCHED: 
-        rec_head.setIncrement(playheads[0].increment); 
-        break;
-    }
-    // Increment recording head
-    rec_head.update();
-
-    // Limit the position of the rec head depending on the active mode
-    if (!stop_after_recording) {
-      if (!stay_within_loop) {
-        // record into whole buffer
-        rec_head.setPosition(fmod(rec_head.read(), float(buffer_length)));
-      } else {
-        // Limit rec head to stay inside the loop
-        rec_head.setPosition(fmod(rec_head.read(), float(loop_start + loop_length)));
-        rec_head.setPosition(max(float(loop_start), rec_head.read()));
-      }
-    } else {
-      // Stop at end (either end of buffer or end of loop)
-      if (!stay_within_loop) {
-        if (rec_head.read() > buffer_length) { SetStopWriting(); }
-      } else {
-        if (rec_head.read() > loop_start + loop_length) { SetStopWriting(); }
-      }
-    }
-
-    // Ensure the Rec-Head is never without bounds, even when running backwards
-    if (rec_head.read() > buffer_length) {
-      rec_head.setPosition(0.0f);
-    } else if (rec_head.read() < 0) {
-      rec_head.setPosition(buffer_length);
-    }
-  }
-}
-
-float Looper::Process() {
-  // Early return if buffer is empty or not playing to save performance
-  if (recording_state == REC_STATE_EMPTY 
-    || playback_state == PLAYBACK_STATE_STOPPED) {
-    return 0;
-  }
-
-  // Deactivate all playheads except first if playback state is Loop
-  switch (playback_state) {
-    case PLAYBACK_STATE_LOOP:
-      playheads[0].activate();
-      for (size_t i=1; i<9; i++) {
-        playheads[i].deactivate();
-      }
-      break;
-    case PLAYBACK_STATE_MULTILOOP:
-      for (size_t i=0; i<9; i++) {
-        playheads[i].activate();
-      }
-      break;
-    case PLAYBACK_STATE_STOPPED:
-      for (size_t i=0; i<9; i++) {
-        playheads[i].deactivate();
-      }
-      break;
-  }
-
-  double mix = 0.0;
-
-  for (size_t i=0; i<grain_count-1; i++) {
-    // Skip inactive playheads
-    if (!playheads[i].isActive()) continue;
-
-    // Ensure we are actually inside the buffer
-    int from_start = int(playheads[i].read()) % loop_length;
-    int play_pos = loop_start + from_start;
-
-    float vol = 1.0f;
-    if (from_start <= kFadeLength) {
-      vol = from_start / float(kFadeLength);
-    }
-    int from_end = abs(int(loop_length) - from_start);
-    if (from_end <= kFadeLength) {
-      vol = from_end / float(kFadeLength);
-    }
-
-    // Read from the buffer
-    mix += buffer[play_pos] * vol;
-
-    // Advance the playhead
-    playheads[i].update();
-
-    // Ensure the playhead stays within bounds of the loop
-    float pos = playheads[i].read();
-    if (pos >= loop_length || pos <= 0.0f) {
-      playheads[i].setPosition(fmod(pos, float(loop_length)));
-    }
-  }
-  return mix;
-}
-
-float Looper::GetPlayhead() {
-  return float(int(playheads[0].read()) % loop_length) / float(buffer_length);
-}
-
-float* Looper::GetPlayheads() {
-  static float playhead_positions[9];
-  for (size_t i=0; i<9; i++) {
-    playhead_positions[i] = float(int(playheads[i].read()) % loop_length) / float(buffer_length);
-  }
-  return playhead_positions;
-}
-
-uint8_t Looper::GetPlayheadCount() {
-  return grain_count;
-}
-
-float Looper::GetRecHead() {
-  return  float(rec_head.read()) / float(buffer_length);
-}
-
-bool Looper::toggleRecMode() {
-  stay_within_loop = !stay_within_loop;
-  return stay_within_loop;
-}
-
-void Looper::setRecModeFull() {
-  stay_within_loop = false;
-  stop_after_recording = false;
-}
-
-void Looper::setRecModeLoop() {
-  stay_within_loop = true;
-  stop_after_recording = false;
-}
-
-void Looper::setRecModeFullShot() {
-  stay_within_loop = false;
-  stop_after_recording = true;
-}
-
-void Looper::setRecModeLoopShot() {
-  stay_within_loop = true;
-  stop_after_recording = true;
-}
-
-void Looper::setPlaybackSpeed(float increment) {
-  switch (playback_state) {
-    case PLAYBACK_STATE_LOOP:
-      playheads[0].setIncrement(increment);
-      break;
-    case PLAYBACK_STATE_MULTILOOP:
-      playheads[0].setIncrement(increment);
-      for (size_t i=1; i<9; i++) {
-        playheads[i].variation_amount = grain_variation;
-        playheads[i].setIncrement(increment + increment*grain_spread);
-      }
-      break;
-  }
-}
-
-void Looper::addToPlayhead(float value) {
-  switch (playback_state) {
-    case PLAYBACK_STATE_LOOP:
-      playheads[0].incrementBy(value);
-      break;
-    case PLAYBACK_STATE_MULTILOOP:
-      playheads[0].incrementBy(value);
-      for (size_t i=1; i<9; i++) {
-        playheads[i].incrementBy(value + value/(1+i));
-      }
-      break;
-  }
-}
-
-void Looper::slowDown() {
-  for (size_t i=0; i<9; i++) {
-    playheads[i].slowDown();
-  }
-}
-
-void Looper::reverse() {
-  for (size_t i=0; i<9; i++) {
-    playheads[i].reverse();
-  }
-}
-
-void Looper::restart() {
-  for (size_t i=0; i<9; i++) {
-    playheads[i].reset();
-  }
-}
-
-void Looper::speedUp() {
-  for (size_t i=0; i<9; i++) {
-    playheads[i].speedUp();
-  }
-}
-
-float* Looper::getBuffer() {
-  return buffer;
-}
-
-size_t Looper::getBufferLength() {
-  return buffer_length;
-}
-
-void Looper::setRecPitchMode(RecPitchMode mode) {
-  rec_pitch_mode = mode;
-}
-
-void Looper::setRecStartMode(RecStartMode mode) {
-  rec_start_mode = mode;
-}
-
-
-
-}; // namespace atoav
\ No newline at end of file
diff --git a/code/daisy-looper/luts.h b/code/daisy-looper/luts.h
deleted file mode 100644
index b332ed6da58ed786d58f0a815e43280de8186beb..0000000000000000000000000000000000000000
--- a/code/daisy-looper/luts.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef LUTs_h
-#define LUTs_h
-
-#include <MultiMap.h>
-
-// Lookup Table for Pitch Knob
-float pitch_knob_lookup_x[] = {0.0, 0.0025, 0.0175, 0.0225, 0.0375, 0.0425, 0.057499999999999996, 0.0625, 0.0775, 0.0825, 0.0975, 0.10250000000000001, 0.1175, 0.1225, 0.1375, 0.14250000000000002, 0.1575, 0.1625, 0.1975, 0.2025, 0.2475, 0.2525, 0.2975, 0.3025, 0.3775, 0.3825, 0.4175, 0.4225, 0.4575, 0.4625, 0.4975, 0.5025, 0.5375000000000001, 0.5425, 0.5775000000000001, 0.5825, 0.6175, 0.6224999999999999, 0.6975, 0.7024999999999999, 0.7475, 0.7525, 0.7975000000000001, 0.8025, 0.8375, 0.8424999999999999, 0.8575, 0.8624999999999999, 0.8775000000000001, 0.8825, 0.8975000000000001, 0.9025, 0.9175000000000001, 0.9225, 0.9375, 0.9424999999999999, 0.9575, 0.9624999999999999, 0.9775, 0.9824999999999999, 0.9975, 1.0};
-float pitch_knob_lookup_y[] = {-1.0, -1.0, -0.9, -0.9, -0.8, -0.8, -0.7, -0.7, -0.6, -0.6, -0.5, -0.5, -0.4, -0.4, -0.3, -0.3, -0.2, -0.2, -0.1, -0.1, -0.05, -0.05, -0.025, -0.025, -0.0125, -0.0125, -0.00625, -0.00625, -0.003125, -0.003125, 0.0, 0.0, 0.003125, 0.003125, 0.00625, 0.00625, 0.0125, 0.0125, 0.025, 0.025, 0.05, 0.05, 0.1, 0.1, 0.2, 0.2, 0.3, 0.3, 0.4, 0.4, 0.5, 0.5, 0.6, 0.6, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 1.0, 1.0};
-size_t pitch_knob_lookup_length = 62;
-
-
-class Easer {
-  float output = 0.0f;
-  float delta = 0.0f;
-  float easing = 0.1f;
-  public:
-    Easer();
-    
-    float Process(float input) {
-      delta = input - output;
-      output += delta * easing;
-      return output;
-    }
-
-    void setFactor(float factor) {
-      easing = min(max(0.00001f, factor), 1.0f);
-    }
-};
-
-Easer::Easer() {
-
-};
-
-float lerp(float a, float b, float f) {
-  f = min(1.0f, max(0.0f, f));
-
-  if (f == 0.0) { return a; }
-  else if (f == 1.0f) { return b; }
-  else { return a * (1.0f-f) + b * f; }
-}
-
-float get_from_xy_table(float* xtable, float* ytable, float f, size_t length) {
-  return multiMap<float>(f, xtable, ytable, length);
-}
-
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/menu.ods b/code/daisy-looper/menu.ods
deleted file mode 100644
index 2b8391b9cf03447b0e7b7cf66da2c734faf8ed40..0000000000000000000000000000000000000000
Binary files a/code/daisy-looper/menu.ods and /dev/null differ
diff --git a/code/daisy-looper/potentiometers.h b/code/daisy-looper/potentiometers.h
deleted file mode 100644
index 055264c4d6e2de012b6d3dbbb39f072120a5487a..0000000000000000000000000000000000000000
--- a/code/daisy-looper/potentiometers.h
+++ /dev/null
@@ -1,257 +0,0 @@
-#include "WCharacter.h"
-#include "wiring_analog.h"
-#include <stdint.h>
-#include <limits>
-#ifndef Potentiometers_h
-#define Potentiometers_h
-#include "Arduino.h"
-#include "luts.h"
-#include "helpers.h"
-
-#include "Adafruit_SH110X.h"
-#include "Adafruit_GFX.h"
-extern Adafruit_SH1106G display;
-
-// The length of the moving average filter that smooths the
-// controls. Higher number is smoother, but less responsive
-// and needs more memory.
-#define POT_MOVING_AVERAGE_SIZE 2
-
-// Length of the Textbuffer for floats in the UI
-#define UI_TEXTBUFFER_LENGTH 6
-
-// Modes
-enum PotMode {
-  POT_MODE_LIN,
-  POT_MODE_BIP,
-  POT_MODE_PITCH,
-  POT_MODE_SWITCH,
-  POT_MODE_LAST
-};
-
-// Display Modes
-enum PotDisplayMode {
-  POT_DISPLAY_MODE_DEFAULT,
-  POT_DISPLAY_MODE_PITCH,
-  POT_DISPLAY_MODE_PERCENT,
-  POT_DISPLAY_MODE_SWITCH,
-  POT_DISPLAY_MODE_SWITCH_NUMBERS,
-  POT_DISPLAY_MODE_LAST
-};
-
-typedef void (*callback_function)(void);
-
-class Potentiometer {
-  int pin;
-  int readings[POT_MOVING_AVERAGE_SIZE];
-  PotMode mode = POT_MODE_LIN;
-  PotDisplayMode display_mode = POT_DISPLAY_MODE_DEFAULT;
-  float last_reading, last_normalized_reading = 0.0f;
-  float display_scale = 1.0f;
-  callback_function onChangeFunction;
-  Easer easer;
-
-  public:
-    Potentiometer(int pin);
-    void init();
-    void setLinear();
-    void setPitch();
-    void setSwitch();
-    float read();
-    void setOnChange(callback_function f);
-    void renderUi();
-    void setDisplayMode(const char *name, float display_scale, PotDisplayMode display_mode);
-    const char *name;
-    double last_displayed = 0.0;
-    bool should_display = false;
-    bool display_value_changes = false;
-    bool last_was_nan = false;
-    uint8_t switch_positions;
-    uint8_t switch_offset = 0;
-    const char* const switch_labels[4] = {"TRI", "SQR", "RAND", "JUMP"};
-};
-
-Potentiometer::Potentiometer(int pin) {
-  this->pin = pin;
-}
-
-void Potentiometer::init() {
-  analogReadResolution(12);
-  easer.setFactor(0.001);
-}
-
-void Potentiometer::setLinear() {
-  this->mode = POT_MODE_LIN;
-}
-
-void Potentiometer::setPitch() {
-  this->mode = POT_MODE_PITCH;
-}
-
-void Potentiometer::setSwitch() {
-  this->mode = POT_MODE_SWITCH;
-}
-
-float Potentiometer::read() {
-  int reading = analogRead(this->pin);
-  // Shift all readings in the buffer over by one position, deleting the oldest
-  // and adding the newest
-  for (int i=0; i<POT_MOVING_AVERAGE_SIZE; i++) {
-    int next = i+1;
-    if (next < POT_MOVING_AVERAGE_SIZE) {
-      (this->readings)[i] = (this->readings)[next];
-    }
-  }
-  (this->readings)[POT_MOVING_AVERAGE_SIZE-1] = reading;
-
-  // Get the average of the last readings
-  reading = 0;
-  for (int i=0; i<POT_MOVING_AVERAGE_SIZE; i++) {
-    reading += (this->readings)[i];
-  }
-  reading = reading / POT_MOVING_AVERAGE_SIZE;
-
-  // Convert the last reading to a float and return
-  float current_reading = easer.Process(reading / 4096.0f);
-  float normalized_reading = current_reading;
-
-  // Depending on the Mode
-  switch (this->mode) {
-    case POT_MODE_PITCH:
-      current_reading = get_from_xy_table(pitch_knob_lookup_x, pitch_knob_lookup_y, current_reading, pitch_knob_lookup_length);
-      break;
-    case POT_MODE_SWITCH:
-      current_reading = int(current_reading * switch_positions);
-      break;
-  }
-
-  bool changed = abs(normalized_reading - this->last_normalized_reading) > 0.002;
-
-  // If the difference to the last reading is big enough assume the knob has been touched
-  if (this->last_normalized_reading && changed) {
-    if (display_value_changes) {
-      last_displayed = millis();
-      should_display = true;
-    }
-    if (this->onChangeFunction) { this->onChangeFunction(); }
-  }
-
-  if (this->last_normalized_reading && !changed) {
-    // if (!last_was_nan) {
-    //   Serial.print(this->name);
-    //   Serial.println(" returned NaN");
-    // }
-    last_was_nan = true;
-    return std::numeric_limits<float>::quiet_NaN();
-  }
-  last_was_nan = false;
-  this->last_reading = current_reading;
-  this->last_normalized_reading = normalized_reading;
-  return current_reading;
-}
-
-void Potentiometer::setOnChange(callback_function f) {
-  this->onChangeFunction = f;
-}
-
-void Potentiometer::setDisplayMode(const char *name, float display_scale, PotDisplayMode display_mode) {
-  this->display_value_changes = true;
-  this->name = name;
-  this->display_scale = display_scale;
-  this->display_mode = display_mode;
-}
-
-void Potentiometer::renderUi() {
-  double now = millis();
-    if (this->should_display) {
-      int x_margin = 28;
-      int y_margin = 13;
-      int x_center = display.width()/2;
-      int y_center = display.height()/2;
-      // Render a rectangle Backdrop for the text
-      display.fillRect(3+x_margin, 3+y_margin, display.width()-x_margin*2, display.height()-y_margin*2, SH110X_WHITE);
-      display.fillRect(x_margin, y_margin, display.width()-x_margin*2, display.height()-y_margin*2, SH110X_WHITE);
-      display.fillRect(x_margin+1, y_margin+1, display.width()-(x_margin+1)*2, display.height()-(y_margin+1)*2, SH110X_BLACK);
-      
-
-      // Render the name of the parameter (e.g. "Pitch")
-      centeredText(this->name, x_center, y_center-4, SH110X_WHITE);
-      
-      // Choose how many digits to display depending on the mode
-      int digits = 2;
-      if (this->display_mode == POT_DISPLAY_MODE_PERCENT) { digits = 0; }
-      // Allocate a buffer for the float and convert it into characters
-      char value_buffer[UI_TEXTBUFFER_LENGTH]; // Buffer big enough for 7-character float
-      dtostrf(this->last_reading*display_scale, 6, digits, value_buffer); // Leave room for too large numbers!
-      
-      // If we are on a bipolar pot display an indicator if we are in the center
-      if (this->mode == POT_MODE_BIP && this->last_reading > -0.0001 && this->last_reading < 0.0001) {
-        display.fillTriangle(x_center, y_center+10, x_center+3, y_center+15, x_center-3, y_center+15, SH110X_WHITE);
-      }
-
-      // If we are on a pitch pot display an indicator if we are in the the right steps
-      if (this->mode == POT_MODE_PITCH) {
-        float reading_mod = fmod(abs(this->last_reading), 0.05f);
-        if (reading_mod > 0.999f || reading_mod < 0.001f) {
-          display.fillTriangle(x_center, y_center+10, x_center+3, y_center+15, x_center-3, y_center+15, SH110X_WHITE);
-        }
-      }
-
-      // The float value may contain some empty whitespace characters, remove them by
-      // first figuring out which the first actual character is
-      int nonwhite = 0;
-      for (int i=0; i<UI_TEXTBUFFER_LENGTH; i++) {
-        if (value_buffer[i] == ' ') {
-          nonwhite++;
-        }
-      }
-
-      // Create a new buffer that can hold everything
-      char text_buffer[UI_TEXTBUFFER_LENGTH+6];
-
-      // Copy all non-white characters over
-      for (int i = 0; i<UI_TEXTBUFFER_LENGTH; i++) {
-        text_buffer[i] = value_buffer[i+int(nonwhite)];
-      }
-
-      // Figure out where the last character (\0) in our new buffer is
-      int last = UI_TEXTBUFFER_LENGTH+6;
-      for (int i=16; i>0; i--) {
-        if (text_buffer[i] == '\0') {
-          last = i;
-        }
-      }
-
-      // Add units depending on the display mode : )
-      if (this->display_mode == POT_DISPLAY_MODE_PERCENT) {
-        text_buffer[last] = ' ';
-        text_buffer[last+1] = '%';
-        text_buffer[last+2] = '\0';
-      } else if (this->display_mode == POT_DISPLAY_MODE_PITCH) {
-        text_buffer[last] = ' ';
-        text_buffer[last+1] = 'S';
-        text_buffer[last+2] = 'e';
-        text_buffer[last+3] = 'm';
-        text_buffer[last+4] = 'i';
-        text_buffer[last+5] = '\0';
-      }
-
-      // Render that new text
-      if (this->display_mode == POT_DISPLAY_MODE_SWITCH) {
-        centeredText(switch_labels[int(last_reading+switch_offset)], x_center, y_center+4, SH110X_WHITE);
-      } else if (this->display_mode == POT_DISPLAY_MODE_SWITCH_NUMBERS) {
-        sprintf(text_buffer, "%d", int(last_reading));  
-        centeredText(text_buffer, x_center, y_center+4, SH110X_WHITE);
-      } else {
-        centeredText(text_buffer, x_center, y_center+4, SH110X_WHITE);
-      }
-    }
-
-    // Show this for 700 ms after it has been last touched
-    if ((now - this->last_displayed) > 700.0) {
-      this->should_display = false;
-    }
-}
-
-
-#endif
\ No newline at end of file
diff --git a/code/daisy-looper/ui.h b/code/daisy-looper/ui.h
deleted file mode 100644
index 030f2661b16dce56fe0b4c8d2a6348f97cbfdfc6..0000000000000000000000000000000000000000
--- a/code/daisy-looper/ui.h
+++ /dev/null
@@ -1,884 +0,0 @@
-#include <stdint.h>
-#include "WSerial.h"
-#include "usbd_def.h"
-#ifndef Ui_h
-#define Ui_h
-
-#include "Adafruit_SH110X.h"
-#include "Adafruit_GFX.h"
-#include "potentiometers.h"
-#include "buttons.h"
-#include "looper.h"
-#include "button_grid.h"
-
-#define UI_MAX_FPS 10
-#define WAVEFORM_OVERSAMPLING 2
-#define WAVEFORM_LIN true
-
-extern Potentiometer pot_1, pot_2, pot_3, pot_4, pot_5, pot_6, pot_7;
-extern Button button_1, button_2, button_3, button_4, button_5, button_6;
-extern Adafruit_SH1106G display;
-extern atoav::Looper looper_a, looper_b, looper_c, looper_d, looper_e;
-
-// Should the splash-screen be shown on boot?
-bool show_splash = false;
-
-// Represents the possible states of the UI
-enum UiMode {
-  UI_MODE_SPLASH,         // A splash screen that is shown on startup
-  UI_MODE_DEFAULT,        // Default screen: Show Waveform and Parameters
-  UI_MODE_REC_MENU,       // ButtonGrid Menu: Recording Settings
-  UI_MODE_PLAY_MENU,      // ButtonGrid Menu: Playback Settings
-  UI_MODE_TRIGGER_MENU,   // ButtonGrid Menu: Trigger Settings
-  UI_MODE_FX_MENU,        // ButtonGrid Menu: FX Settings
-  UI_MODE_BUFFER_MENU,    // ButtonGrid Menu: Buffer Settings
-  UI_MODE_LAST
-};
-
-// Represents possible recording modes
-enum RecMode {
-  REC_MODE_FULL,          // Record into full buffer (looping back to start)
-  REC_MODE_LOOP,          // Limit recording to the loop
-  REC_MODE_FULL_SHOT,     // Record into full buffer, stop at the end
-  REC_MODE_LAST
-};
-
-// Represents possible recording sources
-enum RecSource {
-  REC_SOURCE_PRE,            // Record Incoming audio
-  REC_SOURCE_LAST_BUF,       // Record Last selected Buffer
-  REC_SOURCE_OUT,            // Record the buffer output
-  REC_SOURCE_NOISE,          // Record Noise
-  REC_SOURCE_LAST
-};
-
-// Represents possible playback modes
-enum PlayMode {
-  PLAY_MODE_DRUNK,        // Drunken Walk
-  PLAY_MODE_WINDOW,       // Sliding window
-  PLAY_MODE_LOOP,         // Loop
-  PLAY_MODE_GRAIN,        // Granular ?
-  PLAY_MODE_ONESHOT,      // Play it once
-  PLAY_MODE_LAST
-};
-
-// Represents possible recording states
-enum RecordingState {
-  REC_STATE_NOT_RECORDING, // Not recording
-  REC_STATE_RECORDING,     // Recording (replace what is in the buffer)
-  REC_STATE_OVERDUBBING,   // Overdubbing (mix recorded values with the existing samples)
-  REC_STATE_LAST
-};
-
-enum ActiveBuffer {
-  ACTIVE_BUFFER_A,
-  ACTIVE_BUFFER_B,
-  ACTIVE_BUFFER_C,
-  ACTIVE_BUFFER_D,
-  ACTIVE_BUFFER_E,
-  ACTIVE_BUFFER_LAST,
-};
-
-enum BufferSummingMode {
-  BUFFER_SUM_MODE_SOLO,
-  BUFFER_SUM_MODE_SUM,
-  BUFFER_SUM_MODE_RING,
-  BUFFER_SUM_MODE_LAST,
-};
-
-enum FXMode {
-  FX_MODE_ALL,
-  FX_MODE_REVERB,
-  FX_MODE_NONE,
-  FX_MODE_LFO,
-  FX_MODE_GRAIN,
-  FX_MODE_FILTER,
-  FX_MODE_LAST,
-};
-
-// The Ui is _the_ coordinating class for the whole interaction.
-// The default mode
-// Note Descriptions get a space of 21 chars and 8 lines
-class Ui {
-  public:
-    Ui() : button_grids {
-      ButtonGrid((int) UI_MODE_REC_MENU, {
-        GridButton("REC\nMENU", &button_1, true),
-        GridButton("MOM\nTOGGLE", &button_2, false, BUTTON_TYPE_TOGGLE, 0),
-        GridButton("PRE\nLAST\nOUT\nNOISE", &button_3, false, BUTTON_TYPE_MULTITOGGLE, 0),
-        GridButton("FULL\nLOOP\nSHOT", &button_4, false, BUTTON_TYPE_MULTITOGGLE, 1),
-        GridButton("NORMAL\nUNPTCH", &button_5, false, BUTTON_TYPE_MULTITOGGLE, 0),
-        GridButton("START\nLOOPST\nPLAYHD", &button_6, false, BUTTON_TYPE_MULTITOGGLE, 0),
-      }),
-      ButtonGrid((int) UI_MODE_PLAY_MENU, {
-        GridButton("STOP\nLOOP\nMULTI\nMIDI", &button_1, false, BUTTON_TYPE_MULTITOGGLE, 1),
-        GridButton("PLAY\nMENU", &button_2, true),
-        GridButton("ACTIVE\nSUM\nRING", &button_3, false, BUTTON_TYPE_MULTITOGGLE, 0),
-        GridButton("RE\nSTART", &button_4, false),
-        GridButton("SLOW\nDOWN", &button_5, false),
-        GridButton("REV\nERSE", &button_6, false),
-      }),
-      ButtonGrid((int) UI_MODE_TRIGGER_MENU, {
-        GridButton("MIDI\nTRIG.", &button_1, false),
-        GridButton("MIDI\nUNMUTE", &button_2, false),
-        GridButton("TRIG.\nMENU", &button_3, true),
-        GridButton("MANUAL\nTRIG.", &button_4, false),
-        GridButton("MANUAL\nUNMUTE", &button_5, false),
-        GridButton("AUTO", &button_6, false),
-      }),
-      ButtonGrid((int) UI_MODE_FX_MENU, {
-        GridButton("ALL", &button_1, false, BUTTON_TYPE_ENUM, 1),
-        GridButton("REVERB", &button_2, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("FX\nMENU", &button_3, true),
-        GridButton("LFO", &button_4, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("GRAIN", &button_5, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("-", &button_6, false, BUTTON_TYPE_ENUM, 0),
-      }),
-      ButtonGrid((int) UI_MODE_BUFFER_MENU, {
-        GridButton("A", &button_1, false, BUTTON_TYPE_ENUM, 1),
-        GridButton("B", &button_2, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("C", &button_3, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("D", &button_4, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("E", &button_5, false, BUTTON_TYPE_ENUM, 0),
-        GridButton("BUFFER\nMENU", &button_6, true),
-      }),
-    } {};
-
-    // Store the Button Grids declared above (make sure the lenght matches!)
-    ButtonGrid button_grids[5];
-
-    // Stores the current Ui Mode
-    UiMode ui_mode = UI_MODE_SPLASH;
-
-    // Default Recording Mode
-    RecMode rec_mode = REC_MODE_LOOP;
-
-    // Default Recording Source
-    RecSource rec_source = REC_SOURCE_PRE;
-
-    // Default active buffer
-    ActiveBuffer active_buffer = ACTIVE_BUFFER_A;
-    ActiveBuffer previous_buffer = ACTIVE_BUFFER_A;
-
-    // Default active summing mode
-    BufferSummingMode buffer_summing_mode = BUFFER_SUM_MODE_SOLO;
-
-    FXMode fx_mode = FX_MODE_ALL;
-
-    // Render the UI
-    // Except for the splash screen this is expected to be called
-    // repeatedly in a loop
-    void Render() {
-      double now = millis();
-      // Serial.println(1000.0/UI_MAX_FPS);
-      if ((now - last_render) > (1000.0/UI_MAX_FPS)) {
-        switch (ui_mode) {
-          case UI_MODE_SPLASH:
-            renderSplash();
-            break;
-          case UI_MODE_DEFAULT:
-            renderDefault();
-            break;
-          case UI_MODE_REC_MENU:
-            renderGrid(0, rec_mode);
-            break;
-          case UI_MODE_PLAY_MENU:
-            renderGrid(1);
-            break;
-          case UI_MODE_TRIGGER_MENU:
-            renderGrid(2);
-            break;
-          case UI_MODE_FX_MENU:
-            renderGrid(3, fx_mode);
-            break;
-          case UI_MODE_BUFFER_MENU:
-            renderGrid(4, active_buffer);
-            break;
-        }
-        last_render = now;
-      }
-    }
-
-    // Helper method to render a certain button grid
-    void renderGrid(size_t num, int button_enum=0) {
-      display.clearDisplay();
-      button_grids[num].render(button_enum);
-      display.display();
-    }
-
-    // Renders a splash screen (runs once)
-    void renderSplash() {
-      display.setTextSize(1);
-
-      // Splash rendering is now done, go to next UI Mode
-      setMode(UI_MODE_DEFAULT);
-    }
-
-    // Helper method to reset the controls
-    void resetControls() {
-      button_1.reset();
-      button_2.reset();
-      button_3.reset();
-      button_4.reset();
-      button_5.reset();
-      button_6.reset();
-    }
-
-    Button* setupButtonGrid(int n) {
-      // Find the index of the home button
-      int home_button_index = button_grids[n].homeButtonIndex();
-
-      // Create a pointer to the hoime button
-      Button* home_button = button_grids[n].grid_buttons_[home_button_index].button;
-
-      // Reset the controls
-      resetControls();
-
-      // Setup the button grid
-      button_grids[n].setup();
-
-      // Return to default mode on release
-      home_button->onReleased([this, n](){
-        this->setMode(UI_MODE_DEFAULT);
-        this->button_grids[n].hideAllDescriptions();
-        activeLooper()->speedUp();
-      });
-
-      // Return pointer to the home button
-      return home_button;
-    }
-
-    // Setup the Recording Menu
-    void setupRecMenu() {
-      // Only run once when the ui_mode changed
-      if (ui_mode == UI_MODE_REC_MENU && last_ui_mode != UI_MODE_REC_MENU) {
-        int n = 0;
-
-        // Setup button Grid
-        Button* home_button = setupButtonGrid(n);
-
-        // Toggle between momentary and toggle recording modes
-        button_2.onPress([this, n](){
-          rec_button_momentary = !rec_button_momentary;
-          button_grids[n].grid_buttons_[1].active = !rec_button_momentary;
-        });
-        
-        // Set Recording Source (Pre/Post/Out/Noise)
-        button_3.onPress([this, n](){
-          button_grids[n].grid_buttons_[2].next();
-          rec_source = (RecSource) button_grids[n].grid_buttons_[2].active;
-        }); 
-
-        // Switch Recording modes (Full/Loop/Oneshot)
-        button_4.onPress([this, n](){ 
-          button_grids[n].grid_buttons_[3].next();
-          // Button.active returns number according to mode, we cast it to a RecMode enum
-          rec_mode = (RecMode) button_grids[n].grid_buttons_[3].active;
-          switch (rec_mode) {
-            case REC_MODE_FULL: 
-              looper_a.setRecModeFull(); 
-              looper_b.setRecModeFull(); 
-              looper_c.setRecModeFull(); 
-              looper_d.setRecModeFull(); 
-              looper_e.setRecModeFull(); 
-              break;
-            case REC_MODE_LOOP: 
-              looper_a.setRecModeLoop();
-              looper_b.setRecModeLoop();
-              looper_c.setRecModeLoop();
-              looper_d.setRecModeLoop();
-              looper_e.setRecModeLoop();
-              break;
-            case REC_MODE_FULL_SHOT:
-              looper_a.setRecModeFullShot();
-              looper_b.setRecModeFullShot();
-              looper_c.setRecModeFullShot();
-              looper_d.setRecModeFullShot();
-              looper_e.setRecModeFullShot();
-              break;
-          }
-        });
-
-        // Set Recording Pitch mode (Normal/Pitched/Unpitched)
-        button_5.onPress([this, n](){ 
-          button_grids[n].grid_buttons_[4].next();
-          looper_a.setRecPitchMode((atoav::RecPitchMode) button_grids[n].grid_buttons_[4].active);
-          looper_b.setRecPitchMode((atoav::RecPitchMode) button_grids[n].grid_buttons_[4].active);
-          looper_c.setRecPitchMode((atoav::RecPitchMode) button_grids[n].grid_buttons_[4].active);
-          looper_d.setRecPitchMode((atoav::RecPitchMode) button_grids[n].grid_buttons_[4].active);
-          looper_e.setRecPitchMode((atoav::RecPitchMode) button_grids[n].grid_buttons_[4].active);
-        });
-
-        // Set Recording Start Option (Buffer Start/Loop Start/Playhead)
-        button_6.onPress([this, n](){
-          button_grids[n].grid_buttons_[5].next();
-          looper_a.setRecStartMode((atoav::RecStartMode) button_grids[n].grid_buttons_[5].active);
-          looper_b.setRecStartMode((atoav::RecStartMode) button_grids[n].grid_buttons_[5].active);
-          looper_c.setRecStartMode((atoav::RecStartMode) button_grids[n].grid_buttons_[5].active);
-          looper_d.setRecStartMode((atoav::RecStartMode) button_grids[n].grid_buttons_[5].active);
-          looper_e.setRecStartMode((atoav::RecStartMode) button_grids[n].grid_buttons_[5].active);
-        });
-
-        // Store the last ui mode, for the check on top
-        last_ui_mode = ui_mode;
-      }
-    }
-
-    // Setup the Buffer Menu
-    void setupBufferMenu() {
-      // Only run once when the ui_mode changed
-      if (ui_mode == UI_MODE_BUFFER_MENU && last_ui_mode != UI_MODE_BUFFER_MENU) {
-        int n = 4;
-
-        // Setup button Grid
-        Button* home_button = setupButtonGrid(n);
-
-        button_1.onPress([this, n](){ 
-          previous_buffer = active_buffer;
-          active_buffer = ACTIVE_BUFFER_A;
-          waveform_cache_dirty = true;
-        });
-        button_2.onPress([this, n](){ 
-          previous_buffer = active_buffer;
-          active_buffer = ACTIVE_BUFFER_B;
-          waveform_cache_dirty = true;
-        });
-        button_3.onPress([this, n](){ 
-          previous_buffer = active_buffer;
-          active_buffer = ACTIVE_BUFFER_C;
-          waveform_cache_dirty = true;
-        });
-        button_4.onPress([this, n](){ 
-          previous_buffer = active_buffer;
-          active_buffer = ACTIVE_BUFFER_D;
-          waveform_cache_dirty = true;
-        });
-        button_5.onPress([this, n](){ 
-          previous_buffer = active_buffer;
-          active_buffer = ACTIVE_BUFFER_E;
-          waveform_cache_dirty = true;
-        });
-
-        // Store the last ui mode, for the check on top
-        last_ui_mode = ui_mode;
-      }
-    }
-
-    // Setup the Play Menu
-    void setupPlayMenu() {
-      // Only run once when the ui_mode changed
-      if (ui_mode == UI_MODE_PLAY_MENU && last_ui_mode != UI_MODE_PLAY_MENU) {
-        int n = 1;
-
-        // Ensure the UI showes the play mode of the active looper
-        button_grids[n].grid_buttons_[0].active = (int) activeLooper()->playback_state ;
-
-        // Setup button Grid
-        Button* home_button = setupButtonGrid(n);
-
-        // Change the way in which buffers are summed
-        button_3.onPress([this, n](){ 
-          button_grids[n].grid_buttons_[2].next();
-          buffer_summing_mode = (BufferSummingMode) button_grids[n].grid_buttons_[2].active;
-        });
-
-        // Change playback state (mode) of the current looper
-        button_1.onPress([this, n](){ 
-          button_grids[n].grid_buttons_[0].next();
-          activeLooper()->playback_state = (atoav::PlaybackState) (button_grids[n].grid_buttons_[0].active);
-        });
-
-        // Restart
-        button_4.onPress([this, n](){ 
-          activeLooper()->restart();
-        });
-
-        // DJ-style slow-down effect
-        button_5.onHold([this, n](){ 
-          activeLooper()->slowDown();
-        });
-        button_5.onReleased([this, n](){ 
-          activeLooper()->speedUp();
-        });
-
-        button_6.onHold([this, n](){ 
-          activeLooper()->reverse();
-        });
-        button_6.onReleased([this, n](){ 
-          activeLooper()->speedUp();
-        });
-
-        // Store the last ui mode, for the check on top
-        last_ui_mode = ui_mode;
-      }
-    }
-
-    // Setup the FX Menu
-    void setupFXMenu() {
-      // Only run once when the ui_mode changed
-      if (ui_mode == UI_MODE_FX_MENU && last_ui_mode != UI_MODE_FX_MENU) {
-        int n = 3;
-
-        // Ensure the UI showes the play mode of the active looper
-        // button_grids[n].grid_buttons_[0].active = (int) fx_mode;
-
-        // Setup button Grid
-        Button* home_button = setupButtonGrid(n);
-
-        // Select the active Effect (All)
-        button_1.onPress([this, n](){ 
-          fx_mode = FX_MODE_ALL;
-          pot_5.setDisplayMode("LFO", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_5.setLinear();
-          pot_6.setDisplayMode("Volume", 400.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_7.setDisplayMode("Reverb", 100.0f, POT_DISPLAY_MODE_PERCENT);
-        });
-
-        // Select the active Effect (Reverb)
-        button_2.onPress([this, n](){ 
-          fx_mode = FX_MODE_REVERB;
-          pot_5.setDisplayMode("Rev. Tone", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_5.setLinear();
-          pot_6.setDisplayMode("Rev. Decay", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_7.setDisplayMode("Reverb Mix", 100.0f, POT_DISPLAY_MODE_PERCENT);
-        });
-
-        // Select the active Effect (LFO)
-        button_4.onPress([this, n](){ 
-          fx_mode = FX_MODE_LFO;
-          pot_5.setDisplayMode("LFO Mode", 100.0f, POT_DISPLAY_MODE_SWITCH);
-          pot_5.setSwitch();
-          pot_5.switch_positions = 4;
-          pot_5.switch_offset = 0;
-          pot_6.setDisplayMode("LFO Speed", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_7.setDisplayMode("LFO Amount", 100.0f, POT_DISPLAY_MODE_PERCENT);
-        });
-
-        // Select the active Effect (GRAIN)
-        button_5.onPress([this, n](){ 
-          fx_mode = FX_MODE_GRAIN;
-          pot_5.setDisplayMode("Grain Num", 100.0f, POT_DISPLAY_MODE_SWITCH_NUMBERS);
-          pot_5.setSwitch();
-          pot_5.switch_positions = 8;
-          pot_6.setDisplayMode("Grn. Spread", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_7.setDisplayMode("Grain Var.", 100.0f, POT_DISPLAY_MODE_PERCENT);
-        });
-
-        // Select the active Effect (FILTER)
-        button_6.onPress([this, n](){ 
-          fx_mode = FX_MODE_FILTER;
-          pot_5.setDisplayMode("Lowpass", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_6.setDisplayMode("Highpass", 100.0f, POT_DISPLAY_MODE_PERCENT);
-          pot_7.setDisplayMode("Resonance", 100.0f, POT_DISPLAY_MODE_PERCENT);
-        });
-
-        // Store the last ui mode, for the check on top
-        last_ui_mode = ui_mode;
-      }
-    }
-
-    // Setup the default (waveform) screen
-    void setupDefault() {
-      // Only run once on mode change
-      if (ui_mode == UI_MODE_DEFAULT && last_ui_mode != UI_MODE_DEFAULT) {
-        // Reset controls
-        resetControls();
-
-        // Set up the initial recording mode
-        switch (rec_mode) {
-          case REC_MODE_FULL: 
-            looper_a.setRecModeFull(); 
-            looper_b.setRecModeFull(); 
-            looper_c.setRecModeFull(); 
-            looper_d.setRecModeFull(); 
-            looper_e.setRecModeFull(); 
-            break;
-          case REC_MODE_LOOP:
-            looper_a.setRecModeLoop(); 
-            looper_b.setRecModeLoop(); 
-            looper_c.setRecModeLoop();
-            looper_d.setRecModeLoop();
-            looper_e.setRecModeLoop(); 
-            break;
-          case REC_MODE_FULL_SHOT:
-            looper_a.setRecModeFullShot();
-            looper_b.setRecModeFullShot();
-            looper_c.setRecModeFullShot();
-            looper_d.setRecModeFullShot();
-            looper_e.setRecModeFullShot();
-            break;
-        };
-
-        // Setup Button functions (these should enter the ButtonGrid Menus)
-        button_1.onHold([this](){ this->setMode(UI_MODE_REC_MENU); });
-        button_2.onHold([this](){ this->setMode(UI_MODE_PLAY_MENU); });
-        button_3.onHold([this](){ this->setMode(UI_MODE_FX_MENU); });
-        button_6.onHold([this](){ this->setMode(UI_MODE_BUFFER_MENU); });
-
-        // Set the recording/overdub buttons to toggle or momentary
-        // depending on the value of the option
-        if (rec_button_momentary) {
-          button_4.onHold([this](){ this->activateRecording(); });
-          button_5.onHold([this](){ this->activateOverdub(); });
-          button_4.onReleased([this](){ this->stopRecording(); });
-          button_5.onReleased([this](){ this->stopRecording(); });
-        } else {
-          button_4.onReleased([this](){ this->toggleRecording(); });
-          button_5.onReleased([this](){ this->toggleOverdub(); });
-        }
-        
-        // Store the last ui mode, for the check on top
-        last_ui_mode = ui_mode;
-      }
-    }
-
-    // Render the default screen (waveform)
-    void renderDefault() {
-      // Store the current time and check how long ago the last frame was
-      // in ms
-      
-      // Clear the display
-      display.clearDisplay();
-
-      // Waveform should be maximum screen-heigh
-      int wave_height = display.height() * 1.0f;
-      // Ensure that when stepping from left to right we fit the waveform on the screen
-      int step = activeLooper()->getBufferLength() / (display.width() * WAVEFORM_OVERSAMPLING);
-      // Helper variable for the bottom of the screen
-      int bottom = display.height()-1;
-
-      // Render the waveform by iterating through the samples (oversampled by a factor
-      // defined on top of this file). Average the samples for each pixel of the 128 px
-      // wide screen and cache the resulting heights so we only have to recalculate when
-      // the waveform changes
-      for (int i=0; i<display.width()*WAVEFORM_OVERSAMPLING; i+=WAVEFORM_OVERSAMPLING) {
-        uint16_t x = int(i / WAVEFORM_OVERSAMPLING);
-        // Only recalculate if the cahce is dirty, else use cache
-        if (waveform_cache_dirty) {
-          float sig = 0.0f;
-          float scale = 1.0f;
-          if (!WAVEFORM_LIN) {
-            scale = 10.0f;
-          }
-          // Step through the buffer and sum the absolute values
-          for (int s=0; s<WAVEFORM_OVERSAMPLING; s++) {
-            float abs_sig = activeLooper()->getBuffer()[step*i];
-            abs_sig = abs(abs_sig) * scale;
-            sig += abs_sig;
-          }
-          // We oversampled so divide here
-          sig = sig / float(WAVEFORM_OVERSAMPLING);
-
-          if (!WAVEFORM_LIN) {
-            // Volume is logarithmic (hiding silent noises)
-            if (sig != 0.0f) {
-              sig = log10(sig);
-            }
-          }
-          waveform_cache[x] = int(sig * wave_height);
-        }
-
-        // Draw the vertical lines from bottom up, depending on the level of the
-        // calulcated wave on this point of the screen
-        display.drawFastVLine(x, bottom, -waveform_cache[x], SH110X_WHITE);
-        
-      }
-      // Draw one horizontal line on bottom
-      display.drawFastHLine(0, bottom, display.width(), SH110X_WHITE);
-
-      // Cache is now marked as clean
-      waveform_cache_dirty = false;
-
-      // Draw Indicator for loop start 
-      int x_start_loop = int(activeLooper()->loop_start_f * display.width());
-      display.drawLine(x_start_loop, 0, x_start_loop, bottom, SH110X_WHITE);
-      display.fillTriangle(x_start_loop, 6, x_start_loop, 0, x_start_loop+3, 0, SH110X_WHITE);
-
-      // Draw Indicator for Loop End
-      int x_loop_length = int(activeLooper()->loop_length_f * display.width());
-      int x_loop_end = (x_start_loop + x_loop_length) % display.width();
-      display.drawLine(x_loop_end, 0, x_loop_end, bottom, SH110X_WHITE);
-      display.fillTriangle(x_loop_end, 6, x_loop_end-3, 0, x_loop_end, 0, SH110X_WHITE);
-
-      // Draw connecting line for start and end
-      if (x_loop_end >= x_start_loop) {
-        display.drawLine(x_start_loop, 0, x_loop_end, 0, SH110X_WHITE);
-      } else {
-        display.drawLine(x_start_loop, 0, display.width(), 0, SH110X_WHITE);
-        display.drawLine(0, 0, x_loop_end, 0, SH110X_WHITE);
-      }
-
-      // Draw Playhead
-      switch (activeLooper()->playback_state) {
-        case atoav::PLAYBACK_STATE_LOOP:
-          {
-            int x_playhead = int(activeLooper()->GetPlayhead() * display.width()) + x_start_loop;
-            display.drawFastVLine(x_playhead, 6, 24, SH110X_WHITE);
-            break;
-          }
-        case atoav::PLAYBACK_STATE_MULTILOOP:
-          {
-            float* playheads = activeLooper()->GetPlayheads();
-            uint8_t count = activeLooper()->GetPlayheadCount();
-            int x_playhead = 0;
-            for (size_t i=0; i<count-1; i++) {
-              x_playhead = int(playheads[i] * display.width()) + x_start_loop;
-              int h = 6 + i*3;
-              display.drawFastVLine(x_playhead, h, 3, SH110X_WHITE);
-            }
-            break;
-          }
-        case atoav::PLAYBACK_STATE_MIDI:
-          {
-            int x_playhead = int(activeLooper()->GetPlayhead() * display.width()) + x_start_loop;
-            display.drawFastVLine(x_playhead, 6, 24, SH110X_WHITE);
-            break;
-          }
-      }
-      
-
-      // Draw Recording Indicator and Recording Head
-      if (recording_state == REC_STATE_RECORDING) {
-        // Draw Rec Head
-        int x_rec_head = int(activeLooper()->GetRecHead() * display.width());
-        display.drawFastVLine(x_rec_head, 10, bottom, SH110X_WHITE);
-        display.fillCircle(x_rec_head, 10, 3, SH110X_WHITE);
-        // Record sign
-        display.fillRect(0, 0, 13, 13, SH110X_WHITE);
-        display.fillRect(2, 2, 12, 12, SH110X_WHITE);
-        display.fillRect(1, 1, 11, 11, SH110X_BLACK);
-        display.fillCircle(6, 6, 3, SH110X_WHITE);
-      }
-
-      // Draw Overdub Indicator and Recording Head
-      if (recording_state == REC_STATE_OVERDUBBING) {
-        // Draw Rec Head
-        int x_rec_head = int(activeLooper()->GetRecHead() * display.width());
-        display.drawFastVLine(x_rec_head, 10, bottom, SH110X_WHITE);
-        display.fillCircle(x_rec_head, 10, 3, SH110X_WHITE);
-
-        // Overdub sign (a "plus")
-        display.fillRect(0, 0, 13, 13, SH110X_WHITE);
-        display.fillRect(2, 2, 12, 12, SH110X_WHITE);
-        display.fillRect(1, 1, 11, 11, SH110X_BLACK);
-        display.drawLine(6, 2, 6, 10, SH110X_WHITE);
-        display.drawLine(2, 6, 10, 6, SH110X_WHITE);
-      }
-
-      // Render potentiometer UIs in case a knob is changed
-      pot_1.renderUi();
-      pot_2.renderUi();
-      pot_3.renderUi();
-      pot_4.renderUi();
-      pot_5.renderUi();
-      pot_6.renderUi();
-      pot_7.renderUi();
-
-      // Display all the things done above
-      display.display();
-    }
-
-    // Activate recording and set the waveform cache to dirty
-    void activateRecording() {
-      if (recording_state != REC_STATE_RECORDING) {
-        activeLooper()->SetRecord();
-        waveform_cache_dirty = true;
-        recording_state = REC_STATE_RECORDING;
-      }
-    }
-
-    // Toggle recording
-    void toggleRecording() {
-      switch (recording_state) {
-        case REC_STATE_NOT_RECORDING:
-          activateRecording();
-          break;
-        case REC_STATE_RECORDING:
-          stopRecording();
-          break;
-        case REC_STATE_OVERDUBBING:
-          activateRecording();
-          break;
-      }
-    }
-
-    // Activates overdubbing
-    void activateOverdub() {
-      if (recording_state != REC_STATE_OVERDUBBING) {
-        waveform_cache_dirty = true;
-        recording_state = REC_STATE_OVERDUBBING;
-        activeLooper()->SetOverdub();
-      }
-    }
-
-    // Stop the recording
-    void stopRecording() {
-      if (recording_state != REC_STATE_NOT_RECORDING) {
-        recording_state = REC_STATE_NOT_RECORDING;
-        activeLooper()->SetStopWriting();
-      }
-    }
-
-    // Toggle overdub off and on
-    void toggleOverdub() {
-      switch (recording_state) {
-        case REC_STATE_NOT_RECORDING:
-          activateOverdub();
-          break;
-        case REC_STATE_OVERDUBBING:
-          stopRecording();
-          break;
-        case REC_STATE_RECORDING:
-          activateOverdub();
-          break;
-      }
-    }
-
-    // Reset the recording state (mark waveform cahce dirty)
-    void resetRecordingState() {
-      if (recording_state == REC_STATE_RECORDING || recording_state == REC_STATE_OVERDUBBING) {
-        waveform_cache_dirty = true; 
-      }
-    }
-
-   // Set the mode of the UI (and thus change the screen)
-    void setMode(UiMode mode) {
-      if (last_ui_mode == mode) { return; }
-      last_ui_mode = ui_mode;
-      ui_mode = mode;
-      switch (ui_mode) {
-        case UI_MODE_SPLASH:
-          break;
-        case UI_MODE_DEFAULT:
-          break;
-        case UI_MODE_REC_MENU:
-          this->button_grids[0].hideAllDescriptions();
-          break;
-        case UI_MODE_PLAY_MENU:
-          this->button_grids[1].hideAllDescriptions();
-          break;
-        case UI_MODE_TRIGGER_MENU:
-          this->button_grids[2].hideAllDescriptions();
-          break;
-        case UI_MODE_FX_MENU:
-          this->button_grids[3].hideAllDescriptions();
-          break;
-        case UI_MODE_BUFFER_MENU:
-          this->button_grids[4].hideAllDescriptions();
-          break;
-      }
-    }
-
-
-    // Update the Ui variables (expected to run repeatedly)
-    void update() {
-      resetRecordingState();
-
-      switch (ui_mode) {
-        case UI_MODE_SPLASH:
-          break;
-        case UI_MODE_DEFAULT:
-          setupDefault();
-          break;
-        case UI_MODE_REC_MENU:
-          setupRecMenu();
-          break;
-        case UI_MODE_PLAY_MENU:
-          setupPlayMenu();
-          break;
-        case UI_MODE_TRIGGER_MENU:
-          break;
-        case UI_MODE_FX_MENU:
-          setupFXMenu();
-          break;
-        case UI_MODE_BUFFER_MENU:
-          setupBufferMenu();
-          break;
-      }
-    }
-
-    // Returns a pointer to the currently active looper
-    atoav::Looper * activeLooper() {
-      switch(active_buffer) {
-        case ACTIVE_BUFFER_A: {
-          atoav::Looper * ptr = &looper_a;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_B: {
-          atoav::Looper * ptr = &looper_b;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_C: {
-          atoav::Looper * ptr = &looper_c;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_D: {
-          atoav::Looper * ptr = &looper_d;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_E: {
-          atoav::Looper * ptr = &looper_e;
-          return ptr;
-          break;
-        }
-      }
-      // Unreachable, but makes the compiler shut up
-      atoav::Looper * ptr = &looper_a;
-      return ptr;
-    }
-
-    // Returns a pointer to the currently active looper
-    atoav::Looper * previousLooper() {
-      switch(previous_buffer) {
-        case ACTIVE_BUFFER_A: {
-          atoav::Looper * ptr = &looper_a;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_B: {
-          atoav::Looper * ptr = &looper_b;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_C: {
-          atoav::Looper * ptr = &looper_c;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_D: {
-          atoav::Looper * ptr = &looper_d;
-          return ptr;
-          break;
-        }
-        case ACTIVE_BUFFER_E: {
-          atoav::Looper * ptr = &looper_e;
-          return ptr;
-          break;
-        }
-      }
-      // Unreachable, but makes the compiler shut up
-      atoav::Looper * ptr = &looper_a;
-      return ptr;
-    }
-
-    // Set the Looper start/length to a given value
-    void setLoop(float start, float length) {
-      activeLooper()->SetLoop(start, length);
-    }
-
-    private:
-      double last_render = 0.0;
-      uint16_t waveform_cache[128] = {0};
-      bool waveform_cache_dirty = true;
-      RecordingState recording_state = REC_STATE_NOT_RECORDING;
-      UiMode last_ui_mode = UI_MODE_LAST;
-      bool rec_button_momentary = true;
-};
-
-
-
-#endif
\ No newline at end of file