Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
|
This need arose from the fact that within the Electronic Cat’s office there is a sound system where music is played, however only one device has control of the music, it also has an ambient lighting system using NeoPixel strips that were in disuse.
The objective of the project was to create an intuitive system with which any person could intuitively control the music for everyone without the need to have access to another person's device, since nowadays every device contains sensitive information, in addition to making use of the ambient lighting that was in place to illuminate a shelf of products.
The development of the project was based on the existing project created by a user of the Arduino community, Opla Spotify Controller, with which you can control the playback of music from a Spotify account through an API. From this project, we were making modifications and adding features to meet the objectives set at the beginning.
The main resource for the development is the Arduino products, both the Arduino MKR IoT Carrier and the Arduino MKR WiFi 1010 board since the original project on which this is based makes use of this hardware and it is necessary to have hardware with WiFi connectivity capabilities, with these two products could have an intuitive interface and hardware for the user showing information of the activity about the music playback through Spotify. And all powered by the tiny but very powerful CatSink!
DevelopmentDuring the development, there were some drawbacks at the hardware level. Arduino MKR IoT Carrier has capacitive buttons capable of detecting the presence of touches without the need to be physically touching these buttons, however, one of these buttons always detected a signal, these can be calibrated by software, but in our application, I could not make it work properly, so it was disabled by software.
Another impediment during development was the differences in libraries used by the different Arduino programmers, such as Arduino IDE, Arduino Web Editor, and Arduino IoT Cloud, and also the lack of knowledge of the number of LEDs that the NeoPixel strip had.
It is recommended to test the Arduino MKR IoT Carrier to rule out failures or take into account calibrations for the capacitive buttons as well as have well-defined functions and hardware that you want to use in the project.
Finally, this project is for those who are excited to learn more about the world of programming and Arduino mainly, since the code is commented in a way that makes it understandable by itself and it is also ready to download and use. However, it is also perfect for those users who have a broader knowledge of both programming and the capabilities of the hardware developed by Arduino being able to customize and add more functionality to the project.
Note: a small function is left with which you will hear the "Game Over" sound of Super Mario Bros every time the code is initialized.
How to make it work?These are the steps to follow to use this project (Arduino Web Editor):
- Make the connections of the sensors and actuators you will use if applicable.
- Download the file and import it to the Arduino Web Editor.
- Create a new application in Spotify Dashboard with the Spotify account that will be in use.
- Once the application is created we will need the following data, Client ID and Client Secret, you can find them by opening the created application.
- Inside our imported files you will find a tab called "Secret", where you will find empty spaces where you can write the requested credentials, such as your Spotify credentials that you just obtained following the previous steps, as well as the credentials of your WiFi network to which the card will connect.
- With the credentials ready it is time to connect your card to the PC and upload the code, remember to select the correct port and card.
- Once the code is uploaded to your board you will see a message with an IP address on the OLED screen of the Arduino MKR IoT Carrier.
- Go back to Spotify Dashboard and you will have to add this IP address to the Redirect URLs section, with the following format http:/[Arduino's IP Address]/redirect/, it is important to add it this way so you will not have problems authenticating. Finally, save the changes you made.
- Now that everything is ready, open a new tab in your browser and use the link with the IP address you just added to your app settings in Spotify Dashboard, you should see a green screen with the text Authenticate Spotify, click on it to access your Spotify account activity.
- You should now see an image with the control icons for your Spotify account on the Arduino MKR IoT carrier. Note: if the Spotify activity is not displayed press any of the buttons to refresh it.
- ¡Enjoy your music!
#include "arduino_secrets.h"
#include <ArduinoJson.h> //Mejor manejo de la memoria, Better memory managment
#include <ArduinoHttpClient.h>
#include <Arduino_MKRIoTCarrier.h>
#include <Adafruit_NeoPixel.h>
#include "thingProperties.h"//Necesario para conexion a internet //Needed to conect to internt
#include "Logo.h" //Se vincula el archivo donde esta nuestra imagen en C //Our imagen in C
#include "pitches.h"
//Configuracion de NeoPixel //NeoPixel variables
#define pin 5
#define numPixels 118
Adafruit_NeoPixel pixels(numPixels, pin, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 50
//Melodia que se tocara en el buzzer, Buzzer melody
/*int melody[] = {
NOTE_C5, NOTE_G4, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_A4,
NOTE_GS4, NOTE_AS4, NOTE_GS4, NOTE_G4, NOTE_D4, NOTE_E4
}; //Cancion de game over Super Mario //Super Mario's Game Over melody
//Duacion de las notas: 4 = cuarto de nota, 8 = octavo de nota, etc., Notes duration
int noteDurations[] = {
4, 4, 4, 8, 8, 8,
8, 8, 8, 8, 8, 2
};*/
//Configuracion de Spotify, Spotify config
enum DrawnState { None, Play, Pause };
const char SPOTIFY_CLIENT[] = SECRET_SPOTIFY_CLIENT; // Cliente ID de la aplicacion de Spotify, Spotify Client ID
const char SPOTIFY_SECRET[] = SECRET_SPOTIFY_SECRET; // Cliente secreto de la aplicacion de Spotify, Spotify Secret Client
const unsigned long TOKEN_REFRESH_RATE = 3000000;
const unsigned long UPDATE_REFRESH_RATE = 500;
//Web Server para autorizacion , Authentication web server
WiFiServer server(80); // Servidor para autorizacion de Spotify, Web server initalization
WiFiSSLClient ssl; // Cliente para peticiones HTTPS de Spotify , HTTPS client for Spotify requests
HttpClient authClient = HttpClient(ssl, "accounts.spotify.com", 443);
HttpClient apiClient = HttpClient(ssl, "api.spotify.com", 443);
MKRIoTCarrier carrier; //Incialia el carrier y le da nombre "carrier" , Start the carrier and name it
String accessToken;
String refreshToken;
bool authenticated = false;
unsigned long lastTokenTime = 0;
unsigned long lastTrackTime = 0;
int songProgress = 0;
DrawnState lastDrawnState = None;
//-----------------------------UTILIDADES------------------------ UTILITIES
// Crear filtro para solo obtener los parametros requeridos, Filter to get the parameters requiered
StaticJsonDocument<200> getFilter() {
StaticJsonDocument<200> filter;
// Colocar "true" para la informacion requerida , Set true for the requiered info
filter["is_playing"] = true;
filter["device"]["volume_percent"] = true;
filter["item"]["name"] = true;
filter["item"]["album"]["artists"] = true;
filter["item"]["duration_ms"] = true;
filter["progress_ms"] = true;
return filter;
}
// Imprime la cancion actual en el Serial , Prints the current song
void printCurrentSong() {
Serial.print("Reproduciendo ahora: ");
Serial.print(song_name);
Serial.print(" de ");
Serial.println(artist_name);
}
// Regresa el estilo de etiqueta HTML, Returns the style HTML tag
const char* getStyle() {
return "<style>html{height:100\%;display:grid;justify-content:center;align-content:center;"
"background-color:#1ED760;font-size:60px;}</style>";
}
String getHTML(const char* message) {
String html = "<!DOCTYPE html>\n";
html += "<html><body>";
html += getStyle();
html += "<div>";
html += message;
html += "</div></body></html>";
return html;
}
// Regresa el indice del ultimo espacio antes del limite, Returns the last space index
int lastSpaceBeforeThreshold(String text, int threshold) {
int prevIndex = 0;
int index = text.indexOf(' ');
while (index >= 0 && index < threshold) {
prevIndex = index;
index = text.indexOf(' ', index + 1);
}
return prevIndex;
}
//Regresa "true" si el indice de bit es 1, Returns true if the index bit is 1
bool isButtonPressed(byte states, byte index) {
return (states & (1 << index)) > 0;
}
//--------------------------------AUTORIZACION-------------------AUTORIZATION
//Obtener el token de autorizacion del usuario, get the authorization user's token
bool getAccessToken(String userCode) {
String postData = "grant_type=authorization_code&code=" + userCode + "&redirect_uri="
"http://" + ip_address + "/redirect/";
authClient.beginRequest();
authClient.post("/api/token");
authClient.sendHeader("Content-Type", "application/x-www-form-urlencoded");
authClient.sendHeader("Content-Length", postData.length());
authClient.sendBasicAuth(SPOTIFY_CLIENT, SPOTIFY_SECRET); // Envia las credenciales de Spotify, Send Spotify's credentials
authClient.beginBody();
authClient.print(postData);
authClient.endRequest();
// Si fue exitoso , If succesful
if (authClient.responseStatusCode() == 200) {
lastTokenTime = millis();
DynamicJsonDocument json(512);
deserializeJson(json, authClient.responseBody());
accessToken = json["access_token"].as<String>();
refreshToken = json["refresh_token"].as<String>();
return true;
}
return false;
}
// Actualiza el token de autorizacion del usuario , Update the token
void refreshAccessToken() {
String postData = "grant_type=refresh_token&refresh_token=" + refreshToken;
authClient.beginRequest();
authClient.post("/api/token");
authClient.sendHeader("Content-Type", "application/x-www-form-urlencoded");
authClient.sendHeader("Content-Length", postData.length());
authClient.sendBasicAuth(SPOTIFY_CLIENT, SPOTIFY_SECRET); // Envia las credenciales de Spotify, Send Spotify's credentials
authClient.beginBody();
authClient.print(postData);
authClient.endRequest();
// Si fue exitoso, If succesful
if (authClient.responseStatusCode() == 200) {
lastTokenTime = millis();
DynamicJsonDocument json(256);
deserializeJson(json, authClient.responseBody());
accessToken = json["access_token"].as<String>();
}
}
//----------------------------------PETICION API-------------------------API REQUEST
//Obtener el estado actual del reproductor, Get the status of the player
void getPlayerState() {
apiClient.beginRequest();
apiClient.get("/v1/me/player");
apiClient.sendHeader("Authorization", "Bearer " + accessToken);
apiClient.endRequest();
int statusCode = apiClient.responseStatusCode();
// Si fue exitoso y esta reproduciendo (se debe de obtener el codigo de estado 204), If sucessful ans it is playing (status code 204)
if (statusCode == 200) {
// Crea un filtro ya que la respuesta es muy prolongada para que el Arduino lo soporte, Creta a filter to the Arduino be able to handle it
StaticJsonDocument<200> filter = getFilter();
DynamicJsonDocument json(4096);
deserializeJson(json, apiClient.responseBody(), DeserializationOption::Filter(filter));
is_playing = json["is_playing"].as<bool>();
volume_percent = json["device"]["volume_percent"].as<int>();
// Si la cancion a cambiado, If the song changes
if (song_name != json["item"]["name"].as<String>()) {
songProgress = json["progress_ms"].as<int>();
}
song_name = json["item"]["name"].as<String>();
artist_name = json["item"]["album"]["artists"][0]["name"].as<String>();
song_length = json["item"]["duration_ms"].as<int>();
is_active = true;
printCurrentSong();
} else {
is_active = false;
is_playing = false;
}
updatePlayerDisplay();
}
//Saltar cancion en una direccion dada //Change song in a given direction
void skipSong(String direction) {
apiClient.beginRequest();
apiClient.post("/v1/me/player/" + direction);
apiClient.sendHeader("Content-Length", 0);
apiClient.sendHeader("Authorization", "Bearer " + accessToken);
apiClient.endRequest();
}
//Saltar a la cancion anterior, Previous Song
void previousSong() {
skipSong("previous");
getPlayerState();
}
//Saltar a la cancion siguiente, Next Song
void nextSong() {
skipSong("next");
getPlayerState();
}
//Volumen del reproductor, Volume
void setVolume(int newVolume) {
apiClient.beginRequest();
apiClient.put("/v1/me/player/volume?volume_percent=" + String(newVolume));
apiClient.sendHeader("Content-Length", 0);
apiClient.sendHeader("Authorization", "Bearer " + accessToken);
apiClient.endRequest();
}
// Subir volumen en un 5 pociento, Turn up the volume in 5%
/*void volumeUp() {
int newVolume = volume_percent > 95 ? 100 : volume_percent + 5;
setVolume(newVolume);
getPlayerState();
}*/
//Bajar Volumen en un 10 porciento, Turn down the volume in 10%
void volumeDown() {
int newVolume = volume_percent < 5 ? 0 : volume_percent - 10;
setVolume(newVolume);
getPlayerState();
}
//Cambio entre play/pause, Play/Pause
void playPause() {
apiClient.beginRequest();
apiClient.put("/v1/me/player/" + String(is_playing ? "pause" : "play"));
apiClient.sendHeader("Content-Length", 0);
apiClient.sendHeader("Authorization", "Bearer " + accessToken);
apiClient.endRequest();
getPlayerState();
}
//----------------------------------CONTROL DE LEDS--------------------------------- LED CONTROL
//Encender todos los LEDs en verde, Turn the LEDs in a green color
void flashLEDs() {
for (int i = 0; i < 2; i++) {
carrier.leds.setPixelColor(0, 0, 128, 0);
carrier.leds.setPixelColor(1, 0, 128, 0);
carrier.leds.setPixelColor(2, 0, 128, 0);
carrier.leds.setPixelColor(3, 0, 128, 0);
carrier.leds.setPixelColor(4, 0, 128, 0);
carrier.leds.show();
delay(100);
turnOffLEDs();
delay(100);
}
}
//Ciclo de LEDs, LED's cycle
void cycleLEDs() {
carrier.leds.setPixelColor(0, 0, 128, 0);
carrier.leds.show();
delay(20);
carrier.leds.setPixelColor(0, 0);
carrier.leds.setPixelColor(1, 0, 128, 0);
carrier.leds.show();
delay(20);
carrier.leds.setPixelColor(1, 0);
carrier.leds.setPixelColor(2, 128, 0, 0);
carrier.leds.show();
delay(20);
carrier.leds.setPixelColor(2, 0);
carrier.leds.setPixelColor(3, 0, 128, 0);
carrier.leds.show();
delay(20);
carrier.leds.setPixelColor(3, 0);
carrier.leds.setPixelColor(4, 0, 128, 0);
carrier.leds.show();
delay(20);
carrier.leds.setPixelColor(4, 0);
carrier.leds.show();
}
//Apagar todos los LEDs, Turn off the LEDs
void turnOffLEDs() {
carrier.leds.setPixelColor(0, 0);
carrier.leds.setPixelColor(1, 0);
carrier.leds.setPixelColor(2, 0);
carrier.leds.setPixelColor(3, 0);
carrier.leds.setPixelColor(4, 0);
carrier.leds.show();
}
//------------------------------CONTROL DE BOTONES------------------- BUTTONS CONROL
//Obetener el estado de todos los botones al mismo tiempo, Get the status of all the buttons at once
byte getButtonStates() {
byte states = 0;
states |= carrier.Buttons.onTouchDown(TOUCH0) << 0;
states |= carrier.Buttons.onTouchDown(TOUCH1) << 1;
states |= carrier.Buttons.onTouchDown(TOUCH2) << 2;
/*states |= carrier.Buttons.onTouchDown(TOUCH3) << 3;*/ //No funciona bien este boton, this buttons didnt work well for us!
states |= carrier.Buttons.onTouchDown(TOUCH4) << 4;
return states;
}
// Checar el estadode los botones y actuar de forma adecuada, Chek the buttons statu
void checkButtonStates() {
carrier.Buttons.update();
byte states = getButtonStates();
if (!authenticated) {
if (states > 0) {
flashLEDs();
}
} else if (!is_active) {
if (states > 0) {
cycleLEDs();
getPlayerState();
}
} else {
// Button 0 - Bajar Volumen, Tunr down volume
if (isButtonPressed(states, 0)) {
carrier.leds.setPixelColor(0, 128, 0, 0);
carrier.leds.show();
volumeDown();
carrier.leds.setPixelColor(0, 0);
carrier.leds.show();
return;
}
// Button 1 - Cancion previa, Previous song
if (isButtonPressed(states, 1)) {
carrier.leds.setPixelColor(1, 128, 0, 0);
carrier.leds.show();
previousSong();
carrier.leds.setPixelColor(1, 0);
carrier.leds.show();
return;
}
// Button 2 - Play/Pause,
if (isButtonPressed(states, 2)) {
carrier.leds.setPixelColor(2, 128, 0, 0);
carrier.leds.show();
playPause();
carrier.leds.setPixelColor(2, 0);
carrier.leds.show();
return;
}
// Button 3 - Subir Volumen, Turn Up volume
/*if (isButtonPressed(states, 3)) {
carrier.leds.setPixelColor(3, 128, 0, 0);
carrier.leds.show();
volumeUp();
carrier.leds.setPixelColor(3, 0);
carrier.leds.show();
return;
}*/
// Button 4 - Canccion siguiente, Next Song
if (isButtonPressed(states, 4)) {
carrier.leds.setPixelColor(4, 128, 0, 0);
carrier.leds.show();
nextSong();
carrier.leds.setPixelColor(4, 0);
carrier.leds.show();
return;
}
}
}
//----------------------------CONTROL DE DISPLAY-------------------- DISPLAY CONTROL
//Imprimir iconos de reproductor, Print player icons
void printMediaIcons() {
// Regresar cancion, Previous song
carrier.display.fillTriangle(38, 51, 51, 43, 51, 59, ST77XX_WHITE);
carrier.display.fillTriangle(51, 51, 64, 43, 64, 59, ST77XX_WHITE);
// Saltar cancion, Next song
carrier.display.fillTriangle(189, 154, 189, 170, 202, 162, ST77XX_WHITE);
carrier.display.fillTriangle(202, 154, 202, 170, 215, 162, ST77XX_WHITE);
// Subir volumen, Turn up volume
//carrier.display.fillRect(203, 43, 8, 24, ST77XX_WHITE);
//carrier.display.fillRect(195, 8, 24, 8, ST77XX_WHITE);
carrier.display.setTextColor(ST77XX_WHITE);
carrier.display.setTextSize(1); // 6 x 8
carrier.display.setCursor(170, 51);
carrier.display.print("No Sirvo"); //I dont work in spanish lol
carrier.display.setTextWrap(true);
// Bajar volumen, Turn Down volume
carrier.display.fillRect(21, 162, 24, 8, ST77XX_WHITE);
// Play/Pause
printPlayPause();
}
//Imprimir el logo, Print logo
void printLogo() {
carrier.display.drawBitmap(60, 60, LOGO, 120, 120, 0x26CC);
}
//Inicializar el display, Starts the display
void initializePlayerDisplay() {
carrier.display.fillScreen(ST77XX_BLACK);
printLogo();
printMediaIcons();
}
//Dibujar el icono de play o pausa dependiendo si esta reproduciendo, Draw the play/pause icon depending on the status
void printPlayPause() {
if (lastDrawnState == (is_playing ? Pause : Play)) {
return;
}
// Primero borrar el display, Erase the display
carrier.display.fillRect(105, 1, 30, 30, ST77XX_BLACK);
// Ahora, dibuja el icono correspondiente, Draw the correct icon
if (is_playing) {
// Pause icono, Pause
carrier.display.fillRect(113, 6, 5, 23, ST77XX_WHITE);
carrier.display.fillRect(122, 6, 5, 23, ST77XX_WHITE);
} else {
// Play icono, Play
carrier.display.fillTriangle(112, 4, 112, 26, 128, 15, ST77XX_WHITE);
}
lastDrawnState = is_playing ? Pause : Play;
}
//Extiende la barra de progreso si la cancion se esta reproduciendo, ademas la elimina, Extend the progress bar if the song is playing
void updateTrackBar() {
if (is_playing) {
songProgress += millis() - lastTrackTime;
if (songProgress > song_length) {
getPlayerState();
return;
}
carrier.display.drawRect(80, 220, 80, 5, ST77XX_GREEN); // Dibuja el contorno de la barra de progreso, Draw the outline of the progress bar
int progress = 78 * songProgress / song_length;
carrier.display.fillRect(81, 221, progress, 3, ST77XX_WHITE); // Dibuja la barra de progreso, Draw the progress bar
carrier.display.fillRect(81 + progress, 221, 76 - progress, 3, ST77XX_BLACK); // Dibuja la barra que en negro (la parte que aun no esta en progreo), Draw the progress bar of the unplayed part of the song
} else {
carrier.display.fillRect(80, 220, 80, 5, ST77XX_BLACK); // Elimina la barra de progreso, Erase the progress bar
}
lastTrackTime = millis();
}
//Actualiza el nombre de la cancion si la cancion se esta reproduciendo, si no la elimina, Update the name of the song if is playing
void updateTrackName() {
carrier.display.fillRect(70, 186, 100, 33, ST77XX_BLACK); // Elimina el nombre de la cancion, Erase the song name
if (is_playing) {
// Imprime el nombre de la cancion, Print the song name
carrier.display.setTextColor(ST77XX_WHITE);
carrier.display.setTextSize(1); // 6 x 8
carrier.display.setCursor(70, 186);
if (song_name.length() > 16) {
// Intenta no partir palabras a la mitad, Try to no break words
int lastSpace = lastSpaceBeforeThreshold(song_name, 16);
if (lastSpace > 0) {
carrier.display.print(song_name.substring(0, lastSpace));
carrier.display.setCursor(70, 194);
carrier.display.print(song_name.substring(lastSpace + 1, song_name.length() > lastSpace + 17 ?
lastSpace + 17 : song_name.length()));
} else {
carrier.display.print(song_name.substring(0, 16));
carrier.display.setCursor(70, 194);
carrier.display.print(song_name.substring(16, song_name.length() > 32 ? 32 : song_name.length()));
}
} else {
carrier.display.print(song_name);
}
// Imprime el nombre del artista, Print the artist name
carrier.display.setTextColor(0xCE59); // Gris, Gray
carrier.display.setTextSize(1); // 6 x 8
carrier.display.setCursor(70, 209);
carrier.display.print(artist_name.substring(0, artist_name.length() > 16 ? 16 : artist_name.length()));
}
}
//Actualiza el estado del reproductor, Update the status of the player
void updatePlayerDisplay() {
printPlayPause();
updateTrackBar();
updateTrackName();
}
//Imprime el mensaje de autenticacion, Print the authentication message
void printAuthMessage() {
carrier.display.fillScreen(ST77XX_BLACK);
carrier.display.setTextColor(ST77XX_WHITE);
carrier.display.setTextSize(2); // 12 x 16
carrier.display.setCursor(80, 92);
carrier.display.print("Porfavor");
//carrier.display.print("Please");
carrier.display.setCursor(30, 110);
carrier.display.print("autentica en");
//carrier.display.print("Authenticate in");
carrier.display.setCursor(30 + (22 - ip_address.length()) / 2, 128);
carrier.display.print(ip_address);
}
//-------------------------EVENTOS--------------------- EVENTS
//Actualiza la direccion IP cuando se conecta, Update the IP address when is connected
void onNetworkConnect() {
IPAddress ip = WiFi.localIP();
ip_address = String(ip[0]) + "." + String(ip[1]) + "." + String(ip[2]) + "." + String(ip[3]);
printAuthMessage();
Serial.println("Please authenticate at " + ip_address);
}
//-----------------------------------SETUP Y LOOP-----------------------
void setup() {
Serial.begin(9600);
//Inicializar las variables // initialize the variables
volume_percent = 0;
song_length = 0;
is_active = false;
is_playing = false;
song_name = "";
artist_name = "";
carrier.Buzzer.beep();
delay(400);
carrier.Buzzer.noSound();
// Definido en thingProperties.h, Defined in thingProperties.h
initProperties();
// Conectar a Arduino IoT Cloud //Connect to Ardino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection, false); // disable watchdog restart
// Anadir una coneccion de llamada, Add a callback connection
ArduinoIoTPreferredConnection.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect);
//Inicializar el carrier, Initialize the carrier
CARRIER_CASE = true;
carrier.begin();
carrier.display.setRotation(0);
/*//Iteracion de las notas de la melodia, Iteration of the notes of the melody
for (int thisNote = 0; thisNote < 8; thisNote++) {
//Para calcular la duracion de las notas, toma 1 segundo dividido por el tipo de nota. To calculate the duration of the notes, take 1 second divided by the type of note
//Ejemplo: Cuarto de nota = 1000/4, etc.
int noteDuration = 1000 / noteDurations[thisNote];
carrier.Buzzer.sound(melody[thisNote]);
delay(noteDuration);
// Para distinguir las notas, configura un minimo de tiempo entre ellos.To distinguish the notes, set a minimum time between them
// la duracion de las notas + 50% trabaja bien. Note duration + 50% works fine
int pauseBetweenNotes = noteDuration * 1.50;
delay(pauseBetweenNotes);
// Detener los sonidos, stop the sound
carrier.Buzzer.noSound();
}*/
//Iniciar el server, Initialize the server
server.begin();
//NeoPixel
pixels.begin(); // Inicializa la barra de NeoPixel, Initalize the NeoPixel Strip
//COLOR
pixels.clear(); // Apaga todos los LEDs, Turn off the leds
//Prende en colores la barra, turn on the strip with colors
for (int i = 0; i < 59; i++) { // Para cada LED... For each LED...
pixels.setPixelColor(i, pixels.Color(0, 255, 100));
pixels.show();
delay(DELAYVAL);
}
// Segunda hilera de LEDs, Second LEDs row
for (int i = 60; i < 118; i++) {
pixels.setPixelColor(i, pixels.Color(255, 0, 255));
pixels.show();
delay(DELAYVAL);
}
}
void loop() {
ArduinoCloud.update();
checkButtonStates();
if (!authenticated) {
// Esperar a que el usuario se conecte, Wait to the user to connect
WiFiClient wifiClient = server.available();
// Si el usuario se ha conectado, If the user has connected
if (wifiClient) {
// Obtener la peticion, Get the request
String header = "";
while (wifiClient.available()) {
header += char(wifiClient.read());
}
// Si esta autenticado, redirigir, If authenticated, redirect
if (header.indexOf("?code") >= 0) {
// Analizar el token, Analize the token
String userCode = header.substring(header.indexOf("code=") + 5, header.indexOf("HTTP/1.1") - 1);
authenticated = getAccessToken(userCode);
if (authenticated) {
wifiClient.print(getHTML("Authenticated!"));
initializePlayerDisplay();
getPlayerState();
} else {
wifiClient.print(getHTML("Authentication failed."));
}
} else if (header.indexOf("?error") >= 0) {
wifiClient.print(getHTML("Cancelled."));
}
else {
// Autenticar el usuario y el token, Authenticate the user and the token
String webpage = "<!DOCTYPE html>\n";
webpage += "<html><body>";
webpage += getStyle();
webpage += "<a href=\"https://accounts.spotify.com/authorize?client_id=";
webpage += SPOTIFY_CLIENT;
webpage += "&response_type=code&redirect_uri=http://";
webpage += ip_address;
webpage += "/redirect/&scope=user-read-playback-state "
"user-modify-playback-state\">Authenticate Spotify</a>\n";
webpage += "</body></html>";
wifiClient.print(webpage);
}
wifiClient.stop();
}
} else if (millis() - lastTokenTime > TOKEN_REFRESH_RATE) {
// Refrescar token si esta a punto de expirar, Refresh the token if is about to expire
refreshAccessToken();
} else if (millis() - lastTrackTime > UPDATE_REFRESH_RATE) {
// Actualzar la barra de progreso, Update the progress bar
updateTrackBar();
}
}
#define SECRET_SPOTIFY_CLIENT ""
#define SECRET_SPOTIFY_SECRET ""
#define SECRET_SSID ""
#define SECRET_PASS ""
// Code generated by Arduino IoT Cloud, DO NOT EDIT.
#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>
const char SSID[] = SECRET_SSID; // Network SSID (name)
const char PASS[] = SECRET_PASS; // Network password (use for WPA, or use as key for WEP)
String artist_name;
String ip_address;
String song_name;
int song_length;
int volume_percent;
bool is_active;
bool is_playing;
void initProperties(){
ArduinoCloud.addProperty(artist_name, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(ip_address, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(song_name, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(song_length, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(volume_percent, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(is_active, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(is_playing, READ, ON_CHANGE, NULL);
}
WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
// Logo, https://github.com/bitbank2/image_to_c
const unsigned char LOGO[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff,
0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x80,
0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00,
0x00, 0x00, 0x00, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00,
0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01,
0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff,
0xff, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfc,
0x00, 0x7e, 0x00, 0x3f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x3f,
0xff, 0xfc, 0x3f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe1, 0xff, 0xff, 0xff,
0xff, 0xff, 0x87, 0xff, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff,
0xf8, 0x03, 0xff, 0x80, 0x03, 0xe0, 0x07, 0xe0, 0x01, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xc0,
0x03, 0xff, 0x80, 0x07, 0xf0, 0x0e, 0x60, 0x03, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x03,
0xff, 0xc0, 0x06, 0x70, 0x0c, 0x70, 0x03, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x03, 0xff,
0xc0, 0x0e, 0x30, 0x0e, 0x7c, 0x03, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xc0,
0x3e, 0x30, 0x0f, 0xff, 0x03, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xc0, 0xff,
0xf0, 0x07, 0xff, 0xc7, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xe3, 0xff, 0xe0,
0x01, 0x0f, 0xf7, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xef, 0xf0, 0x80, 0x00,
0x03, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f,
0xff, 0xf0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
0xf0, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf8,
0x00, 0x07, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00,
0x07, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x3c, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x07,
0xff, 0xe0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3c, 0x7e, 0x00, 0x07, 0xff, 0xff, 0x00, 0x07, 0xff,
0xe0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x7e, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xe0,
0x03, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xe0, 0x1f,
0xff, 0xff, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe7, 0x7f, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x00, 0xfe, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0x7e, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x18, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xfe, 0x00, 0x00, 0x00, 0x01, 0xfe,
0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0x80, 0x00, 0x00, 0x07, 0xf8, 0x03,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xe0, 0x00, 0x03, 0xdf, 0xe0, 0x01, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xfb, 0xc0, 0x07, 0xff, 0x80, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xe0, 0x0e, 0x7c, 0x00, 0x00, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3e, 0x70, 0x0c, 0x78, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf8, 0x00, 0x00, 0x0e, 0x30, 0x0c, 0x70, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff,
0xff, 0xe0, 0x00, 0x00, 0x06, 0x30, 0x0f, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x00, 0x00, 0x07, 0xf0, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x00,
0x00, 0x00, 0x07, 0xe0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00,
0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/*************************************************
* Public Constants
*************************************************/
#define REST 0
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
Comments