Midi Send Note - Displaying Scale Names on LC-Display

Status
Not open for further replies.

marl

Member
Hi Folks,

I need your help once again.

As indicated in the title, I would like to display the scale name of the chosen scale, e.g. "Amaj0", and the note being played, e.g. "A6", on my LC-Display.

Up to now I get the chosen Scale displayed as number between 0 and 19 (20 Scales to choose from) but I only get the first letter of the Scale_Name displayed, e.g. "A", instead of "Amaj0".

1) How do I get the complete Scale_Name of the Scale which has been chosen, e.g. "Amaj0", displayed on my LCD?

In the second row of my LCD I get the note being played displayed as number (according to my scales the numbers range from 57 to 119).

2) How can I get the actual note_name, e.g. "A6", from the const char arrays displayed?

Code:
// include the library code:
#include <LiquidCrystal.h>
#include <MIDI.h>


        

int const numPins = 2; //  number of analog inputs 
int analogPins[] = {  
  0,1   // which analog pins to use
};
// the MIDI channel number to send messages
const int channel = 1;
int theNote;
int OldNote = 0;

// *********************************
// SCALE INFORMATION:
// *********************************

 // *** A Major ***    COUNT: 0
 const int Amaj0[] = {57,59,61,62,64,66,68,69};
 const char *Amaj0_Names[] = {"A6", "B6", "C#6", "C6", "E6", "F#6", "G#6", "A7"};

  // *** A Major 1***    COUNT: 1
const int Amaj1[] = {69,71,73,74,76,78,80,81};
const char *Amaj1_Names[] = {"A7", "B7", "C#7", "C7", "E7", "F#7", "G#7", "A8"};

  // *** B Major ***    COUNT: 2
const int Bmaj0[] = {59,61,63,64,66,68,70,71};
const char *Bmaj0_Names[] = {"B6", "C#6", "D#6", "E6", "F#6", "G#6", "A#7", "B7"};

  // *** B Major 1***    COUNT: 3
const int Bmaj1[] = {71,73,75,76,78,80,82,83};
const char *Bmaj1_Names[] = {"B7", "C#7", "D#7", "E7", "F#7", "G#7", "A#8", "B8"};

  // *** C Major ***    COUNT: 4
const int Cmaj0[] = {60,62,64,65,67,69,71,72};
const char *Cmaj0_Names[] = {"C6", "D6", "E6", "F6", "G6", "A7", "B7", "C7"};
 
  // *** C Major 1 ***    COUNT: 5
const int Cmaj1[] = {72,74,76,77,79,81,83,84};
const char *Cmaj1__Names[] = {"C7", "D7", "E7", "F7", "G7", "A8", "B8", "C8"};

  // *** D Major ***    COUNT: 6
const int Dmaj0[] = {62,64,66,67,69,71,73,74};
const char *Dmaj0_Names[] = {"D6", "E6", "F#6", "G6", "A7", "B7", "C#7", "D7"};

  // *** D Major 1***    COUNT: 7
const int Dmaj1[] = {74,76,78,79,81,83,85,86};
const char *Dmaj1_Names[] = {"D7", "E7", "F#7", "G7", "A8", "B8", "C#8", "D8"};

  // *** E Major ***    COUNT: 8
const int Emaj0[] = {64,66,68,69,71,73,75,76};
const char *Emaj0_Names[] = {"E6", "F#6", "G#6", "A7", "B7", "C#7", "D#7", "E7"};

 // *** E Major 1***    COUNT: 9
const int Emaj1[] = {76,78,80,81,83,85,87,88};
const char *Emaj1_Names[] = {"E7", "F#7", "G#7", "A8", "B8", "C#8", "D#8", "E8"};

  // *** F Major ***    COUNT: 10
const int Fmaj0[] = {65,67,69,70,72,74,76,77};
const char *Fmaj0_Names[] = {"F6", "G6", "A7", "A#7", "C7", "D7", "E7", "F7"};

  // *** F Major 1***    COUNT: 11
const int Fmaj1[] = {77,79,81,82,84,86,88,89};
const char *Fmaj1_Names[] = {"F7", "G7", "A8", "A#8", "C8", "D8", "E8", "F8"};

  // *** G Major ***    COUNT: 12 
const int Gmaj0[] = {55,57,59,60,62,64,66,67};
const char *Gmaj0_Names[] = {"G5", "A6", "B6", "C6", "D6", "E6", "F#6", "G6"};

  // *** G Major 1***    COUNT: 13 
const int Gmaj1[] = {67,69,71,72,74,76,78,79};
const char *Gmaj1_Names[] = {"G6", "A7", "B7", "C7", "D7", "E7", "F#7", "G7"};

  // *** G Mixolydian***    COUNT: 14 
const int Gmix[] = {81,83,84,86,88,89,79,81};
const char *Gmix_Names[] = {"A8", "B8", "C8", "D8", "E8", "F8", "G7", "A8"};

  // *** Pentatonic***    COUNT: 15
const int Pent[] = {0,2,4,7,9};
const char *Pent_Names[] = {"C", "D", "E", "G", "A"};

  // *** Pentatonic 8***    COUNT: 16
const int Pent8[] = {84,86,88,91,93};
const char *Pent8_Names[] = {"C8", "D8", "E8", "G8", "A9"};

  // *** Blues***    COUNT: 17
const int Blue[] = {0,2,3,4,5,7,9,10,11};
const char *Blue_Names[] = {"C", "D", "D#", "E", "F", "G", "A2", "A#2","B2"};

  // *** Bluz 10***    COUNT: 18
const int Bluz[] = {108,110,111,112,113,115,117,118,119};
const char *Bluz_Names[] = {"C10", "D10", "D#10", "E10", "F10", "G10", "A11", "A#11","B11"};

  // *** Phrygian 5***    COUNT: 19
const int Phry5[] = {48,49,51,53,55,56,58};
const char *Phry5_Names[] = {"C5", "C#5", "D#5", "F5", "G5", "G#5", "A#6"};

   
// **********************************************
// ******* END OF SCALE INFORMATION ********
// **********************************************

const int *Scales[] = {Amaj0, Amaj1, Bmaj0, Bmaj1, Cmaj0, Cmaj1, Dmaj0, Dmaj1, Emaj0, Emaj1, Fmaj0, Fmaj1, Gmaj0, Gmaj1, Gmix, Pent, Pent8, Blue, Bluz, Phry5};

const int ScaleLength[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 5, 9, 9, 7};
const char *Scale_Names[] = {"Amaj0_Names", "Amaj1_Names", "Bmaj0_Names", "Bmaj1_Names", "Cmaj0_Names", "Cmaj1_Names", "Dmaj0_Names", "Dmaj1_Names", "Emaj0_Names", "Emaj1_Names", "Fmaj0_Names", "Fmaj1_Names", "Gmaj0_Names", "Gmaj1_Names", "Gmix_Names", "Pent_Names", "Pent8_Names", "Blue_Names", "Bluz_Names", "Phry5_Names"};

const char *Scales_Names[] = {"Amaj0", "Amaj1", "Bmaj0", "Bmaj1", "Cmaj0", "Cmaj1", "Dmaj0", "Dmaj1", "Emaj0", "Emaj1", "Fmaj0", "Fmaj1", "Gmaj0", "Gmaj1", "Gmix", "Pent", "Pent8", "Blue", "Bluz", "Phry5"};


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12,11,5,4,3,2);



void setup() {
  // put your setup code here, to run once:
  MIDI.begin();
   Serial.begin(31250);
 
   // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);

  // include reverse switch 
    pinMode(16, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:

// The pot on A1 selects which of the 20 scales we pull notes from
int whichScale = (analogRead(A1) * 20) / 1024;
const int *theChosenScale = Scales[whichScale];
int theChosenScalesLength = ScaleLength[whichScale];

char theChosenScaleName = (*Scales_Names[whichScale]);





// The pot on A0 selects a note from the chosen scale
int whichNoteOfScale = (analogRead(A0) * theChosenScalesLength) / 1024;


// If the switch is set to reverse, reverse the direction of the sequence
if (digitalRead(16) == HIGH) {

    const int theNote = theChosenScale[((theChosenScalesLength - 1) - whichNoteOfScale)];
    lcd.setCursor(6, 1);
    //print that the Scale is in reverse mode
    lcd.print("Reverse");
   lcd.setCursor(0, 0);
  lcd.print(whichScale);
   lcd.setCursor(6, 0);
  lcd.print(theChosenScaleName);
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the note being played:
  lcd.print(theNote);

} else {

    const int theNote = theChosenScale[whichNoteOfScale];
    lcd.setCursor(6, 1);
    //print that the Scale is in normal mode
    lcd.print("Normal ");
lcd.setCursor(0, 0);
  lcd.print(whichScale);
   lcd.setCursor(6, 0);
  lcd.print(theChosenScaleName);
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the note being played:
  lcd.print(theNote);
    
}
if (theNote != OldNote) {
MIDI.sendNoteOn(theNote, 127, channel);
Serial.println(theNote);
 
}
else {
  MIDI.sendNoteOff(theNote, 127, channel);
}
OldNote = theNote;
}
I still have problems here connecting the int values given from the potis (A0, and A1)and the const char arrays to display the note names themselves.

Any ideas?

Thanks for your help in advance and Happy New Years Celebrations to all of you,
Marl
 
Code:
    void dispNote(uint8_t midi) {
        const char noteStr[12][3] {"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "};
        char disp_buf[6];
    // separate note and octave:
        uint8_t octave = midi / 12;
        uint8_t note = midi - (12 * octave);
    // assemble everything in the display buffer:
        strcpy(disp_buf, noteStr[note]);
        snprintf(disp_buf+2, 6, "%d", octave);
    // show the result:
        Serial.println(disp_buf);
    }
 
Thanks Theremingenieur for the code,

but as I am a real beginner when it comes to programming, I'd be pleased to get some more explanation on the following:

1) Can you please explain a little what your code actually does and what is even more important, how this code refers back to my note that I've chosen (= theNote) through the poti on A0?
Am I right that I need to connect my poti value that creates the note being played with your code to get, for example, "A6" displayed for the note number "57"!?

2) Why do I only get "A" displayed instead of "Amaj0" (for example)? What do I need to change here?
Code:
const char *Scales_Names[] = {"Amaj0", "Amaj1", "Bmaj0", "Bmaj1", "Cmaj0", "Cmaj1", "Dmaj0", "Dmaj1", "Emaj0", "Emaj1", "Fmaj0", "Fmaj1", "Gmaj0", "Gmaj1", "Gmix", "Pent", "Pent8", "Blue", "Bluz", "Phry5"};

char theChosenScaleName = (*Scales_Names[whichScale]);
lcd.setCursor(6, 0);
  lcd.print(theChosenScaleName);

Thanks in advance,
Marl
 
Yes, my code is a subroutine from one of my projects which includes a visual tuner.
1) It accepts a midi note value between 0 and 127 as an input parameter and outputs a char array like for example "A 5" or "D#7" or whatever. In your project, you would use the potentiometer on A0 to pick the note value from your selected array as you do already and you would replace the serial.println(disp_buf); in my routine by lcd.setCursor(0,1); LCD.print(disp_buf); And in your code you would simply replace the lcd.setCursor(0,1); lcd.print(theNote) in both locations by dispNote(theNote);
2) It's normal that you get only a single character displayed here since you define your variable theChosenScaleName as a single char. Give the following alternative a try: char[] theChosenScaleName = (*Scale_Names[whichScale]);

Since you are, as you state yourself, a real beginner when it comes to programming, I'd suggest that you do some simpler coding exercises before you jump into the cold water of multidimensonal array pointers. "Never use whatever code example or library which you haven't fully understood and which you couldn't write by yourself line by line". Please don't feel offended personally but a big part of the forum questions here come from people who tinker a few hardware components together, copy and paste some example code, and include libraries without fully understanding what they do. That's not a very academic approach in my eyes... a little like people driving a car without understanding how the engine works or people playing a keyboard without understanding the difference between additive and subtractive sound synthesis...
 
Thanks again Theremingenieur,

the note display works perfect, but for the Scales_Names I still only get the first character displayed (char[] didn't work as well as char theChosenScaleName[]).

Any more ideas on that?

Of course, I understand your point of learning things step by step, but it's simply this project that encourages me that much:)

Happy New Year,
Marl
 
Yes, these pseudo string operations where one fiddles with char array pointers are a little tricky, sorry.

Here is a working (tested with Serial.println) solution:

Code:
	char *buf; //declares a char buffer
	buf = strdup(Scales_Names[whichScale]); //allocates enough memory for that buffer and copies the content into it.
	lcd.setCursor(6,0);
	lcd.print(buf);

But basically, there is even no need for an intermediate variable, one might print directly:
Code:
	lcd.setCursor(6,0);
	lcd.print(Scales_Names[whichScale]);
 
Last edited:
Thanks again Theremingenieur,

the LCD works perfectly well now.

Now there is only one problem left:
The following part of my code seems to slow down the whole program

Code:
MIDI.sendNoteOn(theNote, 127, channel);
  delay(10);
  MIDI.sendNoteOff(theNote, 127, channel);
  Serial.println(theNote);
}

This creates loads of midi notes being sent to my midi device at almost the same time and therefore it collapses.

Do you have another great idea on how to send only midi notes if the note value has been changed?

Thanks in advance,
Marl
Code:
// include the library code:
#include <LiquidCrystal.h>
#include <MIDI.h>


        

int const numPins = 2; //  number of analog inputs 
int analogPins[] = {  
  0,1   // which analog pins to use
};
// the MIDI channel number to send messages
const int channel = 1;
int theNote;
int OldNote = 0;
char *buf;
int whichScale;

// *********************************
// SCALE INFORMATION:
// *********************************

  // *** A Major ***    COUNT: 0
 const int Amaj0[] = {57,59,61,62,64,66,68,69};
 
  // *** A Major 1***    COUNT: 1
const int Amaj1[] = {69,71,73,74,76,78,80,81};

  // *** B Major ***    COUNT: 2
const int Bmaj0[] = {59,61,63,64,66,68,70,71};

  // *** B Major 1***    COUNT: 3
const int Bmaj1[] = {71,73,75,76,78,80,82,83};

  // *** C Major ***    COUNT: 4
const int Cmaj0[] = {60,62,64,65,67,69,71,72};
 
  // *** C Major 1 ***    COUNT: 5
const int Cmaj1[] = {72,74,76,77,79,81,83,84};

  // *** D Major ***    COUNT: 6
const int Dmaj0[] = {62,64,66,67,69,71,73,74};

  // *** D Major 1***    COUNT: 7
const int Dmaj1[] = {74,76,78,79,81,83,85,86};


  // *** E Major ***    COUNT: 8
const int Emaj0[] = {64,66,68,69,71,73,75,76};

 // *** E Major 1***    COUNT: 9
const int Emaj1[] = {76,78,80,81,83,85,87,88};

  // *** F Major ***    COUNT: 10
const int Fmaj0[] = {65,67,69,70,72,74,76,77};

  // *** F Major 1***    COUNT: 11
const int Fmaj1[] = {77,79,81,82,84,86,88,89};

  // *** G Major ***    COUNT: 12 
const int Gmaj0[] = {55,57,59,60,62,64,66,67};

  // *** G Major 1***    COUNT: 13 
const int Gmaj1[] = {67,69,71,72,74,76,78,79};

  // *** G Mixolydian***    COUNT: 14 
const int Gmix[] = {81,83,84,86,88,89,79,81};

  // *** Pentatonic***    COUNT: 15
const int Pent[] = {0,2,4,7,9};

  // *** Pentatonic 8***    COUNT: 16
const int Pent8[] = {84,86,88,91,93};

  // *** Blues***    COUNT: 17
const int Blue[] = {0,2,3,4,5,7,9,10,11};

  // *** Bluz 10***    COUNT: 18
const int Bluz[] = {108,110,111,112,113,115,117,118,119};

  // *** Phrygian 5***    COUNT: 19
const int Phry5[] = {48,49,51,53,55,56,58};

// **********************************************
// ******* END OF SCALE INFORMATION ********
// **********************************************

const int *Scales[] = {Amaj0, Amaj1, Bmaj0, Bmaj1, Cmaj0, Cmaj1, Dmaj0, Dmaj1, Emaj0, Emaj1, Fmaj0, Fmaj1, Gmaj0, Gmaj1, Gmix, Pent, Pent8, Blue, Bluz, Phry5};

const int ScaleLength[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 5, 9, 9, 7};

const char *Scales_Names[] = {"Amaj0", "Amaj1", "Bmaj0", "Bmaj1", "Cmaj0", "Cmaj1", "Dmaj0", "Dmaj1", "Emaj0", "Emaj1", "Fmaj0", "Fmaj1", "Gmaj0", "Gmaj1", "Gmix", "Pent", "Pent8", "Blue", "Bluz", "Phry5"};


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12,11,5,4,3,2);



void setup() {
  // put your setup code here, to run once:
  MIDI.begin();
   Serial.begin(31250);
 
   // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);

  // include reverse switch 
    pinMode(16, INPUT_PULLUP);
}


void dispNote(uint8_t midi) {
        const char noteStr[12][3] {"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "};
        char disp_buf[6];
    // separate note and octave:
        uint8_t octave = midi / 12;
        uint8_t note = midi - (12 * octave);
    // assemble everything in the display buffer:
        strcpy(disp_buf, noteStr[note]);
        snprintf(disp_buf+2, 6, "%d", octave);
    // show the result:
        lcd.setCursor(0,1);
        lcd.print(disp_buf);
        
   char *buf; //declares a char buffer 
buf = strdup(Scales_Names[whichScale]); //allocates enough memory for that buffer and copies the content into it.
}

void loop() {
  // put your main code here, to run repeatedly:

// The pot on A1 selects which of the 20 scales we pull notes from
int whichScale = (analogRead(A1) * 20) / 1024;
const int *theChosenScale = Scales[whichScale];
int theChosenScalesLength = ScaleLength[whichScale];

char theChosenScaleName = {(*Scales_Names[whichScale])};



// The pot on A0 selects a note from the chosen scale
int whichNoteOfScale = (analogRead(A0) * theChosenScalesLength) / 1024;


// If the switch is set to reverse, reverse the direction of the sequence
if (digitalRead(16) == HIGH) {

    const int theNote = theChosenScale[((theChosenScalesLength - 1) - whichNoteOfScale)];

    lcd.setCursor(6,0);
  lcd.print(Scales_Names[whichScale]);
    lcd.setCursor(9, 1);
    //print that the Scale is in reverse mode
    lcd.print("Reverse");
   lcd.setCursor(0, 0);
   if (whichScale < 10) lcd.print(" ");
  lcd.print(whichScale);
  dispNote(theNote);
  lcd.setCursor(4,1);
  lcd.print("=");
  lcd.setCursor(5,1);
if (theNote < 10) lcd.print(" ");
if (theNote < 100) lcd.print(" ");
lcd.print(theNote);
MIDI.sendNoteOn(theNote, 127, channel);
delay(10);
MIDI.sendNoteOff(theNote, 127, channel);
Serial.println(theNote);
} 

if (digitalRead(16) == LOW) {

    const int theNote = theChosenScale[whichNoteOfScale];

    lcd.setCursor(6,0);
  lcd.print(Scales_Names[whichScale]);
    lcd.setCursor(9, 1);
    //print that the Scale is in normal mode
    lcd.print("Normal ");
lcd.setCursor(0, 0);
if (whichScale < 10) lcd.print(" ");
  lcd.print(whichScale);
 dispNote(theNote);
  lcd.setCursor(4,1);
  lcd.print("=");
  lcd.setCursor(5,1);
if (theNote < 10) lcd.print(" ");
if (theNote < 100) lcd.print(" ");
lcd.print(theNote);
  MIDI.sendNoteOn(theNote, 127, channel);
  delay(10);
  MIDI.sendNoteOff(theNote, 127, channel);
  Serial.println(theNote);
}

if (theNote == OldNote) {
MIDI.sendNoteOff(theNote, 127, channel);
}

OldNote = theNote;
}
 
I even tried the following:

Code:
if (theNote != OldNote) {
MIDI.sendNoteOn(theNote, 127, channel);
Serial.println(theNote);
}
else {
  MIDI.sendNoteOff(theNote, 127, channel);
}
OldNote = theNote;
}

This worked perfectly well in a shorter version without the other IF orders.
But now it keeps sending midi notes throughout, no matter if it is always the same note value or not(theNote != OldNote)!

Why is that? Is it because it is an if-else-order within another if-order?
How can I solve this?


Thanks in advance,
Marl
 
Here is the cleaned up, fixed, and simplified code for everything. I've tested it with a Teensy 3.6, but it works for sure on all Teensy 3.x. As long as the potentiometers are not physically connected, it will naturally send arbitrary notes because the analog inputs are floating in the air. But as soon as the wipers of the potentiometers are connected to A0 and A1 (and the other pins of the potentiometers to GND and +3.3V respectively), everything becomes stable.

Basically, I did not plan to rewrite the complete code for you. I really had preferred that you learn from your mistakes, spend more time learning programming in C/C++ systematically, and fix your code by yourself. But I felt that you would not do that because you are too enthusiastic about your project for the moment, and, in opposite to me, you apparently would never feel ashamed by superficially doing something without deeper understanding of what goes on under the hood.
Code:
// include the library code:
#include <LiquidCrystal.h>
#include <MIDI.h>

int const numPins = 2; //  number of analog inputs
int analogPins[] = {
  0,1   // which analog pins to use
};
// the MIDI channel number to send messages
const int channel = 1;
int theNote;
int OldNote = 0;
char *buf;
int whichScale;
int OldScale = -1;
bool OldDir = LOW;
// *********************************
// SCALE INFORMATION:
// *********************************
  // *** A Major ***    COUNT: 0
const int Amaj0[] = {57,59,61,62,64,66,68,69};
  // *** A Major 1***    COUNT: 1
const int Amaj1[] = {69,71,73,74,76,78,80,81};
  // *** B Major ***    COUNT: 2
const int Bmaj0[] = {59,61,63,64,66,68,70,71};
  // *** B Major 1***    COUNT: 3
const int Bmaj1[] = {71,73,75,76,78,80,82,83};
  // *** C Major ***    COUNT: 4
const int Cmaj0[] = {60,62,64,65,67,69,71,72};
  // *** C Major 1 ***    COUNT: 5
const int Cmaj1[] = {72,74,76,77,79,81,83,84};
  // *** D Major ***    COUNT: 6
const int Dmaj0[] = {62,64,66,67,69,71,73,74};
  // *** D Major 1***    COUNT: 7
const int Dmaj1[] = {74,76,78,79,81,83,85,86};
  // *** E Major ***    COUNT: 8
const int Emaj0[] = {64,66,68,69,71,73,75,76};
 // *** E Major 1***    COUNT: 9
const int Emaj1[] = {76,78,80,81,83,85,87,88};
  // *** F Major ***    COUNT: 10
const int Fmaj0[] = {65,67,69,70,72,74,76,77};
  // *** F Major 1***    COUNT: 11
const int Fmaj1[] = {77,79,81,82,84,86,88,89};
  // *** G Major ***    COUNT: 12
const int Gmaj0[] = {55,57,59,60,62,64,66,67};
  // *** G Major 1***    COUNT: 13
const int Gmaj1[] = {67,69,71,72,74,76,78,79};
  // *** G Mixolydian***    COUNT: 14
const int Gmix[] = {81,83,84,86,88,89,79,81};
  // *** Pentatonic***    COUNT: 15
const int Pent[] = {0,2,4,7,9};
  // *** Pentatonic 8***    COUNT: 16
const int Pent8[] = {84,86,88,91,93};
  // *** Blues***    COUNT: 17
const int Blue[] = {0,2,3,4,5,7,9,10,11};
  // *** Bluz 10***    COUNT: 18
const int Bluz[] = {108,110,111,112,113,115,117,118,119};
  // *** Phrygian 5***    COUNT: 19
const int Phry5[] = {48,49,51,53,55,56,58};
// **********************************************
// ******* END OF SCALE INFORMATION ********
// **********************************************
const int *Scales[] = {Amaj0, Amaj1, Bmaj0, Bmaj1, Cmaj0, Cmaj1, Dmaj0, Dmaj1, Emaj0, Emaj1, Fmaj0, Fmaj1, Gmaj0, Gmaj1, Gmix, Pent, Pent8, Blue, Bluz, Phry5};
const int ScaleLength[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 5, 9, 9, 7};
const char *Scales_Names[] = {"Amaj0", "Amaj1", "Bmaj0", "Bmaj1", "Cmaj0", "Cmaj1", "Dmaj0", "Dmaj1", "Emaj0", "Emaj1", "Fmaj0", "Fmaj1", "Gmaj0", "Gmaj1", "Gmix", "Pent", "Pent8", "Blue", "Bluz", "Phry5"};
// moved here from dispnote();
const char noteStr[12][3] {"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "};
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12,11,5,4,3,2);

void dispNote(uint8_t midi) {
	char disp_buf[6];
    // separate note and octave:
	uint8_t octave = midi / 12;
	uint8_t note = midi - (12 * octave);
    // assemble everything in the display buffer:
	strcpy(disp_buf, noteStr[note]);
	snprintf(disp_buf+2, 6, "%d", octave);
    // show the result:
	lcd.setCursor(0,1);
	lcd.print(disp_buf);
// Moved here from the loop() for better structure and readability since that always goes together
	lcd.setCursor(4,1);
	lcd.print("=");
	lcd.setCursor(5,1);
	if (midi < 10) lcd.print(" ");
	if (midi < 100) lcd.print(" ");
	lcd.print(midi);
}

void playNote(uint8_t midi) {
	MIDI.sendNoteOn(midi, 127, channel);
	delay(10);
	MIDI.sendNoteOff(midi, 127, channel);
}

void dispScale(int scaleNo) {
    lcd.setCursor(6,0);
    lcd.print(Scales_Names[scaleNo]);
    lcd.setCursor(0, 0);
    if (scaleNo < 10) lcd.print(" ");
    lcd.print(scaleNo);
}

void dispDir(bool dir) {
    lcd.setCursor(9, 1);
    if (dir) {
        lcd.print("Reverse");
    } else {
        lcd.print("Normal ");
    }
}

void setup() {
  // put your setup code here, to run once:
  MIDI.begin();
  Serial.begin(31250);
   // set up the LCD's number of rows and columns:
  lcd.begin(16, 2);
  // include reverse switch
  pinMode(16, INPUT_PULLUP);
}

void loop() {
	// The pot on A1 selects which of the 20 scales we pull notes from
	int whichScale = (analogRead(A1) * 20) / 1024;
	const int *theChosenScale = Scales[whichScale];
	int theChosenScalesLength = ScaleLength[whichScale];
	// if the scale has changed, print the new scale:
	if (whichScale != OldScale) {
		dispScale(whichScale);
		OldScale = whichScale;
	}
	// The pot on A0 selects a note from the chosen scale
	int whichNoteOfScale = (analogRead(A0) * theChosenScalesLength) / 1024;

	// Get the direction from the switch on pin 16
	bool actDir = digitalRead(16);
	// if the direction has changed, print the new direction:
	if (actDir != OldDir) {
		dispDir(actDir);
		OldDir = actDir;
	}
	//Calculate the note from potentiometer A0, scale, and direction
	if (actDir){
        theNote = theChosenScale[((theChosenScalesLength - 1) - whichNoteOfScale)];
	} else {
	    theNote = theChosenScale[whichNoteOfScale];
	}
	// if the note has changed, print and play it
	if(theNote != OldNote) {
        dispNote(theNote);
        playNote(theNote);
        Serial.println(theNote);
        OldNote=theNote;
	}
	//Slow the loop down to prevent reading the potentiometers more than 20 x per second
	delay(50);
}
 
Hey Theremingenieur,

thank you very much for your help!

By the way, I also managed to fix my program, as you can see in the following code. Nevertheless, I am a true beginner and your version is the version of a real professional. Therefore, I am very thankful for your help and - believe it or not - I also learned a lot through this project:)

Code:
void loop() {
  // put your main code here, to run repeatedly:

// The pot on A1 selects which of the 20 scales we pull notes from
int whichScale = (analogRead(A1) * 20) / 1024;
const int *theChosenScale = Scales[whichScale];
int theChosenScalesLength = ScaleLength[whichScale];

char theChosenScaleName = {(*Scales_Names[whichScale])};



// The pot on A0 selects a note from the chosen scale
int whichNoteOfScale = (analogRead(A0) * theChosenScalesLength) / 1024;


// If the switch is set to reverse, reverse the direction of the sequence
if (digitalRead(16) == HIGH)
{
  const int theNote = theChosenScale[((theChosenScalesLength - 1) - whichNoteOfScale)];

  if (theNote != OldNote)
  
    lcd.setCursor(6,0);
  lcd.print(Scales_Names[whichScale]);
    lcd.setCursor(9, 1);
    //print that the Scale is in reverse mode
    lcd.print("Reverse");
   lcd.setCursor(0, 0);
   if (whichScale < 10) lcd.print(" ");
  lcd.print(whichScale);
  dispNote(theNote);
  lcd.setCursor(4,1);
  lcd.print("=");
  lcd.setCursor(5,1);
if (theNote < 10) lcd.print(" ");
if (theNote < 100) lcd.print(" ");
lcd.print(theNote);
Serial.println(theNote);
MIDI.sendNoteOn(theNote, 127, channel);
delay(10);
MIDI.sendNoteOff(theNote, 127, channel);
}

if (digitalRead(16) == LOW) 
{
    const int theNote = theChosenScale[whichNoteOfScale];
  if (theNote != OldNote)
    lcd.setCursor(6,0);
  lcd.print(Scales_Names[whichScale]);
    lcd.setCursor(9, 1);
    //print that the Scale is in normal mode
    lcd.print("Normal ");
lcd.setCursor(0, 0);
if (whichScale < 10) lcd.print(" ");
  lcd.print(whichScale);
 dispNote(theNote);
  lcd.setCursor(4,1);
  lcd.print("=");
  lcd.setCursor(5,1);
if (theNote < 10) lcd.print(" ");
if (theNote < 100) lcd.print(" ");
lcd.print(theNote);
Serial.println(theNote);
MIDI.sendNoteOn(theNote, 127, channel);
delay(10);
MIDI.sendNoteOff(theNote, 127, channel);

}
OldNote = theNote;
delay(50);
}

I have an idea. But I also have a day job and a family.

So do I. That is why I could not start of with the real basics of programming once I had this project in mind;)

Thanks again and all the best to you and your family in 2017!
Marl
 
Hey Theremingenieur, hey folks,

I got all my hardware together and built in into a selfmade wooden case at the weekend and it is great fun to play with this controller:)
Thanks again for your help!

Thinking about an updated version, I'd like to use a 4x40 LCD and add one more aspect to it.

Below the note being played I'd like to arrange all the notes of the chosen Scale within one line (third line of the display) and I'd like to highlight (maybe bold print or underline) the note being played.

Example:
A6 B6 C#6 C6 E6 F#6 G#6 A7

while C6 is being played!


So in the end I want to have the chosen scale static on the display while the highlighting jumps from tone to tone while theNote being played changes.

Can I display the notes of the whole scale (being chosen) using the "void dispNote" routine as well and highlight "theNote" (being played) by comparing "theNote" and the notes within the chosen and the displayed scale?

Something like:

Highlight "theNote"(which is the note being played) within the scale.

Thanks for your thoughts and ideas in advance,
Marl
 
Status
Not open for further replies.
Back
Top