Output the audio signal with filtering by IIR filter in the Quad-SPI flash memory using onboard CODEC. QSPI フラッシュメモリのオーディオデータを遮断周波数可変の IIR フィルタを通してボードに搭載されているCODEC で出力するプログラム.

Dependencies:   BSP_DISCO_F746NG_patch_fixed F746_GUI LCD_DISCO_F746NG QSPI_DISCO_F746NG TS_DISCO_F746NG mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //--------------------------------------------------------------
00002 //  QSPI 接続のフラッシュメモリに前もって格納されている音楽データを
00003 //  再生する際に IIR フィルタをかける
00004 //
00005 //  QSPI 接続のフラッシュメモリのデータ構造
00006 //      0x90000000 から 4 バイト:  データ数に対応する (int32_t 型)
00007 //      0x90000004 から 2 バイトごと: int16_t のモノラルデータが続く
00008 //      モノラルデータ: 標本化周波数 16 kHz のもの
00009 //  IIR フィルタ ---- 低域通過および高域通過フィルタ
00010 //
00011 //  2016/04/07, Copyright (c) 2016 MIKAMI, Naoki
00012 //--------------------------------------------------------------
00013 
00014 #include "LCD_DISCO_F746NG.h"
00015 #include "sai_io_o.hpp"
00016 #include "QSPI_BinaryReader.hpp"
00017 #include "ButtonGroup.hpp"
00018 #include "DesignerDrawer.hpp"
00019 
00020 using namespace Mikami;
00021 
00022 const uint32_t N_DATA_ = 1024;
00023 SaiIO_O mySai_(N_DATA_, I2S_AUDIOFREQ_16K);
00024 
00025 const int ORDER_ = 6;   // 次数
00026 Biquad::Coefs ck_[ORDER_/2];
00027 float g0_;
00028 
00029 // フィルタ処理の有無を決める
00030 void FilterOnOff(ButtonGroup &onOff, bool &filterOn);
00031 
00032 // LPF と HPF の切り替えとフィルタの設計
00033 void SwDesign(ButtonGroup &lpHp, DesignerDrawer &drawerObj,
00034               Biquad hn[]);
00035 
00036 int main()
00037 {
00038     Label myLabel(80, 6, "IIR Butterworth filter", Label::LEFT, Font16);
00039 
00040     // ButtonGroup: "PLAY", "PAUSE", "RESUME", "STOP"
00041     const string FUNCTION[4] = {"PLAY", "PAUSE", "RESUME", "STOP"};
00042     ButtonGroup function(390, 10, 80, 38,
00043                          4, FUNCTION, 0, 5, 1);
00044     // PLAY のみアクティブ
00045     function.Activate(0);
00046     for (int n=1; n<4; n++) function.Inactivate(n);
00047 
00048     // ButtonGroup: "LPF", "HPF"
00049     const string LP_HP[2] = {"LPF", "HPF"};
00050     ButtonGroup lpHp(390, 187, 40, 38,
00051                      2, LP_HP, 0, 0, 2, 0);
00052 
00053     // ButtonGroup: "ON", "OFF"
00054     const string ON_OFF[2] = {"ON", "OFF"};
00055     ButtonGroup onOff(390, 230, 40, 38,
00056                       2, ON_OFF, 0, 0, 2, 1);
00057 
00058     // QSPI フラッシュメモリからデータを読み込むための準備
00059     QspiBinaryReader reader;
00060     int32_t size = reader.ReadSize();  // Data number
00061     int32_t frameSize = mySai_.GetLength();
00062     int32_t loopCount = size/frameSize;
00063 
00064     // フィルタの設計と周波数特性描画用
00065     DesignerDrawer drawerObj(
00066                      60,        // グラフの左端の位置
00067                      230,       // グラフの下端の位置
00068                      30,        // 10 dB 当たりのピクセル数
00069                      16000,     // 標本化周波数
00070                      ORDER_,    // 次数
00071                      400,       // 最初に与える遮断周波数
00072                      200,       // 遮断周波数の最小値
00073                      5000,      // 遮断周波数の最大値
00074                      BilinearDesign::LPF);
00075     // フィルタの準備
00076     drawerObj.GetCoefficients(ck_, g0_);
00077     Biquad hn[ORDER_/2];
00078     for (int k=0; k<ORDER_/2; k++) hn[k] = Biquad(ck_[k]);
00079 
00080     int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ
00081     bool playOk = false;
00082     bool filterOn = false;
00083 
00084     while (true)
00085     {
00086         // PLAY がタッチされるまで待つ
00087         if (!playOk)
00088             while (!function.Touched(0))
00089             {
00090                 SwDesign(lpHp, drawerObj, hn);  // フィルタの切り替えとフィルタの設計
00091                 FilterOnOff(onOff, filterOn);   // フィルタ処理の有無を決める
00092                 wait(0.02f);
00093             }
00094         function.Activate(1);   // PAUSE を使えるようにする
00095         function.Activate(3);   // STOP を使えるようにする
00096         
00097         playOk = false;
00098         bool stopOk = false;
00099         mySai_.InitCodecOut();  // SAI の初期化
00100 
00101         // IIR フィルタの内部の遅延器のクリア
00102         for (int k=0; k<ORDER_/2; k++) hn[k].Clear();
00103 
00104         for (int k=0; k<loopCount; k++)
00105         {
00106             if (function.Touched(3)) break; // STOP
00107             if (function.Touched(1))        // PAUSE ?
00108             {
00109                 function.Draw(0);
00110                 function.Activate(2);   // RESUME を使えるようにする
00111                 mySai_.Pause();
00112                 // PLAY か RESUME か STOP がタッチされるまで待つ
00113                 while (!function.Touched(0) && !function.Touched(2)
00114                                             && !function.Touched(3))
00115                 {
00116                     SwDesign(lpHp, drawerObj, hn);  // フィルタの切り替えとフィルタの設計
00117                     FilterOnOff(onOff, filterOn);   // フィルタ処理の有無を決める
00118                 }
00119                 if (function.Touched(0))    // 最初から PLAY
00120                     playOk = true;
00121                 if (function.Touched(2))    // PAUSE したところから PLAY 再開
00122                 {
00123                     mySai_.Resume();
00124                     wait_ms(200);
00125                     function.Inactivate(2);
00126                 }
00127                 if (function.Touched(3))    // STOP
00128                     stopOk = true;
00129 
00130                 function.TouchedColor(0);
00131                 function.Draw(1);
00132             }
00133 
00134             if (playOk || stopOk) break;
00135 
00136             FilterOnOff(onOff, filterOn);   // フィルタ処理の有無を決める
00137 
00138             // データの転送が終わるまで待つ
00139             while (!mySai_.IsXferred()) {}
00140             // 1フレーム分のデータを QSPI フラッシュメモリから読み込む
00141             reader.Read(sn, frameSize*k, frameSize);
00142 
00143             // 1フレーム分を出力する
00144             for (int n=0; n<frameSize; n++)
00145             {
00146                 int16_t value;
00147                 if (filterOn)       // フィルタ処理実行
00148                 {
00149                     float yn = g0_*sn[n];
00150                     for (int k=0; k<ORDER_/2; k++) yn = hn[k].Execute(yn);
00151                     value = (int16_t)yn;
00152                 }
00153                 else
00154                     value = sn[n];  // フィルタ処理なし
00155                 mySai_.Output(value, value);    // 音響信号の出力
00156             }
00157             mySai_.ResetXferred();          // 次のデータ転送に備える
00158             SwDesign(lpHp, drawerObj, hn);  // フィルタの切り替えとフィルタの設計
00159         }
00160 
00161         mySai_.Stop();
00162         if (!playOk) function.Activate(0);  // PLAY のみアクティブにする
00163         for (int n=1; n<4; n++) function.Inactivate(n);
00164     }
00165 }
00166 
00167 // フィルタ処理の有無を決める
00168 void FilterOnOff(ButtonGroup &onOff, bool &filterOn)
00169 {
00170     int num;
00171     if (!onOff.GetTouchedNumber(num)) return;
00172     filterOn = (num == 0) ? true : false;
00173 }
00174 
00175 // フィルタの切り替えとフィルタの設計
00176 void SwDesign(ButtonGroup &lpHp, DesignerDrawer &drawerObj,
00177               Biquad hn[])
00178 { 
00179     static int num = 0;
00180     lpHp.GetTouchedNumber(num);
00181     BilinearDesign::Type typeLH = (BilinearDesign::Type)num;
00182     if (drawerObj.ReDesignAndDraw(ck_, g0_, typeLH))
00183         for (int k=0; k<ORDER_/2; k++)
00184         {
00185             hn[k].SetCoefficients(ck_[k]);
00186             hn[k].Clear();
00187         }
00188 }