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.

What you'll need

2 x Trim Pots
Breadboard trim potentiometer - 10K
1 x Feather Bluefruit nRF52
Adafruit Feather nRF52 Bluefruit LE - nRF52832
1 x Breadboard
Full sized breadboard
1 x Hook-up Wire
Hook-up Wire Spool Set - 22AWG Solid Core - 6 x 25 ft
1 x Wire Strippers
Hakko Professional Quality 20-30 AWG Wire Strippers - CSP-30-1
4 x Buttons
Tactile Switch Buttons (12mm square, 6mm tall) x 10 pack
1 x USB cable
USB cable - USB A to Micro-B - 3 foot long
1 x LiPo Battery
Lithium Ion Polymer Battery - 3.7v 500mAh

Wiring

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.

Go Wireless

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.

iOS

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.

Play

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.

This guide was first published on Dec 04, 2018. It was last updated on Dec 04, 2018.

This page (BLE MIDI Controller) was last updated on Apr 17, 2021.

Text editor powered by tinymce.