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:
Sat Apr 16 13:53:53 2016 +0000
Parent:
3:492cb0f68526
Child:
5:4a99dabc9180
Commit message:
4

Changed in this revision

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/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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/BSP_AudioOut_Overwrite.cpp	Sat Apr 16 13:53:53 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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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/DesignerDrawer.cpp	Sat Apr 16 13:53:53 2016 +0000
@@ -0,0 +1,144 @@
+//------------------------------------------------------------------------------
+//  IIR フィルタを双一次 z 変換で設計し,その周波数特性を描画するためのクラス
+//  
+//  2016/04/16, 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 FrqRespDrawer(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_);
+        frqResp.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);
+
+                frqResp.SetParams(ORDER_, g0_, ck_);
+                drawerObj_->Erase();
+                drawerObj_->DrawAxis();         // 目盛線の描画
+                drawerObj_->DrawGraph(frqResp); // 周波数特性のグラフのカーブを描画する
+
+                if (tch)    // カーソルの移動
+                {
+                    lcd_->SetTextColor(CURSOR_TOUCHED_COLOR_);
+                    lcd_->DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_);
+                }
+                cursorRedraw_ = true;
+                oldCursorX_ = cursorX_;
+                lp_ = lpHp;
+                return true;
+            }
+        }
+        
+        if (!tch && cursorRedraw_)   // カーソルを元の色に戻す
+        {
+            lcd_->SetTextColor(CURSOR_COLOR_);
+            lcd_->DrawVLine(oldCursorX_, CURSOR_Y0_, CURSOR_LENGTH_);
+            cursorRedraw_ = false;
+        }
+        return false;
+    }
+
+    // 周波数特性の描画
+    void DesignerDrawer::DrawResponse()
+    {
+        lblFrq_->Draw("Cutoff frequency = %4d Hz", fC_);
+        DrawAxisNum();                  // 目盛値の描画
+        drawerObj_->DrawAxis();         // 目盛線の描画
+        drawerObj_->DrawGraph(frqResp); // 周波数特性のカーブの描画
+
+        cursorX_ = drawerObj_->X(fC_);
+        lcd_->SetTextColor(CURSOR_COLOR_);
+        lcd_->DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_);
+    }
+
+    // フィルタ係数の取得
+    void DesignerDrawer::GetCoefficients(Biquad::Coefs *c, float &g0)
+    {
+        for (int k=0; k<ORDER_/2; k++) c[k] = ck_[k];
+        g0 = g0_;
+    }
+    
+    // 周波数を 10, 20, 50, 100 Hz の倍数にする
+    int DesignerDrawer::Frq10(float f)
+    {
+        if (f < 1000)
+            return ((int)(f/10.0f + 0.5f))*10;
+        if (f < 2000)
+            return ((int)(f/20.0f + 0.5f))*20;
+        if (f < 3000)
+            return ((int)(f/50.0f + 0.5f))*50;           
+        else
+            return ((int)(f/100.0f + 0.5f))*100;
+    }
+    
+    // 周波数特性の目盛線の描画
+    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	Sat Apr 16 13:53:53 2016 +0000
@@ -0,0 +1,76 @@
+//------------------------------------------------------------------------------
+//  IIR フィルタを双一次 z 変換で設計し,その周波数特性を描画するためのクラス -- Header
+//  
+//  2016/04/16, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------------------------
+
+#ifndef F746_DISIGNER_AND_DRAWER_HPP
+#define F746_DISIGNER_AND_DRAWER_HPP
+
+#include "NumericLabel.hpp"
+#include "TouchPanelDetectorX.hpp"
+#include "FrquencyResponseDrawer.hpp"
+#include "Biquad.hpp"
+#include "BilinearDesignLH.hpp"
+#include "IIR_CascadeFrqResp.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_;
+
+        IIR_CascadeFrqResp frqResp;     // IIR フィルタの周波数応答に対応するオブジェクト
+        BilinearDesign::Coefs *coefs_;  // 設計された係数
+        Biquad::Coefs *ck_;
+        float g0_;                      // 設計された係数(利得定数)
+        
+        int fC_;    // 遮断周波数
+
+        uint16_t cursorX_, oldCursorX_;
+        bool cursorRedraw_;
+        BilinearDesign::Type lp_;
+        
+        FrqRespDrawer *drawerObj_;
+        BilinearDesign *designObj_;
+        TouchPanelDetectorX *tp_;
+        NumericLabel<int> *lblFrq_; // 遮断周波数表示用
+        
+        // 周波数を 10, 20, 50, 100 Hz の倍数にする
+        int Frq10(float f);
+        
+        // 周波数特性の目盛線と目盛値の描画
+        void DrawAxisNum();
+    };
+}
+#endif  // F746_DISIGNER_AND_DRAWER_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FileSelector.hpp	Sat Apr 16 13:53:53 2016 +0000
@@ -0,0 +1,158 @@
+//--------------------------------------------------------------
+//  FileSelector class
+//      SD カード内のファイル名の一覧を表示し,ファイルを選択する
+//
+//  2016/04/10, 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"
+#include <algorithm>    // sort() で使用
+#include <string>
+
+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]),
+              sortedFileNames_(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(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, 270-Y_);
+            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(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 *sortedFileNames_;
+        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 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/FrquencyResponseDrawer.cpp	Sat Apr 16 13:53:53 2016 +0000
@@ -0,0 +1,88 @@
+//-----------------------------------------------------------
+//  FrqRespDrawer class
+//
+//  2016/04/16, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#include "FrquencyResponseDrawer.hpp"
+#include "NumericLabel.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_);
+        for (int n=0; n<= (MAX_DB_ - MIN_DB_)/10; n++)
+            lcd_->DrawHLine(X(MIN_), ORGY_-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 = ORG_ + offsetX;
+        uint16_t y0 = ORGY_ + offsetY;
+        for (int n=0; n<count; n++)
+            new NumericLabel<int>(x0, y0-n*d_dB*DB1_,
+                                  fmt, (int)(MIN_DB_+d_dB*n));
+    }
+
+    // 周波数特性のグラフの描画
+    void FrqRespDrawer::DrawGraph(FrequencyResponse &frqResp)
+    {
+        lcd_->SetTextColor(LINE_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+ORG_);
+            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(ORG_, ORGY_- height, X(MAX_)-X(MIN_)+1, height+1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyClasses_Functions/FrquencyResponseDrawer.hpp	Sat Apr 16 13:53:53 2016 +0000
@@ -0,0 +1,90 @@
+//-----------------------------------------------------------
+//  FrqRespDrawer class Header
+//
+//  2016/04/16, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef F746_FRQ_RESP_DRAWER_HPP
+#define F746_FRQ_RESP_DRAWER_HPP
+
+#include "Label.hpp"
+#include "IIR_CascadeFrqResp.hpp"
+
+namespace Mikami
+{
+    class FrqRespDrawer
+    {
+    public:
+        // Constructor
+        FrqRespDrawer(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)
+            : lcd_(GuiBase::GetLcdPtr()),
+              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),
+              DB1_(db10*0.1f) {}
+
+        // 周波数に対応する x 座標値の取得
+        int X(float frq)
+        {   return Round(ORG_ + DEC_*log10f(frq/MIN_));  }
+
+        // x 座標値を周波数に変換
+        float PosToFrq(uint16_t x)
+        {   return MIN_*powf(10.0f, (x - ORG_)/(float)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), 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(FrequencyResponse &frqResp);
+
+        // 消去
+        void Erase();
+
+    private:
+        LCD_DISCO_F746NG *lcd_;
+        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_;
+        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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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	Sat Apr 16 13:53: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