Last active
June 12, 2020 20:00
-
-
Save ubidefeo/6098d95332b6529f1b0599bfd443ebae to your computer and use it in GitHub Desktop.
Arduino MIDI controller Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Arduino analog to USB MIDI | |
Ubi de Feo @ Bar Arduino | |
https://www.youtube.com/watch?v=0zNmt_IKwRg | |
supported boards: | |
- Arduino MKR Family | |
- Arduino Nano 33 IoT | |
**** Sketch for BLE MIDI (Nano BLE and Nano BLE Sense) **** | |
**** can be found here https://gist.github.com/ubidefeo/3e7362235cee5317cec4a36f07585e29 **** | |
**** Thank you Larry Bank for pointing out the lack of a BLE version **** | |
*/ | |
#include "MIDIUSB.h" | |
void controlChange(byte channel, byte control, byte value) { | |
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value}; | |
MidiUSB.sendMIDI(event); | |
} | |
const int SAMPLES_COUNT = 20; | |
// FIFO | |
int samplesBuffer[SAMPLES_COUNT] = {0}; | |
int sampleIndex = 0; | |
const int knobInputPin = A1; | |
const int changeThreshold = 20; | |
int lastSensorValue; | |
int lastMappedValue; | |
unsigned long samplesSum = 0; | |
void setup() { | |
Serial.begin(57600); | |
delay(5000); | |
Serial.println("SETUP"); | |
} | |
void loop() { | |
int knobReadOut = filterAnalogValue(knobInputPin); | |
int mappedValue = map(knobReadOut, 0, 1023, 0, 127); | |
if(lastMappedValue != mappedValue){ | |
// Serial.println("************ CHANGE ***************"); | |
// Serial.print(">>> "); | |
// Serial.print(mappedValue); | |
// Serial.println(" <<<"); | |
controlChange(0, 4, mappedValue); | |
} | |
lastMappedValue = mappedValue; | |
} | |
int filterAnalogValue(int _inputPin){ | |
samplesSum = 0; | |
int analogValue = analogRead(_inputPin); | |
//int valueDelta = abs(analogValue - lastSensorValue); | |
// Serial.print(analogValue); | |
// Serial.print(" - "); | |
// Serial.println(lastSensorValue); | |
// if(valueDelta < changeThreshold){ | |
// analogValue = lastSensorValue; | |
// } | |
if(sampleIndex < SAMPLES_COUNT){ | |
samplesBuffer[sampleIndex] = analogValue; | |
sampleIndex++; | |
}else{ | |
for(int samplePosition = 0; samplePosition < sampleIndex - 1; samplePosition++){0; | |
samplesBuffer[samplePosition] = samplesBuffer[samplePosition + 1]; | |
} | |
samplesBuffer[SAMPLES_COUNT - 1] = analogValue; | |
} | |
for(int samplePosition = 0; samplePosition < sampleIndex; samplePosition++){0; | |
samplesSum += samplesBuffer[samplePosition]; | |
} | |
//lastSensorValue = analogValue; | |
if(samplesSum == 0) return 0; | |
unsigned int filteredValue = samplesSum / sampleIndex; | |
return filteredValue; | |
} |
The MIDIUSB library complains about compiling on the Nano 33 BLE, but I believe this will work:
#include "MIDIUSB.h"
const int SAMPLES_COUNT = 16; // use a power of 2 to avoid having to use divide for averaging
const int SAMPLES_SHIFT = 4; // the log2 of the samples count
void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
MidiUSB.sendMIDI(event);
}
// Circular buffer
int samplesBuffer[SAMPLES_COUNT] = {0};
int sampleIndex = 0;
unsigned long sampleCount = 0; // total samples collected
const int knobInputPin = A1;
const int changeThreshold = 20;
int lastSensorValue;
int lastMappedValue;
int samplesSum = 0;
void setup() {
Serial.begin(57600);
delay(5000);
Serial.println("SETUP");
}
void loop() {
int knobReadOut = filterAnalogValue(knobInputPin);
int mappedValue = map(knobReadOut, 0, 1023, 0, 127);
if(lastMappedValue != mappedValue){
// Serial.println("************ CHANGE ***************");
// Serial.print(">>> ");
// Serial.print(mappedValue);
// Serial.println(" <<<");
controlChange(0, 4, mappedValue);
}
lastMappedValue = mappedValue;
delay(100);
}
int filterAnalogValue(int _inputPin){
unsigned int filteredValue
int analogValue = analogRead(_inputPin);
//int valueDelta = abs(analogValue - lastSensorValue);
// Serial.print(analogValue);
// Serial.print(" - ");
// Serial.println(lastSensorValue);
// if(valueDelta < changeThreshold){
// analogValue = lastSensorValue;
// }
samplesSum -= samplesBuffer[sampleIndex]; // subtract the oldest value (the index wrapped around)
samplesBuffer[sampleIndex++] = analogValue;
sampleIndex &= (SAMPLE_COUNT-1); // ** MUST BE A POWER OF 2! **
sampleCount++; // keep track of total samples collected
samplesSum += analogValue; // add the newest value
// At startup, return the raw value; once we have enough samples, return the average
if (sampleCount < SAMPLES_COUNT) {
filteredValue = analogValue;
} else {
filteredValue = (samplesSum >> SAMPLES_SHIFT);
}
return filteredValue;
}
hey @bitbank2
you can find the BLE Sketch here https://gist.github.com/ubidefeo/3e7362235cee5317cec4a36f07585e29
I've also added a comment to thank you for pointing it out :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
great approach.
I initially went for
memmove()
but it turned out to be even slower than this cycle approach.A circular buffer came to my mind in the beginning, then I thought this was easier to understand.
Would you care for writing your version and keep the thread running?
I think I can learn something from your proposed optimisation, and I'd love to :)
thanks
u.