nguyen nam / SD_PlayerSkeleton

Dependencies:   SDFileSystem_Warning_Fixed

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Mon Aug 15 04:38:45 2016 +0000
Child:
1:c7968701f7b3
Commit message:
1

Changed in this revision

FileSelectorWav.cpp Show annotated file Show diff for this revision Revisions of this file
FileSelectorWav.hpp Show annotated file Show diff for this revision Revisions of this file
SD_PlayerSkeleton.cpp Show annotated file Show diff for this revision Revisions of this file
SD_PlayerSkeleton.hpp Show annotated file Show diff for this revision Revisions of this file
SD_WavReader.cpp Show annotated file Show diff for this revision Revisions of this file
SD_WavReader.hpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileSelectorWav.cpp	Mon Aug 15 04:38:45 2016 +0000
@@ -0,0 +1,113 @@
+//--------------------------------------------------------------
+//  FileSelector class
+//      SD カード内のファイル名の一覧を表示し,ファイルを選択する
+//
+//  2016/07/27, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "FileSelectorWav.hpp"
+
+namespace Mikami
+{
+    bool FileSelector::CreateTable()
+    {
+        DIR* dp = opendir("/sd");
+        fileCount_ = 0; 
+        if (dp != NULL)
+        {
+            dirent* entry;
+            for (int n=0; n<256; n++)
+            {
+                entry = readdir(dp);
+                if (entry == NULL) break;
+
+                string strName = entry->d_name;
+                if ( (strName.find(".wav") != string::npos) ||
+                     (strName.find(".WAV") != string::npos) )
+                {
+                    sdReader_.Open(strName);        // ファイルオープン
+
+                    // PCM,16 ビットステレオ,標本化周波数 44.1 kHz 以外のファイルは除外
+                    if (sdReader_.IsWavFile())
+                        fileNames_[fileCount_++] = strName;
+                    sdReader_.Close();
+                }
+
+                if (fileCount_ >= MAX_FILES_) break;
+            }
+            closedir(dp); 
+        }
+        else
+            return false;
+
+        if (fileCount_ == 0) return false;
+
+        if (rect_ != NULL) delete rect_;
+        Array<string> nonString(fileCount_, "");
+        rect_ = new ButtonGroup(X_, Y_, W_H_, W_H_, fileCount_,
+                                nonString, 0, V_L_-W_H_, 1,
+                                -1, Font12, 0, GuiBase::ENUM_BACK,
+                                BASE_COLOR_, TOUCHED_COLOR_);
+        for (int n=0; n<fileCount_; n++) rect_->Erase(n);
+        CreateLabels();   
+        prevFileCount_ = fileCount_;
+        return true;
+    }
+
+    // ファイルを選択する
+    bool FileSelector::Select(string &fileName)
+    {
+        int n;
+        if (rect_->GetTouchedNumber(n))
+        {
+            fileNameLabels_[n]->Draw(GetFileNameNoExt(n), TOUCHED_COLOR_);
+            if ((prev_ >= 0) && (prev_ != n))
+                fileNameLabels_[prev_]->Draw(GetFileNameNoExt(prev_));
+            prev_ = n;
+            fileName = fileNames_[n];
+            return true;
+        }
+        else
+            return false;
+    }
+
+    // ファイルの一覧の表示
+    void FileSelector::DisplayFileList(bool sortEnable)
+    {
+        if (sortEnable)
+            std::sort((string *)fileNames_,
+                      (string *)fileNames_+fileCount_); 
+        
+        Erase(X_, Y_, MAX_NAME_LENGTH_*((sFONT *)(&Font16))->Width, 272-Y_);
+        rect_->DrawAll();
+        for (int n=0; n<fileCount_; n++)
+            fileNameLabels_[n]->Draw(GetFileNameNoExt(n));
+    }
+
+    // ファイルの一覧の消去
+    void FileSelector::Erase(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
+               uint32_t color)
+    {
+        lcd_->SetTextColor(color);
+        lcd_->FillRect(x, y, width, height);
+    }
+
+    // Label を生成
+    void FileSelector::CreateLabels()
+    {
+        fileNameLabels_.SetSize(fileCount_);
+                    
+        for (int n=0; n<fileCount_; n++)
+            fileNameLabels_[n] = new Label(X_+30, Y_+5+V_L_*n, "",
+                                           Label::LEFT, Font16,
+                                           BASE_COLOR_);
+    }
+
+    // 拡張子を削除した文字列を取得
+    string FileSelector::GetFileNameNoExt(int n)
+    {
+        string name = fileNames_[n];
+        name.erase(name.find("."));
+        return name.substr(0, MAX_NAME_LENGTH_);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileSelectorWav.hpp	Mon Aug 15 04:38:45 2016 +0000
@@ -0,0 +1,71 @@
+//--------------------------------------------------------------
+//  FileSelector class ---- Header ----
+//      SD カード内のファイル名の一覧を表示し,ファイルを選択する
+//
+//  2016/07/27, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef FILE_SELECTOR_HPP
+#define FILE_SELECTOR_HPP
+
+#include "F746_GUI.hpp"
+#include "SD_WavReader.hpp"
+#include <algorithm>    // sort() で使用
+#include <string>
+
+namespace Mikami
+{
+    class FileSelector
+    {
+    public:
+        FileSelector(uint8_t x0, uint8_t y0, int maxFiles,
+                     int maxNameLength, SD_WavReader &reader)
+            : X_(x0), Y_(y0), W_H_(24), V_L_(36),
+              MAX_FILES_(maxFiles), MAX_NAME_LENGTH_(maxNameLength),
+              BASE_COLOR_(0xFF80FFA0), TOUCHED_COLOR_(0xFF80FFFF),
+              fileNames_(maxFiles),
+              rect_(NULL), lcd_(GuiBase::GetLcdPtr()),
+              sdReader_(reader), prevFileCount_(0), prev_(-1) {}
+
+        virtual ~FileSelector()
+        {   delete rect_; }
+        
+        bool CreateTable();
+
+        // ファイルを選択する
+        bool Select(string &fileName);
+
+        // ファイルの一覧の表示
+        void DisplayFileList(bool sortEnable = true);
+
+        // ファイルの一覧の消去
+        void Erase(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
+                   uint32_t color = GuiBase::ENUM_BACK);
+
+    private:
+        const uint8_t X_, Y_, W_H_, V_L_;
+        const int MAX_FILES_;
+        const int MAX_NAME_LENGTH_;
+        const uint32_t BASE_COLOR_;
+        const uint32_t TOUCHED_COLOR_;
+        
+        Array<string> fileNames_;
+        ButtonGroup *rect_;
+        Array<Label *> fileNameLabels_;
+        LCD_DISCO_F746NG *lcd_;
+        SD_WavReader &sdReader_;
+        int fileCount_, prevFileCount_;
+        int prev_;
+
+        // Label を生成
+        void CreateLabels();
+
+        // 拡張子を削除した文字列を取得
+        string GetFileNameNoExt(int n);
+
+        // disallow copy constructor and assignment operator
+        FileSelector(const FileSelector&);
+        FileSelector& operator=(const FileSelector&);
+    };
+}
+#endif  // FILE_SELECTOR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SD_PlayerSkeleton.cpp	Mon Aug 15 04:38:45 2016 +0000
@@ -0,0 +1,141 @@
+//--------------------------------------------------------------
+//  SD プレーヤー用抽象基底クラス
+//
+//  2016/07/17, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "SD_PlayerSkeleton.hpp"
+
+namespace Mikami
+{
+    SD_PlayerSkeleton::SD_PlayerSkeleton(string str, int fs)
+        : FRAME_SIZE_(2048), sn_(FRAME_SIZE_),
+          mySai_(SaiIO::OUTPUT, FRAME_SIZE_, fs),
+          sdReader_(FRAME_SIZE_),
+          title_(214, 4, str, Label::CENTER, Font16),
+          selector_(4, 22, 7, 37, sdReader_),
+          menu_(BG_LEFT_, 2, BG_WIDTH_, BG_HEIGHT_, 5,
+                (string[]){"OPEN", "PLAY", "PAUSE", "RESUME", "STOP"},
+                0, 2, 1)
+    {
+        if (!selector_.CreateTable())
+            BlinkLabel errLabel(240, 100, "SD CARD ERROR", Label::CENTER);
+
+        menu_.InactivateAll();
+        menu_.Activate(0);
+    }
+
+    void SD_PlayerSkeleton::Execute()
+    {
+        bool playOk = false;
+        bool whileFirst = true;
+        int32_t loopCount;
+
+        while (true)
+        {
+            if (!playOk)
+            {
+                if (whileFirst)
+                {
+                    whileFirst = false;
+                    while (!menu_.Touched(0))   // OPEN がタッチされるまで待つ
+                        Modefy();
+                    SelectFile();
+                }
+                else
+                {
+                    menu_.Activate(1);          // PLAY 有効
+                    int touch10;
+                    while (!menu_.GetTouchedNumber(touch10))
+                        Modefy();
+                    if (touch10 == 0) SelectFile();
+                }
+
+                loopCount = SD_Open();
+                while (!menu_.Touched(1))       // PLAY がタッチされるまで待つ
+                    Modefy();
+            }
+            else
+                loopCount = SD_Open();
+
+            selector_.Erase(0, 0, BG_LEFT_-4, 272);
+            title_.Draw();
+
+            Display();  // アプリ固有の表示処理
+
+            menu_.Inactivate(0);    // OPEN 無効
+            menu_.Activate(2);      // PAUSE 有効
+            menu_.Activate(4);      // STOP 有効
+
+            playOk = false;
+            bool stopOk = false;
+
+            Clear();    // アプリ固有のクリア処理
+
+            mySai_.PlayOut();       // Play 開始
+
+            for (int k=0; k<loopCount; k++)
+            {
+                int touch42 = -1;
+                menu_.GetTouchedNumber(touch42);
+                if (touch42 == 4) break;    // STOP
+                if (touch42 == 2)           // PAUSE
+                {
+                    menu_.Inactivate(2);    // PAUSE 無効
+                    menu_.Activate(3);      // RESUME 有効
+                    mySai_.PauseOut();
+
+                    // PLAY か RESUME か STOP がタッチされるまで待つ
+                    int touch134 = -1;
+                    while (!menu_.GetTouchedNumber(touch134))
+                        Modefy();
+                    switch (touch134)
+                    {
+                        case 1: playOk = true;      // 最初から PLAY
+                                break;
+                        case 3: mySai_.ResumeOut(); // PAUSE したところから PLAY 再開
+                                menu_.Activate(2);
+                                menu_.Inactivate(3);
+                                menu_.TouchedColor(1);
+                                break;
+                        case 4: stopOk = true;      // STOP
+                                break;
+                    }
+                }
+                if (playOk || stopOk) break;
+
+                Modefy();
+                // 1フレーム分の信号処理の実行
+                SignalProcessing();
+            }
+            mySai_.StopOut();
+            menu_.Activate(0);                  // OPEN 有効
+            if (!playOk) menu_.Activate(1);     // PLAY 有効
+            for (int n=2; n<5; n++)             // その他は無効
+                menu_.Inactivate(n);
+            sdReader_.Close();   // SD のファイルのクローズ
+        }
+    }
+
+    // SD カードのファイルのオープン
+    int32_t SD_PlayerSkeleton::SD_Open()
+    {
+        sdReader_.Open(fileName_);
+        sdReader_.IsWavFile();
+        return sdReader_.GetSize()/FRAME_SIZE_;
+    }
+
+    // ファイルの選択
+    //      selectedName:   選択されたファイル名
+    void SD_PlayerSkeleton::SelectFile()
+    {
+        selector_.DisplayFileList();   
+        title_.Draw("Select file");
+        do
+        {
+            if (selector_.Select(fileName_))
+                menu_.Activate(1);      // PLAY 有効
+            wait_ms(200);
+        } while (!menu_.Touched(1));    // PLAY がタッチされるまで繰り返す
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SD_PlayerSkeleton.hpp	Mon Aug 15 04:38:45 2016 +0000
@@ -0,0 +1,64 @@
+//--------------------------------------------------------------
+//  SD プレーヤー用抽象基底クラス(ヘッダ)
+//
+//  2016/07/17, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef F746_SD_PLAYER_SKELETON_HPP
+#define F746_SD_PLAYER_SKELETON_HPP
+
+#include "SAI_InOut.hpp"
+#include "ButtonGroup.hpp"
+#include "FileSelectorWav.hpp"
+#include "SD_WavReader.hpp"
+
+using namespace Mikami;
+
+namespace Mikami
+{
+    class SD_PlayerSkeleton
+    {
+    public:
+        SD_PlayerSkeleton(string str, int fs);
+        virtual ~SD_PlayerSkeleton() {}
+        void Execute();
+
+    protected:
+        // ボタン用の定数
+        static const uint16_t BG_LEFT_ = 414;
+        static const uint16_t BG_WIDTH_ = 66;
+        static const uint16_t BG_HEIGHT_ = 36;
+    
+        const int32_t FRAME_SIZE_;  // フレームバッファのサイズ
+        Array<int16_t> sn_;         // フレームバッファ
+
+        SaiIO mySai_;
+        SD_WavReader sdReader_; // SD カード読み込み用オブジェクト
+
+        string GetFileName() { return fileName_; }
+
+    private:
+        string fileName_;       // 選択されたファイル名
+        Label title_;           // 上部に表示されるタイトル
+        FileSelector selector_;
+        ButtonGroup menu_;
+
+        // SD カードのファイルのオープン
+        int32_t SD_Open();
+        // ファイルの選択
+        void SelectFile();
+
+        //-------------------------------------
+        //      以下は仮想関数
+        //-------------------------------------
+        // 1フレーム分の信号処理の実行
+        virtual void SignalProcessing() = 0;
+        // サウンドエフェクタのパラメータ変更など
+        virtual void Modefy() {}
+        // 曲の再生中に表示する
+        virtual void Display() {}
+        // サウンドエフェクタ処理のデータ等のクリア
+        virtual void Clear() {}
+    };
+}
+#endif  // F746_SD_PLAYER_SKELETON_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SD_WavReader.cpp	Mon Aug 15 04:38:45 2016 +0000
@@ -0,0 +1,119 @@
+//--------------------------------------------------------------
+//  SD_WavReader class
+//      SD カードの *.wav ファイルの内容を読み出す
+//      以下のフォーマット以外は扱わない
+//          PCM,16 ビットステレオ,標本化周波数 44.1 kHz
+//
+//  2016/06/17, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "SD_WavReader.hpp"
+
+namespace Mikami
+{
+    SD_WavReader::SD_WavReader(int32_t bufferSize)
+        : STR_("sd"), ok_(false)
+    {
+        sd_ = new SDFileSystem(STR_.c_str());
+        sd_->mount();      
+        buffer.SetSize(bufferSize*2);
+    }
+
+    SD_WavReader::~SD_WavReader()
+    {
+        sd_->unmount();
+        delete sd_;
+    }
+    
+    void SD_WavReader::Open(const string fileName)
+    {
+        string name = (string)"/" + STR_ + "/" + fileName;
+        fp_ = fopen(name.c_str(), "rb");
+        if (fp_ == NULL) ErrorMsg("open error!!");
+    }
+    
+    
+    // ファイルのヘッダ (RIFFxxxxWAVEfm ) 読み込み
+    //      戻り値: *.wav で,16 ビットステレオ,
+    //             標本化周波数:44.1 kHz の場合 true
+    bool SD_WavReader::IsWavFile()
+    {
+        char data[17];
+        fread(data, 1, 16, fp_);
+        string strRead = "";
+        for (int n=0; n<4; n++) strRead += data[n];
+        for (int n=8; n<16; n++) strRead += data[n];
+
+        // "RIFF", "WAVE", "fmt " が存在することを確認
+        if (strRead != "RIFFWAVEfmt ") return false;
+
+        // fmt chunck のサイズを取得
+        uint32_t fmtChunkSize;
+        fread(&fmtChunkSize, sizeof(uint32_t), 1, fp_);
+
+        // PCM, Stereo, 44.1 kHz, 16 bit であることを確認
+        WaveFormatEx fmtData;
+        fread(&fmtData, fmtChunkSize, 1, fp_);
+        if ((fmtData.wFormatTag     != 1)     ||
+            (fmtData.nChannels      != 2)     ||
+            (fmtData.nSamplesPerSec != 44100) ||
+            (fmtData.wBitsPerSample != 16)
+           ) return false;
+
+        // data chunk を探す
+        char dataId[5];
+        dataId[4] = 0;
+        fread(dataId, 1, 4, fp_);
+        if ("data" != (string)dataId)
+            for (int n=0; n<100; n++)
+            {
+                char oneByte;
+                fread(&oneByte, 1, 1, fp_);
+                for (int k=0; k<3; k++)
+                    dataId[k] = dataId[k+1];
+                dataId[3] = oneByte;
+                if ("data" == (string)dataId) break;
+                
+                if (n == 99) return false;
+            }
+
+        // データサイズ (byte) を取得
+        int32_t sizeByte;
+        fread(&sizeByte, sizeof(int32_t), 1, fp_);
+        size_ = sizeByte/4;
+
+        ok_ = true;
+        return true;
+    }
+
+    // ファイルからステレオデータの取得
+    void SD_WavReader::ReadStereo(Array<int16_t>& dataL,
+                                  Array<int16_t>& dataR)
+    {
+        if (!ok_) ErrorMsg("Get data FAILED");
+        uint32_t size = dataL.Length();
+        fread(buffer, sizeof(int16_t), size*2, fp_);       
+        for (int n=0; n<size; n++)
+        {
+            dataL[n] = buffer[2*n];
+            dataR[n] = buffer[2*n+1];
+        }
+    }
+
+    // ファイルからデータをモノラルに変換しての取得
+    void SD_WavReader::ReadAndToMono(Array<int16_t>& data)
+    {
+        if (!ok_) ErrorMsg("Get data FAILED");
+        uint32_t size = data.Length();
+        fread(buffer, sizeof(int16_t), size*2, fp_);
+        for (int n=0; n<size; n++)
+            data[n] = (buffer[2*n] + buffer[2*n+1])/2;
+    }        
+    
+    // データサイズ(標本化点の数)の取得
+    int32_t SD_WavReader::GetSize()
+    {
+        if (!ok_) ErrorMsg("Get data size FAILED");
+        return size_;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SD_WavReader.hpp	Mon Aug 15 04:38:45 2016 +0000
@@ -0,0 +1,73 @@
+//--------------------------------------------------------------
+//  SD_WavReader class ---- Header
+//      SD カードの *.wav ファイルの内容を読み出す
+//      以下のフォーマット以外は扱わない
+//          PCM,16 ビットステレオ,標本化周波数 44.1 kHz
+//
+//  2016/07/12, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef SD_WAV_READER_HPP
+#define SD_WAV_READER_HPP
+
+#include "SDFileSystem.h"
+#include "BlinkLabel.hpp"
+#include "Array.hpp"
+#include <string>
+
+namespace Mikami
+{
+    class SD_WavReader
+    {
+    public:
+        SD_WavReader(int32_t bufferSize);
+        virtual ~SD_WavReader();
+
+        void Open(const string fileName);
+        
+        void Close() { fclose(fp_); }
+        
+        // ファイルのヘッダ読み込み
+        //      戻り値: *.wav で,16 ビットステレオ,
+        //             標本化周波数:44.1 kHz の場合 true
+        bool IsWavFile();
+
+        // ファイルからステレオデータの取得
+        void ReadStereo(Array<int16_t>& dataL, Array<int16_t>& dataR);
+
+        // ファイルからデータをモノラルに変換しての取得
+        void ReadAndToMono(Array<int16_t>& data);
+        
+        // データサイズ(標本化点の数)の取得
+        int32_t GetSize();
+
+    private:
+        const string STR_;
+        
+        struct WaveFormatEx
+        {
+            uint16_t wFormatTag;        // 1: PCM
+            uint16_t nChannels;         // 1:モノラル,2: ステレオ
+            uint32_t nSamplesPerSec;    // 標本化周波数 (Hz)
+            uint32_t nAvgBytesPerSec;   // 転送速度 (bytes/s)
+            uint16_t nBlockAlign;       // 4: 16ビットステレオの場合
+            uint16_t wBitsPerSample;    // データのビット数,8 または 16
+            uint16_t cbSize;            // PCM の場合使わない
+        };
+
+        SDFileSystem *sd_;
+        FILE *fp_;
+        
+        bool ok_;
+        int32_t size_;          // データサイズ(標本化点の数)
+        Array<int16_t> buffer;  // ステレオをモノラルに変換する際の作業領域
+        
+        void ErrorMsg(char msg[])
+        {   BlinkLabel errLabel(240, 100, msg, Label::CENTER); }
+
+        // disallow copy constructor and assignment operator
+        SD_WavReader(const SD_WavReader&);
+        SD_WavReader& operator=(const SD_WavReader&);
+    };
+}
+#endif  // SD_BINARY_READER_HPP