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
main.cpp@0:2eb96a7cf9b9, 2016-04-01 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Fri Apr 01 05:03:20 2016 +0000
- Revision:
- 0:2eb96a7cf9b9
- Child:
- 1:a1be09c2533a
1
Who changed what in which revision?
User | Revision | Line number | New 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 | 0:2eb96a7cf9b9 | 11 | // 2016/04/01, 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 | 0:2eb96a7cf9b9 | 130 | function.DrawTouched(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 | } |