nlgplay for mbed

Dependencies:   SDFileSystemEx mbed

Files at this revision

API Documentation at this revision

Comitter:
bkc_mbed
Date:
Sat May 17 12:54:13 2014 +0000
Child:
1:ec416e6d5739
Commit message:
first version.

Changed in this revision

SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
lcd.cpp Show annotated file Show diff for this revision Revisions of this file
lcd.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Sat May 17 12:54:13 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/mbed/code/SDFileSystem/#7b35d1709458
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcd.cpp	Sat May 17 12:54:13 2014 +0000
@@ -0,0 +1,88 @@
+#include "mbed.h"
+
+
+I2C i2c(dp5, dp27); // sda, scl
+
+const int AQM0802_addr = 0x7C;
+
+void lcd_cmd(char x)
+{
+  char data[2];
+  data[0] = 0x00; // CO = 0,RS = 0
+  data[1] = x;
+  i2c.write(AQM0802_addr, data, 2);
+}
+
+void lcd_contdata(char x)
+{
+  char data[2];
+  data[0] = 0xC0; //0b11000000 CO = 1, RS = 1
+  data[1] = x;
+  i2c.write(AQM0802_addr, data, 2);
+}
+
+void lcd_lastdata(char x)
+{
+  char data[2];
+  data[0] = 0x40; //0b11000000 CO = 0, RS = 1
+  data[1] = x;
+  i2c.write(AQM0802_addr, data, 2);
+}
+
+void lcd_printStr(const char *s)
+{
+  while(*s) {
+    if(*(s + 1)) {
+      lcd_contdata(*s);
+    } else {
+      lcd_lastdata(*s);
+    }
+    s++;
+  }
+}
+
+void lcd_setContrast(unsigned char c) {
+  lcd_cmd(0x39);
+  lcd_cmd(0x70 | (c & 0x0f)); // contrast Low
+  lcd_cmd(0x5C | ((c >> 4) & 0x03)); // contast High/icon/power
+  lcd_cmd(0x38);
+}
+
+void lcd_printHex(unsigned char num)
+{
+  lcd_contdata(num);
+}
+
+void lcd_init() {
+  int cont = 0;
+  wait(0.04);
+  // LCD initialize
+  lcd_cmd(0x38); // function set
+  lcd_cmd(0x39); // function set
+  lcd_cmd(0x04); // EntryModeSet
+  lcd_cmd(0x14); // interval osc
+  lcd_cmd(0x70 | (cont & 0xF)); // contrast Low
+  lcd_cmd(0x5C | ((cont >> 4) & 0x3)); // contast High/icon/power
+  lcd_cmd(0x6C); // follower control
+  wait(0.2);
+  lcd_cmd(0x38); // function set
+  lcd_cmd(0x0C); // Display On
+  lcd_cmd(0x01); // Clear Display
+  wait(0.2); // need additional wait to Clear Display
+  
+  lcd_setContrast(36);
+
+}
+
+void lcd_setCursor(unsigned char x,unsigned char y) {
+  lcd_cmd(0x80 | (y * 0x40 + x));
+}
+
+void lcd_cls(void)
+{
+    lcd_setCursor(0, 0);
+    lcd_printStr("        ");
+    lcd_setCursor(0, 1);
+    lcd_printStr("        ");
+}
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcd.h	Sat May 17 12:54:13 2014 +0000
@@ -0,0 +1,10 @@
+#ifndef __LCD_H__
+#define __LCD_H__
+
+void lcd_printStr(const char *s);
+void lcd_setContrast(unsigned char c);
+void lcd_setCursor(unsigned char x,unsigned char y);
+void lcd_cls(void);
+void lcd_init();
+
+#endif
--- /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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat May 17 12:54:13 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/8a40adfe8776
\ No newline at end of file