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
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 }
Generated on Sun Jul 17 2022 04:10:57 by 1.7.2