firmware of NBCTRLV1 / AYC01
Dependencies: SDFileSystemEx mbed
main.cpp
- Committer:
- bkc_mbed
- Date:
- 2016-04-18
- Revision:
- 1:29f0e76a9999
- Parent:
- 0:722cc5360dc3
File content as of revision 1:29f0e76a9999:
// // NLGPLAY : NLG file player for mbed // // example to write : // ./lpc21isp -bin file.bin /dev/cu.usbserial-??? 115200 12000 // // 20151008: updated. // 20160418: imporved file/dir selector // improved init sequence // #include <stdio.h> #include "mbed.h" #include "SDFileSystem.h" #include "lcd.h" #include "nlg_mini.h" // SPIモード // #define USE_SPI #ifdef TARGET_LPC1114 // 高速I/Oモード(LPC1114専用) #define USE_FASTIO #endif // ピンアサイン切り替え #include "pindef.h" #define PRG_NAME "NLGPLAY" #define PRG_VER_BASE "V1.30" #ifndef USE_SPI #define PRG_VER PRG_VER_BASE #else #define PRG_VER PRG_VER_BASE "S" #endif //#pragma O3 //#pragma Otime // (pinname, mode) DigitalIn sw_play(DP_PLAY, PullUp); DigitalIn sw_next(DP_NEXT, PullUp); DigitalIn sw_prev(DP_PREV, PullUp); #define MAX_PATH 128 #define MAX_FILENAME 64 #define MAX_DIR 64 // Global Variable struct { bool stop; bool prev; bool one_mode; int idx; int max_entries; char playlist[MAX_FILENAME]; char file[MAX_FILENAME]; char cwd[MAX_DIR]; NLG_CTX nlg; int total_sec; } g; // キーコード #define SW_PLAY 1 #define SW_NEXT 2 #define SW_PREV 4 // ボタンが離されるのを待つ void wait_key_up(void) { while(!sw_next || !sw_play || !sw_prev); } // ボタンの入力を待つ void wait_key_down(void) { while(sw_next && sw_play && sw_prev); } // キー入力 int get_key(void) { int key = 0; if (!sw_next) key |= SW_NEXT; if (!sw_play) key |= SW_PLAY; if (!sw_prev) key |= SW_PREV; return key; } // キー開放待ち void wait_relkey(void) { wait_key_up(); wait(0.1); } // キー待ち int wait_anykey(void) { wait_key_down(); int key = get_key(); wait(0.1); wait_relkey(); return key; } // LED DigitalOut led1(LED1, 0); DigitalOut led2(LED2, 0); // SPI: MOSI, MISO, SCLK, CS SDFileSystem sd(DP_MOSI, DP_MISO, DP_SCLK, DP_SCS, "sd"); // LCD LCD lcd; #define _WAIT for(int wcnt=0; wcnt < 2; wcnt++) //////////////// // 高速IO #define DBS IO_01 // DATA #define CTS IO_02 // CTRL #define RCK IO_04 // LATCH #define SCK IO_03 // SCLK DigitalOut io01(DP_IO01, 0); // P1_4 DigitalOut io02(DP_IO02, 0); // P0_3 DigitalOut io03(DP_IO03, 0); // P1_8 DigitalOut io04(DP_IO04, 0); // P0_11 #if 0 // NBV3での試し機能 #define IO_A0 io05 #define IO_WR io06 DigitalOut io05(DP_IO05, 0); // P1_9 DigitalOut io06(DP_IO06, 0); // P1_2 #endif #define IO_01 (1 << 4) // DBS P1_4 #define IO_02 (1 << 3) // CTS P0_3 #define IO_03 (1 << 8) // SCK P1_8 #define IO_04 (1 << 11) // RCK P0_11 #ifdef USE_FASTIO // ポート出力 #define DATA_HI LPC_GPIO1->DATA |= DBS #define DATA_LO LPC_GPIO1->DATA &= ~DBS #define CTRL_HI LPC_GPIO0->DATA |= CTS #define CTRL_LO LPC_GPIO0->DATA &= ~CTS #define SCK_HI LPC_GPIO1->DATA |= SCK #define SCK_LO LPC_GPIO1->DATA &= ~SCK #define RCK_HI LPC_GPIO0->DATA |= RCK #define RCK_LO LPC_GPIO0->DATA &= ~RCK // 出力設定 #define PORT_DIR LPC_GPIO0->DIR |= (IO_02 | IO_04); \ LPC_GPIO1->DIR |= (IO_01 | IO_03) #else // ポート出力 #define DATA_HI io01 = 1 #define DATA_LO io01 = 0 #define CTRL_HI io02 = 1 #define CTRL_LO io02 = 0 #define SCK_HI io03 = 1 #define SCK_LO io03 = 0 #define RCK_HI io04 = 1 #define RCK_LO io04 = 0 // 出力設定 #define PORT_DIR #endif SPI *spi; // I/O初期化 void ioInit() { // SPIインスタンスの取得 spi = sd.getSPI(); // 出力 PORT_DIR; } #ifndef USE_SPI // 8x2ビットモード #define SHIFTOUT io8x2Out // 8bit 出力 void byteOut(unsigned char data) { int i; for(i = 0; i < 8; i++) { if (data & 0x80) DATA_HI; else DATA_LO; data <<= 1; SCK_HI; SCK_LO; } } // 8x2ビット出力 or 16bit出力選択可能 void io8x2Out(unsigned int ctrl, unsigned int data) { int i; // シフトレジスタ直列モード if (g.one_mode) { // データ順 // <- CCCCCCCC76543210 byteOut(ctrl); byteOut(data); // ラッチ RCK_HI; RCK_LO; } else { // シフトレジスタ並列モード for(i = 0; i < 8; i++) { /* 2ビット分のデータをそれぞれ出力 */ if (ctrl & 0x80) CTRL_HI; else CTRL_LO; if (data & 0x80) DATA_HI; else DATA_LO; ctrl <<= 1; data <<= 1; // シフトクロック SCK_HI; SCK_LO; } // ラッチ RCK_HI; RCK_LO; } } #else // 16bitモード #define SHIFTOUT io16Out // 16bit 出力 void io16Out(unsigned char ctrl, unsigned char data) { spi->write(ctrl); spi->write(data); // byteOut(ctrl); // byteOut(data); // LATCH RCK_HI; RCK_LO; } #endif /* 制御信号定義 */ #define CS_FM3 (1 << 0) #define CS_PSG (1 << 1) #define CS_FM1 (1 << 2) #define CS_FM2 (1 << 3) #define A0 (1 << 4) #define WR (1 << 5) #define ICL (1 << 6) #define CTL (1 << 7) /* アクティブローの制御信号 */ #define ACTLOW (CS_PSG | CS_FM1 | CS_FM2 | CS_FM3 | WR | ICL) /* NBV2互換出力 */ void regOutBase(int addr, int data, int select) { /* アドレスを出力 */ /* A0をローにして待つ */ int ctrl = ACTLOW; /* 裏レジスタ */ if (addr >= 0x100) ctrl |= CTL; addr &= 0xff; SHIFTOUT(ctrl, 0x00); SHIFTOUT(ctrl & ~(select | WR), addr); SHIFTOUT(ctrl, addr); /* チップ処理待ち */ /* データを出力 */ /* A0をハイにして待つ */ ctrl |= A0; SHIFTOUT(ctrl, 0x00); SHIFTOUT(ctrl & ~(select | WR), data); SHIFTOUT(ctrl, data); /* チップ処理待ち */ } /* 出力 */ #define regPSGOut(addr, data) regOutBase(addr, data, CS_PSG) #define regFMOut(addr, data) regOutBase(addr, data, CS_FM1) #define regFM2Out(addr, data) regOutBase(addr, data, CS_FM2) /* 音源出力 */ #define WritePSG regPSGOut #define WriteOPM regFMOut #define WriteOPM2 regFM2Out /* ミュート */ void boardMute(void) { int i; /* PSG初期化 */ regPSGOut(0x00,0); regPSGOut(0x01,0); regPSGOut(0x06, 0x00); regPSGOut(0x07, 0x3f); // ALL OFF regPSGOut(0x08, 0x00); // CH.A 0 regPSGOut(0x09, 0x00); // CH.B 0 regPSGOut(0x0a, 0x00); // CH.C 0 /* MUTE(disable) */ for(i = 0x20; i < 0x28; i++) { regFMOut(i, 0x00); regFM2Out(i, 0x00); } // KEYOFF for(i = 0x00; i < 0x08; i++) { regFMOut(0x08, i & 0x07); regFM2Out(0x08, i & 0x07); } // FORCE RELEASE for(i= 0x00; i < 0x20; i++) { regFMOut(0xE0 + i, 0x0f); regFM2Out(0xE0 + i, 0x0f); } // OPLL ミュート for(i= 0x00; i <= 0x08; i++) { regFMOut(0x20 + i, 0x00); regFMOut(0x30 + i, 0x0f); regFM2Out(0x20 + i, 0x00); regFM2Out(0x30 + i, 0x0f); } } /* ボード初期化 */ void boardInit(void) { wait_ms(20); /* ICLのみをLOW(アクティブ)にする */ SHIFTOUT(ACTLOW & ~(ICL), 0); wait_ms(150); /* 元に戻す */ SHIFTOUT(ACTLOW, 0); wait_ms(10); } ////////////////////////////////////////// // 表示 void dispTime() { char buf[16]; sprintf(buf, "%02d:%02d", g.total_sec / 60, g.total_sec % 60); lcd.setCursor(3,1); lcd.printStr(buf); } #define WAIT_US 10000 // 10ms #define SEC_US 1000000 // 1sec #define NEXT_MAX_US 300000 // 300ms /* NLGの再生 */ int PlayNLG_Loop(void) { int cmd; int addr, data; int result = 0; int us = 0; int diff_us = 0; int count_us = 0; int total_us = 0; // NEXTボタンのカウンタ int next_count = 0; bool wait_skip = false; // GetTickUsNLG int tick_us = GetTickUsNLG(&g.nlg); // printf("tick_us:%d\n", tick_us); g.total_sec = 0; // タイマースタート Timer t; t.start(); // 表示 dispTime(); // LED消灯 led1 = 0; led2 = 0; // LEDカウンタ int led_cnt1 = 0; int led_cnt2 = 0; // ループ while(!g.stop) { /* ウエイトの処理 */ while (count_us >= WAIT_US) { // ボタンチェック if (!sw_next) { // NEXTが押されている if (next_count < NEXT_MAX_US) next_count += count_us; else { // 早送り next_count = NEXT_MAX_US; wait_skip = true; } } else { // NEXTが離されている wait_skip = false; // 一瞬だけボタンが押された場合、次の曲へ if (next_count > 0 && next_count < NEXT_MAX_US) { next_count = 0; goto song_end; } // 早送りの終了 if (next_count == NEXT_MAX_US) { next_count = 0; } } // PREVが押された if (!sw_prev) { g.prev = true; goto song_end; } // PLAYが押された if (!sw_play) { g.stop = true; goto song_end; } // スキップでなければ次のタイミングまで待つ while(!wait_skip && (us = t.read_us()) + diff_us < count_us); // タイマーリセット if (!wait_skip) t.reset(); // 差分を計算 diff_us += us; while(diff_us >= count_us) diff_us -= count_us; // 積算する total_us += count_us; count_us = 0; // 1秒で積算カウントをリセットする if (total_us >= SEC_US) { while(total_us >= SEC_US) { g.total_sec++; total_us -= SEC_US; } // 表示 dispTime(); } } /* コマンドの読み出し */ cmd = ReadNLG(&g.nlg); if (cmd == EOF) { result = EOF; break; } if (cmd < 0x80) { addr = ReadNLG(&g.nlg); data = ReadNLG(&g.nlg); // 裏レジスタ if (cmd >= 0x40) addr |= 0x100; switch(cmd & 0x3f) { case CMD_PSG: WritePSG(addr, data); break; case CMD_FM1: WriteOPM(addr, data); break; case CMD_FM2: WriteOPM2(addr, data); break; } } else { /* コマンドの処理 */ switch (cmd) { case CMD_IRQ: count_us += tick_us; // LED1 led_cnt1++; if (led_cnt1 >= 48) { led_cnt1 = 0; led1 = !led1; } // LED2 led_cnt2++; if (led_cnt2 >= 192) { led_cnt2 = 0; led2 = !led2; } break; case CMD_CTC0: data = ReadNLG(&g.nlg); SetCTC0_NLG(&g.nlg, data); tick_us = GetTickUsNLG(&g.nlg); // printf("CTC0:%d tick_us:%d\n", data, tick_us); break; case CMD_CTC3: data = ReadNLG(&g.nlg); SetCTC3_NLG(&g.nlg, data); tick_us = GetTickUsNLG(&g.nlg); // printf("CTC3:%d tick_us:%d\n", data, tick_us); break; } } } song_end: return result; } // ファイルを再生する int play_file(const char *filename) { /* NLGファイルを開く */ if (OpenNLG(&g.nlg, filename) < 0) { return -1; } /* 再生する */ PlayNLG_Loop(); /* NLGファイルを閉じる */ CloseNLG(&g.nlg); return 0; } // error_sdcard() // エラー! void error_sdcard(void) { lcd.printStr2("SD CARD", "ERROR!"); while(1); } // COM mode void loop_for_com(void) { int sw, val; int adr = 0x00; int baud = 9600; char buf[16]; Serial pc(DP_TX, DP_RX); lcd.cls(); lcd.printStrY(0, "COM MODE"); sprintf(buf, "%-8d", baud); lcd.printStrY(1, buf); pc.printf("COM\n"); // タイマースタート Timer t; t.start(); while(1) { sw = pc.getc(); // 0は同期リセット if (sw == 0x00) continue; if (sw >= 1 && sw <= 3) { adr = pc.getc(); val = pc.getc(); } switch(sw) { case 1: regFMOut(adr, val); break; case 2: regFM2Out(adr, val); break; case 3: regPSGOut(adr, val); break; case 0x0f: // 通信速度設定 val = pc.getc(); baud = (9600 * val); sprintf(buf, "%-8d", baud); lcd.printStrY(1, buf); pc.baud(baud); break; case 0x10: // val = pc.getc(); val = (val * 10000); while(t.read_us() < val); pc.putc('.'); t.reset(); break; case 0x11: t.reset(); break; } // pc.printf("sw = %02x, adr = %02x, val = %02x\n", sw, adr, val); } } // chk_isdir // ディレクトリか否か // return : bool // false if not directory bool chk_isdir(const char *cwd, const char *dir) { char tmp[256]; sprintf(tmp,"%s/%s", cwd, dir); DIR *dp = opendir(tmp); if (!dp) return false; closedir(dp); return true; } #define EXT_LIST ".lst" #define EXT_NLG ".nlg" // get_fileentry // index : index of list , -1 = return number of entries // is_mode : 0 = normal mode // mode = MODE_GETDIR | MODE_GETLIST | MODE_FILE // return : int // -1 = not found or error #define MODE_FILE 0 #define MODE_GETDIR 1 #define MODE_GETLIST 2 int get_fileentry(int index, int mode) { // return -1 if entry is zero. int count = 0; DIR *dp = opendir(g.cwd); g.file[0] = 0; if (!dp) return -1; struct dirent *dent = NULL; while(1) { // エントリの読み出し dent = readdir(dp); // 失敗 if (!dent) break; // リソースか隠しファイル if (dent->d_name[0] == '.') continue; // 拡張子の取得 char *ext = strrchr(dent->d_name, '.'); switch(mode) { // ディレクトリモード case MODE_GETDIR: // ディレクトリでなければ継続 if (!chk_isdir(g.cwd, dent->d_name)) continue; break; // プレイリストモード case MODE_GETLIST: // リストでなければ無視 if (!ext || strcasecmp(ext, EXT_LIST) != 0) continue; break; // ファイルモード case MODE_FILE: // NLGファイルでなければ継続 if (!ext || strcasecmp(ext, EXT_NLG) != 0) continue; break; } // カウントアップ count++; // カウントモードかカウントがindex未満で継続 if (index < 0 || count <= index) continue; // ファイル名をコピーして終了 strcpy(g.file, dent->d_name); break; } closedir(dp); return count; } // // タイトル表示 // int putTitle() { int count_ms = 0; int diff_us = 0; int us = 0; int key = get_key(); // キー入力時はキャンセル if (key) return key; lcd.printStr2(PRG_NAME, PRG_VER); Timer t; t.start(); // 1500msまでループする while(count_ms < 1500) { while((us = t.read_us()) + diff_us < 1000); t.reset(); // キー入力があれば終了 key = get_key(); if (key) return key; // 差分を現在の時間に足して次の差分を作る diff_us += us; while(diff_us >= 1000) { count_ms++; diff_us -= 1000; } } return 0; } // 情報の表示 void show_info(int files) { char buf[16]; Timer t; int result_us = 0; t.reset(); t.start(); // 実際の書き込み時間を計測する regFMOut(0x20, 0x00); regFMOut(0x20, 0x00); regFMOut(0x20, 0x00); regFMOut(0x20, 0x00); regFMOut(0x20, 0x00); // 経過時間を得る result_us = t.read_us(); t.stop(); // 平均値 result_us /= 5; // 結果表示 printf("result_us=%dus\n", result_us); sprintf(buf, "R:%dus", result_us); lcd.printStrY(1, buf); wait(3); // コンパイル時の日付 sprintf(buf, "%8s", __DATE__); lcd.printStrYscr(1, buf); wait(3); if (files < 0) lcd.printStrY(1, "NO FILES"); else { sprintf(buf, "%3dfiles", files); lcd.printStrY(1, buf); } wait(3); lcd.cls(); } // ビットテスト void bit_test() { char buf[9]; lcd.printStrY(0, "BIT_TEST"); wait_key_up(); int pin = 0; int mode = 0; char sig; while(1) { // 表示 if (mode & 1) sig = 'C'; // コントロール else sig = 'D'; // データ if (mode & 2) strcpy(buf,"00"); else sprintf(buf, "%c%d", sig, pin); lcd.printStrY(1, buf); // 出力 if (mode & 2) { SHIFTOUT(0xff, 0x00); } else { int bit = (1 << pin); if (mode & 1) SHIFTOUT(0xff & ~(bit), 0); // コントロール else SHIFTOUT(0xff, bit); // データ } // キー待ち int key = wait_anykey(); // 再生 if (key & SW_PLAY) { mode ^= 2; continue; } // 次 if (key & SW_NEXT) { pin++; if (pin > 7) { pin = 0; mode = (mode + 1) & 1; } } // 前 if (key & SW_PREV) { pin--; if (pin < 0) { pin = 7; mode = (mode - 1) & 1; } } } } // // ファイル選択表示 void disp_filesel(int mode) { char buf[16]; char buf_mode[16]; char *mode_name; switch(mode) { case MODE_GETLIST: mode_name = "LIST"; break; case MODE_GETDIR: mode_name = "DIR "; break; default: mode_name = "FILE"; } sprintf(buf_mode, "%s %03d", mode_name, g.idx + 1); strncpy(buf, g.file, 8); buf[8] = 0; // 表示 lcd.printStr2(buf, buf_mode); } // // ファイル/ディレクトリ選択 // mode = MODE_GETLIST | MODE_GETDIR | MODE_FILE // int file_select(int mode) { // ファイル数を得る int files = get_fileentry(-1, mode); // 最大エントリー g.max_entries = files - 1; // ファイル名の取得 get_fileentry(g.idx, mode); // 表示 disp_filesel(mode); // リリース待ち wait_relkey(); while(1) { // ファイル名の取得 get_fileentry(g.idx, mode); // 表示 disp_filesel(mode); // キー待ち int key = wait_anykey(); // 次のエントリ if (key & SW_NEXT) { if (g.idx < g.max_entries) g.idx++; else g.idx = 0; } // 前のエントリ if (key & SW_PREV) { if (g.idx > 0) g.idx--; else g.idx = g.max_entries; } // 再生ボタンを押した if (key & SW_PLAY) break; } return g.idx; } // get_playlist() // index = リスト位置, -1でエントリ数を返す int get_playlist(int index) { int count = 0; FILE *fp = fopen(g.playlist, "r"); g.file[0] = 0; // プレイリストが開けない if (!fp) return -1; while(1) { // プレイリストから一行読み込む char *p = fgets(g.file, MAX_FILENAME, fp); // EOFなので終了 if (!p) break; // サイズ int len = strlen(g.file); // CR/LFをトリムする while(len > 0 && (unsigned char)g.file[len - 1] < 0x20) { g.file[len - 1] = 0x00; len--; } // 空行は飛ばす if (!len) continue; count++; // カウントモードかカウントがindex未満で継続 if (index < 0 || count <= index) continue; else break; } // プレイリストを閉じる fclose(fp); #if defined(__MICROLIB) && defined(__ARMCC_VERSION) free(fp); #endif return count; } // グローバル変数初期化 void init_globe(void) { memset(&g, 0, sizeof(g)); strcpy(g.cwd,"/sd"); } // パスの作成 void make_path(char *path, const char *dir, const char *file) { sprintf(path, "%s/%s", dir, file); } // 再生モード void play_mode(void) { int files = -1; // プレイリストモードか否か if (g.playlist[0]) files = get_playlist(-1); else files = get_fileentry(-1, MODE_FILE); // エラー表示 if (files < 0) error_sdcard(); g.max_entries = files - 1; bool repeat_flag = false; // ファイルが無い if (files < 1) { lcd.cls(); lcd.printStrY(0, "NO FILES"); wait(1); } // 再生モードループ while(1) { char path[MAX_PATH]; char buf[16]; // プレイリストかどうか? if (g.playlist[0]) get_playlist(g.idx); else get_fileentry(g.idx, MODE_FILE); // フルパスを作成 make_path(path, g.cwd, g.file); // 曲番号 sprintf(buf, "%2d ", g.idx + 1); // ファイル名名表示 lcd.cls(); lcd.printStrY(0, g.file); lcd.printStrY(1, buf); // 再生開始 play_file(path); // ミュート boardMute(); // キー開放待ち wait_relkey(); // 再生ボタンが押された if (g.stop) { // ストップ表示 lcd.printStrY(1, " STOP "); g.stop = false; g.prev = false; g.total_sec = 0; // ボード初期化 boardInit(); // ファイル選択 file_select(MODE_FILE); continue; } // 前の曲を再生 if (g.prev) { g.prev = false; // 同じ曲を再生 if (g.total_sec >= 2) continue; if (g.idx > 0) g.idx--; else g.idx = g.max_entries; continue; } // 繰り返しではない if (!repeat_flag) { if (g.idx < g.max_entries) g.idx++; else g.idx = 0; } repeat_flag = false; } } // // メニュー選択 // #define MENU_FILE 0 #define MENU_DIR 1 #define MENU_LIST 2 #define MENU_INFO 3 #define MENU_COM 4 #define MENU_TEST 5 #define MENU_SMODE 6 #define MENU_MAX 6 // メニュー文字列 const char *menu_modes[] = { "FILE", // 0 "DIR", // 1 "LIST", // 2 "INFO", // 3 "COM", // 4 "TEST", // 5 "Sx16", // 6 }; // メニュー選択表示 void menu_disp(int sel) { char buf[16]; // 表示 lcd.printStrY(0, "MENU SEL"); sprintf(buf, "%02d %-4s", sel, menu_modes[sel]); lcd.printStrY(1, buf); } // モード選択 int menu_select() { int count = 0; // 初期表示 menu_disp(0); // リリース待ち wait_key_up(); while(1) { // キー待ち int key = wait_anykey(); // 次 if (key & SW_NEXT) { if (count < MENU_MAX) count++; else count = 0; } // 前 if (key & SW_PREV) { if (count > 0) count--; else count = MENU_MAX; } // 再生 if (key & SW_PLAY) break; // 表示 menu_disp(count); } return count; } // メニューモード void menu_mode(void) { int files = 0; char path[MAX_PATH]; menu_start: // ボードの初期化 boardInit(); int sw = menu_select(); switch(sw) { // ファイル選択 case MENU_FILE: file_select(MODE_FILE); break; // ディレクトリ選択 case MENU_DIR: file_select(MODE_GETDIR); // パスを結合し、インデックスを初期化 make_path(path, g.cwd, g.file); strcpy(g.cwd, path); g.idx = 0; break; // プレイリスト選択 case MENU_LIST: file_select(MODE_GETLIST); break; // 情報モード case MENU_INFO: files = get_fileentry(-1, MODE_FILE); show_info(files); goto menu_start; // 通信モード case MENU_COM: loop_for_com(); break; // テストモード case MENU_TEST: bit_test(); break; // ストレートモード case MENU_SMODE: g.one_mode = true; lcd.printStr2("","Sx16 ON"); wait(0.5); goto menu_start; } } // // main // int main() { // 初期化 init_globe(); // I/O初期化 ioInit(); // シフトレジスタの初期化 SHIFTOUT(ACTLOW & ~(ICL), 0x00); // 立ち上がり待ち wait_ms(20); // LCD初期化 lcd.init(); // ICLなどをHにする SHIFTOUT(ACTLOW, 0x00); // 消音する boardMute(); // タイトル表示 int key = putTitle(); // NEXTボタンでメニュー表示 if (key & SW_NEXT) menu_mode(); // 再生モード play_mode(); }