0% found this document useful (0 votes)
268 views

Accordion Arduino MIDI Code

This document contains code for an Arduino-based MIDI accordion. It includes code to read inputs from the left and right hands of the accordion, map those inputs to MIDI note numbers, and send MIDI messages for note on/off and expression (volume) changes via USB or Bluetooth. It also contains optional code to integrate a pressure sensor to control volume based on bellows pressure.

Uploaded by

csict
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
268 views

Accordion Arduino MIDI Code

This document contains code for an Arduino-based MIDI accordion. It includes code to read inputs from the left and right hands of the accordion, map those inputs to MIDI note numbers, and send MIDI messages for note on/off and expression (volume) changes via USB or Bluetooth. It also contains optional code to integrate a pressure sensor to control volume based on bellows pressure.

Uploaded by

csict
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

C:\Users\Schools_home\Google Drive\FLASH_DRIVE\Everything_Else\Arduino\Mailson_Souza_Lima_2019\MIDI_AccordionMailsonVavra\MIDI_Accordion.

ino
Thursday, 16 May 2019 10:01
#include <SFE_BMP180.h>
#include <Wire.h>

#include <MIDI.h>

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>
struct MySettings : public midi::DefaultSettings
{

static const bool UseRunningStatus = false;


// Set MIDI baud rate. MIDI has a default baud rate of 31250,
// but we're setting our baud rate higher so that the Serial<->MIDI software
// can properly decode and read outgoing MIDI data on the computer.
static const long BaudRate = 115200;
};

//#define DEBUG//uncomment this line to print serial messages, comment to send MIDI data
//#define BLUETOOTH//uncomment this line to send MIDI data via bluetooth instead of USB
//#define BMP//Puncomment this line to use the BMP180 to add dynamics via bellows

#ifdef BLUETOOTH
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, MIDI, MySettings);
#else
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, MySettings);
#endif

char left_hand_pins[] = { 10, 11, 12 };


// array to store up/down status of left keys
int LeftKeysStatus[] = {
B0000000,
B0000000,
B0000000
};
//Note: Based on how the opto-interruptors are laid out,
//You will likely have to remap their pitch numbers (36-59)
//36-47 are the bass notes, 48-59 are the chord notes
const char left_notes_midi_numbers[][8] = {
{38,39,40,41,50,51,52,53},//10
{46,47,36,37,58,59,48,49},//11
{42,43,44,45,54,55,56,57} //12
};

char right_hand_pins[] = { 2, 3, 4, 5, 6, 7 };
// array to store up/down status of right keys
int RightKeysStatus[] = {
B0000000,
B0000000,
B0000000,
B0000000,
B0000000,
B0000000
};
//Note: Based on how the opto-interruptors are laid out,
//You will likely have to remap their pitch numbers (53-93)
const char right_notes_midi_numbers[][8] = {
{68,66,64,63,61,58,56,54},//2
{67,65,62,60,59,57,55,53},//3
{88,84,81,79,76,74,72,69},//4
{93,91,89,86,83,77,73,71},//5
{90,87,85,82,80,78,75,70},//6
{92,0,0,0,0,0,0,0} //7
};

void setup()
-1-
C:\Users\Schools_home\Google Drive\FLASH_DRIVE\Everything_Else\Arduino\Mailson_Souza_Lima_2019\MIDI_AccordionMailsonVavra\MIDI_Accordion.ino
Thursday, 16 May 2019 10:01
{
#ifdef DEBUG
Serial.begin(9600);
#else
MIDI.begin();
//If we're sending MIDI over Serial1, open Serial for additional debugging
#ifdef BLUETOOTH
Serial.begin(9600);
#endif
#endif
//Digital pins start turned off
for (int i=0; i<sizeof(left_hand_pins);i++){
pinMode(left_hand_pins[i],OUTPUT);
digitalWrite(left_hand_pins[i], LOW);
}
for (int i=0; i<sizeof(right_hand_pins);i++){
pinMode(right_hand_pins[i],OUTPUT);
digitalWrite(right_hand_pins[i], LOW);
}

DDRF = B00000000; // PortF as input (for left hand)


PORTF = B11111111; // turn on pullup resistors

DDRK = B00000000; // PortK as input (for right hand)


PORTK = B11111111; // turn on pullup resistors

#ifdef BMP
init_BMP();
#endif
}

//MIDI Control Change code for expression, which is a percentage of velocity


const int CC_Expression = 11;
int prev_expression = 127;
//The BMP_180 is very sensitive, so readings can vary wildly from sample to sample.
//We're getting around this by computing and sending the average of bmp_sample_rate samples.
//A smaller bmp_sample_rate is more granular, but allows more "noise" to come in.
//A larger bmp_sample_rate is less granular, but has a smoother contour.
//Setting bmp_sample_rate too large may also lose the amount of perceived expression
//and create a noticable delay between squeezing the bellows and hearing the volume change,
//resulting in choppy crescendos and decrescendos.
//Tweak this value as needed.
const int bmp_sample_rate = 5;
int expression_avg[bmp_sample_rate];
int e = 0;

void loop()
{
#ifdef BMP
//Read pressure from the BMP_180 and convert it to MIDI expression
int expression = get_expression(prev_expression);

//Ignore it if it didn't change


if(expression != prev_expression) {
expression_avg[e] = expression;
//Only send MIDI CC every bmp_sample_rate times,
//but send the average of the last bmp_sample_rate deltas
if (e == bmp_sample_rate - 1){
expression = 0;
for (int i=0; i<bmp_sample_rate; i++){
expression += expression_avg[i];
}
expression = expression/bmp_sample_rate;

#ifdef DEBUG
Serial.print("Expression Change: ");
Serial.println(expression);
#else
MIDI.sendControlChange(CC_Expression,expression,1);
//Don't let bass overpower melody
MIDI.sendControlChange(CC_Expression,constrain(expression-6,0,127),2);
-2-
C:\Users\Schools_home\Google Drive\FLASH_DRIVE\Everything_Else\Arduino\Mailson_Souza_Lima_2019\MIDI_AccordionMailsonVavra\MIDI_Accordion.ino
Thursday, 16 May 2019 10:01
//Don't let chords overpower melody
MIDI.sendControlChange(CC_Expression,constrain(expression-12,0,127),3);
#endif
prev_expression = expression;
e = 0;
}
else {
e = e + 1;
}
}
#endif

//Alternate between scanning the left and right hand pins


//to reduce necessary delay between reads
for (int i=0; i<6;i++){
scan_pin(right_hand_pins[i], i, RightKeysStatus[i], false);
scan_pin(left_hand_pins[i%3], i%3, LeftKeysStatus[i%3], true);
}
//Original
//scan_keys(left_hand_pins, sizeof(left_hand_pins), LeftKeysStatus, true);
//scan_keys(right_hand_pins, sizeof(right_hand_pins), RightKeysStatus, false);
}

//This function is currently unused


void scan_keys(char *pins, int pinLength, int *KeysStatus, bool left) {
for (int i=0; i<pinLength;i++){
scan_pin(pins[i], i, KeysStatus[i], left);
}
}

byte reg_values = 0;

//Read the analog port value for the given pin


//If something changed, trigger MIDI signal
void scan_pin(int pin, int index, byte PinStatus, bool left) {
//TODO - I wonder if we can replace this with direct port write for even better performance?
digitalWrite(pin, HIGH);
//A slight delay is needed here or else we'll be reading the previous pin
delayMicroseconds(300);//was able to cut this in half by alternating between left and right
if (left) {
reg_values = ~PINF;
}
else {
reg_values = ~PINK;
}
digitalWrite(pin, LOW);

//check if something changed


if (reg_values != PinStatus){
//if the byte value is greater, we're turning the note on; else, turning it off.
if (reg_values > PinStatus){
//using bit-wise OR to send modified bits only
check_key(reg_values ^ PinStatus, index, true, left);
}
else {
check_key(reg_values ^ PinStatus, index, false, left);
}
}
}

//Check to see which bits have changed and send the appropriate midi message
//Instead of iterating the array from 0-7, use binary search to find the modified bits faster
void check_key(int reg, int group, boolean on, boolean left){
// saving 4 iterations, dividing byte by 2
if (reg & 0xF0) {
for(int i=0; i<4; i++){
if ((reg >> 4+i) & 1){
note_midi(group, i+4, on, left);
}
}
}
-3-
C:\Users\Schools_home\Google Drive\FLASH_DRIVE\Everything_Else\Arduino\Mailson_Souza_Lima_2019\MIDI_AccordionMailsonVavra\MIDI_Accordion.ino
Thursday, 16 May 2019 10:01
else if (reg & 0x0F) {
for(int i=0; i<4; i++){
if ((reg >> i) & 1){
note_midi(group, i, on, left);
}
}
}
}

void note_midi(int group, int position, boolean on, boolean left){


int pitch;
int channel = 1;
int midi_vel = 127;

if (left){
if (on){
LeftKeysStatus[group] |= (1 << position); //setting bit value
}
else {
LeftKeysStatus[group] &= ~(1 << position); //setting bit value
}
pitch = left_notes_midi_numbers[group][position];
if(pitch < 48) {
midi_vel = 120;//Don't let bass overpower melody
channel = 2;
}
else {
midi_vel = 110;//Don't let chords overpower melody
channel = 3;
}
}
else{
if(on) {
RightKeysStatus[group] |= (1 << position); //setting bit value
}
else {
RightKeysStatus[group] &= ~(1 << position); //setting bit value
}
pitch = right_notes_midi_numbers[group][position];
channel = 1;
}

if (pitch){
#ifdef DEBUG
Serial.print("Note ");
if(on){
Serial.print("on: ");
}
else {
Serial.print("off: ");
}
Serial.println(pitch);
#else
if(on) {
MIDI.sendNoteOn(pitch, midi_vel, channel);
}
else {
MIDI.sendNoteOff(pitch, midi_vel, channel);
}
#endif
}

-4-

You might also like