revised version of F746_SD_GraphicEqualizer
Dependencies: BSP_DISCO_F746NG F746_GUI F746_SAI_IO FrequencyResponseDrawer LCD_DISCO_F746NG SDFileSystem_Warning_Fixed TS_DISCO_F746NG mbed
Fork of F746_SD_GraphicEqualizer by
Revision 0:e953eb392151, committed 2016-04-27
- Comitter:
- MikamiUitOpen
- Date:
- Wed Apr 27 13:56:39 2016 +0000
- Child:
- 1:a5837720e14a
- Commit message:
- 1
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BSP_DISCO_F746NG.lib Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/ST/code/BSP_DISCO_F746NG/#458ab1edf6b2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F746_GUI.lib Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/F746_GUI/#7debdaa7b503
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LCD_DISCO_F746NG.lib Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/ST/code/LCD_DISCO_F746NG/#d44525b1de98
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/BSP_AudioOut_Overwrite.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,112 @@
+//--------------------------------------------------------------
+// Overwrite functuions and define calback functions
+// for functions in stm32746g_discovery_audio.cpp
+//--------------------------------------------------------------
+#include "BSP_AudioOut_Overwrite.hpp"
+
+// These three callback functions are modyfied by Mikami
+void BSP_AUDIO_OUT_HalfTransfer_CallBack()
+{
+ Mikami::SaiIO_O::FillBuffer1st();
+}
+
+void BSP_AUDIO_OUT_TransferComplete_CallBack()
+{
+ Mikami::SaiIO_O::FillBuffer2nd();
+}
+
+void BSP_AUDIO_OUT_Error_CallBack()
+{
+ Mikami::SaiIO_O::ErrorTrap();
+}
+
+//--------------------------------------------------------------
+// Followings are original by Nanase
+//--------------------------------------------------------------
+
+DMA_HandleTypeDef hdma_sai_tx;
+
+void AUDIO_OUT_SAIx_DMAx_IRQHandler()
+{
+ HAL_DMA_IRQHandler(&hdma_sai_tx);
+}
+
+void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params)
+{
+ //static DMA_HandleTypeDef hdma_sai_tx;
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* Enable SAI clock */
+ AUDIO_OUT_SAIx_CLK_ENABLE();
+
+ /* Enable GPIO clock */
+ AUDIO_OUT_SAIx_MCLK_ENABLE();
+ AUDIO_OUT_SAIx_SCK_SD_ENABLE();
+ AUDIO_OUT_SAIx_FS_ENABLE();
+
+ /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF;
+ HAL_GPIO_Init(AUDIO_OUT_SAIx_FS_GPIO_PORT, &gpio_init_structure);
+
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_SCK_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = AUDIO_OUT_SAIx_SCK_AF;
+ HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure);
+
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_SD_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF;
+ HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure);
+
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF;
+ HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure);
+
+ /* Enable the DMA clock */
+ AUDIO_OUT_SAIx_DMAx_CLK_ENABLE();
+
+ if(hsai->Instance == AUDIO_OUT_SAIx)
+ {
+ /* Configure the hdma_saiTx handle parameters */
+ hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL;
+ hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE;
+ hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE;
+ hdma_sai_tx.Init.Mode = DMA_CIRCULAR;
+ hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH;
+ hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
+ hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
+ hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE;
+ hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
+
+ hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx);
+
+ /* Deinitialize the Stream for new transfer */
+ HAL_DMA_DeInit(&hdma_sai_tx);
+
+ /* Configure the DMA Stream */
+ HAL_DMA_Init(&hdma_sai_tx);
+ }
+
+ /* SAI DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyClasses_Functions/BSP_AudioOut_Overwrite.hpp Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,14 @@ +//-------------------------------------------------------------- +// Overwrite functuions and define calback function (Header) +// for functions in stm32746g_discovery_audio.cpp +//-------------------------------------------------------------- + +#ifndef F746_AUDIO_OUT_OVERWRITE_HPP +#define F746_AUDIO_OUT_OVERWRITE_HPP + +#include "stm32746g_discovery_audio.h" +#include "SAI_Output.hpp" + +void AUDIO_OUT_SAIx_DMAx_IRQHandler(); + +#endif // F746_AUDIO_OUT_OVERWRITE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/BiquadGrEq.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,66 @@
+//--------------------------------------------------------------
+// グラフィックイコライザで使う 1D タイプの 2 次のフィルタ
+// Biquad filter of 1D type for graphic equalizer
+// このクラスでは,係数は実行中に書き換えられることを想定している
+//
+// u[n] = x[n] + a1*u[n-1] + a2*u[n-2]
+// y[n] = b0*u[n] + b1*u[n-1] + b2*u[n-2]
+// x[n] : input signal
+// y[n] : output signal
+//
+// 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 BiquadGrEq
+ {
+ public:
+ struct Coefs { float a1, a2, b0, b1, b2; };
+
+ BiquadGrEq() {} // Default constructore
+
+ BiquadGrEq(const Coefs ck)
+ {
+ SetCoefficients(ck);
+ Clear();
+ }
+
+ void SetCoefficients(const Coefs ck)
+ {
+ a1_ = ck.a1;
+ a2_ = ck.a2;
+ b0_ = ck.b0;
+ b1_ = ck.b1;
+ b2_ = ck.b2;
+ }
+
+ float Execute(float xn)
+ {
+ float un = xn + a1_*un1_ + a2_*un2_;
+ float yn = b0_*un + b1_*un1_ + b2_*un2_;
+
+ un2_ = un1_;
+ un1_ = un;
+
+ return yn;
+ }
+
+ void Clear() { un1_ = un2_ = 0; }
+
+ private:
+ float a1_, a2_, b0_, b1_, b2_;
+ float un1_, un2_;
+
+ // disallow copy constructor
+ BiquadGrEq(const BiquadGrEq&);
+ };
+}
+#endif // IIR_BIQUAD_HPP
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/DesignerDrawer.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,81 @@
+//------------------------------------------------------------------------------
+// イコライザ用フィルタのパラメータを設定し,その周波数特性を描画するためのクラス
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------------------------
+
+#include "DesignerDrawer.hpp"
+
+namespace Mikami
+{
+ // Constructor
+ DesignerDrawer::DesignerDrawer(uint16_t x0, uint16_t y0,
+ int stages, float f0, int fs, uint16_t db1)
+ : lcd_(GuiBase::GetLcdPtr()), ts_(GuiBase::GetTsPtr()),
+ X0_(x0), Y0_(y0), STAGES_(stages), DB1_(db1), Q_VAL_(1.5f)
+ {
+ drawerObj_ = new FrqRespDrawer(x0, 50.0f, 20000.0f, 142,
+ y0, -12, 12, db1, 3, fs);
+
+ calculator_ = new GrEqParamsCalculator(fs);
+ f0_ = new float[STAGES_];
+ for (int n=0; n<STAGES_; n++)
+ f0_[n] = f0*powf(2, n);
+
+ ck_ = new BiquadGrEq::Coefs[STAGES_];
+ Flatten();
+ frqResp_ = new GrEqualizerFrqResp(STAGES_);
+ frqResp_->SetParams(ck_);
+
+ // 周波数特性の描画
+ DrawResponse();
+ }
+
+ DesignerDrawer::~DesignerDrawer()
+ {
+ delete[] ck_;
+ delete[] f0_;
+ delete calculator_;
+ delete drawerObj_;
+ }
+
+ // 周波数特性の描画
+ void DesignerDrawer::DrawResponse()
+ {
+ drawerObj_->DrawAxis(); // 目盛線の描画
+ FrqRespDrawer::AxisX_Char numX[] = // 横軸の目盛値を描画する際に使う構造体の配列
+ {{ 50, "50"}, { 100, "100"}, { 200, "200"}, { 500, "500"}, { 1000, "1k"},
+ { 2000, "2k"}, { 5000, "5k"}, {10000, "10k"}, {20000, "20k"}};
+ drawerObj_->DrawNumericX(numX, 9, 6, "Frequency [Hz]"); // 横軸の目盛
+ drawerObj_->DrawNumericY(-24, -6, 6, "%3d"); // 縦軸の目盛値は 6 dB 間隔
+ drawerObj_->DrawGraph(frqResp_); // 周波数特性のカーブの描画
+ }
+
+ // 特定のバンドのイコライザ用フィルタのパラメータの設定と周波数特性の再描画
+ void DesignerDrawer::DesignAndRedraw(float gainDb, int n)
+ {
+ ck_[n] = calculator_->Execute(f0_[n], gainDb, Q_VAL_);
+ frqResp_->SetParam(ck_[n], n);
+ drawerObj_->Erase();
+ drawerObj_->DrawAxis(); // 目盛線の描画
+ drawerObj_->DrawGraph(frqResp_); // 周波数特性のグラフのカーブを描画する
+ }
+
+ // 周波数特性をフラットにし,その周波数特性を再描画
+ void DesignerDrawer::DesignAndRedraw()
+ {
+ Flatten();
+ frqResp_->SetParams(ck_);
+ drawerObj_->Erase();
+ drawerObj_->DrawAxis(); // 目盛線の描画
+ drawerObj_->DrawGraph(frqResp_); // 周波数特性のグラフのカーブを描画する
+ }
+
+ // イコライザ用フィルタの周波数特性をフラットにする
+ void DesignerDrawer::Flatten()
+ {
+ for (int n=0; n<STAGES_; n++)
+ ck_[n] = calculator_->Execute(f0_[n], 0, Q_VAL_);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/DesignerDrawer.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,68 @@
+//------------------------------------------------------------------------------
+// イコライザ用フィルタのパラメータを設定し,その周波数特性を描画するためのクラス -- Header
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------------------------
+
+#ifndef F746_DISIGNER_AND_DRAWER_HPP
+#define F746_DISIGNER_AND_DRAWER_HPP
+
+#include "NumericLabel.hpp"
+#include "FrquencyResponseDrawer.hpp"
+#include "GrEqParamsCalculator.hpp"
+#include "GrEqualizerFrqResp.hpp"
+
+namespace Mikami
+{
+ class DesignerDrawer
+ {
+ public:
+ // Constructor
+ DesignerDrawer(uint16_t x0, uint16_t y0,
+ int stages, float f0, int fs, uint16_t db1);
+
+ ~DesignerDrawer();
+
+ // 周波数特性の描画
+ void DrawResponse();
+
+ // 特定のバンドのイコライザ用フィルタのパラメータの設定と周波数特性の再描画
+ void DesignAndRedraw(float gainDb, int n);
+
+ // 周波数特性をフラットにし,その周波数特性を再描画
+ void DesignAndRedraw();
+
+ // イコライザ用フィルタの周波数特性をフラットにする
+ void Flatten();
+
+ void GetCoefficients(BiquadGrEq::Coefs ck[])
+ { for (int n=0; n<STAGES_; n++) ck[n] = ck_[n]; }
+
+ BiquadGrEq::Coefs GetCoefficient(int n) { return ck_[n]; }
+
+ uint16_t GetX0()
+ { return drawerObj_->X(f0_[0]); }
+
+ uint16_t GetSpaceX()
+ { return (uint16_t)(drawerObj_->X(f0_[1])
+ - drawerObj_->X(f0_[0])); }
+
+ int GetStages() { return STAGES_; }
+
+ private:
+ LCD_DISCO_F746NG *lcd_;
+ TS_DISCO_F746NG *ts_;
+
+ const uint16_t X0_, Y0_;
+ const int STAGES_;
+ const uint16_t DB1_;
+ const float Q_VAL_;
+
+ float *f0_;
+ GrEqParamsCalculator *calculator_;
+ GrEqualizerFrqResp *frqResp_; // フィルタの周波数応答に対応するオブジェクト
+ BiquadGrEq::Coefs *ck_; // フィルタの係数
+ FrqRespDrawer *drawerObj_;
+ };
+}
+#endif // F746_DISIGNER_AND_DRAWER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FileSelectorWav.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,182 @@
+//--------------------------------------------------------------
+// FileSelector class
+// SD カード内のファイル名の一覧を表示し,ファイルを選択する
+//
+// 2016/04/18, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef FILE_SELECTOR_HPP
+#define FILE_SELECTOR_HPP
+
+#include "mbed.h"
+#include "Label.hpp"
+#include "ButtonGroup.hpp"
+#include "SD_WavReader.hpp"
+#include "SDFileSystem.h"
+#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_(new string[maxFiles]),
+ sortedFileNames_(new string[maxFiles]),
+ nonString_(NULL), rect_(NULL), fileNameLabels_(NULL),
+ lcd_(GuiBase::GetLcdPtr()),
+ sdReader_(reader), prevFileCount_(0), prev_(-1) {}
+
+ ~FileSelector()
+ {
+ for (int n=0; n<fileCount_; n++)
+ delete fileNameLabels_[n];
+ delete[] fileNameLabels_;
+ delete rect_;
+ delete[] nonString_;
+ delete[] sortedFileNames_;
+ delete[] fileNames_;
+ }
+
+ 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;
+ fileCount_++;
+ }
+ sdReader_.Close();
+ }
+
+
+ if (fileCount_ >= MAX_FILES_) break;
+ }
+ closedir(dp);
+ }
+ else
+ return false;
+
+ if (fileCount_ == 0) return false;
+
+ if (nonString_ == NULL) delete[] nonString_;
+ nonString_ = new string[fileCount_];
+ for (int n=0; n<fileCount_; n++) nonString_[n] = "";
+
+ if (rect_ != NULL) delete rect_;
+ 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 = sortedFileNames_[n];
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // ファイルの一覧の表示
+ void DisplayFileList(bool sort = true)
+ {
+ for (int n=0; n<fileCount_; n++)
+ sortedFileNames_[n] = fileNames_[n];
+ if (sort)
+ std::sort(sortedFileNames_, sortedFileNames_+fileCount_);
+
+ Erase(MAX_NAME_LENGTH_*((sFONT *)(&Font16))->Width, 288);
+ rect_->DrawAll();
+ for (int n=0; n<fileCount_; n++)
+ fileNameLabels_[n]->Draw(GetFileNameNoExt(n));
+ }
+
+ void Erase(uint16_t width, uint16_t height,
+ uint32_t color = GuiBase::ENUM_BACK)
+ {
+ lcd_->SetTextColor(color);
+ lcd_->FillRect(0, 0, 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_;
+
+ string *fileNames_;
+ string *sortedFileNames_;
+ string *nonString_;
+ ButtonGroup *rect_;
+ Label **fileNameLabels_;
+ LCD_DISCO_F746NG *lcd_;
+ SD_WavReader &sdReader_;
+ int fileCount_, prevFileCount_;
+ int prev_;
+
+ // Label を生成
+ void CreateLabels()
+ {
+ if (fileNameLabels_ != NULL)
+ {
+ for (int n=0; n<prevFileCount_; n++)
+ delete fileNameLabels_[n];
+ delete[] fileNameLabels_;
+ }
+ fileNameLabels_ = new Label *[fileCount_+1];
+ 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 = sortedFileNames_[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/MyClasses_Functions/FrequancyResponseBase.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,27 @@
+//------------------------------------------------------
+// FrqRespDrawer クラスで周波数特性を描画する際に使う
+// 周波数応答に対応するクラスの抽象基底クラス
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------
+
+#ifndef FREQUENCY_RESPONSE_BASE_HPP
+#define FREQUENCY_RESPONSE_BASE_HPP
+
+#include <complex> // requisite for complex
+
+namespace Mikami
+{
+ typedef complex<float> Complex; // define "Complex"
+
+ class FrequencyResponse
+ {
+ public:
+ // 周波数応答の絶対値を返す関数, 引数: z^(-1)
+ virtual float AbsH_z(Complex u) = 0;
+
+ protected:
+ FrequencyResponse() {}
+ };
+}
+#endif // F746_FREQUENCY_RESPONSE_BASE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FrquencyResponseDrawer.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,105 @@
+//-----------------------------------------------------------
+// 周波数が対数スケールの周波数特性を描画するクラス
+// FrqRespDrawer class
+//
+// 2016/04/25, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#include "FrquencyResponseDrawer.hpp"
+
+namespace Mikami
+{
+ // 目盛線の描画
+ void FrqRespDrawer::DrawAxis()
+ {
+ uint16_t height = DB1_*(MAX_DB_ - MIN_DB_);
+ int logMin = (int)floorf(log10f(MIN_));
+ int loop = (int)floorf(log10f(MAX_)) - logMin;
+
+ lcd_->SetTextColor(AXIS_COLOR_);
+ uint16_t y0 = ORGY_ - height;
+ lcd_->DrawVLine(X(MIN_), y0, height); // 最小値に対応する線
+
+ float du = powf(10.0, logMin); // 座標値の増分
+ float u1 = (floorf(MIN_/du) + 1.0f)*du; // 最小値に対応する線の次の座標値
+
+ for (int n=0; n<=loop; n++)
+ {
+ float uMax = (10.0f*du < MAX_) ? 10.0f*du : MAX_;
+ for (float u=u1; u<uMax*0.99f; u+=du)
+ lcd_->DrawVLine(X(u), y0, height);
+
+ du = uMax; // 値の増分を 10 倍する
+ u1 = du; // 次の for ループ の最初の値
+ }
+
+ lcd_->DrawVLine(X(MAX_), y0, height); // 最大値に対応する線
+
+ uint16_t width = X(MAX_) - X(MIN_);
+ int count =Round((MAX_DB_ - MIN_DB_)/(Y_SPACE_/DB1_));
+ for (int n=0; n<= count; n++)
+ lcd_->DrawHLine(X(MIN_), ORGY_-Y_SPACE_*n, width);
+ }
+
+ // 横軸の目盛値の表示
+ void FrqRespDrawer::DrawNumericX(AxisX_Char xChar[], int nDisp, int offsetY,
+ string str, sFONT &fonts, uint32_t textColor)
+ {
+ for (int n=0; n<nDisp; n++)
+ Label frq(X(xChar[n].frq), ORGY_+offsetY,
+ xChar[n].str, Label::CENTER);
+ uint16_t x0 = ORGX_ + (uint16_t)(DEC_*log10f(MAX_/MIN_))/2;
+ Label l_frq(x0, ORGY_+20, str, Label::CENTER);
+ }
+
+ // 縦軸の目盛値の表示
+ void FrqRespDrawer::DrawNumericY(int offsetX, int offsetY, uint16_t d_dB,
+ const char fmt[], sFONT &fonts,
+ uint32_t textColor, string str)
+ {
+ uint16_t x0 = ORGX_ + offsetX;
+ uint16_t y0 = ORGY_ + offsetY;
+ int count = Round((MAX_DB_ - MIN_DB_)/d_dB);
+
+ for (int n=0; n<=count; n++)
+ NumericLabel<int> num(x0, y0-n*d_dB*DB1_,
+ fmt, (int)(MIN_DB_+d_dB*n));
+ Label l_dB(x0, y0-count*d_dB*DB1_-12, str);
+ }
+
+ // 周波数特性のグラフの描画
+ void FrqRespDrawer::DrawGraph(FrequencyResponse *frqResp, uint32_t color)
+ {
+ lcd_->SetTextColor(color);
+ uint16_t width = X(MAX_) - X(MIN_);
+ uint16_t x1 = 0;
+ uint16_t y1 = 0;
+ float pi2FsM = -6.283185f/FS_; // -2*PI*Ts
+ for (int n=0; n<=width; n++)
+ {
+ float frq = PosToFrq(n+ORGX_);
+ uint16_t x2 = X(frq);
+ float absHz = frqResp->AbsH_z(exp(Complex(0, pi2FsM*frq)));
+ float dB = (absHz > 0.001f) ? 20.0f*log10f(absHz) : MIN_DB_;
+ uint16_t y2 = ORGY_ - Round((dB - MIN_DB_)*DB1_);
+ if (y2 > ORGY_) y2 = ORGY_;
+
+ if (n != 0) lcd_->DrawLine(x1, y1, x2, y2);
+
+ x1 = x2;
+ y1 = y2;
+ }
+ lcd_->SetTextColor(AXIS_COLOR_);
+ lcd_->DrawHLine(X(MIN_), ORGY_, width);
+ }
+
+ // 消去
+ void FrqRespDrawer::Erase()
+ {
+ lcd_->SetTextColor(BACK_COLOR_);
+ uint16_t height = DB1_*(MAX_DB_ - MIN_DB_);
+ lcd_->FillRect(ORGX_, ORGY_- height, X(MAX_)-X(MIN_)+1, height+1);
+ }
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FrquencyResponseDrawer.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,95 @@
+//-----------------------------------------------------------
+// 周波数が対数スケールの周波数特性を描画するクラス
+// FrqRespDrawer class Header
+//
+// 2016/04/25, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef F746_FRQ_RESP_DRAWER_HPP
+#define F746_FRQ_RESP_DRAWER_HPP
+
+#include "NumericLabel.hpp"
+#include "FrequancyResponseBase.hpp"
+
+namespace Mikami
+{
+ class FrqRespDrawer
+ {
+ public:
+ // 横軸の目盛値を描画する際に使う構造体
+ struct AxisX_Char { uint16_t frq; string str; };
+
+ // Constructor
+ FrqRespDrawer(uint16_t org, float min, float max, uint16_t dec,
+ uint16_t orgY, float minDb, float maxDb,
+ float db1Pixel, float ySpace, float fs,
+ uint32_t lineColor = 0xFF00B0FF,
+ uint32_t axisColor = LCD_COLOR_LIGHTGRAY,
+ uint32_t backColor = GuiBase::ENUM_BACK)
+ : lcd_(GuiBase::GetLcdPtr()),
+ ORGX_(org), MIN_(min), MAX_(max), DEC_(dec),
+ ORGY_(orgY), MIN_DB_(minDb), MAX_DB_(maxDb),
+ DB1_(db1Pixel), Y_SPACE_(db1Pixel*ySpace), FS_(fs),
+ LINE_COLOR_(lineColor),
+ AXIS_COLOR_(axisColor),
+ BACK_COLOR_(backColor) {}
+
+ // 周波数に対応する x 座標値の取得
+ int X(float frq)
+ { return Round(ORGX_ + DEC_*log10f(frq/MIN_)); }
+
+ // x 座標値を周波数に変換
+ float PosToFrq(uint16_t x)
+ { return MIN_*powf(10.0f, (x - ORGX_)/(float)DEC_); }
+
+ // 目盛線の描画
+ void DrawAxis();
+
+ // 横軸の目盛値の表示
+ void DrawNumericX(AxisX_Char xChar[], int nDisp, int offsetY,
+ string str, sFONT &fonts = Font12,
+ uint32_t textColor = LCD_COLOR_WHITE);
+
+ // 縦軸の目盛値の表示
+ void DrawNumericY(int offsetX, int offsetY, uint16_t d_dB,
+ const char fmt[], sFONT &fonts = Font12,
+ uint32_t textColor = LCD_COLOR_WHITE,
+ string str = "[dB]");
+
+ // 周波数特性のグラフの描画
+ void DrawGraph(FrequencyResponse *frqResp, uint32_t color);
+ void DrawGraph(FrequencyResponse *frqResp)
+ { DrawGraph(frqResp, LINE_COLOR_);}
+
+ // 消去
+ void Erase();
+
+ private:
+ LCD_DISCO_F746NG *lcd_;
+ const uint16_t ORGX_; // 横軸の目盛の最小値に対応する位置
+ const float MIN_; // 横軸の目盛の最小値
+ const float MAX_; // 横軸の目盛の最大値
+ const uint16_t DEC_; // 周波数の 10 倍に対応する長さ (pixels)
+ const uint16_t ORGY_; // 縦軸の目盛の最小値に対応する位置
+ const float MIN_DB_; // 縦軸の目盛の最小値 [dB]
+ const float MAX_DB_; // 縦軸の目盛の最大値 [dB]
+ const float DB1_; // 1 dB に対応する pixels 数
+ const float Y_SPACE_; // 縦軸の目盛線の間隔に対応する pixels 数
+ const float FS_; // 標本化周波数
+ const uint32_t LINE_COLOR_;
+ const uint32_t AXIS_COLOR_;
+ const uint32_t BACK_COLOR_;
+
+ // 丸め
+ int Round(float x) { return x + 0.5f - (x < 0); }
+
+ // 10 のべき乗かどうかの検査
+ bool PowersOf10(float x)
+ { return fabsf(log10f(x) - Round(log10f(x))) < 0.01f; }
+
+ // disallow copy constructor and assignment operator
+ FrqRespDrawer(const FrqRespDrawer&);
+ FrqRespDrawer& operator=(const FrqRespDrawer&);
+ };
+}
+#endif // F746_FRQ_RESP_DRAWER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/GrEqParamsCalculator.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,44 @@
+//------------------------------------------------------------------------------
+// Parameters calculator class of buquad unit for graphic equalizer
+// グラフィックイコライザで使う biquad フィルタの係数を計算するクラス
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------------------------
+
+#ifndef GRAPHIC_EQALIZER_PARAMETER_CALCULATOR_HPP
+#define GRAPHIC_EQALIZER_PARAMETER_CALCULATOR_HPP
+
+#include "mbed.h"
+#include "BiquadGrEq.hpp"
+
+namespace Mikami
+{
+ class GrEqParamsCalculator
+ {
+ public:
+ // Constructor
+ GrEqParamsCalculator(float fs) : FS_(fs) {}
+
+ // 係数を計算する
+ BiquadGrEq::Coefs Execute(float f0, float gDb, float qVal)
+ {
+ const float PI = 3.1415926536f;
+ BiquadGrEq::Coefs coefs;
+
+ float g_sqrt = sqrtf(powf(10, gDb/20.0f));
+ float w0 = 2.0f*PI*f0/FS_;
+ float alpha = sinf(w0)/(2.0f*qVal);
+ float a0 = 1.0f + alpha/g_sqrt;
+ coefs.a1 = 2.0f*cosf(w0)/a0;
+ coefs.a2 = -(1.0f - alpha/g_sqrt)/a0;
+ coefs.b0 = (1.0f + alpha*g_sqrt)/a0;
+ coefs.b1 = -coefs.a1;
+ coefs.b2 = (1.0f - alpha*g_sqrt)/a0;
+ return coefs;
+ }
+
+ private:
+ const float FS_;
+ };
+}
+#endif // GRAPHIC_EQALIZER_PARAMETER_CALCULATOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/GrEqualizerFrqResp.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,52 @@
+//-----------------------------------------------------------
+// グラフィックイコライザで使う IIR フィルタの周波数応答
+// Frequency response for graphic equalizer
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef GRAPHIC_EQUALIZER_FREQUENCY_RESPONSE_HPP
+#define GRAPHIC_EQUALIZER_FREQUENCY_RESPONSE_HPP
+
+#include "FrequancyResponseBase.hpp"
+#include "BiquadGrEq.hpp"
+
+namespace Mikami
+{
+ class GrEqualizerFrqResp : public FrequencyResponse
+ {
+ public:
+ GrEqualizerFrqResp(int stages) : STAGES_(stages)
+ { ck_ = new BiquadGrEq::Coefs[stages]; }
+
+ ~GrEqualizerFrqResp()
+ { delete[] ck_; }
+
+ // フィルタの係数設定
+ void SetParams(BiquadGrEq::Coefs ck[])
+ { for (int n=0; n<STAGES_; n++) ck_[n] = ck[n]; }
+
+ void SetParam(BiquadGrEq::Coefs ck, int n)
+ { ck_[n] = ck; }
+
+ // 周波数応答の絶対値を返す関数, 引数: z^(-1)
+ virtual float AbsH_z(Complex u)
+ {
+ Complex h = 1;
+ for (int k=0; k<STAGES_; k++)
+ h = h*(ck_[k].b0 + (ck_[k].b1 + ck_[k].b2*u)*u)
+ /((1.0f - (ck_[k].a1 + ck_[k].a2*u)*u));
+ return abs(h);
+ }
+
+ private:
+ const int STAGES_;
+ float g0_;
+ BiquadGrEq::Coefs *ck_;
+
+ // disallow copy constructor and assignment operator
+ GrEqualizerFrqResp(const GrEqualizerFrqResp&);
+ GrEqualizerFrqResp& operator=(const GrEqualizerFrqResp&);
+ };
+}
+#endif // GRAPHIC_EQUALIZER_FREQUENCY_RESPONSE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/MyFunctions.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,75 @@
+//--------------------------------------------------------------
+// グラフィックイコライザ付き SD オーディオプレーヤーで使う大域関数
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "MyFunctions.hpp"
+
+// 1フレーム分の信号処理 (イコライザ) の実行
+void ProcessSignal(SD_WavReader &sdReader, SaiIO_O &mySai,
+ int16_t sn[], BiquadGrEq hn[], int stages)
+{
+ // 1フレーム分のデータを SD から読み込む
+ sdReader.ReadAndToMono(sn, mySai.GetLength());
+
+ while (!mySai.IsXferred()) {} // データの転送が終わるまで待つ
+ //--------------------------------------------------------------
+ // 1フレーム分のイコライザ処理を行い,その結果を出力する
+ for (int n=0; n<mySai.GetLength(); n++)
+ {
+ // 縦続形の IIR フィルタ実行
+ float yn = sn[n];
+ for (int k=0; k<stages; k++) yn = hn[k].Execute(yn);
+ int16_t value = (int16_t)yn;
+ mySai.Output(value, value); // 音響信号の出力
+ }
+ //--------------------------------------------------------------
+ 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)
+{
+ msg.Draw("Select file");
+ selector.DisplayFileList();
+ do
+ {
+ if (selector.Select(selectedName))
+ menu.Activate(1); // PLAY 有効
+ wait_ms(200);
+ } while (!menu.Touched(1)); // PLAY がタッチされるまで繰り返す
+}
+
+// フィルタの周波数特性の変更
+void ModifyFilter(DesignerDrawer &drawerObj,
+ SeekbarGroup &myBars, BiquadGrEq hn[],
+ Button &reset)
+{
+ if (reset.Touched())
+ {
+ drawerObj.DesignAndRedraw();
+ for (int n=0; n<drawerObj.GetStages(); n++)
+ hn[n] = BiquadGrEq(drawerObj.GetCoefficient(n));
+ myBars.DrawAll(0); // ツマミの位置を 0 dB に設定する
+ reset.Draw();
+ return;
+ }
+ static int num = 0;
+ if (!myBars.GetSlidedNumber(num)) return;
+ drawerObj.DesignAndRedraw(myBars.GetValue(num), num);
+ hn[num] = BiquadGrEq(drawerObj.GetCoefficient(num));
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyClasses_Functions/MyFunctions.hpp Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,37 @@ +//-------------------------------------------------------------- +// グラフィックイコライザ付き SD オーディオプレーヤーで使う大域関数(ヘッダ) +// +// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef F746_MY_FUNCTIONS_HPP +#define F746_MY_FUNCTIONS_HPP + +#include "SAI_Output.hpp" +#include "ButtonGroup.hpp" +#include "FileSelectorWav.hpp" +#include "DesignerDrawer.hpp" +#include "SD_WavReader.hpp" +#include "SeekbarGroup.hpp" +#include "BiquadGrEq.hpp" + +using namespace Mikami; + +// 1フレーム分の信号処理 (イコライザ) の実行 +void ProcessSignal(SD_WavReader &sdReader, SaiIO_O &mySai, + int16_t sn[], BiquadGrEq hn[], int stages); + +// 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, + SeekbarGroup &myBars, BiquadGrEq hn[], + Button &reset); + +#endif // F746_MY_FUNCTIONS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/SAI_Output.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,82 @@
+//-----------------------------------------------------------
+// SiaIO class for output
+// 2016/04/20, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#include "SAI_Output.hpp"
+
+namespace Mikami
+{
+ SaiIO_O::SaiIO_O(int size, int fs) : FS_(fs), tmpIndex_(0)
+ {
+ nData_ = size;
+ bufferSize_ = (size*2)*2;
+ outBuffer_ = new int16_t[(size*2)*2];
+ tmp_ = new int16_t[size*2];
+ xferred_ = false;
+ }
+ SaiIO_O::~SaiIO_O()
+ {
+ delete[] tmp_;
+ delete[] outBuffer_;
+ }
+
+ void SaiIO_O::InitCodecOut()
+ {
+ if (BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_HEADPHONE, VOLUME_OUT_, FS_) == AUDIO_ERROR)
+ ErrorTrap();
+ for (int n=0; n<bufferSize_; n++) outBuffer_[n] = 0;
+ for (int n=0; n<nData_*2; n++) tmp_[n] = 0;
+
+ NVIC_SetVector(AUDIO_OUT_SAIx_DMAx_IRQ, (uint32_t)AUDIO_OUT_SAIx_DMAx_IRQHandler);
+ BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
+
+ if (BSP_AUDIO_OUT_Play((uint16_t *)outBuffer_,
+ bufferSize_*AUDIODATA_SIZE) == AUDIO_ERROR)
+ ErrorTrap();
+ }
+
+ bool SaiIO_O::IsXferred()
+ {
+ if (xferred_)
+ {
+ tmpIndex_ = 0;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ void SaiIO_O::Output(int16_t xL, int16_t xR)
+ {
+ tmp_[tmpIndex_++] = xL; // Left
+ tmp_[tmpIndex_++] = xR; // Right
+ }
+
+ void SaiIO_O::ErrorTrap()
+ {
+ DigitalOut led1(LED1);
+ fprintf(stderr, "\r\n### ERROR\r\n");
+ while(true)
+ {
+ led1 = !led1;
+ wait_ms(250);
+ }
+ }
+
+ void SaiIO_O::FillBuffer(uint32_t offset)
+ {
+ int k = offset;
+ for (int n=0; n<nData_*2; n++)
+ outBuffer_[k++] = tmp_[n];
+ xferred_ = true;
+ }
+
+ // Instances for static variables
+ int32_t SaiIO_O::nData_;
+ int32_t SaiIO_O::bufferSize_;
+ int16_t* SaiIO_O::outBuffer_;
+ int16_t* SaiIO_O::tmp_;
+ __IO bool SaiIO_O::xferred_;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/SAI_Output.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,60 @@
+//-----------------------------------------------------------
+// SiaIO class for output (Header)
+// 2016/04/20, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef F746_SAI_IO_HPP
+#define F746_SAI_IO_HPP
+
+#include "mbed.h"
+#include "stm32746g_discovery_audio.h"
+#include "BSP_AudioOut_Overwrite.hpp"
+
+namespace Mikami
+{
+ class SaiIO_O
+ {
+ public:
+ SaiIO_O(int size, int fs);
+ ~SaiIO_O();
+
+ void InitCodecOut();
+
+ bool IsXferred();
+ void Output(int16_t xL, int16_t xR);
+
+ void ResetXferred() { xferred_ = false; }
+ int32_t GetLength() { return nData_; }
+ void Stop() { BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW); }
+ void Pause() { BSP_AUDIO_OUT_Pause(); }
+ void Resume() { BSP_AUDIO_OUT_Resume(); }
+
+
+ // These three member functions are called from
+ // callback functions in "BSP_AudioOut_Overwrite.cpp"
+
+ // Called form BSP_AUDIO_OUT_HalfTransfer_CallBack()
+ static void FillBuffer1st() { FillBuffer(0); }
+ // Called form BSP_AUDIO_OUT_TransferComplete_CallBack()
+ static void FillBuffer2nd() { FillBuffer(bufferSize_/2); }
+ // Also called form BSP_AUDIO_OUT_Error_CallBack()
+ static void ErrorTrap();
+
+ private:
+ const int FS_;
+ static const uint8_t VOLUME_OUT_ = 90;
+
+ static int32_t nData_;
+ static int32_t bufferSize_;
+
+ static int16_t* outBuffer_;
+ static int16_t* tmp_;
+
+ static __IO bool xferred_;
+
+ __IO int32_t tmpIndex_;
+
+ static void FillBuffer(uint32_t offset);
+ };
+}
+#endif // F746_SAI_IO_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/SD_WavReader.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,113 @@
+//--------------------------------------------------------------
+// SD_WavReader class
+// SD カードの *.wav ファイルの内容を読み出す
+// 以下のフォーマット以外は扱わない
+// PCM,16 ビットステレオ,標本化周波数 44.1 kHz
+//
+// 2016/04/19, 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 = new int16_t[bufferSize*2];
+ }
+
+ SD_WavReader::~SD_WavReader()
+ {
+ delete[] buffer;
+ 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::Read(int16_t data[], uint32_t size)
+ {
+ if (!ok_) ErrorMsg("Get data FAILED");
+ fread(data, sizeof(int16_t), size, fp_);
+ }
+
+ // ファイルからデータをモノラルに変換しての取得
+ void SD_WavReader::ReadAndToMono(int16_t data[], uint32_t size)
+ {
+ if (!ok_) ErrorMsg("Get data FAILED");
+ 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/MyClasses_Functions/SD_WavReader.hpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,72 @@
+//--------------------------------------------------------------
+// SD_WavReader class ---- Header
+// SD カードの *.wav ファイルの内容を読み出す
+// 以下のフォーマット以外は扱わない
+// PCM,16 ビットステレオ,標本化周波数 44.1 kHz
+//
+// 2016/04/19, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef SD_WAV_READER_HPP
+#define SD_WAV_READER_HPP
+
+#include "SDFileSystem.h"
+#include "BlinkLabel.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_); }
+
+ // ファイルのヘッダ (RIFFxxxxWAVEfm ) 読み込み
+ // 戻り値: *.wav で,16 ビットステレオ,
+ // 標本化周波数:44.1 kHz の場合 true
+ bool IsWavFile();
+
+ // ファイルからデータの取得
+ void Read(int16_t data[], uint32_t size);
+
+ // ファイルからデータをモノラルに変換しての取得
+ void ReadAndToMono(int16_t data[], uint32_t size);
+
+ // データサイズ(標本化点の数)の取得
+ 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;
+ };
+
+ SDFileSystem *sd_;
+ FILE *fp_;
+
+ bool ok_;
+ int32_t size_; // モノラルデータのサイズ
+ 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/SDFileSystem_Warning_Fixed.lib Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/SDFileSystem_Warning_Fixed/#225138ac03fd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TS_DISCO_F746NG.lib Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/ST/code/TS_DISCO_F746NG/#fe0cf5e2960f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Apr 27 13:56:39 2016 +0000
@@ -0,0 +1,156 @@
+//--------------------------------------------------------------
+// グラフィックイコライザ付き SD オーディオプレーヤー
+// SD のファイル: *.wav
+// PCM,16 ビットステレオ,標本化周波数 44.1 kHz
+// 上記以外の形式は扱わない
+// 出力:モノラル
+//
+// 2016/04/27, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "MyFunctions.hpp"
+#include "BlinkLabel.hpp"
+
+using namespace Mikami;
+
+int main()
+{
+ Label myLabel(80, 4, "SD Card Audio Player 16:36", Label::LEFT, Font16);
+
+ const int FS = AUDIO_FREQUENCY_44K; // 標本化周波数: 44.1 kHz
+ SaiIO_O mySai(2048, FS);
+
+ SD_WavReader sdReader(mySai.GetLength()); // SD カード読み込み用オブジェクト
+ const int MAX_FILES = 7;
+ FileSelector selector(4, 28, MAX_FILES, 38, sdReader);
+ if (!selector.CreateTable())
+ BlinkLabel errLabel(240, 100, "SD CARD ERROR", Label::CENTER);
+
+ // ボタン用の定数
+ const uint16_t BG_LEFT = 420;
+ const uint16_t BG_WIDTH = 60;
+ const uint16_t BG_HEIGHT = 40;
+
+ // ButtonGroup: "OPEN", "PLAY", "PAUSE", "RESUME", "STOP"
+ const string MENU[5] = {"OPEN", "PLAY", "PAUSE", "RESUME", "STOP"};
+ ButtonGroup menu(BG_LEFT, 2, BG_WIDTH, BG_HEIGHT,
+ 5, MENU, 0, 2, 1);
+ // OPEN のみアクティブ
+ menu.Activate(0);
+ for (int n=1; n<5; n++) menu.Inactivate(n);
+
+ Button flatButton(BG_LEFT, 230, BG_WIDTH, BG_HEIGHT, "FLAT");
+
+ // フィルタの設計と周波数特性描画用
+ const int STAGES = 9; // バンド数
+ DesignerDrawer drawerObj(
+ 30, // グラフの左端の位置
+ 130, // グラフの下端の位置
+ STAGES, // バンド数
+ 62.5f, // 最低域バンドの中心周波数
+ FS, // 標本化周波数
+ 4); // 1 dB 当たりのピクセル数
+
+ // 周波数特性変更用スライダ
+ SeekbarGroup myBars(drawerObj.GetX0(), 186, 66, STAGES,
+ drawerObj.GetSpaceX(), -8, 8, 0,
+ SeekBar::Vertical);
+
+ // フィルタの準備
+ BiquadGrEq::Coefs ck[STAGES];
+ drawerObj.GetCoefficients(ck);
+ BiquadGrEq hn[STAGES];
+ for (int k=0; k<STAGES; k++) hn[k] = BiquadGrEq(ck[k]);
+
+ int32_t frameSize = mySai.GetLength();
+ int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ
+ bool playOk = false;
+ bool whileFirst = true;
+ string fileName;
+ int32_t loopCount;
+
+ while (true)
+ {
+ if (!playOk)
+ {
+ if (whileFirst)
+ {
+ whileFirst = false;
+ while (!menu.Touched(0)) // OPEN がタッチされるまで待つ
+ ModifyFilter(drawerObj, myBars, hn, flatButton);
+ SelectFile(menu, selector, myLabel, fileName);
+ }
+ else
+ {
+ menu.Activate(1); // PLAY 有効
+ int touch10;
+ while (!menu.GetTouchedNumber(touch10))
+ ModifyFilter(drawerObj, myBars, hn, flatButton);
+ if (touch10 == 0)
+ SelectFile(menu, selector, myLabel, fileName);
+ }
+
+ loopCount = SD_Open(sdReader, fileName, frameSize);
+ while (!menu.Touched(1)) // PLAY がタッチされるまで待つ
+ ModifyFilter(drawerObj, myBars, hn, flatButton);
+ }
+ else
+ loopCount = SD_Open(sdReader, fileName, frameSize);
+
+ selector.Erase(BG_LEFT-4, 288);
+ myLabel.Draw("9-band Graphic Equalizer");
+ myBars.RedrawAll();
+ drawerObj.DrawResponse();
+ menu.Inactivate(0); // OPEN 無効
+ menu.Activate(2); // PAUSE 有効
+ menu.Activate(4); // STOP 有効
+
+ playOk = false;
+ bool stopOk = false;
+ mySai.InitCodecOut(); // SAI の初期化
+
+ // IIR フィルタの内部の遅延器のクリア
+ for (int k=0; k<STAGES; k++) hn[k].Clear();
+
+ 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.Pause();
+
+ // PLAY か RESUME か STOP がタッチされるまで待つ
+ int touch134 = -1;
+ while (!menu.GetTouchedNumber(touch134))
+ ModifyFilter(drawerObj, myBars, hn, flatButton);
+ switch (touch134)
+ {
+ case 1: playOk = true; // 最初から PLAY
+ break;
+ case 3: mySai.Resume(); // PAUSE したところから PLAY 再開
+ menu.Activate(2);
+ menu.Inactivate(3);
+ menu.TouchedColor(1);
+ break;
+ case 4: stopOk = true; // STOP
+ break;
+ }
+ }
+ if (playOk || stopOk) break;
+
+ ModifyFilter(drawerObj, myBars, hn, flatButton);
+ // 1フレーム分の信号処理 (イコライザ) の実行
+ ProcessSignal(sdReader, mySai, sn, hn, STAGES);
+ }
+ mySai.Stop();
+ menu.Activate(0); // OPEN 有効
+ if (!playOk) menu.Activate(1); // PLAY 有効
+ for (int n=2; n<5; n++) // その他は無効
+ menu.Inactivate(n);
+ sdReader.Close(); // SD のファイルのクローズ
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Apr 27 13:56:39 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/082adc85693f \ No newline at end of file
