MIDI mapping Slider/Knob Values

So trying to map the data coming in the mindflex EEG sensor to sliders/knobs. So far all I understand how to map is using the noteON/noteOFF commands.
How do i map the data so that effects the the whole range of a slider/knob rather than just turning it on and off? Thanks!

Use Control Change events.
Map the raw data from the sensor to [0, 127], and send it as 0b 1011 nnnn  0ccc cccc  0vvv vvvv, where nnnn is the MIDI channel, ccccccc the controller number and vvvvvvv the mapped sensor value.

Pieter

Can you write some example code for me? I’m pretty noobish. I’m trying to do something like having the MIDI slider go to 0 if attValue < 50 and go to 127 if attValue > 50.

void loop() {
 // Expect packets about once per second.
 if (brain.update()) {
 Serial.println(brain.readCSV());
 
 // Attention runs from 0 to 100.
 attValue = brain.readAttention();
 }
 
 // Make sure we have a signal.
 if(brain.readSignalQuality() == 0) {
 
 // Light up the green LED
 if (attValue < 50) {

// MIDI slider goes to 0

}else{


// MIDI slider goes to 127
 
 
 }

Thanks I appreciate the help

What Arduino are you using?
If it's an UNO or a MEGA, just write out the three bytes of the MIDI event over the Serial port using Serial.write(byte).

Pieter

What Arduino are you using?

I’m using an UNO. I have no idea what I am doing…lol but I am trying!!! Here is some of my code. I’m getting errors on MIDI Hairless. Please What am I doing Wrong? I am not able to assign the data to midi.

#include <Brain.h>
Brain brain(Serial);
const int greenPin = 4;
const int yellowPin = 7;
const int redPin = 8;
long interval = 500;
long previousMillis = 0;
int ledState = LOW;
int attValue;
void setup() {
  // Set up the LED pin.
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);

  // Start the hardware serial.
  Serial.begin(9600);
}
void loop() {
  // Expect packets about once per second.
  if (brain.update()) {
    Serial.println(brain.readCSV());

    // Attention runs from 0 to 100.
    attValue = brain.readMeditation()/8;
  }

  // Make sure we have a signal.
  if (brain.readSignalQuality() == 0) {

    MIDImessage(176,1,attValue);
    delay(200);

    // Light up the green LED
    if (attValue < 50) {
      digitalWrite( greenPin, LOW);
      digitalWrite( yellowPin, LOW);
      digitalWrite( redPin, HIGH);
    }
    //Light up the red LED
    else if (attValue > 70)
    {
      digitalWrite( redPin, LOW);
      digitalWrite( greenPin, HIGH);
      digitalWrite( yellowPin, LOW);
    }
    //Light up the Yellow LED
    else if (attValue < 70 and attValue > 50)
    {
      digitalWrite( yellowPin, HIGH);
      digitalWrite( greenPin, LOW);
      digitalWrite( redPin, LOW);

    }
  }
}

void MIDImessage(byte command, byte data1, byte data2) //pass values out through standard Midi Command
{
   Serial.write(command);
   Serial.write(data1);
   Serial.write(data2);
}

I'm getting errors on MIDI Hairless.

Serial.begin(9600)

Use the same baud rate as Hairless is set to.

MIDI is concerned with discrete note on, note off events. Is that what you want to do?

Or do you want a continuous note who's pitch depends on the output from the sensor?

Hey THanks for the reply.

Use the same baud rate as Hairless is set to.

I've since changed them so they are both 9600 and it seems to still be giving me the same error.

MIDI is concerned with discrete note on, note off events. Is that what you want to do?

Or do you want a continuous note who's pitch depends on the output from the sensor?

I Think I want the latter? I'll explain what I'm trying to do you'll probably know better. I am getting data from an EEG Mindflex device and I want it to change the value of a slider based on that data. I'm super novice and have only been doing arduino/code for a short period of time.

A speed of 9600 is way too slow, change both to the fastest that Hairless will do.

This line:-

    MIDImessage(176,1,attValue);

Is sending a Control Program change MIDI message, That will change the voice or sound of the note. It is only a two byte message and you are sending three bytes hence the error message.

The note on message is 0x90.
Now you want to send a note, a value of 1 is inaudible. You want this to be something in the range of 40 to 70.
You seem to be using the signal to change the velocity of the note, I am sure that is not you want to do.

At a guess you want to have that line as:-

    MIDImessage(0x90,attValue,100);

However you also need a note off message otherwise the note will hang, that is sound continuously.
So just to get you going, replace that line with:-

    MIDImessage(0x90,attValue,100);
   delay(100);
  MIDImessage(0c80,attValue,0);

Grumpy_Mike:
This line:-

    MIDImessage(176,1,attValue);

Is sending a Control change MIDI message, That will change the voice or sound of the note. It is only a two byte message and you are sending three bytes hence the error message.

I think you're confusing Control Change with Program change.
To change the value of a slider, you definitely use Control Change (or Pitch Bend, but that's irrelevant here), and it is indeed a 3-byte message (unlike Program Change, which is only two bytes).

So as long as attValue is between 0 and 0x7F, the above is a valid MIDI message.

blabberbytes:

Brain brain(Serial);

...
    Serial.println(brain.readCSV());
...
    attValue = brain.readMeditation()/8;
...
  if (brain.readSignalQuality() == 0) {

My guess is that Brain (whatever that is) is doing all kinds of things on the Serial port. (The same Serial port you are trying to use for MIDI.) So it's no wonder that Hairless keeps on throwing errors.

Pieter

I think you're confusing Control Change with Program change.

Yes quite correct, although the rest of it is right.

(or Pitch Bend, but that's irrelevant here)

I have a feeling that before the thread is over, we will need to use pitch bend in the solution.

My guess is that Brain (whatever that is)

I think the OP has one of those brain sensors, that pretends to measure brain activity.

Yes drop that line:-

 Serial.println(brain.readCSV());

Okay so tried a few things. First I tried change the baud rate to 115200 on mid hairless and in the code. I noticed after I did that I wasn't receiving packets anymore. The LEDs I have hooked stopped reacting to the data.

So I changed it back to 9600. I then removed the

Serial.println(brain.readCSV());

Which didnt give me and midi data.

I then tried to remove the

 if (brain.readSignalQuality() == 0)

And that allowed me to midi map a slider. But it just kept going from 0-100 in one second intervals and my LEDs were not working.

Maybe this is helpful? GitHub - kitschpatrol/Brain: Arduino library for reading Neurosky EEG brainwave data. (Tested with the MindFlex and Force Trainer toys.)
Suggestions?

You do not seem to have done what I said in reply #7

You need to do all the suggestions at one time. Then if it is not working you post your code again and say what it is doing.

blabberbytes:
How do i map the data so that effects the the whole range of a slider/knob rather than just turning it on and off?

blabberbytes:
I’m trying to do something like having the MIDI slider go to 0 if attValue < 50 and go to 127 if attValue > 50.

You seem to contradict yourself.

If you want to be able to control the slider over its entire range, you have to send a value between 0 and 127. (0 being the lowest slider position, 127 the highest, 63 somewhere in the middle, etc.)

http://developer.neurosky.com/docs/doku.php?id=esenses_tm:
MEDITATION eSense
This unsigned one-byte value reports the current eSense Meditation meter of the user, which indicates the level of a user’s mental “calmness” or “relaxation”. Its value ranges from 0 to 100.

So to control the slider, you have to map the meditation value [0, 100] to a MIDI value [0, 127]:

uint8_t midiVal = meditation * 127 / 100;

Then send it over MIDI:
MIDImessage(0xB0 | (channel - 1), controllerNumber, midiVal); Where 0xB0 (176 dec) is the status byte for control change messages, channel is the MIDI channel, controllerNumber is the MIDI controller number that you can map in your audio software.
I really recommend reading some MIDI documentation first. (https://www.midi.org/)

If you want to do what you said in the second quote:

uint8_t midiVal = meditation >= 50 ? 127 : 0;

( ? : is the ternary operator)

You can’t use the hardware UART for the brain sensor and for MIDI at the same time.
Either use SoftwareSerial for the brain, or get an Arduino that has more than one hardware UART, or one hardware UART and USB.
If you get a board like the Leonardo, you can use USB MIDI (much easier than Hairless), and the hardware UART can be used by the brain sensor.

Pieter

ou do not seem to have done what I said in reply #7

You need to do all the suggestions at one time. Then if it is not working you post your code again and say what it is doing.

Okay good point. There does seem to be an issue with changing the Baud rate from 9600 to 115200. I also tried 19200 and mid hairless al together stops reading the midi, (no green blinks) also i have a processing sketch that visualizes the brain waves and it will not receive the packets when i change the rate. on arduino and processing.

When I make the changes you mentioned in #7, i am now able to midi map, but it just keeps rapidly turning on and off and eventually stops.

#include <MIDI.h>

#include <Brain.h>
Brain brain(Serial);
const int greenPin = 4;
const int yellowPin = 7;
const int redPin = 8;
long interval = 500;
long previousMillis = 0;
int ledState = LOW;
int attValue;

void setup() {
  // Set up the LED pin.
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);

  // Start the hardware serial.
  Serial.begin(115200);
}

void loop() {
  // Expect packets about once per second.
  if (brain.update()) {
    //Serial.println(brain.readCSV());

    // Attention runs from 0 to 100.
    attValue = brain.readMeditation() / 8;

  }

  // Make sure we have a signal.
  if (brain.readSignalQuality() == 0) {
    
      MIDImessage(0x90, attValue, 100);
      delay(100);
      MIDImessage(0x80, attValue, 0);

    // Light up the green LED
    if (attValue < 50) {


      digitalWrite( greenPin, LOW);
      digitalWrite( yellowPin, LOW);
      digitalWrite( redPin, HIGH);
    }
    //Light up the red LED
    else if (attValue > 70)
    {

      digitalWrite( redPin, LOW);
      digitalWrite( greenPin, HIGH);
      digitalWrite( yellowPin, LOW);
    }
    //Light up the Yellow LED
    else if (attValue < 70 and attValue > 50)
    {

      digitalWrite( yellowPin, HIGH);
      digitalWrite( greenPin, LOW);
      digitalWrite( redPin, LOW);

    }
  }
}

void MIDImessage(byte command, byte data1, byte data2) //pass values out through standard Midi Command
{
  Serial.write(command);
  Serial.write(data1);
  Serial.write(data2);
}

blabberbytes:
Okay good point. There does seem to be an issue with changing the Baud rate from 9600 to 115200. I also tried 19200 and mid hairless al together stops reading the midi, (no green blinks) also i have a processing sketch that visualizes the brain waves and it will not receive the packets when i change the rate. on arduino and processing.

With an UNO, you can NOT send MIDI and other data to the computer at the same time, especially if you have something connected to pins 0 and 1.

What brain libiary are you using. I have had a look and found two on the first three returns from google.

I am concerned about the line:-

Brain brain(Serial)

It implies that your brain sensor is communicating with the Arduino through the serial port. How is your sensor connected? If it is to pins 0 & 1 then you can not send MIDI data over the USB and send it to hairless as well as talking to the brain sensor. It is also likely that the brain software is changing the hardware baud rate.

Grumpy_Mike:
What brain libiary are you using. I have had a look and found two on the first three returns from google.

blabberbytes:
Maybe this is helpful? GitHub - kitschpatrol/Brain: Arduino library for reading Neurosky EEG brainwave data. (Tested with the MindFlex and Force Trainer toys.)

The library does indeed use the Serial port. That's why I recommended using SoftwareSerial.

PieterP:
You can't use the hardware UART for the brain sensor and for MIDI at the same time.
Either use SoftwareSerial for the brain, or get an Arduino that has more than one hardware UART, or one hardware UART and USB.
If you get a board like the Leonardo, you can use USB MIDI (much easier than Hairless), and the hardware UART can be used by the brain sensor.

Please explain what it is you are actually trying to do. You talk about controlling sliders and knobs, then you say you want to turn on / off a slider, and now you're posting code for changing the pitch of a note. It doesn't make any sense to me.

Pieter

With an UNO, you can NOT send MIDI and other data to the computer at the same time, especially if you have something connected to pins 0 and 1.

I've taken your advice and ordered an Arduino Leonardo

Please explain what it is you are actually trying to do. You talk about controlling sliders and knobs, then you say you want to turn on / off a slider, and now you're posting code for changing the pitch of a note. It doesn't make any sense to me.

Pieter

Sorry for all the confusion. What I am trying to accomplish is taking the data from brain.readMeditation(); and midi map it to a slider.

// Code for Arduino Leonardo

#include "MIDIUSB.h"
#include <Brain.h>

HardwareSerial& BrainSerial = Serial1;

Brain brain(BrainSerial); // Brain "sensor" is connected to hardware UART

const uint8_t CC = 0xB0; // Control Change header
const uint8_t channel = 1; // MIDI channel 1
const uint8_t controller = 1; // CC controller number 1

void setup() {
  BrainSerial.begin(9600); // Start serial brain connection
  Serial.begin(115200); // Start "Serial" communication with the computer
}

void loop() {
  static uint8_t previousMidiValue = 0;
  if (brain.update()) { // if there's a new "brain" value
    Serial.println(brain.readCSV()); // print brain data to Serial Monitor ?
    uint8_t meditationValue = brain.readMeditation(); // get the meditation value [0, 100]
    uint8_t midiValue = meditationValue * 127 / 100; // map to 7-bit MIDI value [0, 127]
    if (midiValue != previousMidiValue) { // if it's a different value than last time
      sendMIDI(CC, channel, controller, midiValue); // send it as a Control Change value over MIDI
      previousMidiValue = midiValue;
    }
  }
}

void sendMIDI(uint8_t m, uint8_t c, uint8_t d1, uint8_t d2) {
  c--; // Channels are zero-based
  m &= 0xF0;       // bitmask high nibble
  m |= 0b10000000; // set msb
  c &= 0xF;        // bitmask low nibble
  d1 &= 0x7F;      // clear msb
  d2 &= 0x7F;      // clear msb
  midiEventPacket_t msg = {m >> 4, m | c, d1, d2}; // Create 4-byte MIDI USB packet
  MidiUSB.sendMIDI(msg); // Send it
  MidiUSB.flush(); // Wait untill it's sent
}

hello, gives an error, what is it?

ERROR :

In function 'void sendMIDI(uint8_t, uint8_t, uint8_t, uint8_t)':
warning: narrowing conversion of '(((int)m) >> 4)' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]
midiEventPacket_t msg = {m >> 4, m | c, d1, d2}; // Create 4-byte MIDI USB packet

^ warning: narrowing conversion of '(int)(m | c)' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]
midiEventPacket_t msg = {m >> 4, m | c, d1, d2}; // Create 4-byte MIDI USB packet