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
- Committer:
- MikamiUitOpen
- Date:
- 2016-04-07
- Revision:
- 1:a1be09c2533a
- Parent:
- 0:2eb96a7cf9b9
File content as of revision 1:a1be09c2533a:
//-------------------------------------------------------------- // QSPI 接続のフラッシュメモリに前もって格納されている音楽データを // 再生する際に IIR フィルタをかける // // QSPI 接続のフラッシュメモリのデータ構造 // 0x90000000 から 4 バイト: データ数に対応する (int32_t 型) // 0x90000004 から 2 バイトごと: int16_t のモノラルデータが続く // モノラルデータ: 標本化周波数 16 kHz のもの // IIR フィルタ ---- 低域通過および高域通過フィルタ // // 2016/04/07, Copyright (c) 2016 MIKAMI, Naoki //-------------------------------------------------------------- #include "LCD_DISCO_F746NG.h" #include "sai_io_o.hpp" #include "QSPI_BinaryReader.hpp" #include "ButtonGroup.hpp" #include "DesignerDrawer.hpp" using namespace Mikami; const uint32_t N_DATA_ = 1024; SaiIO_O mySai_(N_DATA_, I2S_AUDIOFREQ_16K); const int ORDER_ = 6; // 次数 Biquad::Coefs ck_[ORDER_/2]; float g0_; // フィルタ処理の有無を決める void FilterOnOff(ButtonGroup &onOff, bool &filterOn); // LPF と HPF の切り替えとフィルタの設計 void SwDesign(ButtonGroup &lpHp, DesignerDrawer &drawerObj, Biquad hn[]); int main() { Label myLabel(80, 6, "IIR Butterworth filter", Label::LEFT, Font16); // ButtonGroup: "PLAY", "PAUSE", "RESUME", "STOP" const string FUNCTION[4] = {"PLAY", "PAUSE", "RESUME", "STOP"}; ButtonGroup function(390, 10, 80, 38, 4, FUNCTION, 0, 5, 1); // PLAY のみアクティブ function.Activate(0); for (int n=1; n<4; n++) function.Inactivate(n); // ButtonGroup: "LPF", "HPF" const string LP_HP[2] = {"LPF", "HPF"}; ButtonGroup lpHp(390, 187, 40, 38, 2, LP_HP, 0, 0, 2, 0); // ButtonGroup: "ON", "OFF" const string ON_OFF[2] = {"ON", "OFF"}; ButtonGroup onOff(390, 230, 40, 38, 2, ON_OFF, 0, 0, 2, 1); // QSPI フラッシュメモリからデータを読み込むための準備 QspiBinaryReader reader; int32_t size = reader.ReadSize(); // Data number int32_t frameSize = mySai_.GetLength(); int32_t loopCount = size/frameSize; // フィルタの設計と周波数特性描画用 DesignerDrawer drawerObj( 60, // グラフの左端の位置 230, // グラフの下端の位置 30, // 10 dB 当たりのピクセル数 16000, // 標本化周波数 ORDER_, // 次数 400, // 最初に与える遮断周波数 200, // 遮断周波数の最小値 5000, // 遮断周波数の最大値 BilinearDesign::LPF); // フィルタの準備 drawerObj.GetCoefficients(ck_, g0_); Biquad hn[ORDER_/2]; for (int k=0; k<ORDER_/2; k++) hn[k] = Biquad(ck_[k]); int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ bool playOk = false; bool filterOn = false; while (true) { // PLAY がタッチされるまで待つ if (!playOk) while (!function.Touched(0)) { SwDesign(lpHp, drawerObj, hn); // フィルタの切り替えとフィルタの設計 FilterOnOff(onOff, filterOn); // フィルタ処理の有無を決める wait(0.02f); } function.Activate(1); // PAUSE を使えるようにする function.Activate(3); // 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++) { if (function.Touched(3)) break; // STOP if (function.Touched(1)) // PAUSE ? { function.Draw(0); function.Activate(2); // RESUME を使えるようにする mySai_.Pause(); // PLAY か RESUME か STOP がタッチされるまで待つ while (!function.Touched(0) && !function.Touched(2) && !function.Touched(3)) { SwDesign(lpHp, drawerObj, hn); // フィルタの切り替えとフィルタの設計 FilterOnOff(onOff, filterOn); // フィルタ処理の有無を決める } if (function.Touched(0)) // 最初から PLAY playOk = true; if (function.Touched(2)) // PAUSE したところから PLAY 再開 { mySai_.Resume(); wait_ms(200); function.Inactivate(2); } if (function.Touched(3)) // STOP stopOk = true; function.TouchedColor(0); function.Draw(1); } if (playOk || stopOk) break; FilterOnOff(onOff, filterOn); // フィルタ処理の有無を決める // データの転送が終わるまで待つ while (!mySai_.IsXferred()) {} // 1フレーム分のデータを QSPI フラッシュメモリから読み込む reader.Read(sn, frameSize*k, frameSize); // 1フレーム分を出力する for (int n=0; n<frameSize; n++) { int16_t value; if (filterOn) // フィルタ処理実行 { 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(); // 次のデータ転送に備える SwDesign(lpHp, drawerObj, hn); // フィルタの切り替えとフィルタの設計 } mySai_.Stop(); if (!playOk) function.Activate(0); // PLAY のみアクティブにする for (int n=1; n<4; n++) function.Inactivate(n); } } // フィルタ処理の有無を決める void FilterOnOff(ButtonGroup &onOff, bool &filterOn) { int num; if (!onOff.GetTouchedNumber(num)) return; filterOn = (num == 0) ? true : false; } // フィルタの切り替えとフィルタの設計 void SwDesign(ButtonGroup &lpHp, DesignerDrawer &drawerObj, Biquad hn[]) { static int num = 0; lpHp.GetTouchedNumber(num); BilinearDesign::Type typeLH = (BilinearDesign::Type)num; if (drawerObj.ReDesignAndDraw(ck_, g0_, typeLH)) for (int k=0; k<ORDER_/2; k++) { hn[k].SetCoefficients(ck_[k]); hn[k].Clear(); } }