// ᗜ‿ᗜ
#include <Arduino.h>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
#include "SD.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "myTone.h"
#include "myPin.h"
#include "support.h"
// init settings
void load_SD_card(){
// load SD card
if (!SD.begin(SD_CS_PIN)) {
Serial.println("Card initialization failed!");
while (true);
}
}
// key to C0 function
string* key_to_C0[61]; // example: {{"10", "42"},...} for F♯大調
void set_key_dict(string key){
/*
example key: "42" -> F♯大調
example key: "10" -> C大調
*/
// 10,12(21),20,22,30,40,42,50,52,60,62,70 共 12 鍵,而 p2=(p+1)1 for p = 1,2,4,5,6
for (string* p: key_to_C0){
delete [] p;
}
if (key[1] == '1'){
key[0] = key[0]-1;
key[1] = '2';
}
string arr[12] = {"10","12","20","22","30","40","42","50","52","60","62","70"};
int push_num;
for (int i = 0; i < 12; i++){
if (arr[i] == key){
push_num = i;
break;
}
}
string temp[84] = {"...10","...12","...20","...22","...30","...40","...42","...50","...52","...60","...62","...70","..10","..12","..20","..22","..30","..40","..42","..50","..52","..60","..62","..70",".10",".12",".20",".22",".30",".40",".42",".50",".52",".60",".62",".70","10","12","20","22","30","40","42","50","52","60","62","70","1.0","1.2","2.0","2.2","3.0","4.0","4.2","5.0","5.2","6.0","6.2","7.0","1..0","1..2","2..0","2..2","3..0","4..0","4..2","5..0","5..2","6..0","6..2","7..0","1...0","1...2","2...0","2...2","3...0","4...0","4...2","5...0","5...2","6...0","6...2","7...0"};
for (int i = 0; i < 60; i++){
string* p = new string[2];
p[0] = temp[12 - push_num + i]; p[1] = temp[12 + i];
key_to_C0[i] = p;
}
string* p = new string[2];
p[0] = "00"; p[1] = "00";
key_to_C0[60] = p;
}
string find_freq_from_C0(string s){
if (s[0] == 'x'){
return to_string(BEAT_FREQUENCY);
}
for (string* s_arr:tone_hz_arr_C0){
if (s_arr[0] == s){
return s_arr[1];
}
}
return "error";
}
string find_freq(string s){
if (s[0] == 'x'){
return to_string(BEAT_FREQUENCY);
}
if (s[s.size()-1] == '1'){
s[0] = s[0]-1;
s[s.size()-1] = '2';
}
for (string* s_arr: key_to_C0){
if (s_arr[0] == s){
return find_freq_from_C0(s_arr[1]);
}
}
return "error";
}
// tone object
int buzzer_pin_arr[] = {BUZZER_PIN_1, BUZZER_PIN_2, BUZZER_PIN_3, BUZZER_PIN_4};
void IRAM_ATTR onTimer1() {
static bool state = false;
// change state
digitalWrite(buzzer_pin_arr[0], state);
state = !state;
}
void IRAM_ATTR onTimer2() {
static bool state = false;
// change state
digitalWrite(buzzer_pin_arr[1], state);
state = !state;
}
void IRAM_ATTR onTimer3() {
static bool state = false;
// change state
digitalWrite(buzzer_pin_arr[2], state);
state = !state;
}
void IRAM_ATTR onTimer4() {
static bool state = false;
// change state
digitalWrite(buzzer_pin_arr[3], state);
state = !state;
}
void (*onTimerFuncArr[])() = {&onTimer1, &onTimer2, &onTimer3, &onTimer4};
void playTone(float freq, float duration, int buzzer_num = 0){
if (freq <= 20 || freq >= 20000) {
delay(duration);
return;
}
// set
int timer_num = buzzer_num;
hw_timer_t* timer = timerBegin(timer_num, 80, true);
timerAttachInterrupt(timer, onTimerFuncArr[buzzer_num], true);
timerAlarmWrite(timer, 1000000 / freq / 2, true); // set frequency (change per mu sec)
// play
timerAlarmEnable(timer);
delay(duration);
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
}
void playChord(float* freq_arr, int freq_num, float duration, int* buzzer_num_arr = nullptr){
hw_timer_t* timer_arr[freq_num];
for (int i = 0; i < freq_num; i++){
int buzzer_num;
if (buzzer_num_arr == nullptr){
buzzer_num = i;
}else{
buzzer_num = buzzer_num_arr[i];
}
// set
int timer_num = buzzer_num;
timer_arr[i] = timerBegin(timer_num, 80, true);
// play
timerAttachInterrupt(timer_arr[i], onTimerFuncArr[buzzer_num], true);
timerAlarmWrite(timer_arr[i], 1000000 / freq_arr[i] / 2, true);
timerAlarmEnable(timer_arr[i]);
}
delay(duration);
for (hw_timer_t* timer: timer_arr){
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
}
}
int check_points[] = {0, 0};
/*
【音符設定】 頻,長,連與否(1與0),降(1)升(2)無(0)
設定四分音符為一拍
四分音符的Do - 1,1
四分音符的Re - 2,1
八分音符的Do - 1,0.5
四分音符的高音Do(更高音以此類推) - 1.,1
四分音符的低音Do(更低音以此類推) - .1,1
四分音符的休止符 - 0,1
連音(標註於第一個音) - 1,1,1 例如:連音的四分音符Do-Re-Me為 1,1,1\n2,1,1\n3,1
四分音符的打擊 - x,1
四分音符的降So - 5,1,0,1
四分音符的升Fa - 4,1,0,2
*/
void play_music_01(void *p){
char* path = (char *)p; // 取得傳入的參數
File audioFile = SD.open(path, FILE_READ);
if (!audioFile) {
Serial.println("file was not opened");
while (true) ;
}
for (int i = 0; i < SHEET_LENGTH; i++){
string line = getLine(audioFile);
if (line[0] == '*'){ // revise
check_points[0] += 1;
line = getLine(audioFile);
cout << "1:" << check_points[0] << check_points[1] << endl;
while (check_points[0] > check_points[1]){
delay(1);
}
}
if (line[0] == '/' && line[1] == '*'){
string key_temp;
key_temp += line[4]; key_temp += line[5];
set_key_dict(key_temp);
line = getLine(audioFile);
}
vector<vector<string>> chord;
for (string s:split(line, " ")){
chord.push_back(split(s, ","));
}
int chord_size = chord.size();
if (chord_size == 1){
vector<string> v = chord[0];
float freq = stof(find_freq(v[0] + v[3]));
if (stoi(v[2])){
float duration = stof(v[1]) * QUARTER_NOTE_DURATION;
playTone(freq, duration);
} else {
float duration = stof(v[1]) * (QUARTER_NOTE_DURATION - SHUT_DURATION);
float shut_duration = stof(v[1]) * (SHUT_DURATION);
playTone(freq, duration);
delay(shut_duration);
}
} else {
if (stoi(chord[0][2])){
float duration = stof(chord[0][1]) * QUARTER_NOTE_DURATION;
float freq_arr[chord_size];
for (int j = 0; j < chord_size; j++){
vector<string> v = chord[j];
float freq = stof(find_freq(v[0] + v[3]));
freq_arr[j] = freq;
}
playChord(freq_arr, chord_size, duration);
} else {
float duration = stof(chord[0][1]) * (QUARTER_NOTE_DURATION - SHUT_DURATION);
float shut_duration = stof(chord[0][1]) * (SHUT_DURATION);
float freq_arr[chord_size];
for (int j = 0; j < chord_size; j++){
vector<string> v = chord[j];
float freq = stof(find_freq(v[0] + v[3]));
freq_arr[j] = freq;
}
playChord(freq_arr, chord_size, duration);
delay(shut_duration);
}
}
}
vTaskDelete(NULL); // 任務執行完畢後刪除自身
}
void play_music_02(void *p){
char* path = (char *)p; // 取得傳入的參數
File audioFile = SD.open(path, FILE_READ);
if (!audioFile) {
Serial.println("file was not opened");
while (true) ;
}
for (int i = 0; i < SHEET_LENGTH; i++){
string line = getLine(audioFile);
if (line[0] == '*'){ // revise
check_points[1] += 1;
line = getLine(audioFile);
cout << "2:" << check_points[0] << check_points[1] << endl;
while (check_points[1] > check_points[0]){
delay(1);
}
}
if (line[0] == '/' && line[1] == '*'){
string key_temp;
key_temp += line[4]; key_temp += line[5];
set_key_dict(key_temp);
line = getLine(audioFile);
}
vector<vector<string>> chord;
for (string s:split(line, " ")){
chord.push_back(split(s, ","));
}
int chord_size = chord.size();
if (chord_size == 1){
vector<string> v = chord[0];
float freq = stof(find_freq(v[0] + v[3]));
if (stoi(v[2])){
float duration = stof(v[1]) * QUARTER_NOTE_DURATION;
playTone(freq, duration, 3);
} else {
float duration = stof(v[1]) * (QUARTER_NOTE_DURATION - SHUT_DURATION);
float shut_duration = stof(v[1]) * (SHUT_DURATION);
playTone(freq, duration, 3);
delay(shut_duration);
}
} else {
if (stoi(chord[0][2])){
float duration = stof(chord[0][1]) * QUARTER_NOTE_DURATION;
float freq_arr[chord_size];
for (int j = 0; j < chord_size; j++){
vector<string> v = chord[j];
float freq = stof(find_freq(v[0] + v[3]));
freq_arr[j] = freq;
}
playChord(freq_arr, chord_size, duration, new int [3] {3,2,1});
} else {
float duration = stof(chord[0][1]) * (QUARTER_NOTE_DURATION - SHUT_DURATION);
float shut_duration = stof(chord[0][1]) * (SHUT_DURATION);
float freq_arr[chord_size];
for (int j = 0; j < chord_size; j++){
vector<string> v = chord[j];
float freq = stof(find_freq(v[0] + v[3]));
freq_arr[j] = freq;
}
playChord(freq_arr, chord_size, duration, new int [3] {3,2,1});
delay(shut_duration);
}
}
}
}
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN_1, OUTPUT);
pinMode(BUZZER_PIN_2, OUTPUT);
pinMode(BUZZER_PIN_3, OUTPUT);
pinMode(BUZZER_PIN_4, OUTPUT);
load_SD_card();
char *path = "/sheet-01.txt";
xTaskCreate(play_music_01, "Music", 8192, path, 1, NULL);
char *path02 = "/sheet-02.txt";
play_music_02(path02);
}
void loop() {
delay(5000000);
}