nlgplay for mbed

Dependencies:   SDFileSystemEx mbed

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);
+    }
+}