You can create a BLE MIDI controller using a Feather Bluefruit nRF52 and some basic components on a breadboard. This is a great way to experiment with BLE MIDI control on a mobile device such as an iOS or Android phone.
Mount the Feather, buttons, and trim pots on a breadboard and use jumper wire to make the connections shown in the diagram above.
After translating that diagram into reality, you should have something like this …
The 3-pin strips of male headers seen above the trim pots are in no way necessary and were simply added for mechanical stability.
Once everything's wired up, connect the Feather to your computer using the micro USB cable.
Arduino IDE setup
Follow the steps on this page to download and install the Arduino IDE on your computer. Then install support for the Feather Bluefruit nRF52 by following the steps here.
Once installed, open Arduino and choose Tools -> Sketch -> Manage Libraries from the top menu. In the new window that appears, type MIDI in the search field. Scroll down in the results to MIDI Library by Forty Seven Effects, select it and install the latest version.
Code
Create a new sketch in Arduino and delete the starter code that appears inside of it. Copy the code seen below, paste it into that new blank sketch and save it.
/********************************************************************* * Simple MIDI controller for the Feather Bluefruit NRF52 uses potentiometers connected to pins 2(A0) & 3(A1) + four momentary pushbuttons connected to pins 16, 15, 7, & 11 Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! MIT license *********************************************************************/ /* For BLE MIDI Setup https://learn.adafruit.com/wireless-untztrument-using-ble-midi/overview */ #include <bluefruit.h> #include <MIDI.h> BLEDis bledis; BLEMidi blemidi; // Create a new instance of the Arduino MIDI Library, and attach BluefruitLE MIDI as the transport. MIDI_CREATE_BLE_INSTANCE(blemidi); int buttons[4] = {16, 15, 7, 11}; //pin numbers for each attached button int notes[4] = {57, 62, 66, 69}; //note each button will play bool noteStates[4] = {false}; //keep track of the play state of each note int modPot = 2; //analog pin A0 int pitchPot = 3; //analog pin A1 int lastModVal; int lastPitchVal; void setup(){ Serial.begin(115200); while ( !Serial ) delay(10); // for nrf52840 with native usb //set input modes for buttons for (int i = 0; i < 4; i++) { pinMode(buttons[i], INPUT_PULLUP); } Serial.println("Adafruit Bluefruit52 MIDI over Bluetooth LE Example"); // Config the peripheral connection with maximum bandwidth Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); Bluefruit.begin(); Bluefruit.setName("Bluefruit52 MIDI"); Bluefruit.setTxPower(4); // Setup the on board blue LED to be enabled on CONNECT Bluefruit.autoConnLed(true); // Configure and Start Device Information Service bledis.setManufacturer("Adafruit Industries"); bledis.setModel("Bluefruit Feather52"); bledis.begin(); // Initialize MIDI, and listen to all MIDI channels, will also call blemidi service's begin() MIDI.begin(MIDI_CHANNEL_OMNI); // Attach the handleNoteOn function to the MIDI Library. It will // be called whenever the Bluefruit receives MIDI Note On messages. MIDI.setHandleNoteOn(handleNoteOn); // Do the same for MIDI Note Off messages. MIDI.setHandleNoteOff(handleNoteOff); // Set up and start advertising startAdv(); // Start MIDI read loop Scheduler.startLoop(midiRead); } void startAdv(void){ // Set General Discoverable Mode flag Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); // Advertise TX Power Bluefruit.Advertising.addTxPower(); // Advertise BLE MIDI Service Bluefruit.Advertising.addService(blemidi); // Secondary Scan Response packet (optional) Bluefruit.ScanResponse.addName(); //Start Advertising Bluefruit.Advertising.restartOnDisconnect(true); Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds } void handleNoteOn(byte channel, byte pitch, byte velocity){ // Log when a note is pressed. Serial.printf("Note on: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity); Serial.println(); } void handleNoteOff(byte channel, byte pitch, byte velocity){ // Log when a note is released. Serial.printf("Note off: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity); Serial.println(); } void loop(){ // Don't continue if we aren't connected. if (! Bluefruit.connected()) { return; } // Don't continue if the connected device isn't ready to receive messages. if (! blemidi.notifyEnabled()) { return; } //check pot values int modVal = analogRead(modPot); int pitchVal = analogRead(pitchPot); pitchVal = map(pitchVal, 0, 1023, -8000, 8000); modVal = modVal / 8; //send new mod value if it has changed if (lastModVal != modVal) { Serial.print("modWheel = "); Serial.println(modVal); MIDI.sendControlChange(1, modVal, 1); lastModVal = modVal; } //send new pitch value if it has changed if (lastPitchVal != pitchVal) { Serial.print("pitchBend = "); Serial.println(pitchVal); MIDI.sendPitchBend(pitchVal, 1); //pot value sent as pitch bend lastPitchVal = pitchVal; } //check all buttons for (int i = 0; i < 4; i++) { bool buttonPressed = !digitalRead(buttons[i]); //send note on if button pressed and note is off if (buttonPressed && !noteStates[i]) { Serial.print("Button pressed: "); Serial.println(i); MIDI.sendNoteOn(notes[i], 100, 1); noteStates[i] = true; } //send note off if button released and note is on else if (!buttonPressed && noteStates[i]) { Serial.print("Button released: "); Serial.println(i); MIDI.sendNoteOff(notes[i], 100, 1); noteStates[i] = false; } } delay(100); } void midiRead(){ // Don't continue if we aren't connected. if (! Bluefruit.connected()) { return; } // Don't continue if the connected device isn't ready to receive messages. if (! blemidi.notifyEnabled()) { return; } // read any new MIDI messages MIDI.read(); }
Upload code
Connect your Feather to your computer using a micro USB cable. From Arduino's top menu, go to Tools -> Board and choose Adafruit Bluefruit nRF52832 Feather from the list that appears.
Next, go to Tools -> Port and choose the SLAB_USBtoUART port.
Finally, go Sketch -> Upload or click the right-facing arrow button to upload the sketch to your Feather.
In order to make this a truly wireless test - disconnect the USB cable from the Feather and attach the LiPo battery to Feather's JST port. You'll know Feather is up and running if you see the flashing blue LED.
Using your iPad or iPhone, download & install Garageband from the App Store. Launch the app and create a new project. When prompted, choose the piano keyboard as the first track instrument.
In the main track arrangement view, tap the wrench icon in the upper right corner of the screen. From the Settings menu that appears, choose Advanced, then Bluetooth MIDI Devices. The app will scan for available Bluetooth MIDI devices - choose Bluefruit52 MIDI from the results list.
Once the device is paired, you should be able to control Garageband's piano from your breadboard MIDI controller.
Android
On your Android device, open the Play Store and download both MIDI BLE Connect & General MIDI Synth.
Open MIDI BLE Connect & tap the BLUETOOTH SCAN button. Choose Bluefruit52 MIDI from the results list.
Next, open the General MIDI app, tap the small triangle icon at the top, and choose Bluefruit52 MIDI from the list. Once the device is paired, you should be able to control General MIDI's piano synth from your breadboard BLE MIDI controller.
Each pushbutton will trigger a note, and the potentiometers control pitch bend and modulation. You can easily expand this project by adding more buttons and soldering the components to a protoboard for more durability.
Text editor powered by tinymce.