音譜をテキストファイルに記入し、それを自動演奏させるオルガンを製作しました。
<プログラムの流れ>
<演奏までの流れ>
<表記>
音階の周波数および音譜の表記は、次の表のようになります。(音譜間はカンマ区切り)
<その他の表記>
DO :ド
DO-:ドー
-:休止記号
<表記例:ドレミファソラシ>
DO,RE,MI,FA,SO,RA,SI
<表記例:1オクターブ上のドレミファソラシ>
DO2,RE2,MI2,FA2,SO2,RA2,SI2
//********************************************************************** /* 「簡易自動演奏オルガン(SDC対応)」 */ //********************************************************************** #define SW PORTE.F3 #define LED PORTA.F0 #define CR 0x0d #define LF 0x0a #define DO 262 #define RE 294 #define MI 330 #define FA 349 #define SO 392 #define RA 440 #define SI 494 #define DO2 523 #define RE2 587 #define MI2 659 #define FA2 699 #define SO2 784 #define RA2 880 #define SI2 988 //********************************************************************** void init_sdc() { static short cnt; //SDC(MMC)の初期化 Spi_Init_Advanced(MASTER_OSC_DIV64, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH); if (Mmc_Fat_Init(&PORTC, 6)) { while (1) { LED = 1; Delay_ms(100); LED = 0; Delay_ms(100); } } Spi_Init_Advanced(MASTER_OSC_DIV16, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH); for (cnt = 0; cnt < 3; cnt++) { LED = 1; Delay_ms(300); LED = 0; Delay_ms(300); } } //********************************************************************** void SwitchONcheck() { while (Button(&PORTE, 3, 1, 0) == 0) ; while (Button(&PORTE, 3, 1, 1) == 0) ; } //********************************************************************** void doremiProc(int freq, long time) { static int cnt, tmp; // switch (freq) { case DO: tmp = time / (1000000 / DO); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / DO / 2); PORTC.F2 = 0; Delay_us(1000000 / DO / 2); } break; case RE: tmp = time / (1000000 / RE); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / RE / 2); PORTC.F2 = 0; Delay_us(1000000 / RE / 2); } break; case MI: tmp = time / (1000000 / MI); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / MI / 2); PORTC.F2 = 0; Delay_us(1000000 / MI / 2); } break; case FA: tmp = time / (1000000 / FA); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / FA / 2); PORTC.F2 = 0; Delay_us(1000000 / FA / 2); } break; case SO: tmp = time / (1000000 / SO); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / SO / 2); PORTC.F2 = 0; Delay_us(1000000 / SO / 2); } break; case RA: tmp = time / (1000000 / RA); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / RA / 2); PORTC.F2 = 0; Delay_us(1000000 / RA / 2); } break; case SI: tmp = time / (1000000 / SI); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / SI / 2); PORTC.F2 = 0; Delay_us(1000000 / SI / 2); } break; case DO2: tmp = time / (1000000 / DO2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / DO2 / 2); PORTC.F2 = 0; Delay_us(1000000 / DO2 / 2); } break; case RE2: tmp = time / (1000000 / RE2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / RE2 / 2); PORTC.F2 = 0; Delay_us(1000000 / RE2 / 2); } break; case MI2: tmp = time / (1000000 / MI2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / MI2 / 2); PORTC.F2 = 0; Delay_us(1000000 / MI2 / 2); } break; case FA2: tmp = time / (1000000 / FA2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / FA2 / 2); PORTC.F2 = 0; Delay_us(1000000 / FA2 / 2); } break; case SO2: tmp = time / (1000000 / SO2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / SO2 / 2); PORTC.F2 = 0; Delay_us(1000000 / SO2 / 2); } break; case RA2: tmp = time / (1000000 / RA2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / RA2 / 2); PORTC.F2 = 0; Delay_us(1000000 / RA2 / 2); } break; case SI2: tmp = time / (1000000 / SI2); for (cnt = 0; cnt < tmp; cnt++) { PORTC.F2 = 1; Delay_us(1000000 / SI2 / 2); PORTC.F2 = 0; Delay_us(1000000 / SI2 / 2); } break; } } //********************************************************************** void organProc() { //変数の定義 static char buf[10], character, cnt; static unsigned long fsize, length; //MMCのファイルのオープン Mmc_Fat_Assign("organ.txt", 0); Mmc_Fat_Reset(&fsize); length = 0; cnt = 0; // while (length < fsize) { Mmc_Fat_Read(&character); length++; // switch (character) { case ',': case CR: buf[cnt] = 0x00; cnt = 0; if (strstr(buf, "DO2") != 0x00) { doremiProc(DO2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "RE2") != 0x00) { doremiProc(RE2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "MI2") != 0x00) { doremiProc(MI2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "FA2") != 0x00) { doremiProc(FA2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "SO2") != 0x00) { doremiProc(SO2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "RA2") != 0x00) { doremiProc(RA2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "SI2") != 0x00) { doremiProc(SI2, buf[3] == '-' ? 750000 : 500000); break; } if (strstr(buf, "DO") != 0x00) { doremiProc(DO, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "RE") != 0x00) { doremiProc(RE, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "MI") != 0x00) { doremiProc(MI, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "FA") != 0x00) { doremiProc(FA, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "SO") != 0x00) { doremiProc(SO, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "RA") != 0x00) { doremiProc(RA, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "SI") != 0x00) { doremiProc(SI, buf[2] == '-' ? 750000 : 500000); break; } if (strstr(buf, "-") != 0x00) { Delay_ms(100); break; } break; case ' ': break; case LF: Delay_ms(1000); break; default: buf[cnt] = character; cnt++; break; } } } //********************************************************************** void main() { //コンパレータは使用しない。 CMCON = 0b00000111; //A/D変換の設定 ADCON1.PCFG3 = 1; ADCON1.PCFG2 = 1; ADCON1.PCFG1 = 1; ADCON1.PCFG0 = 1; // OSCCON.IRCF2 = 1; OSCCON.IRCF1 = 1; OSCCON.IRCF0 = 1; //ポートの設定 TRISA = 0b0000000000; TRISB = 0b00000001; TRISC = 0b00000000; //SDC(MMC)の初期化 init_sdc(); // while (1) { SwitchONcheck(); LED = 1; organProc(); LED = 0; } } //**********************************************************************
左側から、スタート用プッシュスイッチ、LED、PIC18F2550、乾電池(単三2本)、SDカード、圧電スピーカ
音譜の例です。“organ.txt”をメモ帳で開いたところです。
<チューリップ>
DO,RE,MI-,-,DO,RE,MI-,-,SO,MI,RE,DO,RE,MI,RE-,-,DO,RE,MI-,-,DO,RE,MI-,-,SO,MI,RE,DO,RE,MI,DO-,-,SO,
SO,MI,SO,RA,RA,SO-,-,MI,MI,RE,RE,DO-
<かえるの歌>
DO,RE,MI,FA,MI,RE,DO-,-,MI,FA,SO,RA,SO,FA,MI-,-,DO,-,-,DO,-,-,DO,-,-,DO,-,-,DO,DO,RE,RE,MI,MI,FA,FA,
MI-,RE-,DO-
如何でしょうか?
もう少し滑らか(自然)に演奏させるには、表記をもっと工夫する必要がありますが、用途によってはこれで十分なのでは。。。