/******************************************************************************* * ソース名:LoopPlayer256_and_VarTempoMID.C * * 機能概要: * LoopPlayer256(256曲MAXのループ再生:8曲×32画面分)と、 * テンポ可変式MIDプレーヤのプログラムを、電源ON時の、SKIP SW * の状態で、切替え実行させる * つまり、1台のハードウエアで、2つのソフトを切替えて実行 * する * SKIP SWを押さないで、電源をONした時は、LoopPlayer256、 * SKIP SWを押しながら、電源をONした時は、テンポ可変式MIDプレーヤ * のプログラムを実行する * * * ファイルシステム: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.11.5 **********************************************************************************/ #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 /// メッセージ・テーブル // LoopPlayer256用 char str_Number[] = "xxx"; char str_Total[] = "xxx"; // VarTempoMID用 char TMP_Vol_buf[] = "xxx"; /// ファイルシステム用変数 FSFILE *fptr; size_t result; SearchRec Record; SearchRec *rptr = &Record; char FileName[256][13]; // 2次元配列: 最大、256ファイルで、1ファイル→13文字(8文字+'.MP3'+NULL)構成 /// VS1011用変数 short Volume, BASS; unsigned char Buffer[256]; /// グローバル変数 short FileNo; short Number; short FileNo_temp; // VarTempoMID用 short Ptr_temp; // VarTempoMID用 short fast= 1; // VarTempoMID用 unsigned int TMP_bpm; // VarTempoMID用 unsigned int Tempo_SMF_Data;// VarTempoMID用 short i; short sq; short FN_Top; // 画面先頭に表示するファイル名バッファのポインタ short sw_m0 = 0; // SKIP SW short sw_m1 = 0; short sw_m2 = 0; short P_Sel; /// プロトタイプ void LoopPlayer256(void); void VarTempoMID(void); void StoreFiles_and_DispFiles(void); void DispNumber(void); void itostring(char digit, unsigned int data, char *buffer); /// VarTempoMID用 short Select(void); void Set_BPM(void); void SMFtempo_to_BPM(void); void SMFtempo24_to_B8x3_Copy(void); /******* メインルーチン ***********/ 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:DOWN_SW(SKIP SW),SW3:ENT_SW,SW4:UP_SW(ESC兼用),SW5:PLAY SW:入力 // 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); // Start VS1011e Sine Test // VS1011_SineTest(); // Start Sin_5kHz sq = 0; /// if (PORTDbits.RD11 != 0) P_Sel = 0; // 電源ON時、SKIP SWが押されなければ、LoopPlayer256を実行 else P_Sel = 1; // 電源ON時、SKIP SWが押されていれば、VarTempoMIDを実行 delay_ms(1000); /************* メインループ ****************/ while(1) { switch (P_Sel) { case 0: // LoopPlayer256を実行 LoopPlayer256(); break; case 1: // VarTempoMIDを実行 VarTempoMID(); break; } } } /**************************************** * 256曲MAXのループプレーヤ・プログラム *****************************************/ void LoopPlayer256(void) { switch (sq) { case 0: /// 最初のファイル発見と、ファイルリスト表示〜最初のファイルオープン lcd_Clear(0); // 画面消去 LATDbits.LATD3 = 1; // デバッグLED消灯 FileNo = 0; FN_Top = 1; fptr = 0; /// カード挿入まで待ちファイル有無確認 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("*.*", ATTR_ARCHIVE, rptr); if(result != 0){ // ファイルありか? lcd_Str(0, 1, "Find No File?"); // ファイル無しメッセージ } else break; // ファイル発見で抜ける } delay_ms(500); // 0.5秒ごとに繰り返し } /// ファイルが発見できた場合の処理 StoreFiles_and_DispFiles(); // FileNameバッファへの、SD内音楽ファイル名の格納(最大1000ファイル)と、 // 初期ファイル名一覧表示処理(最大8ファイル) /// 最初の曲番号表示 DispNumber(); /// 最初のファイルを開く fptr = FSfopen(FileName[FileNo], "r"); sq++; break; case 1: /// 初期ファイルリスト画面→ 8曲分再生 while((fptr != 0) && (FileNo < 8)){ // ファイルオープン成功? lcd_Char(FileNo, 0, 0x8C); // '●'を表示 /// Out of Music Data As Far as EOF of File do{ /// SKIP SW読込み(立下りセンス) sw_m0 = PORTDbits.RD11; //New SW Data sw_m2 = sw_m1^(sw_m0 & sw_m1); //Neg_Edge Sence SW sw_m1 = sw_m0; //Chenge New Data to Old Data m1 if (sw_m2 != 1) { MP3_XDCS_IO = 0; /// File Read (Unit 32Byte) result = FSfread(Buffer, 1, 32, fptr); for( i= 0; i=256) // 格納ファイルが256個目を超えたか? break; // 終了して抜ける } else{ // P_Sel=1 lcd_Str(i++, 2, Record.filename); // ファイル名表示 if(i>=8) // 8個目を超えたか? break; // 終わって抜ける } } if(P_Sel == 0){ /// トータル・曲数(ファイル数)の表示 lcd_Str(0, 15, "Tot"); // 項目:"Tot"表示 itostring(3, i, str_Total); lcd_Str(1, 15, str_Total); } } /************************************** * 曲番号を表示する(lLoopPlayer256用) ***************************************/ void DispNumber(void){ lcd_Str(6, 15, "Num"); // 項目:"Num"表示 Number = FileNo + 1; itostring(3, Number, str_Number); lcd_Str(7, 15, str_Number); } /// 以下は、VarTempoMID用----------------------------------------------------------------------------------------------------------- /*********************************************** * ファイル選択 * 指定されたMIDファイルのファイル番号を返す ***********************************************/ 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); // チャッタリング回避 delay_ms(200); // ユニバーサル基板製作+ケーシング版の、SWはタクトSWと比較 // するとチャッタが多いためか、2ステップ先に飛んでしまうことがあったので // 回避時間を倍に増やした   131014 } } 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 } }