?
Revision 0:cacfc9e25452, committed 2019-06-04
- Comitter:
- phungductung
- Date:
- Tue Jun 04 21:58:08 2019 +0000
- Commit message:
- ?;
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BilinearDesignLH.cpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// Design of Butterworth LPF and HPF using bilinear transform +// +// 2016/03/31, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------------------------------ + +#include "BilinearDesignLH.hpp" + +namespace Mikami +{ + // Execute design + // input + // fc: Cutoff frequency + // pb: Passband (LPF or HPF) + // output + // c : Coefficients for cascade structure + // g : Gain factor for cascade structure + void BilinearDesign::Execute(float fc, Type pb, Coefs c[], float& g) + { + Butterworth(); + Bilinear(fc); + ToCascade(pb); + GetGain(pb); + GetCoefs(c, g); + } + + // Get poles for Butterworth characteristics + void BilinearDesign::Butterworth() + { + float pi_2order = PI_/(2.0f*ORDER_); + for (int j=0; j<ORDER_/2; j++) // Pole with imaginary part >= 0 + { + float theta = (2.0f*j + 1.0f)*pi_2order; + sP_[j] = Complex(-cosf(theta), sinf(theta)); + } + } + + // Bilinear transform + // fc: Cutoff frequency + void BilinearDesign::Bilinear(float fc) + { + float wc = tanf(fc*PI_FS_); + for (int k=0; k<ORDER_/2; k++) + zP_[k] = (1.0f + wc*sP_[k])/(1.0f - wc*sP_[k]); + } + + // Convert to coefficients for cascade structure + void BilinearDesign::ToCascade(Type pb) + { + for (int j=0; j<ORDER_/2; j++) + { + ck_[j].a1 = 2.0f*real(zP_[j]); // a1m + ck_[j].a2 = -norm(zP_[j]); // a2m + ck_[j].b1 = (pb == LPF) ? 2.0f : -2.0f; // b1m + ck_[j].b2 = 1.0f; // b2m + } + } + + // Calculate gain factor + void BilinearDesign::GetGain(Type pb) + { + float u = (pb == LPF) ? 1.0f : -1.0f; + float g0 = 1.0f; + for (int k=0; k<ORDER_/2; k++) + g0 = g0*(1.0f - (ck_[k].a1 + ck_[k].a2*u)*u)/ + (1.0f + (ck_[k].b1 + ck_[k].b2*u)*u); + gain_ = g0; + } + + // Get coefficients + void BilinearDesign::GetCoefs(Coefs c[], float& gain) + { + for (int k=0; k<ORDER_/2; k++) c[k] = ck_[k]; + gain = gain_; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BilinearDesignLH.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// Design of Butterworth LPF and HPF using bilinear transform -- Header +// +// 2016/03/31, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------------------------------ + +#ifndef BILINEAR_BUTTERWORTH_HPP +#define BILINEAR_BUTTERWORTH_HPP + +#include "mbed.h" +#include <complex> // requisite + +namespace Mikami +{ + typedef complex<float> Complex; // define "Complex" + + class BilinearDesign + { + public: + struct Coefs { float a1, a2, b1, b2; }; + enum Type { LPF, HPF }; + + // Constructor + BilinearDesign(int order, float fs) + : PI_FS_(PI_/fs), ORDER_(order) + { + sP_ = new Complex[order/2]; + zP_ = new Complex[order/2]; + ck_ = new Coefs[order/2]; + } + + // Destractor + ~BilinearDesign() + { + delete[] sP_; + delete[] zP_; + delete[] ck_; + } + + // Execution of design + void Execute(float fc, Type pb, Coefs c[], float& g); + + private: + static const float PI_ = 3.1415926536f; + const float PI_FS_; + const int ORDER_; + + Complex* sP_; // Poles on s-plane + Complex* zP_; // Poles on z-plane + Coefs* ck_; // Coefficients of transfer function for cascade form + float gain_; // Gain factor for cascade form + + void Butterworth(); + void Bilinear(float fc); + void ToCascade(Type pb); + void GetGain(Type pb); + void GetCoefs(Coefs c[], float& gain); + }; +} +#endif // BILINEAR_BUTTERWORTH_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Biquad.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,65 @@ +//-------------------------------------------------------------- +// 縦続形 IIR フィルタで使う 1D タイプの 2 次のフィルタ +// Biquad filter of 1D type for IIR filter of cascade structure +// このクラスでは,係数は実行中に書き換えられることを想定している +// +// u[n] = x[n] + a1*u[n-1] + a2*u[n-2] +// y[n] = u[n] + b1*u[n-1] + b2*u[n-2] +// x[n] : input signal +// y[n] : output signal +// b0 = 1 +// +// 2016/03/25, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef IIR_BIQUAD_HPP +#define IIR_BIQUAD_HPP + +#include "mbed.h" + +// 2nd order IIR filter +namespace Mikami +{ + class Biquad + { + public: + struct Coefs { float a1, a2, b1, b2; }; + + Biquad() {} // Default constructore + + Biquad(const Coefs ck) + { + SetCoefficients(ck); + Clear(); + } + + void SetCoefficients(const Coefs ck) + { + a1_ = ck.a1; + a2_ = ck.a2; + b1_ = ck.b1; + b2_ = ck.b2; + } + + float Execute(float xn) + { + float un = xn + a1_*un1_ + a2_*un2_; + float yn = un + b1_*un1_ + b2_*un2_; + + un2_ = un1_; + un1_ = un; + + return yn; + } + + void Clear() { un1_ = un2_ = 0; } + + private: + float a1_, a2_, b1_, b2_; + float un1_, un2_; + + // disallow copy constructor + Biquad(const Biquad&); + }; +} +#endif // IIR_BIQUAD_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DesignerDrawer.cpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// IIR フィルタを双一次 z 変換で設計し,その周波数特性を描画するためのクラス +// +// 2016/05/01, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------------------------------ + +#include "DesignerDrawer.hpp" + +namespace Mikami +{ + // Constructor + DesignerDrawer::DesignerDrawer(uint16_t x0, uint16_t y0, + float db1, int fs, int order, + float fc, uint16_t fL, uint16_t fH, + BilinearDesign::Type lpHp) + : lcd_(GuiBase::GetLcdPtr()), ts_(GuiBase::GetTsPtr()), + X0_(x0), Y0_(y0), ORDER_(order), + CURSOR_Y0_(y0+1-db1*60), CURSOR_LENGTH_(db1*60-1), + LOWER_F_(fL), HIGHER_F_(fH), + CURSOR_COLOR_(0xFFE000D0), CURSOR_TOUCHED_COLOR_(0xFFFF80FF) + { + drawerObj_ = new FrqRespDrawer(x0, 100.0f, 20000.0f, 140, + y0, -60, 0, db1, 10, fs); + + // 双一次 z 変換による IIR フィルタの設計 + designObj_ = new BilinearDesign(order, fs); + coefs_ = new BilinearDesign::Coefs[order/2]; + ck_ = (Biquad::Coefs *)coefs_; + + fC_ = fc; // 最初に与える遮断周波数 + designObj_->Execute(fC_, lpHp, coefs_, g0_); + frqResp_ = new IIR_CascadeFrqResp(); + frqResp_->SetParams(ORDER_, g0_, ck_); + + // 周波数特性の描画 + lblFrq_ = new NumericLabel<int>(110, 38); + DrawResponse(); + tp_ = new TouchPanelDetectorX( + drawerObj_->X(LOWER_F_), drawerObj_->X(HIGHER_F_), + CURSOR_Y0_, y0); + lp_ = lpHp; + cursorRedraw_ = false; + } + + DesignerDrawer::~DesignerDrawer() + { + delete tp_; + delete lblFrq_; + delete coefs_; + delete designObj_; + delete drawerObj_; + } + + // フィルタの再設計と周波数特性の再描画 + bool DesignerDrawer::ReDesignAndDraw(Biquad::Coefs *ck, float &g0, + BilinearDesign::Type lpHp) + { + bool changed = (lpHp != lp_) ? true : false; + bool tch = tp_->IsTouched(cursorX_, cursorX_); + if (tch || changed) + { + int newFc = Frq10(drawerObj_->PosToFrq(cursorX_)); + newFc = (newFc > HIGHER_F_) ? HIGHER_F_ : newFc; + if ((abs(newFc - fC_) >= 10) || changed) + { + fC_ = newFc; + lblFrq_->Draw("Tan So Cat = %4d Hz", newFc); + designObj_->Execute(newFc, lpHp, coefs_, g0_); + GetCoefficients(ck, g0); + + frqResp_->SetParams(ORDER_, g0_, ck_); + drawerObj_->Erase(); + drawerObj_->DrawAxis(); // 目盛線の描画 + drawerObj_->DrawGraph(frqResp_); // 周波数特性のグラフのカーブを描画する + + if (tch) // カーソルの移動 + { + lcd_->SetTextColor(CURSOR_TOUCHED_COLOR_); + lcd_->DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_); + } + cursorRedraw_ = true; + oldCursorX_ = cursorX_; + lp_ = lpHp; + return true; + } + } + + if (!tch && cursorRedraw_) // カーソルを元の色に戻す + { + lcd_->SetTextColor(CURSOR_COLOR_); + lcd_->DrawVLine(oldCursorX_, CURSOR_Y0_, CURSOR_LENGTH_); + cursorRedraw_ = false; + } + return false; + } + + // 周波数特性の描画 + void DesignerDrawer::DrawResponse() + { + lblFrq_->Draw("Tan So Cat = %4d Hz", fC_); + drawerObj_->DrawAxis(); // 目盛線の描画 + FrqRespDrawer::AxisX_Char numX[] = // 横軸の目盛値を描画する際に使う構造体の配列 + {{ 100, "0.1"}, { 200, "0.2"}, { 500, "0.5"}, { 1000, "1"}, + { 2000, "2"}, { 5000, "5"}, {10000, "10"}, {20000, "20"}}; + drawerObj_->DrawNumericX(numX, 8, 6, "Tan So [kHz]"); // 横軸の目盛 + drawerObj_->DrawNumericY(-24, -6, 20, "%3d"); // 縦軸の目盛は 20 dB 間隔 + drawerObj_->DrawGraph(frqResp_); // 周波数特性のカーブの描画 + + cursorX_ = drawerObj_->X(fC_); + lcd_->SetTextColor(CURSOR_COLOR_); + lcd_->DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_); + } + + // フィルタ係数の取得 + void DesignerDrawer::GetCoefficients(Biquad::Coefs *c, float &g0) + { + for (int k=0; k<ORDER_/2; k++) c[k] = ck_[k]; + g0 = g0_; + } + + // 周波数を 10, 20, 50, 100 Hz の倍数にする + int DesignerDrawer::Frq10(float f) + { + if (f < 1000) + return ((int)(f/10.0f + 0.5f))*10; + if (f < 2000) + return ((int)(f/20.0f + 0.5f))*20; + if (f < 3000) + return ((int)(f/50.0f + 0.5f))*50; + else + return ((int)(f/100.0f + 0.5f))*100; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DesignerDrawer.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// IIR フィルタを双一次 z 変換で設計し,その周波数特性を描画するためのクラス -- Header +// +// 2016/05/01, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------------------------------ + +#ifndef F746_DISIGNER_AND_DRAWER_HPP +#define F746_DISIGNER_AND_DRAWER_HPP + +#include "NumericLabel.hpp" +#include "TouchPanelDetectorX.hpp" +#include "FrquencyResponseDrawer.hpp" +#include "BilinearDesignLH.hpp" +#include "IIR_CascadeFrqResp.hpp" + +namespace Mikami +{ + class DesignerDrawer + { + public: + // Constructor + DesignerDrawer(uint16_t x0, uint16_t y0, + float db1, int fs, int order, + float fc, uint16_t fL, uint16_t fH, + BilinearDesign::Type lpHp); + + ~DesignerDrawer(); + + // フィルタの再設計と周波数特性の再描画 + bool ReDesignAndDraw(Biquad::Coefs *ck, float &g0, + BilinearDesign::Type lpHp); + + // 周波数特性の描画 + void DrawResponse(); + + void GetCoefficients(Biquad::Coefs *ck, float &g0); + + uint16_t GetOrder() { return ORDER_; } + + private: + LCD_DISCO_F746NG *lcd_; + TS_DISCO_F746NG *ts_; + + const uint16_t X0_, Y0_; + const uint16_t ORDER_; + const uint16_t CURSOR_Y0_, CURSOR_LENGTH_; + const uint16_t LOWER_F_, HIGHER_F_; + const uint32_t CURSOR_COLOR_, CURSOR_TOUCHED_COLOR_; + + IIR_CascadeFrqResp *frqResp_; // IIR フィルタの周波数応答に対応するオブジェクト + BilinearDesign::Coefs *coefs_; // 設計された係数 + Biquad::Coefs *ck_; + float g0_; // 設計された係数(利得定数) + + int fC_; // 遮断周波数 + + uint16_t cursorX_, oldCursorX_; + bool cursorRedraw_; + BilinearDesign::Type lp_; + + FrqRespDrawer *drawerObj_; + BilinearDesign *designObj_; + TouchPanelDetectorX *tp_; + NumericLabel<int> *lblFrq_; // 遮断周波数表示用 + + // 周波数を 10, 20, 50, 100 Hz の倍数にする + int Frq10(float f); + }; +} +#endif // F746_DISIGNER_AND_DRAWER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FileSelectorWav.cpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,114 @@ +//-------------------------------------------------------------- +// FileSelector class +// SD カード内のファイル名の一覧を表示し,ファイルを選択する +// +// 2016/06/30, 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 Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,214 @@ +//-------------------------------------------------------------- +// FileSelector class ---- Header ---- +// SD カード内のファイル名の一覧を表示し,ファイルを選択する +// +// 2016/06/30, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef FILE_SELECTOR_HPP +#define FILE_SELECTOR_HPP + +#include "Label.hpp" +#include "ButtonGroup.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) {} + + ~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&); + }; +} +/* +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) {} + + ~FileSelector() + { delete rect_; } + + bool 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 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 DisplayFileList(bool sortEnable = true) + { + 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 Erase(uint16_t x, uint16_t y, uint16_t width, uint16_t height, + uint32_t color = GuiBase::ENUM_BACK) + { + lcd_->SetTextColor(color); + lcd_->FillRect(x, y, width, height); + } + + 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() + { + 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 GetFileNameNoExt(int n) + { + string name = fileNames_[n]; + name.erase(name.find(".")); + return name.substr(0, MAX_NAME_LENGTH_); + } + + // 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/IIR_CascadeFrqResp.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,48 @@ +//----------------------------------------------------------- +// Frequency response for IIR filter of cascade form +// +// 2016/04/16, Copyright (c) 2016 MIKAMI, Naoki +//----------------------------------------------------------- + +#ifndef IIR_CASCADE_FREQUENCY_RESPONSE_HPP +#define IIR_CASCADE_FREQUENCY_RESPONSE_HPP + +#include "FrequancyResponseBase.hpp" +#include "Biquad.hpp" + +namespace Mikami +{ + class IIR_CascadeFrqResp : public FrequencyResponse + { + public: + IIR_CascadeFrqResp() {} + + // 次数とフィルタの係数設定 + void SetParams(int order, float g0, Biquad::Coefs ck[]) + { + order_ = order; + g0_ = g0; + ck_ = ck; + } + + // 周波数応答の絶対値を返す関数, 引数: z^(-1) + virtual float AbsH_z(Complex u) + { + Complex h = g0_; + for (int k=0; k<order_/2; k++) + h = h*(1.0f + (ck_[k].b1 + ck_[k].b2*u)*u) + /((1.0f - (ck_[k].a1 + ck_[k].a2*u)*u)); + return abs(h); + } + + private: + int order_; + float g0_; + Biquad::Coefs *ck_; + + // disallow copy constructor and assignment operator + IIR_CascadeFrqResp(const IIR_CascadeFrqResp&); + IIR_CascadeFrqResp& operator=(const IIR_CascadeFrqResp&); + }; +} +#endif // IIR_CASCADE_FREQUENCY_RESPONSE_HPP \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyFunctions.cpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,84 @@ +//-------------------------------------------------------------- +// フィルタ処理付き SD オーディオプレーヤーで使う大域関数(ヘッダ) +// +// 2016/07/04, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#include "MyFunctions.hpp" + +// 1フレーム分の信号処理 (IIR フィルタ) の実行 +void IIR_Filtering(SD_WavReader &sdReader, SaiIO &mySai, + float g0, Biquad hn[], + int order, bool filterOn) +{ + static int32_t frameSize = mySai.GetLength(); + static Array<int16_t> sn(frameSize); // フレームバッファ + + // 1フレーム分のデータを SD から読み込む + sdReader.ReadAndToMono(sn); + + while (!mySai.IsXferred()) {} // データの転送が終わるまで待つ + //-------------------------------------------------------------- + // 1フレーム分の信号処理を行い,その結果を出力する + for (int n=0; n<frameSize; n++) + { + // 縦続形の IIR フィルタ + float yn = g0*sn[n]; + for (int k=0; k<order/2; k++) yn = hn[k].Execute(yn); + + int16_t value = filterOn ? (int16_t)yn : sn[n]; + + // 音響信号の出力,右チャンネルには出力しない + mySai.Output(value, 0); + } + //-------------------------------------------------------------- + mySai.ResetXferred(); // 次のデータ転送に備える +} + +// SD カードのファイルのオープン +int32_t SD_Open(SD_WavReader &sdReader, + string fileName, int32_t frameSize) +{ + sdReader.Open(fileName); + sdReader.IsWavFile(); + return sdReader.GetSize()/frameSize; +} + +// ファイルの選択 +// selectedName: 選択されたファイル名 +void SelectFile(ButtonGroup &menu, FileSelector &selector, + Label &msg, string &selectedName) +{ + selector.DisplayFileList(); + msg.Draw("Chon File"); + do + { + if (selector.Select(selectedName)) + menu.Activate(1); // PLAY 有効 + wait_ms(200); + } while (!menu.Touched(1)); // PLAY がタッチされるまで繰り返す +} + +// フィルタの変更 +void ModifyFilter(DesignerDrawer &drawerObj, + ButtonGroup &lpHp, ButtonGroup &onOff, + Biquad hn[], Biquad::Coefs ck[], + float &g0, bool &filterOn) +{ + // フィルタ処理の有効/無効切り替え + int sw = 0; + if (onOff.GetTouchedNumber(sw)) + filterOn = (sw == 0) ? true : false; + + // フィルタの周波数特性の変更 + static int num = 0; + lpHp.GetTouchedNumber(num); + BilinearDesign::Type typeLH = (BilinearDesign::Type)num; + if (drawerObj.ReDesignAndDraw(ck, g0, typeLH)) + for (int k=0; k<drawerObj.GetOrder()/2; k++) + { + hn[k].SetCoefficients(ck[k]); + hn[k].Clear(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyFunctions.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,37 @@ +//-------------------------------------------------------------- +// フィルタ処理付き SD オーディオプレーヤーで使う大域関数(ヘッダ) +// +// 2016/07/04, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef F746_MY_FUNCTIONS_HPP +#define F746_MY_FUNCTIONS_HPP + +#include "SAI_InOut.hpp" +#include "ButtonGroup.hpp" +#include "FileSelectorWav.hpp" +#include "DesignerDrawer.hpp" +#include "SD_WavReader.hpp" + +using namespace Mikami; + +// 1フレーム分の信号処理 (IIR フィルタ) の実行 +void IIR_Filtering(SD_WavReader &sdReader, SaiIO &mySai, + float g0, Biquad hn[], + int order, bool filterOn); + +// SD カードのファイルのオープン +int32_t SD_Open(SD_WavReader &sdReader, + string fileName, int32_t frameSize); + +// ファイルの選択 +void SelectFile(ButtonGroup &menu, FileSelector &selector, + Label &msg, string &selectedName); + +// フィルタの変更 +void ModifyFilter(DesignerDrawer &drawerObj, + ButtonGroup &lpHp, ButtonGroup &onOff, + Biquad hn[], Biquad::Coefs ck[], + float &g0, bool &filterOn); + +#endif // F746_MY_FUNCTIONS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SD_WavReader.cpp Tue Jun 04 21:58:08 2019 +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("Khong the mo!!"); + } + + + // ファイルのヘッダ (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("Lay du lieu that bai"); + 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("Lay du lieu that bai"); + 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("Loi dung luong du lieu"); + return size_; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SD_WavReader.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,74 @@ +//-------------------------------------------------------------- +// SD_WavReader class ---- Header +// SD カードの *.wav ファイルの内容を読み出す +// 以下のフォーマット以外は扱わない +// PCM,16 ビットステレオ,標本化周波数 44.1 kHz +// +// 2016/06/17, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef SD_WAV_READER_HPP +#define SD_WAV_READER_HPP + +#include "SDFileSystem.h" +#include "BlinkLabel.hpp" +#define DEBUG_ARRAY_CHECK +#include "Array.hpp" +#include <string> + +namespace Mikami +{ + class SD_WavReader + { + public: + SD_WavReader(int32_t bufferSize); + ~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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TouchPanelDetectorX.hpp Tue Jun 04 21:58:08 2019 +0000 @@ -0,0 +1,46 @@ +//------------------------------------------------------ +// Touch panel detector for x axis class +// +// 2016/03/31, Copyright (c) 2016 MIKAMI, Naoki +//------------------------------------------------------ + +#ifndef F746_TOUCH_PANELDETECTORX_HPP +#define F746_TOUCH_PANELDETECTORX_HPP + +#include "GuiBase.hpp" + +namespace Mikami +{ + class TouchPanelDetectorX : public GuiBase + { + public: + // Constructor + TouchPanelDetectorX(uint16_t x1, uint16_t x2, + uint16_t y1, uint16_t y2) + : X1_(x1), X2_(x2), Y1_(y1), Y2_(y2) {} + + bool IsTouched(uint16_t xIn, uint16_t &xOut) + { + GetTsState(); + + if (!state_.touchDetected) return false; + + uint16_t x = state_.touchX[0]; + uint16_t y = state_.touchY[0]; + + if ( (x < X1_) || (x > X2_) || (y < Y1_) || (y > Y2_) ) + return false; + + const int WD = 8; + if ( (x < xIn-WD) || (x > xIn+WD) ) return false; + + xOut = (x >= X1_) ? x : X1_; + xOut = (x <= X2_) ? x : X2_; + return true; + } + + private: + const uint16_t X1_, X2_, Y1_, Y2_; + }; +} +#endif // F746_TOUCH_PANELDETECTORX_HPP