/******************************************************************************* * テンポ可変式MIDプレーヤ Program * ソース名:SD_File_List_Select_MID_Player_TEST.C * * <このTESTの目的> *  @ SDカードに収録されているMIDファイル(SMF0)中の *    テンポ情報(uS単位で表現:24bit)を読出し、 *    それを[BPM]単位の数値に変換して、GLCDに表示することにより *    思惑通り、テンポ情報が抽出できるか検証する *  A UP, DWON SWにより、そのテンポ値を可変できるか試す *  B テンポ変更を、VS1053Bで再生してみて確認する * * <テスト仕様概要> *  @ SDに格納されている、MIDファイルを、8個まで読出し、そのファイルリスト *     を、GLCDに表示する(GLCDの、1画面分で表示できるキャラクタ行が、 * 最大8行なため、これで制限、また今回は、スクロール機能は無しとする) *  A SELECT(DOWN) SWで、選択したいファイルの所へ、●キャラクタを移動 *  B ENTER SWで、選択を確定する *  C ここから、テンポ変更フェーズに移行する *    まず、選択されたMIDファイルの、テンポ設定を読出し、それをBPM単位 * に変換してテンポ表示する *  D ここで、テンポの変更が可能である *    UP SWと、DOWN SWによってテンポを変更する *    設定範囲は、自分の演奏技量に合わせ *    40〜150BPM ±5BPMステップとした *    (シーケンスソフトでSMF0データを作成する時も、この範囲で設定することとする) *  E 希望のテンポに設定したら、PLAY SWを押すと、再生が始まる *  F ここで何もしなければ、再生終了後、@に戻って繰返す *    再生途中で、ESC SW(UP SWと兼用)を長押しすると、再生を中断し *    @に戻って繰返す * * ファイルシステム:MMD File System→ FAT16(FAT32互換) * Graphic LCD(Monochrome): SG12864A * * MPEG Audio and MIDI Codec LSI: VS1053b(EXT CLK:12.288MHz) * * Condition: * 8MHz External X'tal Oscillator, 20x PLL (8MHzx20= 160MHz) * Fcy=160MHz/2=80MHz, Tcy=12.5ns * * CPU: PIC32MX340F256H * * N.Ishii 2013.9.25 **********************************************************************************/ #include /* PIC32 peripheral library */ #include "glcd_lib32k.h" #include #include // コンフィギュレーション設定 // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 /// アスキー変換後の格納バッファ char TMP_Vol_buf[] = "xxx"; /// ファイルシステム用変数 FSFILE *fptr; size_t result; SearchRec Record; SearchRec *rptr = &Record; char FileName[20][13]; /// グローバル変数 short FileNo; short FileNo_temp; short Ptr_temp; short i; short fast= 1; // VS1011用変数 unsigned char Buffer[256]; short Volume, BASS; unsigned int TMP_bpm; unsigned int Tempo_SMF_Data; /// プロトタイプ void DispFiles(void); short Select(void); void Set_BPM(void); void SMFtempo_to_BPM(void); void SMFtempo24_to_B8x3_Copy(void); void itostring(char digit, unsigned int data, char *buffer); /******* メインルーチン ***********/ int main(void) { //システム最適設定 SYSTEMConfigPerformance(80000000); mJTAGPortEnable(DEBUG_JTAGPORT_OFF); // JTAGを無効化 //I/O設定 AD1PCFG = 0xFFFE; // デジタルに // GLCD制御信号レベルの初期化 LCD_E = 0; LCD_CS1 = 1; LCD_CS2 = 1; LCD_RW = 1; LCD_DI = 1; LCD_TRIS = 0x0000; // LCDデータバス(DB0-DB7)オール出力(TRISE= 0) TRISD = 0x0F00; // SW2:SEL_SW,SW3:ENT_SW,未使用SW(SW4,SW5):入力 // LCD_CS1,CS2,RS:出力・デバッグLED:出力、他未使用ピンは出力設定 TRISF = 0x0034; // VS1011_SCK1,SDO:出力、SDI1:入力・ LCD_E,RW:出力、他未使用ピンは入力設定 TRISG = 0x028C; // SD_SDO,SCK:出力、SDI:入力・他未使用ピンは入力設定 TRISB = 0x4FDF; // VS1011_CS,RESET,DCS:出力、DREQ:入力・SD_CS:出力、WE,CD:入力、他未使用ピンは入力設定 CNPUE = 0x0060; // SD_CD(CN5),WE(CN6)のみ内部プルアップ LATDbits.LATD3 = 1; // デバッグLED消灯 // 液晶表示器の初期化 lcd_Init(); /// VS1011eの初期化 VS1011_Init(); // Initialize VS1011 Port+ SPI2(CKP=4M)+ SDI_TestMode+ CLK Doubler Volume = 0x08; // Set Volume = -8[dB] SetVolume(Volume, Volume); BASS = 0; // Set Bass Boost = off SetBassBoost(BASS, 15); delay_ms(1000); // Start VS1011e Sine Test // VS1011_SineTest(); // Start Sin_5kHz /************* メインループ ****************/ while(1) { lcd_Clear(0); // 画面消去 LATDbits.LATD3 = 1; // デバッグLED点灯消灯 /// カード挿入まで待ちファイル有無確認 while(fptr == 0){ lcd_Clear(0); // 画面消去 if(!MDD_MediaDetect()){ // カード挿入中か? lcd_Str(0, 0, "Wait Card Insert!"); // 挿入待ちメッセージ } else{ /*** ファイルオープンとファイル名表示 ***/ lcd_Str(0, 1, "Find Card OK!"); FSInit(); // FS初期化 /* 最初のファイルのサーチ */ result = FindFirst("*.MID", ATTR_ARCHIVE, rptr); if(result != 0){ // MIDファイルありか? lcd_Str(0, 1, "Find No File?"); // ファイル無しメッセージ } else break; // ファイル発見で抜ける } delay_ms(500); // 0.5秒ごとに繰り返し } /// ファイルが発見できた場合の処理 DispFiles(); // ファイル名一覧表示処理 FileNo = Select(); // ファイル選択処理 // LATDbits.LATD3 = 0; // デバッグLED点灯 /// ファイルNo.表示 lcd_Char1(7, 16, 0x4E); // 'N'表示 FileNo_temp = FileNo; FileNo = FileNo | 0x30; // FileNo= 0〜 7の範囲を取得するものとして、アスキー変換 lcd_Char1(7, 17, FileNo); /// 選択されたファイルの再生処理 fptr = FSfopen(FileName[FileNo_temp], "r"); // ファイルを開く if (fptr != 0) { // Success File Open ? // Out of Music Data As Far as EOF of File do{ MP3_XDCS_IO = 0; /// File Read (Unit 256Byte) // result = FSfread(Buffer, 1, 256, fptr); result = FSfread(Buffer, 1, 100, fptr); if (fast) { // 最初の、100バイト読出しの時のみ実行 /// 音楽バッファの先頭から、95byte以降に格納されている、3byteのテンポ情報を読出し、BPM値に変換する SMFtempo_to_BPM(); /// テンポ値(BPM)を、液晶に表示する lcd_Str(0, 15, "TMP"); // 'TMP'表示 itostring(3, TMP_bpm, TMP_Vol_buf); // ascii変換 lcd_Str(1, 15, TMP_Vol_buf); // bpm表示 /// ここでテンポ値を変更したい場合は、UP/DOWNスイッチにより /// テンポを変更し、変更データを、音楽バッファに上書きし /// ENTスイッチが押されたら、テンポ表示を更新する Set_BPM(); fast = 0; } /// VS1053b側へ音楽バッファの内容を、100バイト単位で転送する for( i= 0; i=8) // 8個目を超えたか? break; // 終わって抜ける } } /*********************************************** * ファイル選択 * 指定されたMP3ファイルのファイル番号を返す ***********************************************/ short Select(void){ short i, Ptr; lcd_Char(0, 0, 0x8C); // '●'を選択初期位置(先頭)に表示 Ptr = 0; while(PORTDbits.RD10 != 0){ // Enterスイッチチェック if(PORTDbits.RD11 == 0){ // Selectスイッチチェック Ptr++; // 次の行へ for(i=0; i<=Ptr; i++) // 2つ目以降のファイルが選択された場合、 lcd_Char(i, 0, 0x20); // その前に表示されている、選択キャラクタ'●'をクリアする lcd_Char(Ptr, 0, 0x8C); // '●'を選択位置に表示 if(Ptr > 7) { // 最終行で先頭に戻す Ptr = 0; lcd_Char(7, 0, 0x20); // その前に表示されている、選択キャラクタ'●'をクリアする lcd_Char(0, 0, 0x8C); // '●'を選択初期位置(先頭)に表示 } while(PORTDbits.RD11 == 0); // Selestスイッチリリース待ち delay_ms(100); // チャッタリング回避 } } Ptr_temp = Ptr; return(Ptr); // 行番号を返す } /*********************************************** * テンポを変更し * 変更データを、音楽バッファに上書きし * テンポ表示を更新する ***********************************************/ void Set_BPM(void){ while(PORTDbits.RD8 != 0){ // Playスイッチチェック if(PORTDbits.RD9 == 0){ // UPスイッチチェック TMP_bpm = TMP_bpm + 5; if (TMP_bpm > 150) TMP_bpm = 40; Tempo_SMF_Data = 60000000 / TMP_bpm; /// 24bitバイナリデータを、8bitx3に分解し、それぞれの音楽バッファ位置にコピー後 /// SMFテンポ情報を、BPM値に変換する SMFtempo24_to_B8x3_Copy(); itostring(3, TMP_bpm, TMP_Vol_buf); // BPM値を、ASCII変換 lcd_Str(1, 15, TMP_Vol_buf); // bpm表示更新 } if(PORTDbits.RD11 == 0){ // DOWNスイッチチェック TMP_bpm = TMP_bpm - 5; if (TMP_bpm < 40) TMP_bpm = 150; Tempo_SMF_Data = 60000000 / TMP_bpm; SMFtempo24_to_B8x3_Copy(); itostring(3, TMP_bpm, TMP_Vol_buf); // BPM値を、ASCII変換 lcd_Str(1, 15, TMP_Vol_buf); // bpm表示更新 } while((PORTDbits.RD9 == 0) || (PORTDbits.RD11 == 0)); // UP/DOWNスイッチリリース待ち delay_ms(10); // チャッタリング回避 } /// ENTERが押されたら、選択位置のファイル名の後に、スピーカーキャラクタを表示 lcd_Char1(Ptr_temp, 14, 0x9B); } /*********************************************** * 音楽バッファのテンポ値(8bit*3バッファ)を、 * SMFテンポ値(24bitバイナリデータ)に変換後、 * SMFテンポ情報を、BPM値に変換する ***********************************************/ void SMFtempo_to_BPM(void){ Tempo_SMF_Data = (unsigned int)Buffer[94]<<16 | (unsigned int)Buffer[95]<<8 | (unsigned int)Buffer[96]; TMP_bpm = 60000000 / Tempo_SMF_Data; /// 割り切れない場合(*.999のケース)は、切り上げする(割り切れなくても、*.00000xxのケースは、そのまま切捨てでよいので何もしない) /// SMFデータを作る時、40〜150BPM/5BPM単位の範囲に限定して作成する仕様にした(テンポ可変も、その範囲内に限定) if (TMP_bpm == 64 || TMP_bpm == 69 || TMP_bpm == 89 || TMP_bpm == 94 || TMP_bpm == 104 || TMP_bpm == 109) { TMP_bpm = TMP_bpm + 1; } } /************************************************************* * 変更したテンポ値(24bitバイナリデータ)を、8bitx3に分解し、 * それぞれの音楽バッファ位置にコピー **************************************************************/ void SMFtempo24_to_B8x3_Copy(void){ Buffer[94] = (unsigned char)(Tempo_SMF_Data >> 16) & 0x0000FF; Buffer[95] = (unsigned char)(Tempo_SMF_Data >> 8) & 0x0000FF; Buffer[96] = (unsigned char)(Tempo_SMF_Data) & 0x0000FF; } /***************************************** * 数値から文字列に変換 *****************************************/ void itostring(char digit, unsigned int data, char *buffer){ char i; buffer += digit; // 文字列の最後 for(i=digit; i>0; i--) { // 最下位桁から上位へ buffer--; // ポインター1 *buffer = (data % 10) + '0'; // その桁数値を文字にして格納 data = data / 10; // 桁-1 } }