nlgplay for mbed
Dependencies: SDFileSystemEx mbed
Diff: main.cpp
- Revision:
- 0:2053640461b5
- Child:
- 1:ec416e6d5739
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sat May 17 12:54:13 2014 +0000 @@ -0,0 +1,792 @@ +#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); + + +// 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(8); + + + /* データを出力 */ + /* 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(8); +} + +/* 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) +{ + /* ICLのみをLOW(アクティブ)にする */ + ioShiftOut(ACTLOW & ~(ICL)); + wait_us(200); + + /* 元に戻す */ + ioShiftOut(ACTLOW); + wait_us(200); +} + +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; +} + +byte nlg_hdr[0x80]; + +// NLGファイルを開く +int OpenNLG(const char *file) +{ + 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; + +} 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; + + 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, "%02d:%02d",np->total_sec / 60, np->total_sec % 60); + + lcd_setCursor(0,1); + lcd_printStr(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; + + printf("wait button release\n"); + + // wait until release buttons + while(!sw_next || !sw_play); + + printf("ok\n"); + + 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; + } + 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; +} + +DigitalOut led1(LED1); + +NLG_R n; + +int nlg_play(const char *nlg_file) +{ + + printf("init nlg:%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; + } + + printf("Init board\n"); + + /* 再生する */ + printf("PlayNLG\n"); + PlayNLG(&n, 360); + printf("\n"); + + printf("mute\n"); + + boardMute(); + + printf("close\n"); + + /* 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; + 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]; + + lcd_setCursor(0,0); + lcd_printStr("NBCTRL"); + lcd_setCursor(0,1); + lcd_printStr("Ver 1.0 "); + wait(3); + sprintf(buf, "%s", __DATE__); + lcd_setCursor(0,0); + lcd_printStr("DATE"); + lcd_setCursor(0,1); + lcd_printStr(buf); + wait(3); + + lcd_setCursor(0,1); + if (files < 0) + lcd_printStr("NO FILES"); + else + { + char buf[16]; + sprintf(buf, "%d files", files); + lcd_printStr(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_setCursor(0, 0); + lcd_printStr(file); + + nlg_play(path); + + // wait release + while(!sw_play || !sw_next); + + if (g_stop) + { + lcd_setCursor(0, 1); + lcd_printStr("STOP "); + + while(sw_play && sw_next); + while(!sw_play || !sw_next); + g_stop = 0; + } + + if (idx + 1 < files) + idx++; + else + idx = 0; + } + + while(1) { + led1 = 1; + wait(1); + led1 = 0; + wait(1); + } +}