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

Committer:
MikamiUitOpen
Date:
Thu Apr 07 00:32:00 2016 +0000
Revision:
1:a1be09c2533a
Parent:
0:2eb96a7cf9b9
2

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MikamiUitOpen 0:2eb96a7cf9b9 1 //--------------------------------------------------------------
MikamiUitOpen 0:2eb96a7cf9b9 2 // QSPI 接続のフラッシュメモリに前もって格納されている音楽データを
MikamiUitOpen 0:2eb96a7cf9b9 3 // 再生する際に IIR フィルタをかける
MikamiUitOpen 0:2eb96a7cf9b9 4 //
MikamiUitOpen 0:2eb96a7cf9b9 5 // QSPI 接続のフラッシュメモリのデータ構造
MikamiUitOpen 0:2eb96a7cf9b9 6 // 0x90000000 から 4 バイト: データ数に対応する (int32_t 型)
MikamiUitOpen 0:2eb96a7cf9b9 7 // 0x90000004 から 2 バイトごと: int16_t のモノラルデータが続く
MikamiUitOpen 0:2eb96a7cf9b9 8 // モノラルデータ: 標本化周波数 16 kHz のもの
MikamiUitOpen 0:2eb96a7cf9b9 9 // IIR フィルタ ---- 低域通過および高域通過フィルタ
MikamiUitOpen 0:2eb96a7cf9b9 10 //
MikamiUitOpen 1:a1be09c2533a 11 // 2016/04/07, Copyright (c) 2016 MIKAMI, Naoki
MikamiUitOpen 0:2eb96a7cf9b9 12 //--------------------------------------------------------------
MikamiUitOpen 0:2eb96a7cf9b9 13
MikamiUitOpen 0:2eb96a7cf9b9 14 #include "LCD_DISCO_F746NG.h"
MikamiUitOpen 0:2eb96a7cf9b9 15 #include "sai_io_o.hpp"
MikamiUitOpen 0:2eb96a7cf9b9 16 #include "QSPI_BinaryReader.hpp"
MikamiUitOpen 0:2eb96a7cf9b9 17 #include "ButtonGroup.hpp"
MikamiUitOpen 0:2eb96a7cf9b9 18 #include "DesignerDrawer.hpp"
MikamiUitOpen 0:2eb96a7cf9b9 19
MikamiUitOpen 0:2eb96a7cf9b9 20 using namespace Mikami;
MikamiUitOpen 0:2eb96a7cf9b9 21
MikamiUitOpen 0:2eb96a7cf9b9 22 const uint32_t N_DATA_ = 1024;
MikamiUitOpen 0:2eb96a7cf9b9 23 SaiIO_O mySai_(N_DATA_, I2S_AUDIOFREQ_16K);
MikamiUitOpen 0:2eb96a7cf9b9 24
MikamiUitOpen 0:2eb96a7cf9b9 25 const int ORDER_ = 6; // 次数
MikamiUitOpen 0:2eb96a7cf9b9 26 Biquad::Coefs ck_[ORDER_/2];
MikamiUitOpen 0:2eb96a7cf9b9 27 float g0_;
MikamiUitOpen 0:2eb96a7cf9b9 28
MikamiUitOpen 0:2eb96a7cf9b9 29 // フィルタ処理の有無を決める
MikamiUitOpen 0:2eb96a7cf9b9 30 void FilterOnOff(ButtonGroup &onOff, bool &filterOn);
MikamiUitOpen 0:2eb96a7cf9b9 31
MikamiUitOpen 0:2eb96a7cf9b9 32 // LPF と HPF の切り替えとフィルタの設計
MikamiUitOpen 0:2eb96a7cf9b9 33 void SwDesign(ButtonGroup &lpHp, DesignerDrawer &drawerObj,
MikamiUitOpen 0:2eb96a7cf9b9 34 Biquad hn[]);
MikamiUitOpen 0:2eb96a7cf9b9 35
MikamiUitOpen 0:2eb96a7cf9b9 36 int main()
MikamiUitOpen 0:2eb96a7cf9b9 37 {
MikamiUitOpen 0:2eb96a7cf9b9 38 Label myLabel(80, 6, "IIR Butterworth filter", Label::LEFT, Font16);
MikamiUitOpen 0:2eb96a7cf9b9 39
MikamiUitOpen 0:2eb96a7cf9b9 40 // ButtonGroup: "PLAY", "PAUSE", "RESUME", "STOP"
MikamiUitOpen 0:2eb96a7cf9b9 41 const string FUNCTION[4] = {"PLAY", "PAUSE", "RESUME", "STOP"};
MikamiUitOpen 0:2eb96a7cf9b9 42 ButtonGroup function(390, 10, 80, 38,
MikamiUitOpen 0:2eb96a7cf9b9 43 4, FUNCTION, 0, 5, 1);
MikamiUitOpen 0:2eb96a7cf9b9 44 // PLAY のみアクティブ
MikamiUitOpen 0:2eb96a7cf9b9 45 function.Activate(0);
MikamiUitOpen 0:2eb96a7cf9b9 46 for (int n=1; n<4; n++) function.Inactivate(n);
MikamiUitOpen 0:2eb96a7cf9b9 47
MikamiUitOpen 0:2eb96a7cf9b9 48 // ButtonGroup: "LPF", "HPF"
MikamiUitOpen 0:2eb96a7cf9b9 49 const string LP_HP[2] = {"LPF", "HPF"};
MikamiUitOpen 0:2eb96a7cf9b9 50 ButtonGroup lpHp(390, 187, 40, 38,
MikamiUitOpen 0:2eb96a7cf9b9 51 2, LP_HP, 0, 0, 2, 0);
MikamiUitOpen 0:2eb96a7cf9b9 52
MikamiUitOpen 0:2eb96a7cf9b9 53 // ButtonGroup: "ON", "OFF"
MikamiUitOpen 0:2eb96a7cf9b9 54 const string ON_OFF[2] = {"ON", "OFF"};
MikamiUitOpen 0:2eb96a7cf9b9 55 ButtonGroup onOff(390, 230, 40, 38,
MikamiUitOpen 0:2eb96a7cf9b9 56 2, ON_OFF, 0, 0, 2, 1);
MikamiUitOpen 0:2eb96a7cf9b9 57
MikamiUitOpen 0:2eb96a7cf9b9 58 // QSPI フラッシュメモリからデータを読み込むための準備
MikamiUitOpen 0:2eb96a7cf9b9 59 QspiBinaryReader reader;
MikamiUitOpen 0:2eb96a7cf9b9 60 int32_t size = reader.ReadSize(); // Data number
MikamiUitOpen 0:2eb96a7cf9b9 61 int32_t frameSize = mySai_.GetLength();
MikamiUitOpen 0:2eb96a7cf9b9 62 int32_t loopCount = size/frameSize;
MikamiUitOpen 0:2eb96a7cf9b9 63
MikamiUitOpen 0:2eb96a7cf9b9 64 // フィルタの設計と周波数特性描画用
MikamiUitOpen 0:2eb96a7cf9b9 65 DesignerDrawer drawerObj(
MikamiUitOpen 0:2eb96a7cf9b9 66 60, // グラフの左端の位置
MikamiUitOpen 0:2eb96a7cf9b9 67 230, // グラフの下端の位置
MikamiUitOpen 0:2eb96a7cf9b9 68 30, // 10 dB 当たりのピクセル数
MikamiUitOpen 0:2eb96a7cf9b9 69 16000, // 標本化周波数
MikamiUitOpen 0:2eb96a7cf9b9 70 ORDER_, // 次数
MikamiUitOpen 0:2eb96a7cf9b9 71 400, // 最初に与える遮断周波数
MikamiUitOpen 0:2eb96a7cf9b9 72 200, // 遮断周波数の最小値
MikamiUitOpen 0:2eb96a7cf9b9 73 5000, // 遮断周波数の最大値
MikamiUitOpen 0:2eb96a7cf9b9 74 BilinearDesign::LPF);
MikamiUitOpen 0:2eb96a7cf9b9 75 // フィルタの準備
MikamiUitOpen 0:2eb96a7cf9b9 76 drawerObj.GetCoefficients(ck_, g0_);
MikamiUitOpen 0:2eb96a7cf9b9 77 Biquad hn[ORDER_/2];
MikamiUitOpen 0:2eb96a7cf9b9 78 for (int k=0; k<ORDER_/2; k++) hn[k] = Biquad(ck_[k]);
MikamiUitOpen 0:2eb96a7cf9b9 79
MikamiUitOpen 0:2eb96a7cf9b9 80 int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ
MikamiUitOpen 0:2eb96a7cf9b9 81 bool playOk = false;
MikamiUitOpen 0:2eb96a7cf9b9 82 bool filterOn = false;
MikamiUitOpen 0:2eb96a7cf9b9 83
MikamiUitOpen 0:2eb96a7cf9b9 84 while (true)
MikamiUitOpen 0:2eb96a7cf9b9 85 {
MikamiUitOpen 0:2eb96a7cf9b9 86 // PLAY がタッチされるまで待つ
MikamiUitOpen 0:2eb96a7cf9b9 87 if (!playOk)
MikamiUitOpen 0:2eb96a7cf9b9 88 while (!function.Touched(0))
MikamiUitOpen 0:2eb96a7cf9b9 89 {
MikamiUitOpen 0:2eb96a7cf9b9 90 SwDesign(lpHp, drawerObj, hn); // フィルタの切り替えとフィルタの設計
MikamiUitOpen 0:2eb96a7cf9b9 91 FilterOnOff(onOff, filterOn); // フィルタ処理の有無を決める
MikamiUitOpen 0:2eb96a7cf9b9 92 wait(0.02f);
MikamiUitOpen 0:2eb96a7cf9b9 93 }
MikamiUitOpen 0:2eb96a7cf9b9 94 function.Activate(1); // PAUSE を使えるようにする
MikamiUitOpen 0:2eb96a7cf9b9 95 function.Activate(3); // STOP を使えるようにする
MikamiUitOpen 0:2eb96a7cf9b9 96
MikamiUitOpen 0:2eb96a7cf9b9 97 playOk = false;
MikamiUitOpen 0:2eb96a7cf9b9 98 bool stopOk = false;
MikamiUitOpen 0:2eb96a7cf9b9 99 mySai_.InitCodecOut(); // SAI の初期化
MikamiUitOpen 0:2eb96a7cf9b9 100
MikamiUitOpen 0:2eb96a7cf9b9 101 // IIR フィルタの内部の遅延器のクリア
MikamiUitOpen 0:2eb96a7cf9b9 102 for (int k=0; k<ORDER_/2; k++) hn[k].Clear();
MikamiUitOpen 0:2eb96a7cf9b9 103
MikamiUitOpen 0:2eb96a7cf9b9 104 for (int k=0; k<loopCount; k++)
MikamiUitOpen 0:2eb96a7cf9b9 105 {
MikamiUitOpen 0:2eb96a7cf9b9 106 if (function.Touched(3)) break; // STOP
MikamiUitOpen 0:2eb96a7cf9b9 107 if (function.Touched(1)) // PAUSE ?
MikamiUitOpen 0:2eb96a7cf9b9 108 {
MikamiUitOpen 0:2eb96a7cf9b9 109 function.Draw(0);
MikamiUitOpen 0:2eb96a7cf9b9 110 function.Activate(2); // RESUME を使えるようにする
MikamiUitOpen 0:2eb96a7cf9b9 111 mySai_.Pause();
MikamiUitOpen 0:2eb96a7cf9b9 112 // PLAY か RESUME か STOP がタッチされるまで待つ
MikamiUitOpen 0:2eb96a7cf9b9 113 while (!function.Touched(0) && !function.Touched(2)
MikamiUitOpen 0:2eb96a7cf9b9 114 && !function.Touched(3))
MikamiUitOpen 0:2eb96a7cf9b9 115 {
MikamiUitOpen 0:2eb96a7cf9b9 116 SwDesign(lpHp, drawerObj, hn); // フィルタの切り替えとフィルタの設計
MikamiUitOpen 0:2eb96a7cf9b9 117 FilterOnOff(onOff, filterOn); // フィルタ処理の有無を決める
MikamiUitOpen 0:2eb96a7cf9b9 118 }
MikamiUitOpen 0:2eb96a7cf9b9 119 if (function.Touched(0)) // 最初から PLAY
MikamiUitOpen 0:2eb96a7cf9b9 120 playOk = true;
MikamiUitOpen 0:2eb96a7cf9b9 121 if (function.Touched(2)) // PAUSE したところから PLAY 再開
MikamiUitOpen 0:2eb96a7cf9b9 122 {
MikamiUitOpen 0:2eb96a7cf9b9 123 mySai_.Resume();
MikamiUitOpen 0:2eb96a7cf9b9 124 wait_ms(200);
MikamiUitOpen 0:2eb96a7cf9b9 125 function.Inactivate(2);
MikamiUitOpen 0:2eb96a7cf9b9 126 }
MikamiUitOpen 0:2eb96a7cf9b9 127 if (function.Touched(3)) // STOP
MikamiUitOpen 0:2eb96a7cf9b9 128 stopOk = true;
MikamiUitOpen 0:2eb96a7cf9b9 129
MikamiUitOpen 1:a1be09c2533a 130 function.TouchedColor(0);
MikamiUitOpen 0:2eb96a7cf9b9 131 function.Draw(1);
MikamiUitOpen 0:2eb96a7cf9b9 132 }
MikamiUitOpen 0:2eb96a7cf9b9 133
MikamiUitOpen 0:2eb96a7cf9b9 134 if (playOk || stopOk) break;
MikamiUitOpen 0:2eb96a7cf9b9 135
MikamiUitOpen 0:2eb96a7cf9b9 136 FilterOnOff(onOff, filterOn); // フィルタ処理の有無を決める
MikamiUitOpen 0:2eb96a7cf9b9 137
MikamiUitOpen 0:2eb96a7cf9b9 138 // データの転送が終わるまで待つ
MikamiUitOpen 0:2eb96a7cf9b9 139 while (!mySai_.IsXferred()) {}
MikamiUitOpen 0:2eb96a7cf9b9 140 // 1フレーム分のデータを QSPI フラッシュメモリから読み込む
MikamiUitOpen 0:2eb96a7cf9b9 141 reader.Read(sn, frameSize*k, frameSize);
MikamiUitOpen 0:2eb96a7cf9b9 142
MikamiUitOpen 0:2eb96a7cf9b9 143 // 1フレーム分を出力する
MikamiUitOpen 0:2eb96a7cf9b9 144 for (int n=0; n<frameSize; n++)
MikamiUitOpen 0:2eb96a7cf9b9 145 {
MikamiUitOpen 0:2eb96a7cf9b9 146 int16_t value;
MikamiUitOpen 0:2eb96a7cf9b9 147 if (filterOn) // フィルタ処理実行
MikamiUitOpen 0:2eb96a7cf9b9 148 {
MikamiUitOpen 0:2eb96a7cf9b9 149 float yn = g0_*sn[n];
MikamiUitOpen 0:2eb96a7cf9b9 150 for (int k=0; k<ORDER_/2; k++) yn = hn[k].Execute(yn);
MikamiUitOpen 0:2eb96a7cf9b9 151 value = (int16_t)yn;
MikamiUitOpen 0:2eb96a7cf9b9 152 }
MikamiUitOpen 0:2eb96a7cf9b9 153 else
MikamiUitOpen 0:2eb96a7cf9b9 154 value = sn[n]; // フィルタ処理なし
MikamiUitOpen 0:2eb96a7cf9b9 155 mySai_.Output(value, value); // 音響信号の出力
MikamiUitOpen 0:2eb96a7cf9b9 156 }
MikamiUitOpen 0:2eb96a7cf9b9 157 mySai_.ResetXferred(); // 次のデータ転送に備える
MikamiUitOpen 0:2eb96a7cf9b9 158 SwDesign(lpHp, drawerObj, hn); // フィルタの切り替えとフィルタの設計
MikamiUitOpen 0:2eb96a7cf9b9 159 }
MikamiUitOpen 0:2eb96a7cf9b9 160
MikamiUitOpen 0:2eb96a7cf9b9 161 mySai_.Stop();
MikamiUitOpen 0:2eb96a7cf9b9 162 if (!playOk) function.Activate(0); // PLAY のみアクティブにする
MikamiUitOpen 0:2eb96a7cf9b9 163 for (int n=1; n<4; n++) function.Inactivate(n);
MikamiUitOpen 0:2eb96a7cf9b9 164 }
MikamiUitOpen 0:2eb96a7cf9b9 165 }
MikamiUitOpen 0:2eb96a7cf9b9 166
MikamiUitOpen 0:2eb96a7cf9b9 167 // フィルタ処理の有無を決める
MikamiUitOpen 0:2eb96a7cf9b9 168 void FilterOnOff(ButtonGroup &onOff, bool &filterOn)
MikamiUitOpen 0:2eb96a7cf9b9 169 {
MikamiUitOpen 0:2eb96a7cf9b9 170 int num;
MikamiUitOpen 0:2eb96a7cf9b9 171 if (!onOff.GetTouchedNumber(num)) return;
MikamiUitOpen 0:2eb96a7cf9b9 172 filterOn = (num == 0) ? true : false;
MikamiUitOpen 0:2eb96a7cf9b9 173 }
MikamiUitOpen 0:2eb96a7cf9b9 174
MikamiUitOpen 0:2eb96a7cf9b9 175 // フィルタの切り替えとフィルタの設計
MikamiUitOpen 0:2eb96a7cf9b9 176 void SwDesign(ButtonGroup &lpHp, DesignerDrawer &drawerObj,
MikamiUitOpen 0:2eb96a7cf9b9 177 Biquad hn[])
MikamiUitOpen 0:2eb96a7cf9b9 178 {
MikamiUitOpen 0:2eb96a7cf9b9 179 static int num = 0;
MikamiUitOpen 0:2eb96a7cf9b9 180 lpHp.GetTouchedNumber(num);
MikamiUitOpen 0:2eb96a7cf9b9 181 BilinearDesign::Type typeLH = (BilinearDesign::Type)num;
MikamiUitOpen 0:2eb96a7cf9b9 182 if (drawerObj.ReDesignAndDraw(ck_, g0_, typeLH))
MikamiUitOpen 0:2eb96a7cf9b9 183 for (int k=0; k<ORDER_/2; k++)
MikamiUitOpen 0:2eb96a7cf9b9 184 {
MikamiUitOpen 0:2eb96a7cf9b9 185 hn[k].SetCoefficients(ck_[k]);
MikamiUitOpen 0:2eb96a7cf9b9 186 hn[k].Clear();
MikamiUitOpen 0:2eb96a7cf9b9 187 }
MikamiUitOpen 0:2eb96a7cf9b9 188 }