#include "pitches.h"

#define REST 0
#define SPEAKER_PIN 8

// 按钮引脚
const uint8_t buttonPins[] = { 12, 11, 10, 9, 7, 6, 5, 4 };
const int numButtons = sizeof(buttonPins) / sizeof(buttonPins[0]);

// 第一首歌
const int melody1[] = { 
    REST,NOTE_F4,NOTE_FS4,NOTE_GS4,NOTE_AS4,NOTE_AS3,NOTE_CS4,NOTE_CS5,NOTE_AS4,NOTE_CS3,NOTE_F3,NOTE_GS3,
    NOTE_F4,NOTE_FS4,NOTE_GS4,NOTE_AS4,NOTE_AS3,NOTE_CS4,NOTE_CS5,NOTE_AS4,NOTE_GS4,NOTE_AS4,NOTE_FS4,NOTE_GS4,
    NOTE_F4,NOTE_FS4,NOTE_CS4,NOTE_F4,NOTE_FS4,NOTE_GS4,NOTE_AS4,NOTE_AS3,NOTE_CS4,NOTE_CS5,NOTE_AS4,
    NOTE_CS3,NOTE_F3,NOTE_GS3,NOTE_F4,NOTE_FS4,NOTE_GS4,NOTE_AS4,NOTE_AS3,NOTE_CS4,NOTE_CS5,NOTE_AS4,
    NOTE_GS4,NOTE_AS4,NOTE_FS4,NOTE_GS4,NOTE_F4,NOTE_FS4,NOTE_CS4
};

const int melody1Beats[] = { 
    2500,183,183,183,183,183,183,183,183,366,366,732,
    183,183,183,183,183,183,183,183,183,183,183,183,
    183,183,366,183,183,183,183,183,183,183,183,
    366,366,732,183,183,183,183,183,183,183,183,
    183,183,183,183,183,183,366
};

// 第二首歌
const int melody2[] = { 
    NOTE_D3,NOTE_D2,NOTE_D3,NOTE_D6,NOTE_D3,NOTE_D2,NOTE_D3,NOTE_D7,
NOTE_D3,NOTE_D2,NOTE_D3,NOTE_DH1,NOTE_D7,NOTE_D5,
NOTE_D3,NOTE_D2,NOTE_D3,NOTE_D6,NOTE_D3,NOTE_D2,NOTE_D3,NOTE_D7,
NOTE_D5,NOTE_D2,NOTE_DL7,
NOTE_D3,NOTE_D2,NOTE_D3,NOTE_D6,NOTE_D3,NOTE_D2,NOTE_D3,NOTE_D7,
NOTE_D3,NOTE_D2,NOTE_D3,NOTE_DH1,NOTE_D7,NOTE_D5,
NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_DL5,
NOTE_DL6,NOTE_D1,NOTE_DL7,

NOTE_DL6,NOTE_D1,NOTE_D1,NOTE_D2,NOTE_D2,NOTE_D3,NOTE_D3,NOTE_D5,NOTE_D6,
NOTE_D5,NOTE_D3,NOTE_D2,
NOTE_DL6,NOTE_D1,NOTE_D1,NOTE_D2,NOTE_D2,NOTE_D3,NOTE_D3,NOTE_DL6,NOTE_DL5,
NOTE_DL6,NOTE_D1,NOTE_D1,NOTE_D2,NOTE_D2,NOTE_D3,NOTE_D3,NOTE_D5,NOTE_D6,
NOTE_D5,NOTE_D3,NOTE_D2,
NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_DL5,NOTE_DL6,

NOTE_DL6,NOTE_D1,NOTE_D2,NOTE_D1,NOTE_DL6,
NOTE_DL6,NOTE_D1,NOTE_D2,NOTE_D1,NOTE_D3,
NOTE_D3,NOTE_D5,NOTE_D6,NOTE_D6,NOTE_D5,NOTE_D3,NOTE_D2,NOTE_D1,NOTE_D2,NOTE_D3,
NOTE_DL6,NOTE_D1,NOTE_D2,NOTE_D1,NOTE_DL6,
NOTE_DL6,NOTE_D1,NOTE_D2,NOTE_D1,NOTE_D3,
NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_DL5,NOTE_DL6,

NOTE_D3,NOTE_D5,NOTE_DH1,NOTE_D7,NOTE_D3,
NOTE_D3,NOTE_D2,NOTE_D1,NOTE_D1,NOTE_D2,NOTE_D3,
NOTE_D3,NOTE_D2,NOTE_D1,NOTE_D6,NOTE_DH1,NOTE_D7,NOTE_D6,NOTE_D5,NOTE_D2,NOTE_D3,
NOTE_D3,NOTE_D5,NOTE_DH1,NOTE_D7,NOTE_D3,
NOTE_D3,NOTE_D2,NOTE_D1,NOTE_D1,NOTE_D2,NOTE_D3,
NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_D2,NOTE_D3,NOTE_DL6,NOTE_DL5,NOTE_DL6
};

const int melody2Beats[] = {
250,250,250,250,500,500,
250,250,250,250,250,250,250,250,
500,500,1000,
250,250,250,250,250,250,250,250,
250,250,250,250,500,500,
250,250,500,250,250,250,250,500,500,1000,
 
250,250,250,250,250,250,250,125,125,
750,250,1000,
250,250,250,250,250,250,500,500,1500,
250,250,250,250,250,250,250,125,125,
750,250,1000,
250,250,500,250,250,250,250,1500,

250,250,750,250,500,250,250,
750,250,500,250,250,500,250,250,250,250,500,500,1000,
250,250,875,125,500,250,250,500,500,1000,
250,250,500,250,250,250,250,1500,

250,250,750,250,500,250,250,
500,250,250,500,250,250,500,250,250,250,250,250,250,1500,
250,250,750,250,500,250,250,
500,250,250,1000,250,250,500,250,250,250,250,2000};
const int melody3[] = {  NOTE_G5,NOTE_E5,NOTE_F5,NOTE_G5,NOTE_E5,NOTE_F5,
  NOTE_G5,NOTE_G4,NOTE_A4,NOTE_B4,NOTE_C5,NOTE_D5,NOTE_E5,NOTE_F5,
  NOTE_E5,NOTE_C5,NOTE_D5,NOTE_E5,NOTE_E4,NOTE_F4,
  NOTE_G4,NOTE_A4,NOTE_G4,NOTE_F4,NOTE_G4,NOTE_E4,NOTE_F4,NOTE_G4,
  NOTE_F4,NOTE_A4,NOTE_G4,NOTE_F4,NOTE_E4,NOTE_D4,
  NOTE_E4,NOTE_D4,NOTE_C4,NOTE_D4,NOTE_E4,NOTE_F4,NOTE_G4,NOTE_A4,
  NOTE_F4,NOTE_A4,NOTE_G4,NOTE_A4,NOTE_B4,NOTE_C5,
  NOTE_G4,NOTE_A4,NOTE_B4,NOTE_C5,NOTE_D5,NOTE_E5,NOTE_F5,NOTE_G5
 };
const int melody3Beats[] = {500,250,250,500,250,250,
500,250,250,250,250,250,250,250,
500,250,250,500,250,250,
500,250,250,250,250,250,250,250,
500,250,250,500,250,250,
500,250,250,250,250,250,250,250,
500,250,250,500,250,250,
500,250,250,250,250,250,250,250

 };
// 歌曲数组
const int* melodies[] = { melody1, melody2 ,melody3};
const int* beatArrays[] = { melody1Beats, melody2Beats ,melody3Beats};
const int melodyLengths[] = { 
    sizeof(melody1) / sizeof(melody1[0]),
    sizeof(melody2) / sizeof(melody2[0]),
    sizeof(melody3) / sizeof(melody3[0])
};

const int numMelodies = sizeof(melodies) / sizeof(melodies[0]);

// 全局变量
int currentMelody = 0;
bool isPlaying = false;
int currentNote = 0;
unsigned long lastNoteTime = 0;
int tempo = 120;

void setup() {
    // 初始化按钮引脚
    for (uint8_t i = 0; i < numButtons; i++) {
        pinMode(buttonPins[i], INPUT_PULLUP);
    }
    pinMode(SPEAKER_PIN, OUTPUT);
}

void loop() {
    // 读取按钮状态
    for (uint8_t i = 0; i < numButtons; i++) {
        if (digitalRead(buttonPins[i]) == LOW) {
            handleButton(i);
            delay(20); // 消抖
        }
    }

    // 播放音乐
    if (isPlaying) {
        playMelody();
    }
}

void handleButton(int buttonIndex) {
    if (buttonIndex < numMelodies) {
        // 选择歌曲
        currentMelody = buttonIndex;
        currentNote = 0;
        isPlaying = true;
    } 
    else if (buttonIndex == numMelodies) {
        // 暂停/播放
        isPlaying = !isPlaying;
        if (!isPlaying) {
            noTone(SPEAKER_PIN);
        }
    }
    else if (buttonIndex == numMelodies + 1) {
        // 加速
        tempo = min(tempo + 10, 240);
    }
    else if (buttonIndex == numMelodies + 2) {
        // 减速
        tempo = max(tempo - 10, 1);
    }
    else if (buttonIndex == numMelodies + 3) {
        // 下一首
        currentMelody = (currentMelody + 1) % numMelodies;
        currentNote = 0;
        isPlaying = true;
    }
    else if (buttonIndex == numMelodies + 4) {
        // 上一首
        currentMelody = (currentMelody > 0) ? (currentMelody - 1) : (numMelodies - 1);
        currentNote = 0;
        isPlaying = true;
    }
}

void playMelody() {
    if (currentNote >= melodyLengths[currentMelody]) {
        isPlaying = false;
        noTone(SPEAKER_PIN);
        return;
    }

    unsigned long currentMillis = millis();
    unsigned long noteDuration = beatArrays[currentMelody][currentNote];

    if (currentMillis - lastNoteTime >= noteDuration) {
        int note = melodies[currentMelody][currentNote];
        if (note != REST) {
            tone(SPEAKER_PIN, note, noteDuration);
        } else {
            noTone(SPEAKER_PIN);
        }
        lastNoteTime = currentMillis;
        currentNote++;
    }
}