/* Pour télécharger le ficher pitches.h
  https://drive.google.com/file/d/0B3uxfp2Hl_RXVzFydWZrSjJ0bDg/view?usp=sharing&resourcekey=0-80XXqrJoeZZbEtR24HMKRQ

  Cours d'initiation:
  https://youtu.be/r5ZzGTsYlIo
*/

#include "pitches.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Déclare le Joystick
const int btn_Select = 2, btn_Vert = A0, btn_Horz = A1 ;
int select_Value = 0, horz_Value = 0, vert_Value = 0;
int select = 0, horizontal = 0, vertical = 0;
const int buzzer = 13;

bool play = false, etatBtnPresser;
/*
Pourquoi ne peut-il y avoir plus de 88 touches sur un piano ?

Bien que l'oreille humaine puisse discerner des sons compris entre 20 et 20 000 Hz, 
elle ne peut déterminer la hauteur que jusqu'à un niveau maximum d'environ 4 000 Hz.
Le piano inventé initialement par Bartolomeo Cristofori en Italie ne possédait que 54 touches. 
Au fil du développement et de l’évolution de la musique pour piano, 
l’étendue du clavier a été progressivement élargie en réponse aux exigences des compositeurs qui 
aspiraient à un plus vaste potentiel d’expression.

Dès 1890, le clavier moderne actuel s’imposait avec 88 touches couvrant 7¼ octaves (de La 2 à Do 5 ; 27,5 Hz à 4,186 Hz*). 
L'oreille humaine est capable d'entendre les sons dans la plage de 20 Hz à 20 000 Hz environ, 
mais la limite supérieure des fréquences pouvant être distinguées par le cerveau humain est tout au plus de 4 000 Hz environ. 
Même si l'étendue devait être élargie en augmentant le nombre de touches sur le piano, pour l'oreille humaine, 
les notes rajoutées au niveau des basses ne seraient rien de plus qu'un grondement, 
et les notes aigües supplémentaires seraient perçues comme un bruit dissonant et désagréable, 
absolument pas dans une plage sonore. Cette démarche serait ainsi quasiment dénuée de sens d’un point de vue musical. 
Bösendorfer fabrique des pianos à 97 touches avec neuf touches supplémentaires dans le segment des basses du clavier (Do 2 à Do 5). 
Cependant, les cordes correspondant à ces neuf touches dans le segment des plus graves ne sont réellement là que 
pour conférer une sonorité plus riche lorsque d'autres touches sont jouées en résonant avec elles. 
Dans la pratique, les touches supplémentaires elles-mêmes ne sont quasiment jamais jouées directement.

* Lorsque le La est réglé sur 440 Hz. La hauteur tonale des touches individuelles varie en fonction de la méthode d’accordage.
_________________________________________________________________________________________________________________________________*/

// Tableaux des octaves contenant 89 tonalités tempérées 
const int Octave0[1]  =  {NOTE_B0}; // octave 0
const int Octave1[12] =  {NOTE_C1, NOTE_CS1, NOTE_D1, NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1, NOTE_B1}; // octave 1
const int Octave2[12] =  {NOTE_C2, NOTE_CS2, NOTE_D2, NOTE_DS2, NOTE_E2, NOTE_F2, NOTE_FS2, NOTE_G2, NOTE_GS2, NOTE_A2, NOTE_AS2, NOTE_B2}; // octave 2
const int Octave3[12] =  {NOTE_C3, NOTE_CS3, NOTE_D3, NOTE_DS3, NOTE_E3, NOTE_F3, NOTE_FS3, NOTE_G3, NOTE_GS3, NOTE_A3, NOTE_AS3, NOTE_B3}; // octave 3
const int Octave4[12] =  {NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4}; // octave 4
const int Octave5[12] =  {NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5}; // octave 5
const int Octave6[12] =  {NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6}; // octave 6
const int Octave7[12] =  {NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7}; // octave 7
const int Octave8[4]  =  {NOTE_C8, NOTE_CS8, NOTE_D8, NOTE_DS8};                                                                             // octave 8

String Touche[] = {"Do", "Do#", "Re", "Re#", "Mi", "Fa", "Fa#", "Sol", "Sol#", "La", "La#", "Si"};

int pitch = 0;

void setup() { // Initialisation.
  lcd.init(); lcd.backlight();
 
  pinMode(buzzer, OUTPUT);
  pinMode(btn_Select, INPUT_PULLUP); // Mode INPUT_PULLUP pour le bouton central "Select"

  }

void loop() {
  Fn_Joystick(); // Appel de la fonction perso "Fn_Joystick" dont le rôle est d'identifier le bouton pressé.
  Fn_Display(); // Fonction d'affichage.
  if (play) PlayNote(horz_Value, vert_Value);
  else noTone(buzzer);

}

void Fn_Joystick() {
  // Balaie en boucle l'état des boutons du Joystick.
  select = digitalRead(btn_Select);
  horizontal = analogRead(btn_Horz);
  vertical = analogRead(btn_Vert);

  if (!select && etatBtnPresser == LOW) {
    etatBtnPresser = HIGH;
    lcdPrintCenter("                    ", 1);
    play = !play;//delay(500);
    while (select)  select = digitalRead(btn_Select);
  }
  if (select == HIGH && etatBtnPresser == HIGH) {
    // La variable etatBtnPresser prend la valeur de 0.
    etatBtnPresser = !etatBtnPresser; // inversion etatBtnPresser
  }
if(play){ // Si play == HIGH; Active les boutons horizontal et vertical.
  switch (vertical) { // commute vers la case correspondant à la valeur du bouton vertical.
    case 0:  vert_Value--; if (vert_Value < 0)vert_Value = 0; delay(250);
      lcdPrintCenter("                    ", 3);
      break;
    case 1023: vert_Value++; delay(250);
      lcdPrintCenter("                    ", 3);
      break;
  }
  // commute vers la case correspondant à la valeur du bouton Horizontal.
  switch (horizontal) {
    case 0: horz_Value++ ; if (horz_Value > 8)horz_Value = 8; delay(250);
      lcdPrintCenter("                    ", 3);
      break;
    case 1023: horz_Value--; if (horz_Value < 0)horz_Value = 0; delay(250);
      lcdPrintCenter("                    ", 3);
      break;
  }
}
}
void Fn_Display() {
  if (!play) {
    lcdPrintCenter("                    ", 2);
    //lcdPrintCenter("                    ", 3);
    lcdPrintCenter("Press Select", 1);
  }
  if (play) {
    lcdPrintCenter("Octave->Btn Horiz", 1);
    lcdPrintCenter("Note->Btn Vertical", 2);

  }
  lcdPrintCenter("Tone Generator", 0);

  //lcdPrintCenter(String(vert_Value), 1);
  //lcdPrintCenter(String(horz_Value), 2);

}
// fonction  pour centrer le texte à afficher sur lcd.============
void lcdPrintCenter(String text, int ligne) {
  int len = text.length();// longeur de la variable text
  // positionne le curseur au centre de la ligne choisie et
  // soustrait la longeur du text à afficher
  lcd.setCursor((20 - len) / 2, ligne);
  lcd.print(text);    // affiche le text centré
}
void PlayNote(int octave, int Note) {
  //if( octave > 8)octave =8;
  lcdPrintCenter("Octave: " + String(octave) + " Note: " + String(Touche[Note]), 3);
//lcd.setCursor(16,0);
  switch (octave) {
    case 0: if (Note > 0)Err_Message(); else  tone(buzzer, Octave0[Note]); break;
    case 1: if (Note > 11)Err_Message(); else tone(buzzer, Octave1[Note]); break;
    case 2: if (Note > 11)Err_Message(); else tone(buzzer, Octave2[Note]); break;
    case 3: if (Note > 11)Err_Message(); else tone(buzzer, Octave3[Note]); break;
    case 4: if (Note > 11)Err_Message(); else tone(buzzer, Octave4[Note]); break;
    case 5: if (Note > 11)Err_Message(); else tone(buzzer, Octave5[Note]); break;
    case 6: if (Note > 11)Err_Message(); else tone(buzzer, Octave6[Note]); break;
    case 7: if (Note > 11)Err_Message(); else tone(buzzer, Octave7[Note]); break;
    case 8: if (Note > 4)Err_Message(); else tone(buzzer, Octave8[Note]); break;
  }
}
void Err_Message() {
  vert_Value = 0;
  lcdPrintCenter("                    ", 1);
  lcdPrintCenter("                    ", 2);
  lcdPrintCenter("                    ", 3);
  lcdPrintCenter("Out of Range!", 3);
  //noTone(buzzer);
  play = false;
}