Arduino noob; I used to code BASIC and assembly-trying to use midi library

Hello/please help -

I've gotten my data structures and logic together, but I'm new at C.
Been reading a lot of arduino/C documentation/manuals/books/tutorials. . .
. . . I'm stuck.

I was under the impression that I could "include" libraries,
that would define/declare functions that I could use in my code.

but I'm getting these errors:

mono_notes_chord_key____sketch_jan16a.ino: In function 'void handleControlChange(byte, byte, byte)':
mono_notes_chord_key____sketch_jan16a:75: error: 'sendPitchBend' was not declared in this scope
mono_notes_chord_key____sketch_jan16a.ino: In function 'void handleNoteOn(byte, byte, byte)':
mono_notes_chord_key____sketch_jan16a:84: error: 'sendPitchBend' was not declared in this scope
mono_notes_chord_key____sketch_jan16a:85: error: 'sendNoteOn' was not declared in this scope
mono_notes_chord_key____sketch_jan16a.ino: In function 'void handleNoteOff(byte, byte, byte)':
mono_notes_chord_key____sketch_jan16a:89: error: 'sendNoteOff' was not declared in this scope

So, I must be missing something

I only need to read all 16 channels of noteons, and 2 controlchanges on 1 channel.
I feel like the midi input callbacks are setup correctly (at least they aren't giving me errors).
But the midi output functions (I only need to send noteons, noteoffs, and pitchbends)
I've done wrong somehow.

Here's the code thus far:

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

byte IncomingSongRoot = 0;
byte SongRootShift = 0;
byte IncomingChordRoot = 0;
byte IncomingNoteType [16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte ScaleDegree [12] = {0,0,1,1,1,0,1,0,0,1,1,2};
byte SemitoneOffset [12] = {0,0,2,2,4,5,4,7,7,9,9,11};
double PitchGrid [3][12] = {
{0,-1,-2,1,0,2,1,0,-1,-2,2,1},
{0,-1,-2,0,-1,2,1,0,-1,-2,2,1},
{0,-1,-2,0,2,1,0,-1,-2,-1,2,1},
};
byte ChordRootShift = 0;
byte ChordType = 0;
byte ChordRoot = 0;

MIDI_CREATE_DEFAULT_INSTANCE();


void handleControlChange(byte channel, byte number, byte value) {
    if (channel == 16) { 
      if (number == 14) {
        IncomingSongRoot = value % 12;
        SongRootShift = (12 - IncomingSongRoot) % 12;
      }
      if (number == 15) {
        IncomingChordRoot = value % 12;
      }
      if ((number == 14) || (number == 15)) {
        byte ChordLookup = (IncomingChordRoot + SongRootShift) % 12;
        ChordType = ScaleDegree [ChordLookup];
        ChordRoot = (SemitoneOffset [ChordLookup] + IncomingSongRoot) % 12;
        ChordRootShift = (12 - ChordRoot) % 12;
        for (byte ChnCount = 0; ChnCount<16; ++ChnCount) {
          byte NoteShift = (ChordRootShift + IncomingNoteType [ChnCount]) % 12;
          double BendAmount = PitchGrid [ChordType][NoteShift];
          sendPitchBend(BendAmount, ChnCount);
        }
      }
    }
}
void handleNoteOn(byte channel, byte pitch, byte velocity) {
    byte NoteIn = pitch % 12;
    byte NoteShift = (ChordRootShift + NoteIn) % 12;
    double BendAmount = PitchGrid [ChordType][NoteShift];
    sendPitchBend(BendAmount, channel);
    sendNoteOn(pitch, velocity, channel);
    IncomingNoteType [channel] = NoteIn;
  }
void handleNoteOff(byte channel, byte pitch, byte velocity) {
    sendNoteOff(pitch, velocity, channel);
  }
// -----------------------------------------------------------------------------
void setup()
{
    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
    MIDI.setHandleControlChange(handleControlChange);
    MIDI.begin(MIDI_CHANNEL_OMNI);
    MIDI.turnThruOff();
    // ----------------------------find out how to turn off running status
}

void loop()
{
    MIDI.read();
}

apologies if this should be in the "programming questions" sub-forum

You really should have read the How to use this forum - please read post at the top of the index page and How to use this forum before posting.

ie Your code and any error messages should always be placed between code tags. Posting it inline as you have done makes it much harder to read or copy and paste for diagnosis.

It's still not too late to edit your post and do this. You'll make potential helpers much happier. :slight_smile:

OldSteve:
code and any error messages should always be placed between code tags.

got it, thanks. sleep escapes me lately

Thanks for that.

And in return, here's your repaired code:-

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

byte IncomingSongRoot = 0;
byte SongRootShift = 0;
byte IncomingChordRoot = 0;
byte IncomingNoteType [16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte ScaleDegree [12] = {0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 2};
byte SemitoneOffset [12] = {0, 0, 2, 2, 4, 5, 4, 7, 7, 9, 9, 11};
double PitchGrid [3][12] =
{
    {0, -1, -2, 1, 0, 2, 1, 0, -1, -2, 2, 1},
    {0, -1, -2, 0, -1, 2, 1, 0, -1, -2, 2, 1},
    {0, -1, -2, 0, 2, 1, 0, -1, -2, -1, 2, 1},
};
byte ChordRootShift = 0;
byte ChordType = 0;
byte ChordRoot = 0;

MIDI_CREATE_DEFAULT_INSTANCE();


void handleControlChange(byte channel, byte number, byte value)
{
    if (channel == 16)
    {
        if (number == 14)
        {
            IncomingSongRoot = value % 12;
            SongRootShift = (12 - IncomingSongRoot) % 12;
        }
        if (number == 15)
        {
            IncomingChordRoot = value % 12;
        }
        if ((number == 14) || (number == 15))
        {
            byte ChordLookup = (IncomingChordRoot + SongRootShift) % 12;
            ChordType = ScaleDegree [ChordLookup];
            ChordRoot = (SemitoneOffset [ChordLookup] + IncomingSongRoot) % 12;
            ChordRootShift = (12 - ChordRoot) % 12;
            for (byte ChnCount = 0; ChnCount < 16; ++ChnCount)
            {
                byte NoteShift = (ChordRootShift + IncomingNoteType [ChnCount]) % 12;
                double BendAmount = PitchGrid [ChordType][NoteShift];
                MIDI.sendPitchBend(BendAmount, ChnCount);
            }
        }
    }
}
void handleNoteOn(byte channel, byte pitch, byte velocity)
{
    byte NoteIn = pitch % 12;
    byte NoteShift = (ChordRootShift + NoteIn) % 12;
    double BendAmount = PitchGrid [ChordType][NoteShift];
    MIDI.sendPitchBend(BendAmount, channel);
    MIDI.sendNoteOn(pitch, velocity, channel);
    IncomingNoteType [channel] = NoteIn;
}
void handleNoteOff(byte channel, byte pitch, byte velocity)
{
    MIDI.sendNoteOff(pitch, velocity, channel);
}
// -----------------------------------------------------------------------------
void setup()
{
    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
    MIDI.setHandleControlChange(handleControlChange);
    MIDI.begin(MIDI_CHANNEL_OMNI);
    MIDI.turnThruOff();
    // ----------------------------find out how to turn off running status
}

void loop()
{
    MIDI.read();
}

On the offending lines, you forgot "MIDI."
ie:
MIDI.sendNoteOn();

Edit: I've no idea if the code actually works, but I fixed the obvious errors and it now compiles fine.

Thanks!
I actually had it like that before I cleaned up some typos, but was unsure.

Now I'm getting:

C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp: In member function 'void midi::MidiInterface<SerialPort, Settings>::sendPitchBend(double, midi::Channel) [with SerialPort = HardwareSerial, Settings = midi::DefaultSettings]':
mono_notes_chord_key____sketch_jan16a.ino:82:   instantiated from here
C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp:282: error: 'Toto' is not a member of 'midi::DefaultSettings'

I'm not sure what "instantiated from here" means
and the others look like errors with the library

RoyFnBerry:
Thanks!
I actually had it like that before I cleaned up some typos, but was unsure.

Now I'm getting:

C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp: In member function 'void midi::MidiInterface<SerialPort, Settings>::sendPitchBend(double, midi::Channel) [with SerialPort = HardwareSerial, Settings = midi::DefaultSettings]':

mono_notes_chord_key____sketch_jan16a.ino:82:   instantiated from here
C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp:282: error: 'Toto' is not a member of 'midi::DefaultSettings'




I'm not sure what "instantiated from here" means
and the others look like errors with the library

You're getting those errors with the modified version of the code that I just posted?

It compiles fine for me, with no errors whatsoever.
Arduino V1.6.5, UNO board selected:-

Sketch uses 5,588 bytes (17%) of program storage space. Maximum is 32,256 bytes.
Global variables use 555 bytes (27%) of dynamic memory, leaving 1,493 bytes for local variables. Maximum is 2,048 bytes.

"instantiated from here" means that's where the instance was created.

I notice that your sketch with the 'latest' errors is dated two days ago. Try pasting the modified code that I posted into a new sketch. Something isn't right here.

The errors you posted indicate that the error originates in line 282 of "MIDI.hpp".
When I look at line 282 of "MIDI.hpp", what I see is this:-

  const int value = inPitchValue * MIDI_PITCHBEND_MAX;

Not a "Toto" to be seen anywhere. (Or in any nearby lines.)
In fact, I just searched the whole "MIDI.hpp" file, and there is no "Toto" in it anywhere.
(Reminds me of the dog in 'Wizard of Oz'.)

Please stop changing your opening post. It just adds to the confusion. If there's something new, add it in a reply.

Edit: Actually, I think I misread the error, I think. It's actually in line 82 of your sketch, which should be 81 lines long. (Mine is.)
Something there that shouldn't be?

Sorry for the OCD editing; just trying to be clear.

Strange. . . It was copy/paste of your revision
(date of sketch was part of the default filename that I left as part of my filename).
I pasted it over the same code.
There are several lines of my //remarks that I didn't bother pasting/posting to the forum.

Just tried it in a new sketch, UNO selected; looks like the same errors.

C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp: In member function 'void midi::MidiInterface<SerialPort, Settings>::sendPitchBend(double, midi::Channel) [with SerialPort = HardwareSerial, Settings = midi::DefaultSettings]':
revision_sketch_jan18a.ino:49:   instantiated from here
C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp:282: error: 'Toto' is not a member of 'midi::DefaultSettings'

In the MIDI.hpp, "Toto" is on the end of line 282

278 template<class SerialPort, class Settings>
279 void MidiInterface<SerialPort, Settings>::sendPitchBend(double inPitchValue,
280                                                         Channel inChannel)
281 {
282     const int value = inPitchValue * MIDI_PITCHBEND_MAX * Settings::Toto;
283     sendPitchBend(value, inChannel);
284 }

My IDE version says 1.0.5-r2 (downloaded some months ago).
I guess I'll try updating.

RoyFnBerry:
Sorry for the OCD editing; just trying to be clear.

Strange. . . It was copy/paste of your revision
(date of sketch was part of the default filename that I left as part of my filename).
I pasted it over the same code.
There are several lines of my //remarks that I didn't bother pasting/posting to the forum.

Just tried it in a new sketch, UNO selected; looks like the same errors.

C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp: In member function 'void midi::MidiInterface<SerialPort, Settings>::sendPitchBend(double, midi::Channel) [with SerialPort = HardwareSerial, Settings = midi::DefaultSettings]':

revision_sketch_jan18a.ino:49:   instantiated from here
C:\Users\Roy Berry\Documents\Arduino\libraries\MIDI/MIDI.hpp:282: error: 'Toto' is not a member of 'midi::DefaultSettings'




In the MIDI.hpp, "Toto" is on the end of line 282


278 template<class SerialPort, class Settings>
279 void MidiInterface<SerialPort, Settings>::sendPitchBend(double inPitchValue,
280                                                         Channel inChannel)
281 {
282     const int value = inPitchValue * MIDI_PITCHBEND_MAX * Settings::Toto;
283     sendPitchBend(value, inChannel);
284 }





My IDE version says 1.0.5-r2 (downloaded some months ago).
I guess I'll try updating.

It's probably not your IDE - the version of "MIDI.hpp" is obviously different to the one that I downloaded, since the one that I downloaded has no "Toto" in it at all.

I only downloaded it today to help with your problem, from here:-
FortySevenEffects/arduino_midi_library

Since the above version of the library compiles fine, and doesn't have "Toto" in it, maybe you should uninstall the lib that you have and install the same one that I did?

If you check "MIDI.hpp" under 'src' in the library that I linked, you'll see the same line 282 that I have.
I think you have an old, or dud, copy of the library.

I'll keep a copy of the sketch, and keep the library installed for now, until this is sorted out.
Then I'll uninstall that lib, because I'll never use it again. I don't have a use for MIDI stuff personally.

OldSteve:
It's probably not your IDE - the version of "MIDI.hpp" is obviously different to the one that I downloaded, since the one that I downloaded has no "Toto" in it at all.

I only downloaded it today to help with your problem, from here:-
FortySevenEffects/arduino_midi_library

Since the above version of the library compiles fine, and doesn't have "Toto" in it, maybe you should uninstall the lib that you have and install the same one that I did?

If you check "MIDI.hpp" under 'src' in the library that I linked, you'll see the same line 282 that I have.
I think you have an old, or dud, copy of the library.

I'll keep a copy of the sketch, and keep the library installed for now, until this is sorted out.
Then I'll uninstall that lib, because I'll never use it again. I don't have a use for MIDI stuff personally.

That's where I got the library, and also where I see this:

It looks like this has been an issue, and maybe every download link wasn't updated, and whichever link or mirror link I used, was a dud. There are several links around the midi library GitHub --- "download zip", "Download the latest version here", then at the "latest version" link, bottom of page: "Arduino_MIDI_Library_v4.2.zip", "Source code (zip)", "Source code (tar.gz)".

Yesterday, things seemed buggy and I was bleary-eyed tired.
Today, I cant remember which 2 of the 5 download links I used.
Woo hoo! Process of elimination time!

No process of elimination needed. Just download the exact same copy that I did. On the page I linked, press the "Download ZIP" button at the top, right of the page. I've already tested it and it compiles fine.
Typically, on GitHub, that's where you get the latest version. Ignore all of the other links.

OK -

I ended up doing kind-of a manual install:

  • copied the "src" folder to where the contributed libraries go
    (subfolder of where sketches are saved by default)
  • renamed the folder "MIDI".

"include library", "add .ZIP library" didn't wanna act right.

It seems to have worked:

Sketch uses 5,588 bytes (17%) of program storage space. Maximum is 32,256 bytes.
Global variables use 555 bytes (27%) of dynamic memory, leaving 1,493 bytes for local variables. Maximum is 2,048 bytes.

Thank you so much for the help! I really appreciate it.

Now to make sure all of what I'm trying to do works;

If you're curious what I'm up to with this code,
here are my rambling remarks:

// Might not be able to explain this well, but this is a . . . . 
// Method for tuning midi notes to ----- notes within a chord within a key ----- using pitch bends
// this method assumes incoming notes are monophonically sequenced, and going out to monophic synths 
// also assumes pitch bend range is 2 semitones up and down for all connected synths
// 
// this will effectively "quantize" pitch (to use a modular synth term) or "midi auto tune" or "force to scale"
// 
// ACTUALLY, it doesn't tune to the full scale, it tunes to notes from chords within the scale
// 
// MIDI CC14 ch16 is for song root note - any number; will be modulo12'd (reduced to one octave)
// works kinda like transpose-after-tuning on a quantizer, but really, it's more like: transpose the scale, but don't move the notes
// 
// MIDI CC15 ch16 is for chord root note - first it gets modulo12'd (reduced to one octave)
// then any non-scale notes are forced to scale (because a chord within a key can't start from a non-scale note)
// this is similar to transpose before quantizing, but only tunes to a subset of the scale (a chord)
// the way this works, for example, in C (all white keys), sharps/flats (all black keys) are 
// moved to the pentatonic subset (CDEGA) for all chord root notes to fall within the key
// 
// but this is all to get to the referenced scale, a: Root, 3rd, 5th chord, within the key
//
// upon reception of noteon: store most recent note, lookup bend amount, send bend to that channel, send noteon
// upon reception of song root note: all is recalculated/looked up/etc. and a pitch bend is sent to each of 16 channels 
// upon reception of chord root note: all is recalculated/looked up/etc. (except for songrootshift and incoming songroot) and a pitch bend is sent to each of 16 channels 
// noteoff goes straight to the midi output
// 
// main loop just waits/looks for midi

For some reason, I didn't get a notification of your last post, and only just found it.

I had to do a bit of messing around to install that library too.

Anyway, I'm pleased to hear that it's all working fine now, Roy.
I'll delete your program and uninstall the library.

Good luck with the rest of your project. :slight_smile: