Sending midi notes istead of producing tones

Hello to all!
I'm trying to modify a piece of code that produces tones using the pitches.h library. I wish to send midi notes instead of creating tones.
Here is what I have modified so far...

//#include "pitches.h"
#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

// Two things need to be created: the array for the notes of the melody (in order)
// and the duration of each (think of it like sheet music in two parts)

// BOTH ARRAYS MUST BE THE SAME SIZE!

// The melody array 
int melody[] = {
  78, 78, 74, 71, 71, 76, 
  76, 76, 80, 80, 81, 83, 
  81, 81, 81, 76, 74, 78, 
  78, 78, 76, 76, 78, 76
};

// The note duration, 8 = 8th note, 4 = quarter note, etc.
int durations[] = {
  8, 8, 8, 4, 4, 4, 
  4, 5, 8, 8, 8, 8, 
  8, 8, 8, 4, 4, 4, 
  4, 5, 8, 8, 8, 8
};
// determine the length of the arrays to use in the loop iteration
int songLength = sizeof(melody)/sizeof(melody[0]);
void setup() {
 // Set MIDI baud rate:
  Serial.begin(31250);
}

void loop() {
  // Iterate through both arrays
  // Notice how the iteration variable thisNote is created in the parenthesis
  // The for loop stops when it is equal to the size of the melody array
  for (int thisNote = 0; thisNote < songLength; thisNote++){
    // determine the duration of the notes that the computer understands
    // divide 1000 by the value, so the first note lasts for 1000/8 milliseconds
    int duration = 1000/ durations[thisNote];
    tone(8, melody[thisNote], duration);
    // pause between notes
    int pause = duration * 1.3;
    delay(pause);
    // stop the tone
    noTone(8);
  }
}

I'm guessing my issue is around this segment

tone(8, melody[thisNote], duration);

Where "tone" needs to replaced with sending midi?
Any help at all will be appreciated :slightly_smiling_face:

Yes, with any luck that's where you can do the thing you want.

In the meantime try google

midi send note arduino

That should turn up lotsa small and otherwise example programs.

You probably need to initiate the hardware with some kind of call in setup().

Are you using midi over USB or what?

a7

Thanks alto777. I'm sending midi over serial.

OK, so I'm at beyond my level of knowledge and experience, but google turns up lotsa good stuff, viz:

https://itp.nyu.edu/physcomp/labs/labs-serial-communication/lab-midi-output-using-an-arduino/

Poke around a bit, try to get an example program working without you having to change it, then see how things from it might fit into your current sketch.

Idea: leave the tone code in and whatever it tones on attached! It might help finding errors, there will probably be some as you go. Errors.

Stuck? Post both you sketch and the example you are trying to steal borrow from, we take a look.

a7

Poking and stealing to my hearts content! Almost have it working except it's not playing the entire melody for some reason. I'll post what I have now in case someone notices a glaring flaw!

//#include "pitches.h"
#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

 

// Two things need to be created: the array for the notes of the melody (in order)
// and the duration of each (think of it like sheet music in two parts)

// BOTH ARRAYS MUST BE THE SAME SIZE!

// The melody array 
int melody[] = {
  78, 78, 74, 71, 71, 76, 
  76, 76, 80, 80, 81, 83, 
  81, 81, 81, 76, 74, 78, 
  78, 78, 76, 76, 78, 76
};

// The note duration, 8 = 8th note, 4 = quarter note, etc.
int durations[] = {
  8, 8, 8, 4, 4, 4, 
  4, 7, 8, 8, 8, 8, 
  8, 8, 8, 4, 4, 4, 
  4, 7, 8, 8, 8, 8
};
// determine the length of the arrays to use in the loop iteration
int songLength = sizeof(melody)/sizeof(melody[0]);
void setup() {
 // Set MIDI baud rate:
  Serial.begin(31250);
}

void loop() {
  // Iterate through both arrays
  // Notice how the iteration variable thisNote is created in the parenthesis
  // The for loop stops when it is equal to the size of the melody array
  for (int thisNote = 0; thisNote < songLength; thisNote++){
    // determine the duration of the notes that the computer understands
    // divide 1000 by the value, so the first note lasts for 1000/8 milliseconds
    int duration = 1000/ durations[thisNote];
    tone(8, melody[thisNote], duration);
    noteOn(0x90, melody[thisNote], duration);
    // pause between notes
    int pause = duration * 1.8;
    delay(pause);
    // stop the tone
    noTone(8);
    noteOn(0x90, melody[thisNote], 0x00);
  }
}
//  plays a MIDI note.  Doesn't check to see that
  //  cmd is greater than 127, or that data values are  less than 127:
  void noteOn(byte cmd, byte data1, byte data2) {
    Serial.write(cmd);
    Serial.write(data1);
    Serial.write(data2);
  }

So I've noticed that the notes that are missing from the melody are the ones that correspond with

Anything that doesn't correspond with an "8" doesn't play!

Instead of using the durations array, just for now make duration some constant and see if you get all the notes except badly timed. Or make all the values that Magic 8.

Iā€™m not at the big rig, but it looks like a math integer error maybe.

Perhaps printing the delay() amount would shed light.

L8R I can run this code. Something dumb or simple I hope.

a7

Will do! :wink:

Changed a few fours to eights in "int durations" and the extra notes played. I'll keep tinkering!

So far, I'm thinking the problem is around this area...

noteOn(0x90, melody[thisNote], 0x00);

Ok! I found the issue. "duration" was throwing the whole thing after all!
I changed to...

noteOn(0x90, melody[thisNote], 0x45);

from...

noteOn(0x90, melody[thisNote], duration);

and now its working fine.
Thanks alto777 for your help!

1 Like

Yay! I was just sitting down to help, so now I'll go to the beach instead. :expressionless:

Good work.

a7

The beach?
Lucky you!!!

Here's the full code for anyone who may need it!
Anything referring to "tone" can be commented out but it isn't necessary.

//A-ha!
//by GeneralSpud

// For this to work, we need the pitches library

//#include "pitches.h"
#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

 

// Two things need to be created: the array for the notes of the melody (in order)
// and the duration of each (think of it like sheet music in two parts)

// BOTH ARRAYS MUST BE THE SAME SIZE!

// The melody array 
int melody[] = {
  78, 78, 74, 71, 71, 76, 
  76, 76, 80, 80, 81, 83, 
  81, 81, 81, 76, 74, 78, 
  78, 78, 76, 76, 78, 76
};

// The note duration, 8 = 8th note, 4 = quarter note, etc.
int durations[] = {
  8, 8, 8, 4, 4, 4, 
  4, 7, 8, 8, 8, 8, 
  8, 8, 8, 4, 4, 4, 
  4, 7, 8, 8, 8, 8
};
// determine the length of the arrays to use in the loop iteration
int songLength = sizeof(melody)/sizeof(melody[0]);
void setup() {
 // Set MIDI baud rate:
  Serial.begin(31250);
}

void loop() {
  // Iterate through both arrays
  // Notice how the iteration variable thisNote is created in the parenthesis
  // The for loop stops when it is equal to the size of the melody array
  for (int thisNote = 0; thisNote < songLength; thisNote++){
    // determine the duration of the notes that the computer understands
    // divide 1000 by the value, so the first note lasts for 1000/8 milliseconds
    int duration = 1000/ durations[thisNote];
    tone(8, melody[thisNote], duration);
    noteOn(0x90, melody[thisNote], 0x45);
    // pause between notes
    int pause = duration * 1.8;
    delay(pause);
    // stop the tone
    noTone(8);
    noteOn(0x90, melody[thisNote], 0x00);
  }
}
//  plays a MIDI note.  Doesn't check to see that
  //  cmd is greater than 127, or that data values are  less than 127:
  void noteOn(byte cmd, byte data1, byte data2) {
    Serial.write(cmd);
    Serial.write(data1);
    Serial.write(data2);
  }

What midi library are you using? I see you are directly using serial, so whatever the library adds or doesn't is not important, just curious here.

Midi "Note-on" is command 0x90 and the next two parameters are the key and the velocity.

As you have learned or discovered, a velocity of 0 seems to be turning off the note. There is a midi "Note-off" command, too.

The duration is handled by how long you wait between the two calls to noteOn.

FWIW noteOn is misnamed - since you are passing the command 0x90 that means "note on" noteOn would be more like sendMidiCommand, viz:

//  sends a MIDI command and two parameters.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:

  void sendMidiCommand(byte cmd, byte data1, byte data2) {
    Serial.write(cmd);
    Serial.write(data1);
    Serial.write(data2);
  }

Or if you like *noteOn*, the 0x90 part can be build in:
//  sends a MIDI command and two parameters.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:

  void noteOn(byte theKey, byte theVelocity) {
    Serial.write(0x90);  // midi note on command
    Serial.write(data1);
    Serial.write(data2);
  }

I like to run these things to ground.

a7

MIDI.h is the library I'm using but of course I've made a mishmash of everything. That library just makes it easier to code the actual notes such as "60" instead of "0x3C". I need to look at the library closer and try and use it exclusively or not at all I guess. Using "noteOn" made sense to me in order to replace "tone" but of course I have "0x90" straight after it! Mental I know!

My project here is to be able to write a number of melodies that can be selected and triggered with sensors.

I have it now...

MIDI.sendNoteOn(melody[thisNote], 127, 1);

and

    MIDI.sendNoteOff(melody[thisNote], 0, 1);

These replace noteOn completely now and keep with the library!

So I've removed all the "tone" coding as it's pointless now since it isn't using any correct array, and stuck with the MIDI.h library exclusively. Full code...

//A-ha!
//by GeneralSpud

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();



// Two things need to be created: the array for the notes of the melody (in order)
// and the duration of each (think of it like sheet music in two parts)

// BOTH ARRAYS MUST BE THE SAME SIZE!

// The melody array
int melody[] = {
  78, 78, 74, 71, 71, 76,
  76, 76, 80, 80, 81, 83,
  81, 81, 81, 76, 74, 78,
  78, 78, 76, 76, 78, 76
};

// The note duration, 8 = 8th note, 4 = quarter note, etc.
int durations[] = {
  8, 8, 8, 4, 4, 4,
  4, 7, 8, 8, 8, 8,
  8, 8, 8, 4, 4, 4,
  4, 7, 8, 8, 8, 8
};
// determine the length of the arrays to use in the loop iteration
int songLength = sizeof(melody) / sizeof(melody[0]);
void setup() {

  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop() {
  // Iterate through both arrays
  // Notice how the iteration variable thisNote is created in the parenthesis
  // The for loop stops when it is equal to the size of the melody array
  for (int thisNote = 0; thisNote < songLength; thisNote++) {
    // determine the duration of the notes that the computer understands
    // divide 1000 by the value, so the first note lasts for 1000/8 milliseconds
    int duration = 1000 / durations[thisNote];
    MIDI.sendNoteOn(melody[thisNote], 127, 1);
    // pause between notes
    int pause = duration * 1.8;
    delay(pause);
    // stop the note
    MIDI.sendNoteOff(melody[thisNote], 0, 1);
  }
}