By Harry Schneider

Description:

The MINI controller is a compact and portable MIDI controller which allows you to produce music more efficiently.

Discussion:

Overall, I am very happy with how this project turned out. I am very pleased with the build quality despite it being my first time 3D printing. Also I think the size and overall durability is great. My goal was to make something that, if manufactured, I would personally purchase and use. Maybe I am just overly critical but I would have liked to go smaller if possible. The current size is 3 x 3 inches but I would love if it could fit comfortably in my pocket. The current size was already a challenge for me. It was very hard to fit all of the electronics inside especially with the usb input attachment. This attachment came with a large cable that took up a lot of space on the inside. In the future I would like to make another version which would have a USB type C input instead of type B. Type C is much smaller and more compatible with current technology. Also I would make it around 2 inches by 2 inches instead of 3 inches. In addition I would also make it slimmer. I found the 3D printing process to be really fun. It was very difficult designing everything in cad but with the help of my teacher I was able to actualize the case for the midi controller.
I was very happy with the feedback from my critique. However I was told to consider labeling the functions of the potentiometers. I understand how this makes sense but in reality, the assignments of the knobs change depending on how I intend to use them. Also it was suggested that I could use a micro Arduino if I wanted to go smaller. I will definitely use a smaller Arduino in the future. I think this was really great feedback.

 

Photos and Videos

Process

This is the initial working prototype. At this point the code was working properly and all of the components where working on the breadboard. At this point I was designing the case where I needed to fit these components and I had to measure everything in order to create an accurate 3D model.

3D Modeling

After assembling the prototype, I created the case in cad, a 2 piece design with a bottom plate with screw holes as well as a 3D printed shell.

These are the electronics soldered together in a way to maximize internal space

This image shows how everything fits together in the 3D printed case. This part was a challenge and I was worried about everything fitting and at a point I was considering remaking the 3d model by making it bigger but I really wanted to keep it as small as possible. I decided to re-solder everything in a way that I could fit everything. I decided to use a flexible protoboard which I cut down in size to maximize as much space as possible

Schematic

Schematic

Block Diagram

Functional block diagram

/*
 Harry Schneider: MINI Controller
 Adapted from code for midi potentiometers from Gustavo Silviera Aka "Nerd musician" on youtube (http://www.youtube.com/musiconerd)
*/

#define ATMEGA32U4 1
#ifdef ATMEGA328
#include <MIDI.h>
#elif ATMEGA32U4
#include "MIDIUSB.h"
#endif

const int N_POTS = 4; // total numbers of pots
const int POT_ARDUINO_PIN[N_POTS] = {A0, A1, A2, A3};

int potCState[N_POTS] = {0}; // Current state of the pot
int potPState[N_POTS] = {0}; // Previous state of the pot
int potVar = 0; // Difference between the current and previous state of the pot

int midiCState[N_POTS] = {0}; // Current state of the midi value
int midiPState[N_POTS] = {0}; // Previous state of the midi value

const int TIMEOUT = 300; // Amount of time the potentiometer will be read after it exceeds the varThreshold
const int varThreshold = 10; // Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[N_POTS] = {0}; // Previously stored time
unsigned long timer[N_POTS] = {0}; // Stores the time that has elapsed since the timer was reset

// MIDI
byte midiCh = 0; // MIDI channel to be used
byte note = 36; // Lowest note to be used
byte cc = 1; // Lowest MIDI CC to be used

// SETUP
void setup() {

  Serial.begin(115200);

#ifdef DEBUG
  Serial.println("Debug mode");
  Serial.println();
#endif
}

#ifdef pin13
if (i == pin13index) {
  buttonCState[i] = !buttonCState[i]; // inverts the pin 13 because it has a pull down resistor instead of a pull up
}
#endif

// Sends the MIDI note ON accordingly to the chosen board
#ifdef ATMEGA328
// use if using with ATmega328 (uno, mega, nano...)
MIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel

#elif ATMEGA32U4
// use if using with ATmega32U4 (micro, pro micro, leonardo...)

#elif TEENSY
//do usbMIDI.sendNoteOn if using with Teensy
usbMIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel

#elif DEBUG
Serial.print(i);
Serial.println(": button on");
#endif

// Sends the MIDI note OFF accordingly to the chosen board
#ifdef ATMEGA328
// use if using with ATmega328 (uno, mega, nano...)
MIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel

#elif ATMEGA32U4
// use if using with ATmega32U4 (micro, pro micro, leonardo...)

#elif TEENSY
//do usbMIDI.sendNoteOn if using with Teensy
usbMIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel

#elif DEBUG
Serial.print(i);
Serial.println(": button off");
#endif

/////////////////////////////////////////////
// POTENTIOMETERS
void potentiometers() {


  for (int i = 0; i < N_POTS; i++) { // Loops through all the potentiometers

    potCState[i] = analogRead(POT_ARDUINO_PIN[i]); // reads the pins from arduino

    midiCState[i] = map(potCState[i], 0, 1023, 0, 127); // Maps the reading of the potCState to a value usable in midi

    potVar = abs(potCState[i] - potPState[i]); // Calculates the absolute value between the difference between the current and previous state of the pot

    if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
      PTime[i] = millis(); // Stores the previous time
    }

    timer[i] = millis() - PTime[i]; // Resets the timer 11000 - 11000 = 0ms

    if (timer[i] < TIMEOUT) {
      potMoving = true;
    }
    else {
      potMoving = false;
    }

    if (potMoving == true) { // If the potentiometer is still moving, send the change control
      if (midiPState[i] != midiCState[i]) {

        // Sends the MIDI CC accordingly to the chosen board
#ifdef ATMEGA328
        MIDI.sendControlChange(cc + i, midiCState[i], midiCh); // cc number, cc value, midi channel

#elif ATMEGA32U4

        controlChange(midiCh, cc + i, midiCState[i]); //
        MidiUSB.flush();

#elif TEENSY
        usbMIDI.sendControlChange(cc + i, midiCState[i], midiCh); // cc number, cc value, midi channel

#elif DEBUG
        Serial.print("Pot: ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println(midiCState[i]);
        //Serial.print("  ");
#endif

        potPState[i] = potCState[i]; // Stores the current reading of the potentiometer to compare with the next
        midiPState[i] = midiCState[i];
      }
    }
  }
}

#ifdef ATMEGA32U4

// Arduino (pro)micro midi functions MIDIUSB Library
void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOff);
}

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);
}
#endif