/*
Tirando um som no Arduino Nano, com Dante Meira
*/
unsigned long temposil_inicio = 0; // variável auxiliar para medir tempo de silêncio entre notas
unsigned long temposil_agora = 0; // variável auxiliar para medir tempo de silêncio entre notas
unsigned long tempo1 = 0;
unsigned long tempo2 = 0;
unsigned long long microssegundos1 = 0;
unsigned long long microssegundos2 = 0;
unsigned long long microssegundos3 = 0;
unsigned long long microssegundos4 = 0;

unsigned long tempo_pisca = 0;
						
 // frequências das notas musicais
 // fonte: https://www.if.ufrgs.br/cref/ntef/som/oitavas.html           
const double Do4 = 261.63;
const double Re4 = 293.66;
const double Mi4 = 329.63;
const double Fa4 = 349.23;
const double Sol4 = 391.99;
const double La4 = 440.00;
const double Si4 = 485.80;
	
const double Do5 = 523.25;
const double Re5 = 587.33;
const double Mi5 = 659.26;
const double Fa5 = 698.46;
const double Sol5 = 783.99;
const double La5 = 880.00;
const double Si5 = 971.60;
					
const double Do6 = 1046.5;
const double Re6 = 1174.7;
const double Mi6 = 1318.5;
const double Fa6 = 1396.9;
const double Sol6 = 1568.0;
const double La6 = 1760.0;
const double Si6 = 1943.2;
						
const double Do7 = 2093.0;
const double Re7 = 2349.3;
const double Mi7 = 2637.0;
const double Fa7 = 2793.8;
const double Sol7 = 3136.0;
const double La7 = 3520.0;
const double Si7 = 3886.4;

double notaAF2;
double notaAF3;

typedef struct{
    double nota1;
    double nota2;
    int silencio; // tempo de silêncio após estas notas
}notas;

notas melodia[22]; // array de struct notas 

double hertz = 1;
double aux = 1;
unsigned long intervaloAF2 = 1;
unsigned long intervaloAF3 = 1;

boolean boolAF2 = false;
boolean boolAF3 = false;
boolean intervalo = false; // variável intervalo é iniciada como false

#define AF2 2 // AF2 = autofalante conectado ao pino 2
#define AF3 3 // AF3 = autofalante conectado ao pino 3

#define VERMELHO 12
#define VERDE 11
#define AZUL 10
#define AMARELO 9

int tam_array;
int pos_array;
int mil_inter = 0; // quantidade de milésimos de segundo do intervalo de silêncio atual

void setup() {
  pinMode(AF2, OUTPUT);
  pinMode(AF3, OUTPUT);
  pinMode(VERMELHO, OUTPUT);
  pinMode(VERDE, OUTPUT);
  pinMode(AZUL, OUTPUT);
  pinMode(AMARELO, OUTPUT); 

 pinMode(13, OUTPUT); 

// configurando a sequencia de notas da melodia

  melodia[0].nota1 = Do5;
  melodia[0].nota2 = Do5;
  melodia[0].silencio = 70;

  melodia[1].nota1 = Re5;
  melodia[1].nota2 = Re5;
  melodia[1].silencio = 70;

  melodia[2].nota1 = Mi5;
  melodia[2].nota2 = Mi5;
  melodia[2].silencio = 70;

  melodia[3].nota1 = Fa5;
  melodia[3].nota2 = Fa5;
  melodia[3].silencio = 170;

  melodia[4].nota1 = Fa5;
  melodia[4].nota2 = Fa6;
  melodia[4].silencio = 70;

  melodia[5].nota1 = Fa5;
  melodia[5].nota2 = Fa6;
  melodia[5].silencio = 150;

  melodia[6].nota1 = Do5;
  melodia[6].nota2 = Do6;
  melodia[6].silencio = 70;

  melodia[7].nota1 = Re5;
  melodia[7].nota2 = Re6;
  melodia[7].silencio = 70;

  melodia[8].nota1 = Do5;
  melodia[8].nota2 = Do6;
  melodia[8].silencio = 70;

  melodia[9].nota1 = Re5;
  melodia[9].nota2 = Re6;
  melodia[9].silencio = 170;      

  melodia[10].nota1 = Re5;
  melodia[10].nota2 = Re6;
  melodia[10].silencio = 70;  

  melodia[11].nota1 = Re5;
  melodia[11].nota2 = Re6;
  melodia[11].silencio = 150;     

  melodia[12].nota1 = Do5;
  melodia[12].nota2 = Do6;
  melodia[12].silencio = 70;  

  melodia[13].nota1 = Sol5;
  melodia[13].nota2 = Sol6;
  melodia[13].silencio = 70;  

  melodia[14].nota1 = Fa5;
  melodia[14].nota2 = Fa6;
  melodia[14].silencio = 70;  

  melodia[15].nota1 = Mi5;
  melodia[15].nota2 = Mi6;
  melodia[15].silencio = 170; 

  melodia[16].nota1 = Mi5;
  melodia[16].nota2 = Mi6;
  melodia[16].silencio = 70; 

  melodia[17].nota1 = Mi5;
  melodia[17].nota2 = Mi6;
  melodia[17].silencio = 170; 

  melodia[18].nota1 = Do5;
  melodia[18].nota2 = Do7;
  melodia[18].silencio = 70; 

  melodia[19].nota1 = Re5;
  melodia[19].nota2 = Re7;
  melodia[19].silencio = 70;    

  melodia[20].nota1 = Mi5;
  melodia[20].nota2 = Mi7;
  melodia[20].silencio = 70; 

  melodia[21].nota1 = Fa5;
  melodia[21].nota2 = Fa7;
  melodia[21].silencio = 370;    

  tam_array = 22; // informando tamanho do array da melodia
  pos_array = 0;


 while(true){
      TocaNotas(melodia);

      /* todo o código abaixo da chamada à função TocaNotas será executado durante
        os intervalos de silêncio entre uma nota e outra
      */
      if( (millis() - tempo_pisca) > 250 ){
            digitalWrite(13, ( !(digitalRead(13)) ) );
            tempo_pisca = millis();
      }


 }
}


void TocaNotas(notas melo[]){

     if(intervalo == true){
         temposil_agora = millis();
         if (temposil_agora < temposil_inicio + mil_inter){           
             return; // sai da função se ainda estiver no período de intervalo entre as notas
         }else{
          intervalo = false;         
         }
     }     

     notaAF2 = melo[pos_array].nota1;
     notaAF3 = melo[pos_array].nota2;

      if(notaAF2 == Do5){
          digitalWrite(VERMELHO, HIGH);
          digitalWrite(VERDE, LOW);
          digitalWrite(AZUL, LOW);
          digitalWrite(AMARELO, LOW);
      }   
      if(notaAF2 == Re5){
          digitalWrite(VERMELHO, LOW);
          digitalWrite(VERDE, HIGH);
          digitalWrite(AZUL, LOW);
          digitalWrite(AMARELO, LOW);
      }        
      if(notaAF2 == Mi5){
          digitalWrite(VERMELHO, LOW);
          digitalWrite(VERDE, LOW);
          digitalWrite(AZUL, HIGH);
          digitalWrite(AMARELO, LOW);
      }  
       if(notaAF2 == Fa5){
          digitalWrite(VERMELHO, LOW);
          digitalWrite(VERDE, LOW);
          digitalWrite(AZUL, LOW);
          digitalWrite(AMARELO, HIGH);
      }        

      tempo2 = millis();
      microssegundos1 = micros();
      microssegundos2 = micros();
      microssegundos3 = micros();
      microssegundos4 = micros();      

      hertz = notaAF2;
      aux = (1000000/hertz) ;
      intervaloAF2 = round(aux);

      hertz = notaAF3;
      aux = (1000000/hertz) ;
      intervaloAF3 = round(aux);

    while(tempo1 < (tempo2 + 80)){   // cada nota tem duração de 80 milissegundos

      if( microssegundos2 < microssegundos1 + intervaloAF2){
            microssegundos2 = micros();
      }else{
           microssegundos1 = micros();
            if(boolAF2 == false){
                boolAF2 = true;
                digitalWrite(AF2, HIGH);
            }else{
                boolAF2 = false;
                digitalWrite(AF2, LOW);
            }
      }    


      if( microssegundos4 < microssegundos3 + intervaloAF3){
            microssegundos4 = micros();
      }else{
           microssegundos3 = micros();
            if(boolAF3 == false){
                boolAF3 = true;
                digitalWrite(AF3, HIGH);
            }else{
                boolAF3 = false;
                digitalWrite(AF3, LOW);
            }
      }  

      tempo1 = millis();
      asm volatile ("nop   \n\t");     
    }

    if(intervalo == false){ 
          temposil_inicio = millis();
          mil_inter = melo[pos_array].silencio; // milésimos de segundo para o próximo intervalo de silêncio
          if(pos_array == tam_array-1){ pos_array = 0; }else{ pos_array++ ; }
          intervalo = true;
       }
  
}