nlgplay for mbed
Dependencies: SDFileSystemEx mbed
main.cpp
- Committer:
- bkc_mbed
- Date:
- 2014-05-19
- Revision:
- 1:ec416e6d5739
- Parent:
- 0:2053640461b5
- Child:
- 2:f0b7779b03c7
File content as of revision 1:ec416e6d5739:
#include "mbed.h" #include "SDFileSystem.h" #include "lcd.h" DigitalOut io01(dp13); DigitalOut io02(dp26); DigitalOut io03(dp17); DigitalOut io04(dp4); DigitalIn sw_play(dp24,PullUp); DigitalIn sw_next(dp10,PullUp); DigitalOut led1(LED1); DigitalOut led2(LED2); // 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[80]; 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 void init_io(void) { RCK = 0; SCK = 0; DBS = 0; CTS = 0; } // 16bit output 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; SCK = 0; } RCK = 1; RCK = 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 ACTLOW (CS_PSG | CS_FM1 | CS_FM2 | WR | ICL) /* 出力 */ void regOutBase(int addr, int data,int select) { /* アドレスを出力 */ /* A0をローにして待つ */ ioShiftOut((addr << 8) | (ACTLOW)); ioShiftOut((addr << 8) | (ACTLOW & ~(select | WR))); ioShiftOut((addr << 8) | (ACTLOW)); /* チップ側の処理を待つ */ if (!(select & CS_PSG)) wait_us(10); /* データを出力 */ /* A0をハイにして待つ */ ioShiftOut((data << 8) | A0 | (ACTLOW)); ioShiftOut((data << 8) | A0 | (ACTLOW & ~(select | WR))); ioShiftOut((data << 8) | A0 | (ACTLOW)); /* wait if FM */ if (!(select & CS_PSG)) wait_us(10); } /* 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 /* FM音源初期化 */ for(i = 0x20; i < 0x28; i++) regFMOut(i, 0x00); for(i = 0x20; i < 0x28; i++) regFM2Out(i, 0x00); } /* ボード初期化 */ void boardInit(void) { wait_ms(20); /* ICLのみをLOW(アクティブ)にする */ ioShiftOut(ACTLOW & ~(ICL)); wait_ms(50); /* 元に戻す */ 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[0x80]; 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; } // 書き込み用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 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; } // コマンドの書き込み 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); } // データの読み出し 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; } // CTC0値の設定 void SetCTC0_NLG(int value) { nlg_ctc0 = value; nlg_tick = ((nlg_ctc0 * 256) * nlg_ctc3); } // CTC3値の設定 void SetCTC3_NLG(int value) { nlg_ctc3 = value; nlg_tick = ((nlg_ctc0 * 256) * nlg_ctc3); } // 曲の長さを得る 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; int song_no; } 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); } int g_stop = 0; 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, "%d.%02d:%02d",np->song_no, np->total_sec / 60, np->total_sec % 60); lcd_printStrY(1, buf); } /* 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; Timer t; t.start(); total_us = 0; // wait until release buttons while(!sw_next || !sw_play); DispNLG(np); while(np->total_sec < sec && !g_stop) { // push next if (!sw_next) break; // push play if (!sw_play) { g_stop = 1; 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; 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,int song_no) { printf("nlg_play:%s\n",nlg_file); /* NLGの初期化 */ if (initNLG(&n, nlg_file) < 0) { lcd_setCursor(0,1); lcd_printStr("ERROR!!"); printf("Failed to init.\n"); return -1; } n.song_no = song_no; /* 再生する */ PlayNLG(&n, 360); printf("\n"); 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_setCursor(0, 1); lcd_printStr("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; } int main() { char file[32]; char path[64]; led1 = 0; led2 = 0; lcd_init(); 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]; printf("DATE:%s\nTIME:%s", __DATE__, __TIME__); lcd_printStr2("NBCTRL", "Ver 1.04"); wait(3); sprintf(buf, "%8s", __DATE__); lcd_printStrYscr(1, buf); wait(3); sprintf(buf, "%8s", __TIME__); 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(); } int idx = 0; while(files > 0) { get_nlg_file(file, idx); sprintf(path, "/sd/%s", file); printf("path=%s\n",path); lcd_printStrY(0, file); nlg_play(path, idx); // wait for chattering wait(0.25); // wait release while(!sw_play || !sw_next); bool prev_flag = false; if (g_stop) { lcd_printStrY(1, "STOP "); // wait push while(sw_play && sw_next); if (!sw_play) prev_flag = true; // wait release while(!sw_play || !sw_next); g_stop = 0; // reset board boardInit(); } if (prev_flag) { if (idx - 1 >= 0) idx--; else idx = files - 1; } else { if (idx + 1 < files) idx++; else idx = 0; } } /* while(1) { led1 = 1; wait(1); led1 = 0; wait(1); } */ }