Go Down

Topic: Successfully sending MIDI CC over Bluetooth? (Not note on/off) (Read 1 time) previous topic - next topic

Monoth

Hi there,

I recently got a few adafruit bluefruit feather LE boards as I read that they can send MIDI over USB:
https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/overview

I tried one and yes indeed, it sure can. However, it only seems to be able to send note values and not continuous control messages for pots/sliders etc..

The only examples I see of midi being sent are in these examples, and they only concern note on/off:
https://learn.adafruit.com/bluetooth-le-midi-controller/software
https://learn.adafruit.com/wireless-untztrument-using-ble-midi/overview-uniontownlabs

I have already posted on the Adafruit forum and no response so I'm just wondering if anyone on here has found a way to send CC over bluetooth?

p.s. if this post is not permitted as it's not an Arduino product then my apologies.

Thank you :)

PieterP

CC messages are almost identical to note messages. Just replace the 0x8 or 0x9 status nibble (for note off and note on resp.) with the 0xB status nibble for CC. Data 1 is the controller number instead of the note number, and data 2 is the CC value instead of the velocity.

Pieter

Monoth

Thanks so much for your response. So, if I understand you correctly, the setup would not be like this?:

Code: [Select]
  // send note on
  midi.send(0x90, current_note, 0x64);

  // send note off
  midi.send(0x80, current_note, 0x64);

  // Send cc instead
  midi.send(0xB, contoller_number, ccvalue);



"midi.send" is the function used in the BLE library for the Adafruit controller

PieterP

Almost, 0xB is the high nibble of the status byte. The low nibble is the channel (0x0 - 0xF for channels 1 - 16 respectively). So if you want to send on channel 1, you use 0xB0 as status byte, 0xB1 for channel 2, 0xB2 for channel 3, etc.

Monoth

Great. Thanks so much for clearing that up:) I was used to using the midi serial midi library which has separate functions for notes and cc's. That's why I was confused.

I'll test this out asap and report back!

wheels1758

I am not the OP but I am having an issue sending CC messages using the adafruit blemidi library. I was able to successfully send a CC signal, but it is hit and miss. If I print my Cc value to the serial monitor, I can see that it is changing, so the hardware setup seems to be fine, but it only occasionally sends the signal (testing by controlling loopcommunity PRIME via midimittr). Is there a way to flush the midi commands to ensure they actually send?

Troub99

#6
Aug 01, 2019, 09:28 pm Last Edit: Aug 02, 2019, 12:49 am by Troub99 Reason: putting code in code box
Hello

First time posting, but I've been here many, many times over the last few days as I attempt to build a midi controller with an adafruit 32u4 bluefruit. This thread in particular shone much light down a very dark tunnel. Pieter P, I've found your wisdom in many places, hopefully coming back here might get me to my short term destination.

I trying to complete a sketch with 7 buttons(sending note on / note off) and 8 knobs (sending cc's). I started with this excellent tutorial for a midi guitar and the code he provides (15 buttons sending note data) https://www.youtube.com/watch?v=QPgYpVHFSQY.

I've then been trying to modify his code (with very little starting knowledge) to give me Control change data on my knobs. I've got as far as the code below, successfully mapping 8 analogue pins to CC Knobs and 7 pins to note buttons (as kill switches, so both press and release set to a 0 value). Can anyone advise me how to get the CC Knobs as continuous controllers? At the moment I just have them on/off. I feel I've read the internet inside out, but after that and intensively learning to read code, I now need to ask for help.

First bit of code is the notes, second bit the control changes (though it still says 'notenumber').

Code: [Select]

{
 unsigned long currentMillis = millis();
 for (int i=0; i<7; i++) {
   boolean state = !digitalRead(ButtonPins[i]);  // 'true'==pressed, 'false'==released
   // Check for state change and do debounce
   if (state != LastButtonState[i] && currentMillis-LastButtonChangeTime[i] > 50) {
     LastButtonState[i] = state;
     LastButtonChangeTime[i] = currentMillis;
     if (state)
       midi.send(0x90, NoteNumber[i], 0x00);  // Pressed
     else
       midi.send(0x80, NoteNumber[i], 0x00);  // Released
     }
   }
 }
//-----------------------------------------------------------------------------------//
 {
 unsigned long currentMillis = millis();
 for (int i=7; i<15; i++) {
   boolean state = !digitalRead(ButtonPins[i]);  // 'true'==pressed, 'false'==released
   // Check for state change and do debounce
   if (state != LastButtonState[i] && currentMillis-LastButtonChangeTime[i] > 50) {
     LastButtonState[i] = state;
     LastButtonChangeTime[i] = currentMillis;
     if (state)
       midi.send(0xB0, NoteNumber[i], 0x00);  // Pressed
     else
       midi.send(0xB0, NoteNumber[i], 0x127);  // Released
     }

Grumpy_Mike

Quote
Can anyone advise me how to get the CC Knobs as continuous controllers?
The last of the three bytes is the value of the CC, for switches this is either 0 or 127 for off and on. Simply replace this last value with an analogue reading divided by 8 or more efficiently shifted to the right by three places. The >> is the shift right operator.

Your code is mangled by the forum software please read the how to use this forum sticky sticky post to find out how to post code correctly, then go and modify the first post.

Troub99

Thank you - I'd completely run out of brain cells earlier, pleased to now know how to post code correctly.

I think I understand what you are saying, I'm old to midi if new to Arduino, but I'm not sure how to put that in code, at the moment I have values for 'press' and 'release' where I've modified the code from the note on/off part of the sketch.

I've learnt from notesandvolts.com that the analogue range of a 10k potentiometer is 0 - 1023 and that dividing by 8 brings it into valid midi numbers.

Where would I enter the replacement code, do I just need one line (instead of the 2 for press and release)? e.g:

 midi.send(0x90, NoteNumber, 0x>>127);

I'll give it a go, trial and error is slowly getting me there, but any further advice much appreciated.

Grumpy_Mike

Code: [Select]
midi.send(0x90, NoteNumber, 0x>>127);
No
For a CC message:-

Code: [Select]
midi.send(0xB0, controllerNumber, analogRead(pin) >> 3);

but you might want to use something like this
Code: [Select]

potValue = analogRead(pin);
if( abs(lastPotValue - potValue) > 4) midi.send(0xB0, controllerNumber, potValue >> 3);
lastPotValue = potValue;

In order to stop sending CC messages every time you look at / scan the pot. This only sends the CC when you move the pot.

Troub99

Thank you again Grumpy_Mike, I've been in deep again, but my novice status is thwarting me.

However, one of my 8 knobs is sending continuous controller information when turned, so I can see something is going right. Previously I had all the pins defined together as 'button pins' and was then able to split them into 'note' and 'CC' by the order I'd listed them, but I'm clearly not doing things right when trying to define controllerNumber(s) to the analogue pins. Also, despite working with your much appreciated code, I'm not cracking the midi send end of things.

Are you able to have a look at my sketch please? I know I need to do some more thorough learning, but I'm thinking this is maybe not so far away to educated eyes. I've tried many things, but this is the best version I've managed (it uploads, my note buttons work and one knob is sending controller data). I've put comments in where I've been doing damage. Thank you, any help very welcome.

Code: [Select]

/*
Video for this project here:https://youtu.be/QPgYpVHFSQY

Thank you for checking out my video and my code!

For more videos and information check out
https://www.youtube.com/merwinmusic
http://www.lukemerwin.com/

*/

#include <Arduino.h>
#include <SPI.h>

#if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VARIANT_ARDUINO_ZERO_)
  #include <SoftwareSerial.h>
#endif

#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"
#include "Adafruit_BLEMIDI.h"

#include "BluefruitConfig.h"

#define FACTORYRESET_ENABLE         0
#define MINIMUM_FIRMWARE_VERSION    "0.7.0"


Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

Adafruit_BLEMIDI midi(ble);

bool isConnected = false;


// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

// callback
void connected(void)
{
  isConnected = true;

  Serial.println(F(" CONNECTED!"));
  delay(1000);

}

void disconnected(void)
{
  Serial.println("disconnected");
  isConnected = false;
}

void BleMidiRX(uint16_t timestamp, uint8_t status, uint8_t byte1, uint8_t byte2)
{
  Serial.print("[MIDI ");
  Serial.print(timestamp);
  Serial.print(" ] ");

  Serial.print(status, HEX); Serial.print(" ");
  Serial.print(byte1 , HEX); Serial.print(" ");
  Serial.print(byte2 , HEX); Serial.print(" ");

  Serial.println();
}

//this is the original 'midi guitar' code, changed to 7 from 15 buttons and note numbers changed//                             

const int ButtonPins[7] = {2, 3, 5, 10, 11, 12, 13};

int LastButtonState[7] = {0};
int currentMillis = 0;
int LastButtonChangeTime[7] = {currentMillis};

int NoteNumber[7] = {36, 37, 38, 39, 40, 41, 42};


//this is my new attempt at code attempting to define the analogue pins with CC numbers//

const int pin[8] = {6, 9, 18, 19, 20, 21, 22, 23};
//lastPotValue[8] = {0};
int potValue = {0};
int lastPotValue = potValue;
int lastPotChangeTime[8] = {potValue};


int controllerNumber[8] = {1, 2, 8, 7, 6, 5, 4, 3};



void setup(void)


{
 
                                       
 
 

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit MIDI Example"));
  Serial.println(F("---------------------------------------"));

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  if ( FACTORYRESET_ENABLE )
  {
    /* Perform a factory reset to make sure everything is in a known state */
    Serial.println(F("Performing a factory reset: "));
    if ( ! ble.factoryReset() ) {
      error(F("Couldn't factory reset"));
    }
  }

  //ble.sendCommandCheckOK(F("AT+uartflow=off"));
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();

  /* Set BLE callbacks */
  ble.setConnectCallback(connected);
  ble.setDisconnectCallback(disconnected);

  // Set MIDI RX callback
  midi.setRxCallback(BleMidiRX);

  Serial.println(F("Enable MIDI: "));
  if ( ! midi.begin(true) )
  {
    error(F("Could not enable MIDI"));
  }

  ble.verbose(false);
  Serial.print(F("Waiting for a connection..."));

for(int i=0; i < 15; i++)
  pinMode(ButtonPins[i],INPUT_PULLUP);

}

void loop() {
  //-------------------------------------------------------------------------------------//
  // interval for each scanning ~ 500ms (non blocking)
  ble.update(250);

  // bail if not connected
  if (! isConnected)
    return;



//-----------------------------------------------------------------------------------//
   
 
//--------original midi guitar code, i<7 inserted instead of i<15---------------//
   {
  unsigned long currentMillis = millis();
  for (int i=0; i<7; i++) {
    boolean state = !digitalRead(ButtonPins[i]);  // 'true'==pressed, 'false'==released
    // Check for state change and do debounce
    if (state != LastButtonState[i] && currentMillis-LastButtonChangeTime[i] > 50) {
      LastButtonState[i] = state;
      LastButtonChangeTime[i] = currentMillis;
      if (state)
        midi.send(0x90, NoteNumber[i], 0x00);  // Pressed
      else
        midi.send(0x80, NoteNumber[i], 0x00);  // Released
      }
    }
  }
//-----new attempt at code, continuos CC12 being sent, Knob to pin 23 (A5) sending CC12 from 0-127 (so some hope)-------//

unsigned long potValue = analogRead(pin);
for (int i=8; i<15; i++) {
if( abs(lastPotValue - potValue) > 4) midi.send(0xB0, controllerNumber, potValue >> 3);
else
midi.send(0xB0, controllerNumber, potValue >> 127);
lastPotValue = potValue;


}

}           

Grumpy_Mike

Quote
However, one of my 8 knobs is sending continuous controller information when turned,
There is a very good reason for that, you are only reading one pot in that code.

Code: [Select]
unsigned long potValue = analogRead(pin);
for (int i=8; i<15; i++) {
if( abs(lastPotValue - potValue) > 4) midi.send(0xB0, controllerNumber, potValue >> 3);
else
midi.send(0xB0, controllerNumber, potValue >> 127);
lastPotValue = potValue;
}


You read potValue once and never read it again. Why are you running the for loop from 7 to 15? You don't seem to use it at all. You need to run it from 0 to <8 and then you can use i as an index to the arrays which you don't seem to be using at all. WTF is  potValue >> 127 all about? You can't shift anything 127 places to the left. An int variable only has 16 bits so if you shift it to the left 16 times you get zero.

You have :-
Code: [Select]
const int pin[8] = {6, 9, 18, 19, 20, 21, 22, 23};
//lastPotValue[8] = {0};
int potValue = {0};
int lastPotValue = potValue;
int lastPotChangeTime[8] = {potValue};

which is not right. Each pot needs its own lastPot value, for starters you can make this 1040, a value you will never receive. Thus ensuring the first time you run the code all the pot values will be sent. The variable potValue does not need to be an array but a simple int. Why are you recording the pot change time? If you do want to do that it has to be an unsigned long.

So make the changes to the above.
Then try this:-
Code: [Select]

for (int i=0; i<8; i++) { // for 8 pots
    potValue = analogRead(pin[i]); // read the analogue input given by the pin ARRAY
    if( abs(lastPotValue[i] - potValue) > 4) midi.send(0xB0, controllerNumber[i], potValue >> 3);
    lastPotValue[i] = potValue;
}






Troub99

Brilliant, brilliant, thank you so much. Is it too soon to say I love you ? :)

I must confess I wasn't really sure what an array was earlier, but in the time between my posts I'd been learning all about them. Your instructions above were perfect, just enough guidance to make me actually work out what was going on, understand it and put it into action.

I now have 7 buttons sending notes and 7 knobs sending CC's (1 knob not working, but I'll get to the bottom of that later). If anyone's interested, I'm making the controller to use with Turnado by Sugarbytes (desktop FX plugin / iOS), though obviously it can have many uses. My family have gone away and I had a few days to make some music... instead I've spent the whole time, night and day on this project. I had a building disgust with myself for disappearing down a rabbit hole and frittering precious time away. Now though I am grinning from ear to ear, I have a working prototype bluetooth midi controller and have learnt a huge amount to carry forward with me.

Grumpy_Mike, thank you so much for your help and for persevering with my crys for help.

Go Up