nlgplay for mbed
Dependencies: SDFileSystemEx mbed
main.cpp
- Committer:
- bkc_mbed
- Date:
- 2014-08-18
- Revision:
- 7:7e183b33c3f9
- Parent:
- 6:e48296dca6bb
- Child:
- 8:88c89fd324bd
File content as of revision 7:7e183b33c3f9:
#include "mbed.h" #include "SDFileSystem.h" #include "lcd.h" // #define USE_NBV3 // (pinname, initial value) DigitalOut io01(dp13, 0); DigitalOut io02(dp26, 0); DigitalOut io03(dp17, 0); DigitalOut io04(dp4, 0); DigitalOut io05(dp18, 0); DigitalOut io06(dp11, 0); // (pinname, mode) DigitalIn sw_play(dp24, PullUp); DigitalIn sw_next(dp10, PullUp); DigitalIn sw_prev(dp9, PullUp); // LED DigitalOut led1(LED1); DigitalOut led2(LED2); // SPI: MOSI, MISO, SCLK, CS SDFileSystem sd(dp2, dp1, dp6, dp25, "sd"); // // nlg_emb.c // #define CMD_PSG 0x00 #define CMD_OPM 0x01 #define CMD_OPM2 0x02 #define CMD_IRQ 0x80 #define CMD_CTC0 0x81 #define CMD_CTC3 0x82 #define NLG_VER (110) #define NLG_BASECLK (4000000) FILE *nlg_file; char nlg_title[65]; int nlg_baseclk; int nlg_tick; int nlg_length; int nlg_loop_ptr; int nlg_version; int nlg_ctc0; int nlg_ctc3; #define RCK io04 #define SCK io03 #define DBS io01 #define CTS io02 #define IO_A0 io05 #define IO_WR io06 #define _WAIT for(int wcnt=0; wcnt < 2; wcnt++) // 16bit output inline void ioShiftOut(unsigned int data) { int i; for(i = 0; i < 8; i++) { /* 2ビット分のデータをそれぞれ出力 */ if (data & 0x80) CTS = 1; else CTS = 0; if (data & 0x8000) DBS = 1; else DBS = 0; data <<= 1; SCK = 1; // _WAIT; SCK = 0; // _WAIT; } RCK = 1; // _WAIT; RCK = 0; // _WAIT; } /* 制御信号定義 */ #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 ACTLOW (CS_PSG | CS_FM1 | CS_FM2 | WR | ICL) #ifdef USE_NBV3 /* 16bit出力 */ void regOutBase(int addr, int data,int select) { /* アドレスを出力 */ /* A0をローにして待つ */ IO_A0 = 0; ioShiftOut((addr << 8) | (ACTLOW & ~(select | WR))); ioShiftOut((addr << 8) | (ACTLOW)); /* チップ側の処理を待つ */ /* データを出力 */ /* A0をハイにして待つ */ IO_A0 = 1; ioShiftOut((data << 8) | (ACTLOW & ~(select | WR))); ioShiftOut((data << 8) | (ACTLOW)); /* 処理を待つ */ } #else /* NBV2互換出力 */ void regOutBase(int addr, int data,int select) { /* アドレスを出力 */ /* A0をローにして待つ */ ioShiftOut((addr << 8) | (ACTLOW)); ioShiftOut((addr << 8) | (ACTLOW & ~(select | WR))); ioShiftOut((addr << 8) | (ACTLOW)); /* チップ処理待ち */ /* データを出力 */ /* A0をハイにして待つ */ ioShiftOut((data << 8) | A0 | (ACTLOW)); ioShiftOut((data << 8) | A0 | (ACTLOW & ~(select | WR))); ioShiftOut((data << 8) | A0 | (ACTLOW)); /* チップ処理待ち */ } #endif /* PSG出力 */ void regPSGOut(int addr, int data) { regOutBase(addr, data, CS_PSG); } /* FM2出力 */ void regFM2Out(int addr, int data) { regOutBase(addr, data, CS_FM2); } /* FM音源にデータを出力 */ void regFMOut(int addr,int data) { regOutBase(addr, data, CS_FM1); } /* ボード消音 */ 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); } } /* ボード初期化 */ void boardInit(void) { wait_ms(20); /* ICLのみをLOW(アクティブ)にする */ ioShiftOut(ACTLOW & ~(ICL)); wait_ms(150); /* 元に戻す */ ioShiftOut(ACTLOW); wait_ms(10); } typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; // 変数書き出し(WORD) void WriteWORD(byte *p,word val) { p[0] = (val & 0xff); p[1] = ((val>>8) & 0xff); } // 変数書き出し(DWORD) void WriteDWORD(byte *p,dword val) { p[0] = (val & 0xff); p[1] = ((val>>8) & 0xff); p[2] = ((val>>16) & 0xff); p[3] = ((val>>24) & 0xff); } // 変数読み出し(WORD) word ReadWORD(byte *p) { return ((word)p[0]) | ((word)p[1])<<8; } // 変数読み出し(DWORD) dword ReadDWORD(byte *p) { return ((dword)p[0]) | ((dword)p[1])<<8 | ((dword)p[2])<<16 | ((dword)p[3])<<24; } // NLGファイルを開く int OpenNLG(const char *file) { byte nlg_hdr[0x60]; nlg_file = fopen(file, "rb"); if (!nlg_file) { printf("File open error:%s\n", file); return -1; } fread(nlg_hdr, 0x60, 1, nlg_file); if (memcmp(nlg_hdr, "NLG1", 4) != 0) { printf("Unknown format!\n"); fclose(nlg_file); return -1; } nlg_version = ReadWORD(nlg_hdr + 4); memcpy(nlg_title, nlg_hdr + 8, 64); nlg_title[64]=0; nlg_baseclk = ReadDWORD(nlg_hdr + 72); nlg_tick = ReadDWORD(nlg_hdr + 76); nlg_length = ReadDWORD(nlg_hdr + 88); nlg_loop_ptr = (long)ReadDWORD(nlg_hdr + 92); fseek(nlg_file, 0x60, SEEK_SET); nlg_ctc0 = nlg_ctc3 = 0; return 0; } #if 0 // 書き込み用NLGファイルを開く int CreateNLG(const char *file) { byte hdr[0x80]; nlg_file = fopen(file, "wb"); if (!nlg_file) { printf("File open error:%s\n", file); return -1; } memset(hdr, 0, 0x80); memcpy(hdr,"NLG1",4); WriteWORD(hdr + 4, NLG_VER); // Version WriteDWORD(hdr + 72, NLG_BASECLK); // BaseCLK WriteDWORD(hdr + 76, 0); // Tick WriteDWORD(hdr + 88, 0); // Length WriteDWORD(hdr + 92, 0); // Loop Pointer fwrite(hdr, 0x60, 1, nlg_file); nlg_ctc0 = nlg_ctc3 = 0; return 0; } // コマンドの書き込み void WriteNLG_CMD(int cmd) { if (!nlg_file) return; fputc(cmd, nlg_file); } // CTC定数の書き込み void WriteNLG_CTC(int cmd,int ctc) { if (!nlg_file) return; fputc(cmd, nlg_file); fputc(ctc, nlg_file); } // データの書き込み void WriteNLG_Data(int cmd,int addr,int data) { if (!nlg_file) return; fputc(cmd, nlg_file); fputc(addr, nlg_file); fputc(data, nlg_file); } #endif // ファイルを閉じる void CloseNLG(void) { if (!nlg_file) return; fclose(nlg_file); #if defined(__MICROLIB) && defined(__ARMCC_VERSION) // with microlib and ARM compiler free(nlg_file); #endif nlg_file = NULL; } // データの読み出し int ReadNLG(void) { return fgetc(nlg_file); } // ファイルポインタの位置を取得 long TellNLG(void) { return ftell(nlg_file); } // ファイルポインタの位置を設定 void SeekNLG(long pos) { fseek(nlg_file, pos, SEEK_SET); } // タイトルの取得 char *GetTitleNLG(void) { return nlg_title; } // ティックの取得 int GetTickNLG(void) { return nlg_tick; } // Set Tick inline void SetTick(void) { nlg_tick = ((nlg_ctc0 * 256) * nlg_ctc3); // printf("nlg_tick=%d\n", nlg_tick); } // CTC0値の設定 void SetCTC0_NLG(int value) { nlg_ctc0 = value; SetTick(); } // CTC3値の設定 void SetCTC3_NLG(int value) { nlg_ctc3 = value; SetTick(); } // 曲の長さを得る int GetLengthNLG(void) { return nlg_length; } // ループポインタを得る int GetLoopPtrNLG(void) { return nlg_loop_ptr; } // ベースクロックを得る int GetBaseClkNLG(void) { return nlg_baseclk; } #define CMD_PSG 0x00 #define CMD_OPM 0x01 #define CMD_OPM2 0x02 #define CMD_IRQ 0x80 #define CMD_CTC0 0x81 #define CMD_CTC3 0x82 /* 単位を扱いやすいように */ typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; /* NLGを処理するための構造体 */ typedef struct { int base_clk; int clk_per_sample; int freeze; int total_samples; int total_sec; int current_samples; int tick; int tick_sec; int irq_count; int irq_loop; long loop_address; int irq_counter; int irq_counter2; } NLG_R; /* 初期化 */ int initNLG(NLG_R *np, const char *nlg_name) { if (OpenNLG(nlg_name) < 0) return -1; np->base_clk = GetBaseClkNLG(); /* printf("Title:%s %d %d %dsec %d\n", GetTitleNLG(), GetBaseClkNLG(), GetTickNLG(), GetLengthNLG(), GetLoopPtrNLG()); */ np->total_samples = 0; np->current_samples = 0; np->total_sec = 0; np->tick = 0; np->tick_sec = 0; np->freeze = 0; np->irq_count = 0; np->irq_loop = GetLoopPtrNLG(); np->loop_address = -1; np->irq_counter = 0; np->irq_counter2 = 0; return 0; } /* PSGへの出力 */ void WritePSG(int addr,int value) { regPSGOut(addr, value); } /* FM1への出力 */ void WriteOPM(int addr,int value) { regFMOut(addr, value); } /* FM2への出力 */ void WriteOPM2(int addr,int value) { regFM2Out(addr, value); } // stop flag bool g_stop = false; bool g_prev = false; void DispNLG(NLG_R *np) { // printf("Time %02d:%02d\r",np->total_sec / 60, np->total_sec % 60); // fflush(stdout); char buf[16]; sprintf(buf, "%02d:%02d", np->total_sec / 60, np->total_sec % 60); lcd_setCursor(3,1); lcd_printStr(buf); } // wait until release buttons void waitButtonRelease(void) { while(!sw_next || !sw_play || !sw_prev); } // wait until press buttons void waitButtonPress(void) { while(sw_next && sw_play && sw_prev); } /* NLGの再生 */ int PlayNLG(NLG_R *np, int sec) { int cmd; int addr, data; int result = 0; int tick; int total_us = 0; int us_tick = np->base_clk / 1000000; printf("start play\n"); Timer t; t.start(); total_us = 0; // wait until release buttons waitButtonRelease(); DispNLG(np); while(np->total_sec < sec && !g_stop) { // push next if (!sw_next) break; // push prev if (!sw_prev) { g_prev = true; break; } // push play if (!sw_play) { g_stop = true; break; } /* ウエイトの処理 */ while (np->tick >= us_tick) { int us = np->tick / us_tick; np->tick -= (us * us_tick); while(t.read_us() < total_us + us); total_us += us; // reset timer if (total_us >= 1000000) { total_us -= t.read_us(); t.reset(); } // DELAY_NEXT(us); // printf("delay : %dus\n",us); } /* コマンドの読み出し */ cmd = ReadNLG(); if (cmd == EOF) { if (np->loop_address >= 0) { SeekNLG(np->loop_address); cmd = ReadNLG(); } else { result = EOF; break; } } /* コマンドの処理 */ switch (cmd) { case CMD_PSG: addr = ReadNLG(); data = ReadNLG(); WritePSG(addr, data); break; case CMD_OPM: addr = ReadNLG(); data = ReadNLG(); WriteOPM(addr, data); break; case CMD_OPM2: addr = ReadNLG(); data = ReadNLG(); WriteOPM2(addr, data); break; case CMD_IRQ: tick = GetTickNLG(); np->tick_sec += tick; np->tick += tick; np->irq_count++; if (np->irq_count == np->irq_loop) { /* ループ位置の設定 */ np->loop_address = TellNLG(); np->loop_address -= 1; } np->irq_counter++; if (np->irq_counter >= 48) { np->irq_counter = 0; led1 = !led1; np->irq_counter2++; if (np->irq_counter2 >= 4) { np->irq_counter2 = 0; led2 = !led2; } } break; case CMD_CTC0: SetCTC0_NLG(ReadNLG()); break; case CMD_CTC3: SetCTC3_NLG(ReadNLG()); break; } /* 秒情報の表示 */ while (np->tick_sec >= np->base_clk) { np->tick_sec -= np->base_clk; np->total_sec++; DispNLG(np); } } return result; } NLG_R n; int nlg_play(const char *nlg_file) { printf("nlg_play:%s\n",nlg_file); /* NLGの初期化 */ if (initNLG(&n, nlg_file) < 0) { lcd_printStrY(1, " ERROR!!"); printf("Failed to init.\n"); return -1; } printf("Play..\n"); /* 再生する */ PlayNLG(&n, 360); /* mute */ boardMute(); /* NLGファイルを閉じる */ CloseNLG(); return 0; } int get_nlg_file(char *dest, int index) { char *cwd = "/sd/"; int count = -1; DIR *dir = opendir(cwd); dest[0] = 0; if (dir == NULL) { lcd_printStr2("SD CARD", "ERROR!"); return -1; } struct dirent *dent; while(1) { dent = readdir(dir); if (!dent) break; // resource or hidden file if (dent->d_name[0] == '.') continue; char *ext = strrchr(dent->d_name, '.'); if (!ext) continue; if (strcasecmp(ext, ".nlg") != 0) continue; if (count < 0) count = 0; count++; if (index < 0) continue; if (count <= index) continue; strcpy(dest, dent->d_name); break; } closedir(dir); return count; } // // title // void putTitle() { lcd_printStr2("NBCTRL", "Ver 1.11"); wait(1.5); } // // main // int main() { char file[32]; char path[48]; led1 = 0; led2 = 0; wait_ms(20); // reset SHIFT REGISTER ioShiftOut((0xFF << 8) | (ACTLOW)); lcd_init(); putTitle(); boardInit(); int files = 0; int disp_mode = 0; if (!sw_next) disp_mode = 1; files = get_nlg_file(file, -1); if (disp_mode) { char buf[16]; Timer t; int result_us = 0; t.reset(); t.start(); // actual timing regFMOut(0x20, 0x00); result_us = t.read_us(); t.stop(); printf("result_us=%dus\n", result_us); printf("DATE:%s\nTIME:%s\n", __DATE__, __TIME__); sprintf(buf, "%8s", __DATE__); lcd_printStrYscr(1, buf); wait(3); sprintf(buf, "%8s", __TIME__); lcd_printStrY(1, buf); wait(3); sprintf(buf, "R:%dus", result_us); lcd_printStrY(1, buf); wait(3); if (files < 0) lcd_printStrY(1, "NO FILES"); else { char buf[16]; sprintf(buf, "%3dfiles", files); lcd_printStrY(1, buf); } wait(3); lcd_cls(); } bool repeat_flag = false; int idx = 0; while(files > 0) { char buf[16]; get_nlg_file(file, idx); sprintf(path, "/sd/%s", file); printf("path=%s\n",path); lcd_cls(); lcd_printStrY(0, file); sprintf(buf, "%2d ", idx + 1); lcd_printStrY(1, buf); nlg_play(path); // wait for chattering wait(0.25); // wait release waitButtonRelease(); // if play button is pressed if (g_stop) { g_stop = false; g_prev = false; lcd_printStrY(1, " STOP "); // wait any button is pressed waitButtonPress(); // if (!sw_prev) { lcd_printStrY(1, " PREV "); g_prev = true; } if (!sw_play) { lcd_printStrY(1, " PLAY "); repeat_flag = true; } if (!sw_next) { lcd_printStrY(1, " NEXT "); repeat_flag = false; } // wait release waitButtonRelease(); // reset board boardInit(); } // play prev or next song if (g_prev) { g_prev = false; if (idx - 1 >= 0) idx--; else idx = files - 1; continue; } if (!repeat_flag) { if (idx + 1 < files) idx++; else idx = 0; } repeat_flag = false; } }