Output the audio signal (*.bin) with filtering by IIR filter in the SD card using onboard CODEC. For *.wav file, F746_SD_WavPlayer and F746_SD_GraphicEqualiser are published on mbed. SD カードのオーディオ信号 (*.bin) を遮断周波数可変の IIR フィルタを通して,ボードに搭載されているCODEC で出力する.*.wav 形式のファイル用には,F746_SD_WavPlayer と F746_SD_GraphicEqualiser を mbed で公開している.

Dependencies:   BSP_DISCO_F746NG_patch_fixed F746_GUI LCD_DISCO_F746NG SDFileSystem_Warning_Fixed TS_DISCO_F746NG mbed

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Fri Apr 08 13:11:53 2016 +0000
Child:
1:e891c9b4f980
Commit message:
1

Changed in this revision

BSP_DISCO_F746NG_patch_fixed.lib Show annotated file Show diff for this revision Revisions of this file
F746_GUI.lib Show annotated file Show diff for this revision Revisions of this file
LCD_DISCO_F746NG.lib Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/BSP_AudioOut_Overwrite.cpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/BSP_AudioOut_Overwrite.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/BilinearDesignLH.cpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/BilinearDesignLH.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/Biquad.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/BiquadFrqRespDrawer.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/DesignerDrawer.cpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/DesignerDrawer.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/FileSelector.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/FrquencyResponseDrawer.cpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/FrquencyResponseDrawer.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/MyFunctions.cpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/MyFunctions.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/SD_BinaryReader.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/TouchPanelDetectorX.hpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/sai_io_o.cpp Show annotated file Show diff for this revision Revisions of this file
MyClasses_Functions/sai_io_o.hpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
TS_DISCO_F746NG.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BSP_DISCO_F746NG_patch_fixed.lib	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/the_sz/code/BSP_DISCO_F746NG_patch_fixed/#a4e658110084
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F746_GUI.lib	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/F746_GUI/#cbf7ed9092a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LCD_DISCO_F746NG.lib	Fri Apr 08 13:11:53 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	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,111 @@
+//--------------------------------------------------------------
+//  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	Fri Apr 08 13:11:53 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_io_o.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/BilinearDesignLH.cpp	Fri Apr 08 13:11:53 2016 +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/MyClasses_Functions/BilinearDesignLH.hpp	Fri Apr 08 13:11:53 2016 +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/MyClasses_Functions/Biquad.hpp	Fri Apr 08 13:11:53 2016 +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/MyClasses_Functions/BiquadFrqRespDrawer.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,47 @@
+//--------------------------------------------------------------
+//  BiquadFrqRespDrawer class (Derived class of FrqRespDrawer)
+//  縦続形 IIR フィルタの周波数特性を描画するためのクラス
+//  このクラスは,FrqRespDrawer の派生クラス
+//
+//  2016/03/31, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef F746_BILINEAR_FRQ_RESP_DRAWER_HPP
+#define F746_BILINEAR_FRQ_RESP_DRAWER_HPP
+
+#include "Biquad.hpp"
+#include "FrquencyResponseDrawer.hpp"
+
+namespace Mikami
+{
+    class BiquadFrqRespDrawer : public FrqRespDrawer
+    {
+    public:
+        BiquadFrqRespDrawer(FrqRespDrawer::Params p)
+            : FrqRespDrawer(p) {}
+
+        // 次数とフィルタの係数設定
+        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_;
+    };
+}
+#endif  // F746_BILINEAR_FRQ_RESP_DRAWER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/DesignerDrawer.cpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,146 @@
+//------------------------------------------------------------------------------
+//  IIR フィルタを双一次 z 変換で設計し,その周波数特性を描画するためのクラス
+//  
+//  2016/04/08, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------------------------
+
+#include "DesignerDrawer.hpp"
+
+namespace Mikami
+{
+    // Constructor
+    DesignerDrawer::DesignerDrawer(uint16_t x0, uint16_t y0,
+                                   uint16_t db10, 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), DB10_(db10), ORDER_(order),
+          CURSOR_Y0_(y0+1-db10*6), CURSOR_LENGTH_(db10*6-1),
+          LOWER_F_(fL), HIGHER_F_(fH),
+          CURSOR_COLOR_(0xFFE000D0), CURSOR_TOUCHED_COLOR_(0xFFFF80FF)
+    {
+        drawerObj_ = new BiquadFrqRespDrawer(
+                        FrqRespDrawer::Params(x0, 100.0f, 8000.0f, 150,
+                                              y0, -60, 0, db10, 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_);
+        drawerObj_->SetParams(ORDER_, g0_, ck_);
+        lblFrq_ = new NumericLabel<int>(110, 30);
+
+        // 周波数特性の描画
+        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("Cutoff frequency = %4d Hz", newFc);
+                designObj_->Execute(newFc, lpHp, coefs_, g0_);
+                GetCoefficients(ck, g0);
+
+                drawerObj_->SetParams(ORDER_, g0_, ck_);
+                drawerObj_->Erase();
+                drawerObj_->DrawAxis();   // 目盛線の描画
+                drawerObj_->DrawGraph();  // 周波数特性のグラフのカーブを描画する
+
+                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("Cutoff frequency = %4d Hz", fC_);
+        DrawAxisNum();              // 目盛値の描画
+        drawerObj_->DrawAxis();     // 目盛線の描画
+        drawerObj_->DrawGraph();    // 周波数特性のカーブの描画
+
+        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;
+    }
+    
+    // 周波数特性の目盛線の描画
+    void DesignerDrawer::DrawAxisNum()
+    {
+        const int16_t OFS = 6;
+        drawerObj_->DrawCharX(100,  OFS, "0.1");
+        drawerObj_->DrawCharX(300,  OFS, "0.3");
+        drawerObj_->DrawCharX(1000, OFS, "1.0");
+        drawerObj_->DrawCharX(3000, OFS, "3.0");
+        drawerObj_->DrawCharX(8000, OFS, "8.0");
+
+        Label l_frq(drawerObj_->X(900), Y0_+20, "Frequency [kHz]",
+                    Label::CENTER);
+        drawerObj_->DrawNumericY(-24, -6, 4, 20, "%3d");  // 縦軸の目盛は 20 dB 間隔
+        Label l_dB(X0_-24, Y0_-DB10_*6-20, "[dB]");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/DesignerDrawer.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//  IIR フィルタを双一次 z 変換で設計し,その周波数特性を描画するためのクラス -- Header
+//  
+//  2016/04/06, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------------------------
+
+#ifndef F746_DISIGNER_AND_DRAWER_HPP
+#define F746_DISIGNER_AND_DRAWER_HPP
+
+#include "NumericLabel.hpp"
+#include "TouchPanelDetectorX.hpp"
+#include "BiquadFrqRespDrawer.hpp"
+#include "BilinearDesignLH.hpp"
+
+namespace Mikami
+{
+    class DesignerDrawer
+    {
+    public:
+        // Constructor
+        DesignerDrawer(uint16_t x0, uint16_t y0,
+                       uint16_t db10, 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 DB10_;
+        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_;
+
+        BilinearDesign::Coefs *coefs_;  // 設計された係数
+        Biquad::Coefs *ck_;
+        float g0_;                      // 設計された係数(利得定数)
+        
+        int fC_;    // 遮断周波数
+
+        uint16_t cursorX_, oldCursorX_;
+        bool cursorRedraw_;
+        BilinearDesign::Type lp_;
+        
+        BiquadFrqRespDrawer *drawerObj_;
+        BilinearDesign *designObj_;
+        TouchPanelDetectorX *tp_;
+        NumericLabel<int> *lblFrq_;
+        
+        // 周波数を 10, 20, 50, 100 Hz の倍数にする
+        int Frq10(float f);
+        
+        // 周波数特性の目盛線と目盛値の描画
+        void DrawAxisNum();
+    };
+}
+#endif  // F746_DISIGNER_AND_DRAWER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FileSelector.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,149 @@
+//--------------------------------------------------------------
+//  FileSelector class
+//      SD カード内のファイル名の一覧を表示し,ファイルを選択する
+//
+//  2016/04/05, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef FILE_SELECTOR_HPP
+#define FILE_SELECTOR_HPP
+
+#include "mbed.h"
+#include "Label.hpp"
+#include "ButtonGroup.hpp"
+#include "SD_BinaryReader.hpp"
+#include "SDFileSystem.h"
+
+namespace Mikami
+{
+    class FileSelector
+    {
+    public:
+        FileSelector(uint8_t x0, uint8_t y0, int maxFiles,
+                     int maxNameLength, SD_BinaryReader &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]),
+              lcd_(GuiBase::GetLcdPtr()),
+              sdReader_(reader), prev_(-1) {}
+
+        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(".bin") != string::npos) ||
+                         (strName.find(".BIN") != string::npos) )
+                    {
+                        sdReader_.Open(strName);        // ファイルオープン
+                        // 小さすぎるファイルは除外
+                        if ((sdReader_.ReadSize()) > 4096)
+                        {
+                            fileNames_[fileCount_] = strName;
+                            fileCount_++;
+                        }
+                        sdReader_.Close();
+                    }
+                    if (fileCount_ >= MAX_FILES_) break;
+                }
+                closedir(dp); 
+            }
+            else
+                return false;
+                
+            if (fileCount_ == 0) return false;
+
+            nonString_  = new string[fileCount_];
+            for (int n=0; n<fileCount_; n++) nonString_[n] = "";
+            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();   
+
+            return true;
+        }
+
+        // ファイルを選択する
+        bool Select(string &fileName)
+        {
+            int n;
+            if (rect_->GetTouchedNumber(n))
+            {
+                fileNameLabels_[n]->Draw(DeleteBin(n), TOUCHED_COLOR_);
+                if ((prev_ >= 0) && (prev_ != n))
+                    fileNameLabels_[prev_]->Draw(DeleteBin(prev_));
+                prev_ = n;
+                fileName = fileNames_[n];
+                return true;
+            }
+            else
+                return false;
+        }
+
+        // ファイルの一覧の表示
+        void DisplayFileList()
+        {
+            Erase(MAX_NAME_LENGTH_*((sFONT *)(&Font16))->Width, 270-Y_);
+            rect_->DrawAll();
+            for (int n=0; n<fileCount_; n++)
+                fileNameLabels_[n]->Draw(DeleteBin(n));
+        }
+
+        void Erase(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_;
+        
+        string *fileNames_;
+        string *nonString_;
+        ButtonGroup *rect_;
+        Label **fileNameLabels_;
+        LCD_DISCO_F746NG *lcd_;
+        SD_BinaryReader &sdReader_;
+        int fileCount_;
+        int prev_;
+
+        // Label を生成
+        void CreateLabels()
+        {
+            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 DeleteBin(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/MyClasses_Functions/FrquencyResponseDrawer.cpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,89 @@
+//-----------------------------------------------------------
+//  FrqRespDrawer class (Abstract base class)
+//
+//  2016/03/31, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#include "FrquencyResponseDrawer.hpp"
+#include "NumericLabel.hpp"
+
+namespace Mikami
+{
+    // 目盛線の描画
+    void FrqRespDrawer::DrawAxis()
+    {
+        uint16_t height = DB1_*(P_.MAX_DB - P_.MIN_DB);
+        int logMin = (int)floorf(log10f(P_.MIN));
+        int loop = (int)floorf(log10f(P_.MAX)) - logMin;
+
+        lcd_->SetTextColor(P_.AXIS_COLOR);
+        uint16_t y0 = P_.ORGY- height;
+        lcd_->DrawVLine(X(P_.MIN), y0, height);      // 最小値に対応する線
+
+        float du = powf(10.0, logMin);              // 座標値の増分
+        float u1 = (floorf(P_.MIN/du) + 1.0f)*du;   // 最小値に対応する線の次の座標値
+
+        for (int n=0; n<=loop; n++)
+        {
+            float uMax = (10.0f*du < P_.MAX) ? 10.0f*du : P_.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(P_.MAX), y0, height);      // 最大値に対応する線
+        
+        uint16_t width = X(P_.MAX) - X(P_.MIN);
+        for (int n=0; n<= (P_.MAX_DB - P_.MIN_DB)/10; n++)
+            lcd_->DrawHLine(X(P_.MIN), P_.ORGY-P_.DB10*n, width);
+    }
+
+    // 縦軸の数値の表示
+    void FrqRespDrawer::DrawNumericY(int offsetX, int offsetY, int count,
+                                     uint16_t d_dB, const char fmt[], sFONT &fonts,
+                                     uint32_t textColor)
+    {
+        uint16_t x0 = P_.ORG + offsetX;
+        uint16_t y0 = P_.ORGY + offsetY;
+        for (int n=0; n<count; n++)
+            new NumericLabel<int>(x0, y0-n*d_dB*DB1_,
+                                  fmt, (int)(P_.MIN_DB+d_dB*n));
+    }
+
+    // 周波数特性のグラフの描画
+    void FrqRespDrawer::DrawGraph()
+    {
+        lcd_->SetTextColor(P_.LINE_COLOR);
+        uint16_t width = X(P_.MAX) - X(P_.MIN);   
+        uint16_t x1 = 0;
+        uint16_t y1 = 0;
+        float pi2FsM = -6.283185f/P_.FS;    // -2*PI*Ts
+        for (int n=0; n<=width; n++)
+        {
+            float frq = PosToFrq(n+P_.ORG);
+            uint16_t x2 = X(frq);
+
+            float absHz = AbsH_z(exp(Complex(0, pi2FsM*frq)));
+            float dB = (absHz > 0.001f) ? 20.0f*log10f(absHz) : P_.MIN_DB;
+            uint16_t y2 = P_.ORGY - Round((dB - P_.MIN_DB)*DB1_);
+            if (y2 > P_.ORGY) y2 = P_.ORGY;
+
+            if (n != 0) lcd_->DrawLine(x1, y1, x2, y2);
+
+            x1 = x2;
+            y1 = y2;
+        }
+        lcd_->SetTextColor(P_.AXIS_COLOR);
+        lcd_->DrawHLine(X(P_.MIN), P_.ORGY, width);
+    }
+
+    // 消去
+    void FrqRespDrawer::Erase()
+    {
+        lcd_->SetTextColor(P_.BACK_COLOR);
+        uint16_t height = DB1_*(P_.MAX_DB - P_.MIN_DB);
+        lcd_->FillRect(P_.ORG, P_.ORGY- height, X(P_.MAX)-X(P_.MIN)+1, height+1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FrquencyResponseDrawer.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,101 @@
+//-----------------------------------------------------------
+//  FrqRespDrawer class (Abstract base class) -- Header
+//
+//  2016/03/30, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef F746_FRQ_RESP_DRAWER_HPP
+#define F746_FRQ_RESP_DRAWER_HPP
+
+#include <complex>  // requisite for complex
+#include "Label.hpp"
+
+namespace Mikami
+{
+    typedef complex<float> Complex; // define "Complex"
+
+    class FrqRespDrawer
+    {
+    public:
+        struct Params
+        {
+            const uint16_t ORG;     // 横軸の目盛の最小値に対応する位置
+            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 uint16_t DB10;    // 10 dB 対応する長さ (pixels)
+            const float FS;         // 標本化周波数
+            const uint32_t LINE_COLOR;
+            const uint32_t AXIS_COLOR;
+            const uint32_t BACK_COLOR;
+            
+            Params(uint16_t org, float min, float max, uint16_t dec,
+                   uint16_t orgY, float minDb, float maxDb, uint16_t db10,
+                   float fs,
+                   uint32_t lineColor = 0xFF00B0FF,
+                   uint32_t axisColor = LCD_COLOR_LIGHTGRAY,
+                   uint32_t backColor = GuiBase::ENUM_BACK)
+                : ORG(org), MIN(min), MAX(max), DEC(dec),
+                  ORGY(orgY), MIN_DB(minDb), MAX_DB(maxDb), DB10(db10),
+                  FS(fs),
+                  LINE_COLOR(lineColor),
+                  AXIS_COLOR(axisColor),
+                  BACK_COLOR(backColor) {}
+        };
+        
+        // Constructor
+        FrqRespDrawer(Params p)
+            : lcd_(GuiBase::GetLcdPtr()), P_(p), DB1_(p.DB10*0.1f) {}
+
+        // 周波数に対応する x 座標値の取得
+        int X(float frq)
+        {   return Round(P_.ORG + P_.DEC*log10f(frq/P_.MIN));  }
+
+        // x 座標値を周波数に変換
+        float PosToFrq(uint16_t x)
+        { return P_.MIN*powf(10.0f, (x - P_.ORG)/(float)P_.DEC); }
+
+        // 目盛線の描画
+        void DrawAxis();
+
+        // 横軸の目盛値の表示用
+        void DrawCharX(uint32_t frq, int offsetY,
+                          const char str[], sFONT &fonts = Font12,
+                          uint32_t textColor = LCD_COLOR_WHITE)
+        {   Label frequency(X(frq), P_.ORGY+offsetY, str, Label::CENTER); }
+
+        // 縦軸の目盛値の表示
+        void DrawNumericY(int offsetX, int offsetY, int count,
+                          uint16_t d_dB, const char fmt[], sFONT &fonts = Font12,
+                          uint32_t textColor = LCD_COLOR_WHITE); 
+
+        // 周波数特性のグラフの描画
+        void DrawGraph();
+        
+        // 周波数応答の絶対値を返す関数, 引数: z^(-1)
+        virtual float AbsH_z(Complex u) = 0;
+
+        // 消去
+        void Erase();
+
+    private:
+        LCD_DISCO_F746NG *lcd_;
+        const Params P_;
+        const float DB1_;
+
+        // 丸め
+        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/MyFunctions.cpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,81 @@
+//--------------------------------------------------------------
+//  フィルタ処理付き SD オーディオプレーヤーで使う大域関数(ヘッダ)
+//
+//  2016/04/07, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "MyFunctions.hpp"
+
+// 1フレーム分の信号処理 (IIR フィルタ) の実行
+void ProcessSignal(SD_BinaryReader &sdReader, SaiIO_O &mySai,
+                   int16_t sn[], float g0, Biquad hn[],
+                   int order, bool filterOn)
+{
+    sdReader.Read(sn, mySai.GetLength());   // 1フレーム分のデータを SD から読み込む
+
+    while (!mySai.IsXferred()) {}  // データの転送が終わるまで待つ
+    //--------------------------------------------------------------
+    // 1フレーム分の信号処理を行い,その結果を出力する
+    for (int n=0; n<mySai.GetLength(); n++)
+    {
+        int16_t value;
+        if (filterOn)       // フィルタ処理実行
+        {
+            // 縦続形の IIR フィルタ
+            float yn = g0*sn[n];
+            for (int k=0; k<order/2; k++) yn = hn[k].Execute(yn);
+            value = (int16_t)yn;
+        }
+        else
+            value = sn[n];  // フィルタ処理なし
+        mySai.Output(value, value);    // 音響信号の出力
+    }
+    //--------------------------------------------------------------
+    mySai.ResetXferred();   // 次のデータ転送に備える
+}
+
+// SD カードのファイルのオープン
+int32_t SD_Open(SD_BinaryReader &sdReader,
+                string fileName, int32_t frameSize)
+{
+    sdReader.Open(fileName);
+    return sdReader.ReadSize()/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,
+                   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/MyClasses_Functions/MyFunctions.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,37 @@
+//--------------------------------------------------------------
+//  フィルタ処理付き SD オーディオプレーヤーで使う大域関数(ヘッダ)
+//
+//  2016/04/07, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef F746_MY_FUNCTIONS_HPP
+#define F746_MY_FUNCTIONS_HPP
+
+#include "sai_io_o.hpp"
+#include "ButtonGroup.hpp"
+#include "FileSelector.hpp"
+#include "DesignerDrawer.hpp"
+#include "SD_BinaryReader.hpp"
+
+using namespace Mikami;
+
+// 1フレーム分の信号処理 (IIR フィルタ) の実行
+void ProcessSignal(SD_BinaryReader &sdReader, SaiIO_O &mySai,
+                   int16_t sn[], float g0, Biquad hn[],
+                   int order, bool filterOn);
+
+// SD カードのファイルのオープン
+int32_t SD_Open(SD_BinaryReader &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/MyClasses_Functions/SD_BinaryReader.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,86 @@
+//--------------------------------------------------------------
+//  SD_BinaryReader class
+//      SD カードの内容を読み出す
+//          最初の4バイト:データサイズ
+//          それ以降: int16_t のデータ
+//
+//  2016/04/07, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef SD_BINARY_READER_HPP
+#define SD_BINARY_READER_HPP
+
+#include "SDFileSystem.h"
+#include "BlinkLabel.hpp"
+#include <string>
+
+namespace Mikami
+{
+    class SD_BinaryReader
+    {
+    public:
+        SD_BinaryReader() : STR_("sd"), ok_(false)
+        {
+            sd_ = new SDFileSystem(STR_.c_str());
+            sd_->mount();
+        }
+
+        ~SD_BinaryReader()
+        {
+            sd_->unmount();
+            delete sd_;
+        }
+        
+        void Open(const string fileName)
+        {
+            string name = (string)"/" + STR_ + "/" + fileName;
+            fp_ = fopen(name.c_str(), "rb");
+            if (fp_ == NULL) ErrorMsg("open error!!");
+        }
+        
+        void Close() { fclose(fp_); }
+        
+        // ファイルからデータサイズの読み出し
+        //      戻り値: int16_t 型のデータサイズ
+        int32_t ReadSize()
+        {
+            fread(&size_, sizeof(int), 1, fp_);
+            ok_ = true;
+            return size_;
+        }
+
+        // ファイルからデータの取得
+        void Read(int16_t data[], uint32_t size)
+        {
+            if (!ok_) ErrorMsg("Get data FAILED");
+            fread(data, sizeof(int16_t), size, fp_);
+        }        
+
+        // データサイズの取得
+        //      戻り値: int16_t 型のデータサイズ
+        int32_t GetSize()
+        {
+            if (!ok_) ErrorMsg("Get data size FAILED");
+            return size_;
+        }
+
+    private:
+        const string STR_;
+        
+        SDFileSystem *sd_;
+        FILE *fp_;
+        
+        bool ok_;
+        int32_t size_;  // word count, word = int16_t
+        
+        void ErrorMsg(char msg[])
+        {
+            BlinkLabel errLabel(240, 100, msg, Label::CENTER);
+        }
+
+        // disallow copy constructor and assignment operator
+        SD_BinaryReader(const SD_BinaryReader&);
+        SD_BinaryReader& operator=(const SD_BinaryReader&);
+    };
+}
+#endif  // SD_BINARY_READER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/TouchPanelDetectorX.hpp	Fri Apr 08 13:11:53 2016 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/sai_io_o.cpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,77 @@
+//-----------------------------------------------------------
+//  SiaIO class for output
+//  2016/02/16, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#include "sai_io_o.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;
+    }
+
+    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_io_o.hpp	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------
+//  SiaIO class for output (Header)
+//  2016/02/16, 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);
+
+        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/SDFileSystem.lib	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/DieterGraef/code/SDFileSystem/#c03ef1abef0e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TS_DISCO_F746NG.lib	Fri Apr 08 13:11:53 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	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,169 @@
+//--------------------------------------------------------------
+//  フィルタ処理付き SD オーディオプレーヤー
+//      SD のファイル
+//          先頭から 4 バイト:  データ数に対応する (int32_t 型)
+//          それ以降 2 バイトごと: int16_t のモノラルデータが続く
+//          データ: 標本化周波数 16 kHz のもの
+//          拡張子: "*.bin", "*.BIN"
+//      IIR フィルタ ---- 低域通過および高域通過フィルタ
+//
+//  2016/04/08, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "MyFunctions.hpp"
+#include "BlinkLabel.hpp"
+
+using namespace Mikami;
+
+int main()
+{
+    Label myLabel(80, 4, "SD Card Audio Player", Label::LEFT, Font16);
+
+    const int FS = I2S_AUDIOFREQ_16K;   // 標本化周波数: 16 kHz
+    SaiIO_O mySai(1024, FS);
+
+    SD_BinaryReader sdReader;   // SD カード読み込み用オブジェクト
+    const int MAX_FILES = 7;
+    FileSelector selector(4, 28, MAX_FILES, 32, sdReader);
+    if (!selector.CreateTable())
+        BlinkLabel errLabel(240, 100, "SD CARD ERROR", Label::CENTER);
+
+    // ボタン用の定数
+    const uint16_t BG_LEFT = 390;
+    const uint16_t BG_WIDTH = 80;
+    const uint16_t BG_HEIGHT = 36;
+
+    // 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);
+
+    // ButtonGroup: "LPF", "HPF"
+    const string LP_HP[2] = {"LPF", "HPF"};
+    ButtonGroup lpHp(BG_LEFT, 197, BG_WIDTH/2, BG_HEIGHT,
+                     2, LP_HP, 0, 0, 2, 0);
+
+    // ButtonGroup: "ON", "OFF"
+    const string ON_OFF[2] = {"ON", "OFF"};
+    ButtonGroup onOff(BG_LEFT, 235, BG_WIDTH/2, BG_HEIGHT,
+                      2, ON_OFF, 0, 0, 2, 1);
+
+    // フィルタの設計と周波数特性描画用
+    const int ORDER = 6;        // フィルタの次数
+    DesignerDrawer drawerObj(
+                     60,        // グラフの左端の位置
+                     230,       // グラフの下端の位置
+                     30,        // 10 dB 当たりのピクセル数
+                     FS,        // 標本化周波数
+                     ORDER,     // フィルタの次数
+                     400,       // 最初に与える遮断周波数
+                     200,       // 遮断周波数の最小値
+                     5000,      // 遮断周波数の最大値
+                     BilinearDesign::LPF);  // 低域通過フィルタ
+
+    // フィルタの準備
+    Biquad::Coefs ck[ORDER/2];
+    float g0;
+    drawerObj.GetCoefficients(ck, g0);
+    Biquad hn[ORDER/2];
+    for (int k=0; k<ORDER/2; k++) hn[k] = Biquad(ck[k]);
+
+    int32_t frameSize = mySai.GetLength();
+    int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ
+    bool playOk = false;
+    bool filterOn = false;
+    bool whileFirst = true;
+    string fileName;
+    int32_t loopCount;
+
+    while (true)
+    {
+        if (!playOk)
+        {
+            if (whileFirst)
+            {
+                whileFirst = false;
+                while (!menu.Touched(0))    // OPEN がタッチされるまで待つ
+                    ModifyFilter(drawerObj, lpHp, onOff,
+                                 hn, ck, g0, filterOn);
+                SelectFile(menu, selector, myLabel, fileName);
+            }
+            else
+            {
+                menu.Activate(1);       // PLAY 有効
+                int touch10;
+                while (!menu.GetTouchedNumber(touch10))
+                    ModifyFilter(drawerObj, lpHp, onOff,
+                                 hn, ck, g0, filterOn);
+                if (touch10 == 0)
+                    SelectFile(menu, selector, myLabel, fileName);
+            }
+
+            loopCount = SD_Open(sdReader, fileName, frameSize);
+            while (!menu.Touched(1))    // PLAY がタッチされるまで待つ
+                ModifyFilter(drawerObj, lpHp, onOff,
+                             hn, ck, g0, filterOn);
+        }
+        else
+            loopCount = SD_Open(sdReader, fileName, frameSize);
+
+        selector.Erase(BG_LEFT-4, 244);
+        myLabel.Draw("IIR Butterworth filter");
+        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<ORDER/2; 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, lpHp, onOff,
+                                 hn, ck, g0, filterOn);
+                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, lpHp, onOff, hn, ck, g0, filterOn);
+            // 1フレーム分の信号処理 (IIR フィルタ) の実行
+            ProcessSignal(sdReader, mySai, sn, g0, hn, ORDER, filterOn);
+        }
+        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	Fri Apr 08 13:11:53 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/99a22ba036c9
\ No newline at end of file