반응형

"Simple Melody" 안드로이드 앱

play.google.com/store/apps/details?id=com.appybuilder.dfplayer_basic.DFcontroller_basic 

 

[arduino] - 아두이노/ESP32 - 피에조 부저, 악보를 보고 동요 멜로디 코딩하기(동요 겨울밤, 다람쥐, 옹달샘, 작은별)

[Simple Melody] - Simple Melody - 화사 마리아 멜로디 code 파일 (Hwa Sa Maria)

[Simple Melody] - Simple Melody - 방탄소년단 DNA 멜로디 code 파일 (BTS DNA)

[Simple Melody] - Simple Melody - BTS Dynamite 멜로디 code 파일

[arduino] - 아두이노 - 피에조 부저 멜로디 BTS DNA

[arduino] - 아두이노 - 피에조 부저 멜로디 Hwasa Maria

[arduino] - 아두이노 - 피에조 부저 멜로디 BTS Dynamite

 

- Download example note file

겨울밤.note
0.00MB
귀여운 꼬마.note
0.00MB
동네 한 바퀴.note
0.00MB
둥근해가떴습니다.note
0.00MB
바둑이 방울.note
0.00MB
산골짝에 다람쥐.note
0.00MB
어린 송아지.note
0.00MB
어린 음악대.note
0.00MB
옹달샘.note
0.00MB
작은별.note
0.00MB

 

 

Simple Melody 앱 개요

(*** 앱에서 와이파이 연결은 안드로이드8 [갤럭시S7]이하 버전에서만 작동합니다 ***)

 

1. 건반을 터치하여 연주할 수 있습니다. 

2. 저장된 note 파일을 불러올 수 있습니다. 

3. 불러온 악보를 자동 연주할 수 있습니다. 

4. 악보를 수정하거나 새로 작성할 수 있습니다. 

5. 수정하거나 새로 작성한 악보를 note 파일로 저장할 수 있습니다.

6. 악보를 PNG 이미지 파일로 저장할 수 있습니다.

7. 와이파이 연결을 통해 아두이노에 멜로디 코드를 전송하고 제어할 수 있습니다. 아두이노에 멜로디 코드를 전송하고 제어하기 위해서는 아두이노에서 코드를 수신할 수 있도록 코딩하고 설정해야 합니다.  

8. note 파일의 멜로디 코드를 복사하여 아두이노에서 피에조 부저를 이용한 멜로디 연주에 사용할 수 있습니다.

 

- Main Screen

 

- Note Screen

 

- Edit or New Screen

 

쉼표 및 이음표 입력 방법

 

쉼표는 음이름 선택에서 "R"을 박자에서 해당 박자를 선택한 뒤 수정 및 추가 버튼을 터치하시면 입력됩니다. 

이음표는 음이름에서 "R"과 옥타브에서 "0"을 선택하고 박자에서 해당 박자를 선택한 뒤 수정 및 추가 버튼을 터치하시면 입력 됩니다. 두개가 연속되는 이음표는 입력할 수 없습니다. 

 

* 한박을 3등분하는 3잇단음표의 입력은 지원하지 않습니다. 3잇단음표의 경우 16분음표 두개와 8분음표 한개를 사용하여 한박을 맞춰 주어야 합니다.  

 

변화표의 입력

변화표 입력은 음이름 앞의 Note: 버튼을 터치하면 입력할 수 있습니다. 변화표는 마디안에서 유효하며 마디안에서 변화표가 이미 입력된 음이름을 다시 입력할 때에는 변화표를 다시 설정하지 않아도 적용됩니다. 또한 옥타브가 다른 경우에도 마디안에 있다면 변화표의 적용을 받습니다. 

 

- Musical Note Image

악보 이미지를 저장하기 전에 음표 간 거리와 악절 간 거리를 입력한 후 아래 아이콘을 클릭하여 악보를 페이지에 맞게 조절하면 상기와 같은 이미지를 저장할 수 있습니다.

 

 

플로팅 버튼 기능

 

- 화면 녹화

- 저장된 동영상 폴더 열기 

- 플로팅 버튼 숨기기

- 플로팅 버튼의 모든 기능 종료 및 버튼 숨기기

- 메트로놈

- 노트 녹화 

 

 

노트 녹화 버튼을 클릭하여 관련 버튼이 활성화 된 상태에서 피아노 건반을 터치하면 건반의 현재 음이름, 옥타브, 터치된 길이에 맞게 박자 값이 저장됩니다. 조표를 변경하고 건반을 터치할 경우 조표값이 반영됩니다. 쉼표는 쉼표 표시 버튼을 클릭하여야 입력됩니다. 입력하는 중간에 플레이 버튼을 클릭하여 입력된 멜로디를 확인할 수 있습니다. 입력이 완료되면 "E" 번튼을 터치하여 Edit 화면으로 이동한 후 수정하고 저장할 수 있습니다.  

 

Edit 화면에서 이어서 피아노 건반에서 입력하고자 한다면 "P" 버튼을 터치하여 피아노 화면으로 이동하고 피아노 건반으로 멜로디를 이어서 입력할 수 있습니다. 

 

 

 

- Code Screen

코드 화면에서는 아두이노 와이파이 연결 설정과 아두이노용 멜로디 코드를 확인할 수 있습니다. Edit 또는 New 화면에서 저장 버튼을 클릭하면 스마트폰 Download 폴더에 상기 멜로디 코드가 파일 이름. note로 저장됩니다.

note 파일을 아래 그림처럼 연결 프로그램 -> 권장하는 프로그램 또는 기타 프로그램에서 메모장을 선택하고 열면 아두이노용 멜로디 코드를 확인하고 복사하여 아두이노 IDE에 코드를 붙여 넣을 수 있습니다.

 

아두이노 설정

 

1. 아두이노 연결 - Esp01 와이파이 모듈, 피에조 부저

- 피에조 부저 + ==> 아두이노 10

- 피에조 부저 -  ==> 아두이노 GND

- Esp01 TX ==> 아두이노 2

- Esp01 RX ==> 아두이노 3

- Esp01 CH_PD & VCC ==> 아두이노 3.3V

- Esp01 GND ==> 아두이노 GND

Esp01 핀 배열

 

2. Note 파일의 멜로디 코드를 복사하여 아두이노 피에조 코드 작성하기 

아래 코드를 다운로드 후 주석 처리된 note setup 항목 안의 Note Code 부분을 Note 파일의 멜로디 코드로 대체한 뒤 아두이노에 업로드합니다. 

업로드가 완료되면 시리얼 모니터에 "0"을 입력하면 멜로디가 재생되고 "0"을 한번 더 입력하면 재생이 정지됩니다.

arduinoUno_melody_progmem.ino
0.01MB

// --------------- note setup ----------------------------------

// 12화음 이름 정의
typedef enum {
  NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, 
  NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX
} note_t;

// 화음별 피에조 부저 진동수 정의 및 옥타브에 따른 값 변경 함수
double ledcWriteNote(note_t note, uint8_t octave){
  const uint16_t noteFrequencyBase[12] = {
  //  1      2      3      4      5      6     7       8     9       10    11      12
  //  C      C#     D      Eb     E      F     F#      G     G#      A     Bb      B
     4186,  4435,  4699,  4978,  5274,  5588,  5920,  6272,  6645,  7040,  7459,  7902
  };
  if(octave > 8 || note >= NOTE_MAX){
    return 0;
  }
  double noteFreq =  (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
  return noteFreq;
}

// Note Code
// ---------------------------------------------------------------------- 동요: 겨울밤
uint8_t Tempo = 120; // 1, 1박자 = 1000/(tempoRatio), 비트수 = 2 = 2000
uint8_t tempoRatio = Tempo/60;
uint8_t KeySign = 0; //  0 ~ 14, flat: 1 ~ 7, sharp: 8 ~ 14
uint8_t octaveTemp = 4; // 조표 변화시 옥타브 변경에 사용

const note_t Mnote[] PROGMEM= { // 겨울밤
NOTE_G, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_E, NOTE_E, NOTE_MAX,
NOTE_F, NOTE_F, NOTE_F, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_D, NOTE_D, NOTE_MAX,
NOTE_C, NOTE_D, NOTE_E, NOTE_F, NOTE_G, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_MAX,
NOTE_C, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_F, NOTE_G, NOTE_MAX,
NOTE_C, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_C, NOTE_MAX,
};

const uint8_t Moct[] PROGMEM= { // 멜로디 옥타브 C ~ B, 4옥타브: 88키보드 가운데 도(C4) ~ 시(B4)
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
0,
};

const uint8_t localKey[] PROGMEM= {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0,
};

const uint8_t Mdur[] PROGMEM= {
16, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
};
// ----------------------------------------------------------------------

uint8_t noteNum = 0;

note_t keySignature(note_t note) {
  if (pgm_read_byte(&localKey[noteNum]) == 0) {
    if (KeySign == 1) { // F Major (바장조)
      if (note == NOTE_B) note = NOTE_Bb;
    } else if (KeySign == 2) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
    } else if (KeySign == 3) {
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
    } else if (KeySign == 4) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
    } else if (KeySign == 5) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
    } else if (KeySign == 6) {
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
    } else if (KeySign == 7) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
      else if (note == NOTE_F) note = NOTE_E;
    } else if (KeySign == 8) { 
      if (note == NOTE_F) note = NOTE_Fs;
    } else if (KeySign == 9) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
    } else if (KeySign == 10) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
    } else if (KeySign == 11) { 
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
    } else if (KeySign == 12) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
    } else if (KeySign == 13) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_F;
    } else if (KeySign == 14) { 
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_F;
      else if (note == NOTE_B) { note = NOTE_C; octaveTemp += 1; }
    }
  }
  else { // 1. natural
    if (pgm_read_byte(&localKey[noteNum]) == 2) { // 2. b
      if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_F) note = NOTE_E;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_B) note = NOTE_Bb;
    }
    else if (pgm_read_byte(&localKey[noteNum]) == 3) { // 3. #
      if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_E) note = NOTE_F;
      else if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_B) { note = NOTE_C; octaveTemp += 1; }
    }
    else if (pgm_read_byte(&localKey[noteNum]) == 4) { // 4. bb
      if (note == NOTE_C) { note = NOTE_Bb; octaveTemp -= 1; }
      else if (note == NOTE_D) note = NOTE_C;
      else if (note == NOTE_E) note = NOTE_D;
      else if (note == NOTE_F) note = NOTE_Eb;
      else if (note == NOTE_G) note = NOTE_F;
      else if (note == NOTE_A) note = NOTE_G;
      else if (note == NOTE_B) note = NOTE_A;
    }
    else if (pgm_read_byte(&localKey[noteNum]) == 5) { // 5. ##
      if (note == NOTE_C) note = NOTE_D;
      else if (note == NOTE_D) note = NOTE_E;
      else if (note == NOTE_E) note = NOTE_Fs;
      else if (note == NOTE_F) note = NOTE_G;
      else if (note == NOTE_G) note = NOTE_A;
      else if (note == NOTE_A) note = NOTE_B;
      else if (note == NOTE_B) { note = NOTE_Cs; octaveTemp += 1; }
    }
  }
  return note;
}

// --------------- note setup ----------------------------------

int beepPin = 10;

void setup() {
  Serial.begin(9600);
}

bool beepMelody = false;
unsigned long int beepTime = 0;

void loop() {
  if(Serial.available() > 0){
    String temp = Serial.readStringUntil('\n');
    Serial.println(temp);
    if (temp == "0") {
      beepMelody = !beepMelody;
      noteNum = 0; beepTime = 0;
      if (!beepMelody) noTone(beepPin);  
    }
  }
  if (beepMelody) {
    if (millis() - beepTime >= pgm_read_byte(&Mdur[noteNum])*(1000/(4*tempoRatio))) {
      beepTime = millis();
      noTone(beepPin);
      octaveTemp = pgm_read_byte(&Moct[noteNum]);
      note_t KeyNote = keySignature(pgm_read_word(&Mnote[noteNum]));
      tone(beepPin, ledcWriteNote(KeyNote, octaveTemp));  
      noteNum++;
      if (noteNum == sizeof(Mdur)) { // 초기화
        noTone(beepPin);  
        noteNum = 0; 
      }
    }
  } 
}

 

아두이노 피에조 제어 코드의 자세한 설명은 이전 글 아두이노/ESP32 - 피에조 부저, 악보를 보고 동요 멜로디 코딩하기(동요 겨울밤, 다람쥐, 옹달샘, 작은 별)을 참조하시기 바랍니다.

 

3.WiFiEsp 라이브러리를 이용한 wifi 코드 작성 및 스마트 폰에서 Esp01에 연결하기 

(*** 앱에서 와이파이 연결은 안드로이드8 [갤럭시S7]이하 버전에서만 작동합니다 ***)

ESP01wifi 모듈 설정
ESP01의 시리얼 통신 보드 레이트가 9600으로 설정되어 있어야 합니다. ESP01의 연결 설정 및 자세한 방법에 관해서는 이전 글 아두이노 - ESP01wifi 모듈 무선 원격제어 그리고 시리얼 통신 - 6편을 참조하기 바랍니다.

 

-WiFiEsp 라이브러리 다운로드 및 설치

github.com/bportaluri/WiFiEsp

ESP01 모듈 웹서버 라이브러리 다운로드

 

다운로드 후 압축을 풀면 아래와 같이 WiFiEsp-master 폴더 안에 똑같은 WiFiEsp-master 있는데 안의 폴더명에서 "-master"삭제하여 WiFiEsp로 변경한 뒤 폴더를 복사합니다.

 

내 컴퓨터의 라이브러리의 문서 -> Arduino -> libraries 폴더로 이동하여 붙여 넣기를 해줍니다.

 라이브러리 설치가 되었습니다. 아두이노 IDE가 실행되고 있다면 종료 후 재 실행하시기 바랍니다. 

 

아두이노 코드를 다운로드하고 와이파이 공유기에 연결하고자 한다면 아래 코드를 수정한 뒤 아두이노에 코드를 업로드해줍니다. 

 

const char ssid[] = "SK_WiFiGIGA40F7";    // 공유기 이름
const char pass[] = "1712037218";              // 공유기 비밀번호

arduinoUno_melody_wifi.ino
0.01MB

// --------------- note setup ----------------------------------

// 12화음 이름 정의
typedef enum {
  NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, 
  NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX
} note_t;

// 화음별 피에조 부저 진동수 정의 및 옥타브에 따른 값 변경 함수
double ledcWriteNote(note_t note, uint8_t octave){
  const uint16_t noteFrequencyBase[12] = {
  //  1      2      3      4      5      6     7       8     9       10    11      12
  //  C      C#     D      Eb     E      F     F#      G     G#      A     Bb      B
     4186,  4435,  4699,  4978,  5274,  5588,  5920,  6272,  6645,  7040,  7459,  7902
  };
  if(octave > 8 || note >= NOTE_MAX){
    return 0;
  }
  double noteFreq =  (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
  return noteFreq;
}

uint8_t noteNum = 0;

note_t noteConvertor(uint8_t note) {
  note_t temp;
  if (note < 7) {
    if (note == 0) temp = NOTE_MAX;
    else if (note == 1) temp = NOTE_C;
    else if (note == 2) temp = NOTE_Cs;
    else if (note == 3) temp = NOTE_D;
    else if (note == 4) temp = NOTE_Eb;
    else if (note == 5) temp = NOTE_E;
    else if (note == 6) temp = NOTE_F;
  } else {
    if (note == 7) temp = NOTE_Fs;
    else if (note == 8) temp = NOTE_G;
    else if (note == 9) temp = NOTE_Gs;
    else if (note == 10) temp = NOTE_A;
    else if (note == 11) temp = NOTE_Bb;
    else if (note == 12) temp = NOTE_B;
  }
  return temp;
}

// --------------- note setup ----------------------------------

#include <EEPROM.h>
#include <WiFiEsp.h>

#include <SoftwareSerial.h> 
#define rxPin 3 
#define txPin 2 
SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX);

const char ssid[] = "SK_WiFiGIGA40F7";    // your network SSID (name)
const char pass[] = "1712037218";         // your network password
int status = WL_IDLE_STATUS;              // the Wifi radio's status

const char ssid_AP[] = "esp01_AP";        // AP Name
const char pass_AP[] = "1234test";        // AP password

WiFiEspServer server(80);

int beepPin = 10;

void setup() {
  Serial.begin(9600);
  esp01.begin(9600);   //와이파이 시리얼
  WiFi.init(&esp01);   // initialize ESP module
  while ( status != WL_CONNECTED) {   // 약 10초동안 wifi 연결 시도
    Serial.print(F("Attempting to connect to WPA SSID: "));
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);    // Connect to WPA/WPA2 network
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);
  }
  WiFi.beginAP(ssid_AP, 10, pass_AP, ENC_TYPE_WPA2_PSK, false); // 10:채널, false: softAP와 station 동시 사용모드
  IPAddress ap = WiFi.localIP();
  Serial.print("AP Address: ");
  Serial.println(ap);
  server.begin();
}

uint8_t Tempo = 120; // 1, 1박자 = 1000/(tempoRatio), 비트수 = 2 = 2000
uint8_t tempoRatio = Tempo/60;
uint8_t octaveTemp = 4; // 조표 변화시 옥타브 변경에 사용

unsigned long int beepTime = 0;

uint16_t noteTTL = 10; // 2,3
const uint8_t noteSt = 4;
uint16_t octSt = 18;   // noteTTL+noteSt
uint16_t durSt = 29;   // noteTTL+octSt+1

bool eepromMelody = false;
uint8_t eepromDur = 0;

void wifi() {
  WiFiEspClient client = server.available();  // listen for incoming clients
  if (client) {                               // if you get a client,
    while (client.connected()) {              // loop while the client's connected
      if (client.available()) {               // if there's bytes to read from the client,
        String line = client.readStringUntil('\n');
        String temp = line.substring(5, 9); // "GET /%%F0"
        if (temp == F("%%F0")) { // GET /%%F0tempo,notenum%(note,...)%(oct,...)%(dur,...)\n
          temp = line.substring(9, 12);
          if (temp == F("%S%")) {
            eepromMelody = false;
            noTone(beepPin);  
          } 
          else if (temp == F("%P%")) {
            eepromMelody = true;
            noteNum = 0; beepTime = 0;
            Tempo = EEPROM.read(1);
            EEPROM.get(2, noteTTL); //EEPROM.get(2);
            octSt = noteTTL+noteSt;  
            durSt = noteTTL+octSt+1; 
            tempoRatio = Tempo/60;
            eepromDur = EEPROM.read(durSt+noteNum);
          } 
          else {
            uint8_t value = 0;
            uint16_t indexSt = 9;
            uint16_t indexEd = line.indexOf(F(","));
            String temp = line.substring(indexSt, indexEd);
            value = temp.toInt();
            Tempo = value;    
            indexSt = line.indexOf(F("%"),indexEd);
            temp = line.substring(indexEd+1,indexSt);
            value = temp.toInt();
            noteTTL = value;
            octSt = noteTTL+noteSt;  
            durSt = noteTTL+octSt+1; 
            EEPROM.write(1,Tempo);
            EEPROM.put(2,noteTTL);
            uint8_t indexDel = line.lastIndexOf(F("%"));
            indexSt = indexDel+1;
            for (int i = 0; i < noteTTL+1; i++) {
              indexEd = line.indexOf(F(","), indexSt);
              temp = line.substring(indexSt, indexEd);
              value = temp.toInt();
              EEPROM.write(durSt+i,value);
              indexSt = indexEd+1;
            }
            line.remove(indexDel);
            indexDel = line.lastIndexOf(F("%"));
            indexSt = indexDel+1;
            for (int i = 0; i < noteTTL+1; i++) {
              indexEd = line.indexOf(F(","), indexSt);
              temp = line.substring(indexSt, indexEd);
              value = temp.toInt();
              EEPROM.write(octSt+i,value);
              indexSt = indexEd+1;
            }
            line.remove(indexDel);
            indexDel = line.lastIndexOf(F("%"));
            indexSt = indexDel+1;
            for (int i = 0; i < noteTTL; i++) {
              indexEd = line.indexOf(F(","), indexSt);
              temp = line.substring(indexSt, indexEd);
              value = temp.toInt();
              EEPROM.write(noteSt+i,value);
              indexSt = indexEd+1;
            }
            eepromMelody = true;
          }
          client.flush();
          client.println(F("HTTP/1.1 200 OK\nContent-type:text/html\nConnection: close\r\n"));
          client.println(F("%M%"));
        } else {
          client.flush();
          client.println(F("HTTP/1.1 200 OK\nContent-type:text/html\nConnection: close\r\n"));
          client.println(F("%C%"));
        }
        break;
      }
    }
    client.stop();
    Serial.println(F("Client disconnected"));
  }
}

void loop() {
  wifi();
  if (eepromMelody) {
    if (millis() - beepTime >= eepromDur*(1000/(4*tempoRatio))) {
      beepTime = millis();
      noTone(beepPin);   
      octaveTemp = EEPROM.read(octSt+noteNum);
      note_t KeyNote = noteConvertor(EEPROM.read(noteSt+noteNum));
      tone(beepPin, ledcWriteNote(KeyNote, octaveTemp));
      noteNum++;
      if (noteNum == noteTTL+1) { // 초기화
        noTone(beepPin);    //  noTone() - ledcWrite(uint8_t channel, uint32_t duty);
        noteNum = 0; 
      }
      eepromDur = EEPROM.read(durSt+noteNum);
    }
  }
  if(Serial.available() > 0){
    String temp = Serial.readStringUntil('\n');
    Serial.println(temp);
    if (temp == "1") {
      eepromMelody = !eepromMelody;
      noteNum = 0; beepTime = 0;
      if (eepromMelody) {
        Tempo = EEPROM.read(1);
        EEPROM.get(2, noteTTL); 
        octSt = noteTTL+noteSt;  
        durSt = noteTTL+octSt+1; 
        tempoRatio = Tempo/60;
        eepromDur = EEPROM.read(durSt+noteNum);
      } else {
        noTone(beepPin);  
      }
    }
    else if (temp == "2") {
      eepromMelody = false;
      noTone(beepPin);  
    }
  }
}

 

아두이노에 코드를 업로드하면 아두이노는 공유기에 연결을 하게 되고 또한 동시에 와이파이 액세스 포이트(AP)도 활성화하여 스마트폰이 연결할 수 있도록 대기하게 되고 아래 그림처럼 아두이노 시리얼 모니터에 공유기에서 할당받은 IP 주소와 외부장치 연결용 AP주소를 표시해 줍니다. 

 

공유기에서 할당받은 IP로 접속하기

(*** 앱에서 와이파이 연결은 안드로이드8 [갤럭시S7]이하 버전에서만 작동합니다 ***)

스마트폰이 공유기에 와이파이로 연결되어 있으면 와이파이 표시 아이콘이 파란색으로 표시됩니다. 와이파이 아이콘이 파란색인 상태에서 공유기에서 할당받은 IP "192.168.35.176"을 아이피 주소 입력창에 입력한 뒤 "Confirm" 버튼을 클릭하게 되면 공유기를 통해 Esp01 와이파이 서버에 연결을 시도하게 되고 Esp01 모듈로부터 응답을 받게 되면 "Confirm" 버튼이 "연결" 이미지 버튼으로 변경되게 됩니다.

Esp01 AP 주소로 접속하기

Esp01 AP 주소로 접속하기 위해서는 스마트폰의 와이파이가 ESP01 와이파이와 연결되어야 합니다. 만약 스마트폰의 와이파이가 공유기에 연결되어 있다면 공유기와의 연결을 끊고 ESP01 와이파이와 연결을 시켜줍니다.

 비밀번호 입력창에 비밀번호를 입력하고 연결을 클릭합니다.

아래와 같은 메시지가 나오면 "WI-FI 연결 유지"를 클릭해 줍니다.

 

 Simple Melody 앱에서 Esp01 AP 주소를 입력해주고 "Confirm" 버튼을 클릭해 주면 연결됩니다. 

 

Esp01 연결 이미지 버튼이 표시된 상태에서 "Send"버튼을 클릭하면 멜로디 코드가 Esp01로 전송되고 아두이노에서 수신된 멜로디 코드를 EEPROM에 저장한 다음 피에조 부저 멜로디 재생 코드를 실행하게 됩니다. 멜로디 코드 전송이 완료된 뒤에는 앱의 "Send" 아이콘이 "Stop"으로 변경되고 "Stop"버튼을 클릭하면 멜로디의 재생은 정지됩니다. 

 

 

PROGMEM 코드와 wifi 수신 동시 작동 코드

arduinoUno_melody_wifi_progmem.ino
0.01MB

// --------------- note setup ----------------------------------

// 12화음 이름 정의
typedef enum {
  NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, 
  NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX
} note_t;

// 화음별 피에조 부저 진동수 정의 및 옥타브에 따른 값 변경 함수
double ledcWriteNote(note_t note, uint8_t octave){
  const uint16_t noteFrequencyBase[12] = {
  //  1      2      3      4      5      6     7       8     9       10    11      12
  //  C      C#     D      Eb     E      F     F#      G     G#      A     Bb      B
     4186,  4435,  4699,  4978,  5274,  5588,  5920,  6272,  6645,  7040,  7459,  7902
  };
  if(octave > 8 || note >= NOTE_MAX){
    return 0;
  }
  double noteFreq =  (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
  return noteFreq;
}

// Note Code
// ---------------------------------------------------------------------- 동요: 겨울밤
uint8_t Tempo = 120; // 1, 1박자 = 1000/(tempoRatio), 비트수 = 2 = 2000
uint8_t tempoRatio = Tempo/60;
uint8_t KeySign = 0; //  0 ~ 14, flat: 1 ~ 7, sharp: 8 ~ 14
uint8_t octaveTemp = 4; // 조표 변화시 옥타브 변경에 사용

const note_t Mnote[] PROGMEM= { // 겨울밤
NOTE_G, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_E, NOTE_E, NOTE_MAX,
NOTE_F, NOTE_F, NOTE_F, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_D, NOTE_D, NOTE_MAX,
NOTE_C, NOTE_D, NOTE_E, NOTE_F, NOTE_G, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_MAX,
NOTE_C, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_F, NOTE_G, NOTE_MAX,
NOTE_C, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_C, NOTE_MAX,
};

const uint8_t Moct[] PROGMEM= { // 멜로디 옥타브 C ~ B, 4옥타브: 88키보드 가운데 도(C4) ~ 시(B4)
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
0,
};

const uint8_t localKey[] PROGMEM= {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0,
};

const uint8_t Mdur[] PROGMEM= {
16, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
};
// ----------------------------------------------------------------------

uint8_t noteNum = 0;

note_t keySignature(note_t note) {
  if (pgm_read_byte(&localKey[noteNum]) == 0) {
    if (KeySign == 1) { // F Major (바장조)
      if (note == NOTE_B) note = NOTE_Bb;
    } else if (KeySign == 2) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
    } else if (KeySign == 3) {
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
    } else if (KeySign == 4) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
    } else if (KeySign == 5) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
    } else if (KeySign == 6) {
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
    } else if (KeySign == 7) { 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
      else if (note == NOTE_F) note = NOTE_E;
    } else if (KeySign == 8) { 
      if (note == NOTE_F) note = NOTE_Fs;
    } else if (KeySign == 9) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
    } else if (KeySign == 10) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
    } else if (KeySign == 11) { 
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
    } else if (KeySign == 12) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
    } else if (KeySign == 13) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_F;
    } else if (KeySign == 14) { 
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_F;
      else if (note == NOTE_B) { note = NOTE_C; octaveTemp += 1; }
    }
  }
  else { // 1. natural
    if (pgm_read_byte(&localKey[noteNum]) == 2) { // 2. b
      if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_F) note = NOTE_E;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_B) note = NOTE_Bb;
    }
    else if (pgm_read_byte(&localKey[noteNum]) == 3) { // 3. #
      if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_E) note = NOTE_F;
      else if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_B) { note = NOTE_C; octaveTemp += 1; }
    }
    else if (pgm_read_byte(&localKey[noteNum]) == 4) { // 4. bb
      if (note == NOTE_C) { note = NOTE_Bb; octaveTemp -= 1; }
      else if (note == NOTE_D) note = NOTE_C;
      else if (note == NOTE_E) note = NOTE_D;
      else if (note == NOTE_F) note = NOTE_Eb;
      else if (note == NOTE_G) note = NOTE_F;
      else if (note == NOTE_A) note = NOTE_G;
      else if (note == NOTE_B) note = NOTE_A;
    }
    else if (pgm_read_byte(&localKey[noteNum]) == 5) { // 5. ##
      if (note == NOTE_C) note = NOTE_D;
      else if (note == NOTE_D) note = NOTE_E;
      else if (note == NOTE_E) note = NOTE_Fs;
      else if (note == NOTE_F) note = NOTE_G;
      else if (note == NOTE_G) note = NOTE_A;
      else if (note == NOTE_A) note = NOTE_B;
      else if (note == NOTE_B) { note = NOTE_Cs; octaveTemp += 1; }
    }
  }
  return note;
}

note_t noteConvertor(uint8_t note) {
  note_t temp;
  if (note < 7) {
    if (note == 0) temp = NOTE_MAX;
    else if (note == 1) temp = NOTE_C;
    else if (note == 2) temp = NOTE_Cs;
    else if (note == 3) temp = NOTE_D;
    else if (note == 4) temp = NOTE_Eb;
    else if (note == 5) temp = NOTE_E;
    else if (note == 6) temp = NOTE_F;
  } else {
    if (note == 7) temp = NOTE_Fs;
    else if (note == 8) temp = NOTE_G;
    else if (note == 9) temp = NOTE_Gs;
    else if (note == 10) temp = NOTE_A;
    else if (note == 11) temp = NOTE_Bb;
    else if (note == 12) temp = NOTE_B;
  }
  return temp;
}

// --------------- note setup ----------------------------------

#include <EEPROM.h>
#include <WiFiEsp.h>

#include <SoftwareSerial.h> 
#define rxPin 3 
#define txPin 2 
SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX);

const char ssid[] = "SK_WiFiGIGA40F7";    // your network SSID (name)
const char pass[] = "1712037218";         // your network password
int status = WL_IDLE_STATUS;              // the Wifi radio's status

const char ssid_AP[] = "esp01_AP";        // AP Name
const char pass_AP[] = "1234test";        // AP password

WiFiEspServer server(80);

int beepPin = 10;

void setup() {
  Serial.begin(9600);
  esp01.begin(9600);   //와이파이 시리얼
  WiFi.init(&esp01);   // initialize ESP module
  while ( status != WL_CONNECTED) {   // 약 10초동안 wifi 연결 시도
    Serial.print(F("Attempting to connect to WPA SSID: "));
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);    // Connect to WPA/WPA2 network
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);
  }
  WiFi.beginAP(ssid_AP, 10, pass_AP, ENC_TYPE_WPA2_PSK, false); // 10:채널, false: softAP와 station 동시 사용모드
  IPAddress ap = WiFi.localIP();
  Serial.print("AP Address: ");
  Serial.println(ap);
  server.begin();
}

bool beepMelody = false;
unsigned long int beepTime = 0;

uint16_t noteTTL = 10; // 2,3
const uint8_t noteSt = 4;
uint16_t octSt = 18;   // noteTTL+noteSt
uint16_t durSt = 29;   // noteTTL+octSt+1

bool eepromMelody = false;
uint8_t eepromDur = 0;

void wifi() {
  WiFiEspClient client = server.available();  // listen for incoming clients
  if (client) {                               // if you get a client,
    while (client.connected()) {              // loop while the client's connected
      if (client.available()) {               // if there's bytes to read from the client,
        String line = client.readStringUntil('\n');
        String temp = line.substring(5, 9); // "GET /%%F0"
        if (temp == F("%%F0")) { // GET /%%F0tempo,notenum%(note,...)%(oct,...)%(dur,...)\n
          temp = line.substring(9, 12);
          if (temp == F("%S%")) {
            eepromMelody = false;
            noTone(beepPin);  
          } 
          else if (temp == F("%P%")) {
            eepromMelody = true;
            noteNum = 0; beepTime = 0;
            Tempo = EEPROM.read(1);
            EEPROM.get(2, noteTTL); //EEPROM.get(2);
            octSt = noteTTL+noteSt;  
            durSt = noteTTL+octSt+1; 
            tempoRatio = Tempo/60;
            eepromDur = EEPROM.read(durSt+noteNum);
          } 
          else {
            uint8_t value = 0;
            uint16_t indexSt = 9;
            uint16_t indexEd = line.indexOf(F(","));
            String temp = line.substring(indexSt, indexEd);
            value = temp.toInt();
            Tempo = value;    
            indexSt = line.indexOf(F("%"),indexEd);
            temp = line.substring(indexEd+1,indexSt);
            value = temp.toInt();
            noteTTL = value;
            octSt = noteTTL+noteSt;  
            durSt = noteTTL+octSt+1; 
            EEPROM.write(1,Tempo);
            EEPROM.put(2,noteTTL);
            uint8_t indexDel = line.lastIndexOf(F("%"));
            indexSt = indexDel+1;
            for (int i = 0; i < noteTTL+1; i++) {
              indexEd = line.indexOf(F(","), indexSt);
              temp = line.substring(indexSt, indexEd);
              value = temp.toInt();
              EEPROM.write(durSt+i,value);
              indexSt = indexEd+1;
            }
            line.remove(indexDel);
            indexDel = line.lastIndexOf(F("%"));
            indexSt = indexDel+1;
            for (int i = 0; i < noteTTL+1; i++) {
              indexEd = line.indexOf(F(","), indexSt);
              temp = line.substring(indexSt, indexEd);
              value = temp.toInt();
              EEPROM.write(octSt+i,value);
              indexSt = indexEd+1;
            }
            line.remove(indexDel);
            indexDel = line.lastIndexOf(F("%"));
            indexSt = indexDel+1;
            for (int i = 0; i < noteTTL; i++) {
              indexEd = line.indexOf(F(","), indexSt);
              temp = line.substring(indexSt, indexEd);
              value = temp.toInt();
              EEPROM.write(noteSt+i,value);
              indexSt = indexEd+1;
            }
            if (beepMelody) beepMelody = false;
            eepromMelody = true;
          }
          client.flush();
          client.println(F("HTTP/1.1 200 OK\nContent-type:text/html\nConnection: close\r\n"));
          client.println(F("%M%"));
        } else {
          client.flush();
          client.println(F("HTTP/1.1 200 OK\nContent-type:text/html\nConnection: close\r\n"));
          client.println(F("%C%"));
        }
        break;
      }
    }
    client.stop();
    Serial.println(F("Client disconnected"));
  }
}

void loop() {
  wifi();
  if (beepMelody) {
    if (millis() - beepTime >= pgm_read_byte(&Mdur[noteNum])*(1000/(4*tempoRatio))) {
      beepTime = millis();
      noTone(beepPin);
      octaveTemp = pgm_read_byte(&Moct[noteNum]);
      note_t KeyNote = keySignature(pgm_read_word(&Mnote[noteNum]));
      tone(beepPin, ledcWriteNote(KeyNote, octaveTemp));  // ledcWriteNote(uint8_t channel, note_t note, uint8_t octaveTemp);
      noteNum++;
      if (noteNum == sizeof(Mdur)) { // 초기화
        noTone(beepPin);  
        noteNum = 0; 
      }
    }
  } 
  else if (eepromMelody) {
    if (millis() - beepTime >= eepromDur*(1000/(4*tempoRatio))) {
      beepTime = millis();
      noTone(beepPin);   
      octaveTemp = EEPROM.read(octSt+noteNum);
      note_t KeyNote = noteConvertor(EEPROM.read(noteSt+noteNum));
      tone(beepPin, ledcWriteNote(KeyNote, octaveTemp));
      noteNum++;
      if (noteNum == noteTTL+1) { // 초기화
        noTone(beepPin);    //  noTone() - ledcWrite(uint8_t channel, uint32_t duty);
        noteNum = 0; 
      }
      eepromDur = EEPROM.read(durSt+noteNum);
    }
  }
  if(Serial.available() > 0){
    String temp = Serial.readStringUntil('\n');
    Serial.println(temp);
    if (temp == "0") {
      beepMelody = !beepMelody;
      noteNum = 0; beepTime = 0;
      if (!beepMelody) noTone(beepPin);  
      eepromMelody = false;
    }
    else if (temp == "1") {
      eepromMelody = !eepromMelody;
      noteNum = 0; beepTime = 0;
      Tempo = EEPROM.read(1);
      EEPROM.get(2, noteTTL); 
      octSt = noteTTL+noteSt;  
      durSt = noteTTL+octSt+1; 
      tempoRatio = Tempo/60;
      eepromDur = EEPROM.read(durSt+noteNum);
    }
    else if (temp == "2") {
      beepMelody = false;
      eepromMelody = false;
      noTone(beepPin);  
    }
  }
}

 

 

ESP32 모듈 코드

esp32_melody.ino
0.01MB

// --------------- note setup ----------------------------------
// Note Code
// ---------------------------------------------------------------------- 동요: 겨울밤
uint8_t Tempo = 120; // 1, 1박자 = 1000/(tempoRatio), 비트수 = 2 = 2000
uint8_t tempoRatio = Tempo/60;
uint8_t KeySign = 0; //  0 ~ 14, flat: 1 ~ 7, sharp: 8 ~ 14
uint8_t octaveTemp = 4; // 조표 변화시 옥타브 변경에 사용
//float beatTime = 2/4; // 박자표 - 멜로디 코드에서는 사용하지 않는다.

const note_t Mnote[] PROGMEM= { // 겨울밤
NOTE_G, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_E, NOTE_E, NOTE_MAX,
NOTE_F, NOTE_F, NOTE_F, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_D, NOTE_D, NOTE_MAX,
NOTE_C, NOTE_D, NOTE_E, NOTE_F, NOTE_G, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_MAX,
NOTE_C, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_F, NOTE_G, NOTE_MAX,
NOTE_C, NOTE_G, NOTE_G, NOTE_A, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_C, NOTE_MAX,
};

const uint8_t Moct[] PROGMEM= { // 멜로디 옥타브 C ~ B, 4옥타브: 88키보드 가운데 도(C4) ~ 시(B4)
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
0,
};

const uint8_t localKey[] PROGMEM= {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0,
};

const uint8_t Mdur[] PROGMEM= {
16, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 4, 4, 2, 2, 2, 2, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 
};
// ----------------------------------------------------------------------

uint8_t noteNum = 0;

note_t keySignature(note_t note) {
  if (localKey[noteNum] == 0) {
    if (KeySign == 1) { // F Major (바장조)
      if (note == NOTE_B) note = NOTE_Bb;
    } else if (KeySign == 2) { // B E - 마지막 E의 앞 조표가(B) Key -> Bb Major(나장조)
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
    } else if (KeySign == 3) {
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
    } else if (KeySign == 4) { // 
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
    } else if (KeySign == 5) { // B E A D G - 마지막 G의 앞 조표가(D) Key -> Db Major(내림라장조)
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
    } else if (KeySign == 6) {
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
    } else if (KeySign == 7) { //
      if (note == NOTE_B) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
      else if (note == NOTE_F) note = NOTE_E;
    } else if (KeySign == 8) { // F에서 한음 올린다 -> G Mager key(사장조)
      if (note == NOTE_F) note = NOTE_Fs;
    } else if (KeySign == 9) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
    } else if (KeySign == 10) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
    } else if (KeySign == 11) { // F C G D - 마지막 D(레)에서 한음 올린다 -> E Major key(마장조)
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
    } else if (KeySign == 12) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
    } else if (KeySign == 13) {
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_F;
    } else if (KeySign == 14) { // F C G D A E B - 마지막 B(시)에서 한음 올린다 -> C이지만 앞에서 이미 C를 올렸으므로 C# Major (올림 다장조)
      if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_E) note = NOTE_F;
      else if (note == NOTE_B) { note = NOTE_C; octaveTemp += 1; }
    }
  }
  else { // 1. natural
    if (localKey[noteNum] == 2) { // 2. b
      if (note == NOTE_C) { note = NOTE_B; octaveTemp -= 1; }
      else if (note == NOTE_D) note = NOTE_Cs;
      else if (note == NOTE_E) note = NOTE_Eb;
      else if (note == NOTE_F) note = NOTE_E;
      else if (note == NOTE_G) note = NOTE_Fs;
      else if (note == NOTE_A) note = NOTE_Gs;
      else if (note == NOTE_B) note = NOTE_Bb;
    }
    else if (localKey[noteNum] == 3) { // 3. #
      if (note == NOTE_C) note = NOTE_Cs;
      else if (note == NOTE_D) note = NOTE_Eb;
      else if (note == NOTE_E) note = NOTE_F;
      else if (note == NOTE_F) note = NOTE_Fs;
      else if (note == NOTE_G) note = NOTE_Gs;
      else if (note == NOTE_A) note = NOTE_Bb;
      else if (note == NOTE_B) { note = NOTE_C; octaveTemp += 1; }
    }
    else if (localKey[noteNum] == 4) { // 4. bb
      if (note == NOTE_C) { note = NOTE_Bb; octaveTemp -= 1; }
      else if (note == NOTE_D) note = NOTE_C;
      else if (note == NOTE_E) note = NOTE_D;
      else if (note == NOTE_F) note = NOTE_Eb;
      else if (note == NOTE_G) note = NOTE_F;
      else if (note == NOTE_A) note = NOTE_G;
      else if (note == NOTE_B) note = NOTE_A;
    }
    else if (localKey[noteNum] == 5) { // 5. ##
      if (note == NOTE_C) note = NOTE_D;
      else if (note == NOTE_D) note = NOTE_E;
      else if (note == NOTE_E) note = NOTE_Fs;
      else if (note == NOTE_F) note = NOTE_G;
      else if (note == NOTE_G) note = NOTE_A;
      else if (note == NOTE_A) note = NOTE_B;
      else if (note == NOTE_B) { note = NOTE_Cs; octaveTemp += 1; }
    }
  }
  return note;
}

note_t noteConvertor(uint8_t note) {
  note_t temp;
  if (note < 7) {
    if (note == 0) temp = NOTE_MAX;
    else if (note == 1) temp = NOTE_C;
    else if (note == 2) temp = NOTE_Cs;
    else if (note == 3) temp = NOTE_D;
    else if (note == 4) temp = NOTE_Eb;
    else if (note == 5) temp = NOTE_E;
    else if (note == 6) temp = NOTE_F;
  } else {
    if (note == 7) temp = NOTE_Fs;
    else if (note == 8) temp = NOTE_G;
    else if (note == 9) temp = NOTE_Gs;
    else if (note == 10) temp = NOTE_A;
    else if (note == 11) temp = NOTE_Bb;
    else if (note == 12) temp = NOTE_B;
  }
  return temp;
}
// --------------- note setup ----------------------------------

#include <WiFi.h>
#include <WiFiAP.h>
#include <WiFiClient.h>
WiFiServer server(80);
#include <EEPROM.h>
#define EEPROM_SIZE 1024

char ssid[21] = "skynet";    // "SK_WiFiGIGA40F7" your network SSID (name)
char pass[21] = "skynet00";  // "1712037218" your network password

char ssidAP[21] = "LED Clock";    // your network SSID (name)
char passAP[21] = "";             // your network password

int beepPin = 4;

void setup() {
  Serial.begin(115200);
  ledcSetup(0,1E5,12);  // ESP32 톤전용 ledcSetup: ledcSetup(channel,1E5,12);
  ledcAttachPin(beepPin,0);  // ledcAttachPin(uint8_t pin, uint8_t channel);
  if (!EEPROM.begin(EEPROM_SIZE)) {
    Serial.println("failed to initialise EEPROM");
  }
  WiFi.mode(WIFI_AP_STA);  
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  WiFi.softAP(ssidAP, passAP);
  Serial.print(F("AP Address: "));
  Serial.println(WiFi.softAPIP());
  server.begin();  
}

bool beepMelody = false;
unsigned long int beepTime = 0;

uint16_t noteTTL = 10; // 2,3
const uint8_t noteSt = 4;
uint16_t octSt = 18;   // noteTTL+noteSt
uint16_t durSt = 29;   // noteTTL+octSt+1

bool eepromMelody = false;
uint8_t eepromDur = 0;

void wifi() {
  WiFiClient client = server.available();  // listen for incoming clients
  if (client.available()) {  
    String line = client.readStringUntil('\n');
    String temp = line.substring(5, 9); // "GET /%%F0"
    if (temp == F("%%F0")) { // GET /%%F0tempo,notenum%(note,...)%(oct,...)%(dur,...)\n
      temp = line.substring(9, 12);
      if (temp == F("%S%")) {
        eepromMelody = false;
        ledcWrite(0,0);
      } 
      else if (temp == F("%P%")) {
        eepromMelody = true;
        noteNum = 0; beepTime = 0;
        Tempo = EEPROM.read(1);
        noteTTL = EEPROM.readShort(2); //EEPROM.get(2);
        octSt = noteTTL+noteSt;  
        durSt = noteTTL+octSt+1; 
        tempoRatio = Tempo/60;
        eepromDur = EEPROM.read(durSt+noteNum);
      } 
      else {
        uint8_t value = 0;
        uint16_t indexSt = 9;
        uint16_t indexEd = line.indexOf(F(","));
        String temp = line.substring(indexSt, indexEd);
        value = temp.toInt();
        Tempo = value;    
        indexSt = line.indexOf(F("%"),indexEd);
        temp = line.substring(indexEd+1,indexSt);
        value = temp.toInt();
        noteTTL = value;
        octSt = noteTTL+noteSt;  
        durSt = noteTTL+octSt+1; 
        EEPROM.write(1,Tempo);
        EEPROM.put(2,noteTTL);
        uint8_t indexDel = line.lastIndexOf(F("%"));
        indexSt = indexDel+1;
        for (int i = 0; i < noteTTL+1; i++) {
          indexEd = line.indexOf(F(","), indexSt);
          temp = line.substring(indexSt, indexEd);
          value = temp.toInt();
          EEPROM.write(durSt+i,value);
          indexSt = indexEd+1;
        }
        line.remove(indexDel);
        indexDel = line.lastIndexOf(F("%"));
        indexSt = indexDel+1;
        for (int i = 0; i < noteTTL+1; i++) {
          indexEd = line.indexOf(F(","), indexSt);
          temp = line.substring(indexSt, indexEd);
          value = temp.toInt();
          EEPROM.write(octSt+i,value);
          indexSt = indexEd+1;
        }
        line.remove(indexDel);
        indexDel = line.lastIndexOf(F("%"));
        indexSt = indexDel+1;
        for (int i = 0; i < noteTTL; i++) {
          indexEd = line.indexOf(F(","), indexSt);
          temp = line.substring(indexSt, indexEd);
          value = temp.toInt();
          EEPROM.write(noteSt+i,value);
          indexSt = indexEd+1;
        }
        EEPROM.commit();
        if (beepMelody) beepMelody = false;
        eepromMelody = true;
      }
      client.println(F("HTTP/1.1 200 OK\nContent-type:text/html\nConnection: close\r\n"));
      client.println(F("%M%"));
    } else {
      client.println(F("HTTP/1.1 200 OK\nContent-type:text/html\nConnection: close\r\n"));
      client.println(F("%C%"));
    }
    client.stop();
  }
}

void loop() {
  wifi();
  if (beepMelody) {
    if (millis() - beepTime >= Mdur[noteNum]*(1000/(4*tempoRatio))) {
      beepTime = millis();
      ledcWrite(0,0); 
      octaveTemp = Moct[noteNum];
      note_t KeyNote = keySignature(Mnote[noteNum]);
      ledcWriteNote(0, KeyNote, octaveTemp);  // ledcWriteNote(uint8_t channel, note_t note, uint8_t octaveTemp);
      noteNum++;
      if (noteNum == sizeof(Mdur)) { // 초기화
        ledcWrite(0,0);  //  noTone() - ledcWrite(uint8_t channel, uint32_t duty);
        noteNum = 0; 
      }
    }
  }
  else if (eepromMelody) {
    if (millis() - beepTime >= eepromDur*(1000/(4*tempoRatio))) {
      beepTime = millis();
      ledcWrite(0,0); 
      octaveTemp = EEPROM.read(octSt+noteNum);
      note_t KeyNote = noteConvertor(EEPROM.read(noteSt+noteNum));
      ledcWriteNote(0, KeyNote, octaveTemp);  // ledcWriteNote(uint8_t channel, note_t note, uint8_t octaveTemp);
      noteNum++;
      if (noteNum == noteTTL+1) { // 초기화
        ledcWrite(0,0);  //  noTone() - ledcWrite(uint8_t channel, uint32_t duty);
        noteNum = 0; 
      }
      eepromDur = EEPROM.read(durSt+noteNum);
    }
  }
  if(Serial.available() > 0){
    String temp = Serial.readStringUntil('\n');
    Serial.println(temp);
    if (temp == "0") {
      beepMelody = !beepMelody;
      noteNum = 0; beepTime = 0;
      if (!beepMelody) ledcWrite(0,0);  
      eepromMelody = false;
    }
    else if (temp == "1") {
      eepromMelody = !eepromMelody;
      noteNum = 0; beepTime = 0;
      Tempo = EEPROM.read(1);
      noteTTL = EEPROM.readShort(2); //EEPROM.get(2);
      octSt = noteTTL+noteSt;  
      durSt = noteTTL+octSt+1; 
      tempoRatio = Tempo/60;
      eepromDur = EEPROM.read(durSt+noteNum);
    }
    else if (temp == "2") {
      beepMelody = false;
      eepromMelody = false;
      ledcWrite(0,0);
    }
  }
}

 

+ Recent posts