#include <Arduino.h>
#define BUZZER_PIN 8

// Classe per rappresentare una melodia
class Melodia {
  private:
    char nome[32]; // Nome della melodia
    int tempo; // Tempo in battiti al minuto
    int ottave; // Numero di ottave
    int velocita; // velocita in battiti al minuto
    
    // Array di note e pause
    struct Nota {
      int durata;
      int altezza;
    } note[100];
    int numNote;
  
  public:
    Melodia() {}

    // Estrae le informazioni dalla stringa
    void carica(const char* str) {

      // Nome
      int i = 0;
      while (str[i] != ':') {
        nome[i] = str[i];
        i++;
      }
      nome[i] = '\0';
      Serial.print("Brano: "); Serial.println(nome);

      // Impostazioni di base
      // Estrazione dei valori di d, o e b dalla stringa
      char *token = strtok(str, ":");
      while (token != NULL) {
        if (strstr(token, "d=")) {
          tempo = atoi(strstr(token, "d=") + 2);
          Serial.print("Tempo: "); Serial.println(tempo);
        } else if (strstr(token, "o=")) {
          ottave = atoi(strstr(token, "o=") + 2);
          Serial.print("Ottava: "); Serial.println(ottave);
        } else if (strstr(token, "b=")) {
          velocita = atoi(strstr(token, "b=") + 2);
          Serial.print("Velocita: "); Serial.println(velocita);
        } else {
          // Estrazione delle note con relativa durata e altezza
          char *noteToken = strtok(token, ",");
          while (noteToken != NULL) {
            char *durationPtr = noteToken;
            char *notePtr = strchr(noteToken, ':');
            int duration = atoi(durationPtr);
            if (notePtr != NULL) {
              notePtr++;
              int noteValue = frequencyFromNoteName(notePtr, ottava);
              Serial.print("Nota: ");
              Serial.print(noteValue);
              Serial.print(", Durata: ");
              Serial.println(duration);
            }
            noteToken = strtok(NULL, ",");
          }
        }
        token = strtok(NULL, ":");
      }
    }

    // Suona la melodia
    void suona() {
      for (int i = 0; i < numNote; i++) {
        int frequenza = 440 * pow(2, (note[i].altezza - 69) / 12.0) * ottave;
        tone(BUZZER_PIN, frequenza, note[i].durata * (60000 / tempo));
        delay(note[i].durata * (60000 / tempo));
      }
    }

    // Stampa le informazioni della melodia
    void stampa() {
      Serial.print("Nome: ");
      Serial.println(nome);
      Serial.print("Tempo: ");
      Serial.println(tempo);
      Serial.print("Ottave: ");
      Serial.println(ottave);
      Serial.print("velocita: ");
      Serial.println(velocita);
      Serial.println("Note:");
      for (int i = 0; i < numNote; i++) {
        Serial.print(note[i].durata);
        Serial.print(",");
        Serial.println(note[i].altezza);
      }
    }
};

char takeOnMe[] = "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5";

// Funzione di setup
void setup() {
  // Inizializzazione
  Serial.begin(9600);
  Serial.println("Avvio...");
  pinMode(BUZZER_PIN, OUTPUT);

  // Crea un'istanza della classe Melodia
  Melodia melodia;

  // Carica la melodia dalla stringa
  melodia.carica(takeOnMe);

  // Stampa le informazioni della melodia
  melodia.stampa();

  // Suona la melodia
  melodia.suona();
}

// Funzione di loop
void loop() {
  // Niente da fare qui
}