// SimulIDE Compilar=Arduino Board=Mega
/* ------------------------------------------------------ */
/* melody_player.ino - Melodyplayer */
/* ------------------------------------------------------ */
#include "pitches.h"
#include <Wire.h>
/* Define constants. ------------------------------------ */
/* Melodies. */
#define MELODIES 2
#define MELODY_NAME_LEN 15
#define MELODY_NOTES 10
/* Modes. */
#define MODE_SELECT 0
#define MODE_PLAY 1
/* Rotary encoder. */
#define ROTARY_EVENT_NONE 0
#define ROTARY_EVENT_SWITCH 1
#define ROTARY_EVENT_RIGHT 2
#define ROTARY_EVENT_LEFT 3
/* LCD. */
#define LCD_I2C_ADDR 0x3E
#define LCD_MODE_COMMAND 0x00
#define LCD_MODE_DATA 0x40
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINC 0x01
#define LCD_ENTRYSHIFTDEC 0x00
/* Typedefs. -------------------------------------------- */
typedef struct {
int frequency; /* Hz */
int duration; /* ms */
} note;
typedef struct {
char name[MELODY_NAME_LEN + 1];
note notes[MELODY_NOTES];
} melody;
/* Constants. ------------------------------------------- */
const melody melodies[MELODIES] = {
{
"Melodia A",
{ {NOTE_C4, 250}, {NOTE_G3, 125}, {NOTE_G3, 125}, {NOTE_A3, 250}, {NOTE_G3, 250}, {0, 250}, {NOTE_B3, 250}, {NOTE_C4, 250}, {0, 250}, {-1, 0} }
},
{
"Melodia B",
{ {NOTE_C3, 125}, {NOTE_C3, 125}, {NOTE_D3, 250}, {NOTE_C3, 250}, {NOTE_F3, 250}, {NOTE_E3, 500}, {0, 250}, {-1, 0}, {-1, 0}, {-1, 0} }
}
};
const int PIN_CLK = 2;
const int PIN_DT = 3;
const int PIN_BOTON = 4;
const int PIN_BUZZER = 8;
/* Global variables. ------------------------------------- */
int mode = MODE_SELECT;
int CLK_ANTERIOR = LOW;
int DT_ANTERIOR = LOW;
int BOTON_ANTERIOR = HIGH;
int buttonState = HIGH;
int prevButtonState = HIGH;
int prev_pos = 0;
/* Rotary encoder functions. ----------------------------- */
void rotarySetup() {
pinMode(PIN_CLK, INPUT);
pinMode(PIN_DT, INPUT);
pinMode(PIN_BOTON, INPUT_PULLUP);
}
int rotaryReadEvent() {
int CLK_ACTUAL = digitalRead(PIN_CLK);
int DT_ACTUAL = digitalRead(PIN_DT);
buttonState = digitalRead(PIN_BOTON);
int event = ROTARY_EVENT_NONE;
if (buttonState != prevButtonState) {
if (buttonState == LOW) {
event = ROTARY_EVENT_SWITCH;
if (mode == MODE_SELECT) {
mode = MODE_PLAY;
play_start();
play_show();
} else {
mode = MODE_SELECT;
play_stop();
melody_show();
}
}
prevButtonState = buttonState;
} else if (CLK_ACTUAL != CLK_ANTERIOR) {
CLK_ANTERIOR = CLK_ACTUAL;
if (DT_ACTUAL != CLK_ACTUAL) {
event = ROTARY_EVENT_LEFT;
} else {
event = ROTARY_EVENT_RIGHT;
}
}
return event;
}
/* LCD functions. ----------------------------------------- */
void lcdSend (unsigned char value, unsigned char mode) {
Wire.beginTransmission(LCD_I2C_ADDR);
Wire.write(mode);
Wire.write(value);
Wire.endTransmission();
delayMicroseconds(50);
}
void lcdSetup() {
Wire.begin();
lcdSend(LCD_FUNCTIONSET|LCD_8BITMODE|LCD_2LINE|LCD_5x8DOTS, LCD_MODE_COMMAND);
lcdSend(LCD_DISPLAYCONTROL|LCD_DISPLAYON|LCD_CURSOROFF|LCD_BLINKOFF, LCD_MODE_COMMAND);
lcdSend(LCD_CLEARDISPLAY, LCD_MODE_COMMAND);
delayMicroseconds(2000);
lcdSend(LCD_ENTRYMODESET|LCD_ENTRYLEFT|LCD_ENTRYSHIFTDEC, LCD_MODE_COMMAND);
}
void lcdClear(){
lcdSend(LCD_CLEARDISPLAY, LCD_MODE_COMMAND);
delayMicroseconds(2000);
}
void lcdSetCursor(int x,int y){
unsigned char value = 0;
if (y>0){
value = 0x40;
}
value += x;
lcdSend(LCD_SETDDRAMADDR | value, LCD_MODE_COMMAND);
}
void lcdPrint(const char *str) {
while (*str != 0) {
lcdSend(*str, LCD_MODE_DATA);
str++;
}
}
/* Play functions. --------------------------------------- */
int current_melody = 0;
int current_note = 0;
int current_speed = 100;
bool playing = false;
/* Play functions. --------------------------------------- */
void play_start() {
playing = true;
current_note = 0; // Reiniciar la nota actual
play_task(); // Reproducir la primera nota inmediatamente
}
void play_task() {
if (playing) {
static unsigned long previous_time = 0;
unsigned long current_time = millis();
unsigned long elapsed_time = current_time - previous_time;
if (elapsed_time >= melodies[current_melody].notes[current_note].duration * current_speed / 100) {
int frequency = melodies[current_melody].notes[current_note].frequency;
if (frequency >= 0) {
tone(PIN_BUZZER, frequency, melodies[current_melody].notes[current_note].duration);
} else {
noTone(PIN_BUZZER);
}
current_note++;
if (current_note >= MELODY_NOTES) {
// Reiniciar la nota actual para reproducir en bucle
current_note = 0;
} else if (frequency < 0) {
// Si la frecuencia es negativa, se alcanzó la última nota y se reproduce en bucle
current_note = MELODY_NOTES - 1;
}
previous_time = current_time;
delay(25); // Agregar un retardo de 25 ms entre notas
}
}
}
void play_stop()
{
playing = false;
noTone(PIN_BUZZER);
}
void play_decrease_speed()
{
current_speed--;
if (current_speed < 50) {
current_speed = 50;
}
}
void play_increase_speed()
{
current_speed++;
if (current_speed > 150) {
current_speed = 150;
}
}
void play_show()
{
lcdClear();
lcdSetCursor(0, 0);
lcdPrint(melodies[current_melody].name);
lcdSetCursor(0, 1);
lcdPrint("Notas:");
lcdSetCursor(6, 1);
char buffer[4];
itoa(MELODY_NOTES - 1, buffer, 10);
lcdPrint(buffer);
lcdSetCursor(10, 1);
itoa(current_speed, buffer, 10);
lcdPrint(buffer);
lcdPrint("%");
}
/* Melody functions. --------------------------------------- */
void melody_previous()
{
current_melody--;
if (current_melody < 0) {
current_melody = MELODIES - 1;
}
if (playing) {
play_start();
} else {
melody_show();
}
}
void melody_show()
{
lcdClear();
lcdSetCursor(0, 0);
lcdPrint("Pista:");
lcdSetCursor(8, 0);
lcdPrint(String(current_melody + 1).c_str());
lcdSetCursor(0, 1);
lcdPrint(melodies[current_melody].name);
}
void melody_next()
{
current_melody++;
if (current_melody >= MELODIES) {
current_melody = 0;
}
if (playing) {
play_start();
} else {
melody_show();
}
}
/* Mode control functions. --------------------------------------- */
void mode_select()
{
int event = rotaryReadEvent();
switch(event) {
case ROTARY_EVENT_SWITCH:
play_start();
play_show();
mode = MODE_PLAY;
break;
case ROTARY_EVENT_LEFT:
melody_previous();
melody_show();
break;
case ROTARY_EVENT_RIGHT:
melody_next();
melody_show();
break;
}
}
void mode_play()
{
play_task();
int event = rotaryReadEvent();
switch(event) {
case ROTARY_EVENT_SWITCH:
play_stop();
melody_show();
mode = MODE_SELECT;
break;
case ROTARY_EVENT_LEFT:
play_decrease_speed();
play_show();
break;
case ROTARY_EVENT_RIGHT:
play_increase_speed();
play_show();
break;
}
}
/* Arduino main functions. -------------------------------- */
void setup(){
lcdSetup();
rotarySetup();
melody_show();
}
void loop()
{
switch (mode) {
case MODE_SELECT:
play_task();
mode_select();
break;
case MODE_PLAY:
play_task();
mode_play();
break;
}
}
/* --------------------------------------------------------- */