Output the audio signal (*.bin) with filtering by IIR filter in the SD card using onboard CODEC. For *.wav file, F746_SD_WavPlayer and F746_SD_GraphicEqualiser are published on mbed. SD カードのオーディオ信号 (*.bin) を遮断周波数可変の IIR フィルタを通して,ボードに搭載されているCODEC で出力する.*.wav 形式のファイル用には,F746_SD_WavPlayer と F746_SD_GraphicEqualiser を mbed で公開している.
Dependencies: BSP_DISCO_F746NG_patch_fixed F746_GUI LCD_DISCO_F746NG SDFileSystem_Warning_Fixed TS_DISCO_F746NG mbed
main.cpp@5:4a99dabc9180, 2016-04-17 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Sun Apr 17 08:44:43 2016 +0000
- Revision:
- 5:4a99dabc9180
- Parent:
- 2:f963cb0d323f
6
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 0:6748e3332e85 | 1 | //-------------------------------------------------------------- |
MikamiUitOpen | 0:6748e3332e85 | 2 | // フィルタ処理付き SD オーディオプレーヤー |
MikamiUitOpen | 0:6748e3332e85 | 3 | // SD のファイル |
MikamiUitOpen | 0:6748e3332e85 | 4 | // 先頭から 4 バイト: データ数に対応する (int32_t 型) |
MikamiUitOpen | 0:6748e3332e85 | 5 | // それ以降 2 バイトごと: int16_t のモノラルデータが続く |
MikamiUitOpen | 0:6748e3332e85 | 6 | // データ: 標本化周波数 16 kHz のもの |
MikamiUitOpen | 0:6748e3332e85 | 7 | // 拡張子: "*.bin", "*.BIN" |
MikamiUitOpen | 0:6748e3332e85 | 8 | // IIR フィルタ ---- 低域通過および高域通過フィルタ |
MikamiUitOpen | 0:6748e3332e85 | 9 | // |
MikamiUitOpen | 5:4a99dabc9180 | 10 | // 2016/04/17, Copyright (c) 2016 MIKAMI, Naoki |
MikamiUitOpen | 0:6748e3332e85 | 11 | //-------------------------------------------------------------- |
MikamiUitOpen | 0:6748e3332e85 | 12 | |
MikamiUitOpen | 0:6748e3332e85 | 13 | #include "MyFunctions.hpp" |
MikamiUitOpen | 0:6748e3332e85 | 14 | #include "BlinkLabel.hpp" |
MikamiUitOpen | 0:6748e3332e85 | 15 | |
MikamiUitOpen | 0:6748e3332e85 | 16 | using namespace Mikami; |
MikamiUitOpen | 0:6748e3332e85 | 17 | |
MikamiUitOpen | 0:6748e3332e85 | 18 | int main() |
MikamiUitOpen | 0:6748e3332e85 | 19 | { |
MikamiUitOpen | 0:6748e3332e85 | 20 | Label myLabel(80, 4, "SD Card Audio Player", Label::LEFT, Font16); |
MikamiUitOpen | 0:6748e3332e85 | 21 | |
MikamiUitOpen | 0:6748e3332e85 | 22 | const int FS = I2S_AUDIOFREQ_16K; // 標本化周波数: 16 kHz |
MikamiUitOpen | 0:6748e3332e85 | 23 | SaiIO_O mySai(1024, FS); |
MikamiUitOpen | 0:6748e3332e85 | 24 | |
MikamiUitOpen | 0:6748e3332e85 | 25 | SD_BinaryReader sdReader; // SD カード読み込み用オブジェクト |
MikamiUitOpen | 0:6748e3332e85 | 26 | const int MAX_FILES = 7; |
MikamiUitOpen | 0:6748e3332e85 | 27 | FileSelector selector(4, 28, MAX_FILES, 32, sdReader); |
MikamiUitOpen | 0:6748e3332e85 | 28 | if (!selector.CreateTable()) |
MikamiUitOpen | 0:6748e3332e85 | 29 | BlinkLabel errLabel(240, 100, "SD CARD ERROR", Label::CENTER); |
MikamiUitOpen | 0:6748e3332e85 | 30 | |
MikamiUitOpen | 0:6748e3332e85 | 31 | // ボタン用の定数 |
MikamiUitOpen | 0:6748e3332e85 | 32 | const uint16_t BG_LEFT = 390; |
MikamiUitOpen | 0:6748e3332e85 | 33 | const uint16_t BG_WIDTH = 80; |
MikamiUitOpen | 0:6748e3332e85 | 34 | const uint16_t BG_HEIGHT = 36; |
MikamiUitOpen | 0:6748e3332e85 | 35 | |
MikamiUitOpen | 0:6748e3332e85 | 36 | // ButtonGroup: "OPEN", "PLAY", "PAUSE", "RESUME", "STOP" |
MikamiUitOpen | 0:6748e3332e85 | 37 | const string MENU[5] = {"OPEN", "PLAY", "PAUSE", "RESUME", "STOP"}; |
MikamiUitOpen | 0:6748e3332e85 | 38 | ButtonGroup menu(BG_LEFT, 2, BG_WIDTH, BG_HEIGHT, |
MikamiUitOpen | 0:6748e3332e85 | 39 | 5, MENU, 0, 2, 1); |
MikamiUitOpen | 0:6748e3332e85 | 40 | // OPEN のみアクティブ |
MikamiUitOpen | 0:6748e3332e85 | 41 | menu.Activate(0); |
MikamiUitOpen | 0:6748e3332e85 | 42 | for (int n=1; n<5; n++) menu.Inactivate(n); |
MikamiUitOpen | 0:6748e3332e85 | 43 | |
MikamiUitOpen | 0:6748e3332e85 | 44 | // ButtonGroup: "LPF", "HPF" |
MikamiUitOpen | 0:6748e3332e85 | 45 | const string LP_HP[2] = {"LPF", "HPF"}; |
MikamiUitOpen | 0:6748e3332e85 | 46 | ButtonGroup lpHp(BG_LEFT, 197, BG_WIDTH/2, BG_HEIGHT, |
MikamiUitOpen | 0:6748e3332e85 | 47 | 2, LP_HP, 0, 0, 2, 0); |
MikamiUitOpen | 0:6748e3332e85 | 48 | |
MikamiUitOpen | 0:6748e3332e85 | 49 | // ButtonGroup: "ON", "OFF" |
MikamiUitOpen | 0:6748e3332e85 | 50 | const string ON_OFF[2] = {"ON", "OFF"}; |
MikamiUitOpen | 0:6748e3332e85 | 51 | ButtonGroup onOff(BG_LEFT, 235, BG_WIDTH/2, BG_HEIGHT, |
MikamiUitOpen | 0:6748e3332e85 | 52 | 2, ON_OFF, 0, 0, 2, 1); |
MikamiUitOpen | 0:6748e3332e85 | 53 | |
MikamiUitOpen | 0:6748e3332e85 | 54 | // フィルタの設計と周波数特性描画用 |
MikamiUitOpen | 0:6748e3332e85 | 55 | const int ORDER = 6; // フィルタの次数 |
MikamiUitOpen | 0:6748e3332e85 | 56 | DesignerDrawer drawerObj( |
MikamiUitOpen | 0:6748e3332e85 | 57 | 60, // グラフの左端の位置 |
MikamiUitOpen | 0:6748e3332e85 | 58 | 230, // グラフの下端の位置 |
MikamiUitOpen | 0:6748e3332e85 | 59 | 30, // 10 dB 当たりのピクセル数 |
MikamiUitOpen | 0:6748e3332e85 | 60 | FS, // 標本化周波数 |
MikamiUitOpen | 0:6748e3332e85 | 61 | ORDER, // フィルタの次数 |
MikamiUitOpen | 0:6748e3332e85 | 62 | 400, // 最初に与える遮断周波数 |
MikamiUitOpen | 0:6748e3332e85 | 63 | 200, // 遮断周波数の最小値 |
MikamiUitOpen | 0:6748e3332e85 | 64 | 5000, // 遮断周波数の最大値 |
MikamiUitOpen | 0:6748e3332e85 | 65 | BilinearDesign::LPF); // 低域通過フィルタ |
MikamiUitOpen | 0:6748e3332e85 | 66 | |
MikamiUitOpen | 0:6748e3332e85 | 67 | // フィルタの準備 |
MikamiUitOpen | 0:6748e3332e85 | 68 | Biquad::Coefs ck[ORDER/2]; |
MikamiUitOpen | 0:6748e3332e85 | 69 | float g0; |
MikamiUitOpen | 0:6748e3332e85 | 70 | drawerObj.GetCoefficients(ck, g0); |
MikamiUitOpen | 0:6748e3332e85 | 71 | Biquad hn[ORDER/2]; |
MikamiUitOpen | 0:6748e3332e85 | 72 | for (int k=0; k<ORDER/2; k++) hn[k] = Biquad(ck[k]); |
MikamiUitOpen | 0:6748e3332e85 | 73 | |
MikamiUitOpen | 0:6748e3332e85 | 74 | int32_t frameSize = mySai.GetLength(); |
MikamiUitOpen | 0:6748e3332e85 | 75 | int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ |
MikamiUitOpen | 0:6748e3332e85 | 76 | bool playOk = false; |
MikamiUitOpen | 0:6748e3332e85 | 77 | bool filterOn = false; |
MikamiUitOpen | 0:6748e3332e85 | 78 | bool whileFirst = true; |
MikamiUitOpen | 0:6748e3332e85 | 79 | string fileName; |
MikamiUitOpen | 0:6748e3332e85 | 80 | int32_t loopCount; |
MikamiUitOpen | 0:6748e3332e85 | 81 | |
MikamiUitOpen | 0:6748e3332e85 | 82 | while (true) |
MikamiUitOpen | 0:6748e3332e85 | 83 | { |
MikamiUitOpen | 0:6748e3332e85 | 84 | if (!playOk) |
MikamiUitOpen | 0:6748e3332e85 | 85 | { |
MikamiUitOpen | 0:6748e3332e85 | 86 | if (whileFirst) |
MikamiUitOpen | 0:6748e3332e85 | 87 | { |
MikamiUitOpen | 0:6748e3332e85 | 88 | whileFirst = false; |
MikamiUitOpen | 0:6748e3332e85 | 89 | while (!menu.Touched(0)) // OPEN がタッチされるまで待つ |
MikamiUitOpen | 0:6748e3332e85 | 90 | ModifyFilter(drawerObj, lpHp, onOff, |
MikamiUitOpen | 0:6748e3332e85 | 91 | hn, ck, g0, filterOn); |
MikamiUitOpen | 0:6748e3332e85 | 92 | SelectFile(menu, selector, myLabel, fileName); |
MikamiUitOpen | 0:6748e3332e85 | 93 | } |
MikamiUitOpen | 0:6748e3332e85 | 94 | else |
MikamiUitOpen | 0:6748e3332e85 | 95 | { |
MikamiUitOpen | 0:6748e3332e85 | 96 | menu.Activate(1); // PLAY 有効 |
MikamiUitOpen | 0:6748e3332e85 | 97 | int touch10; |
MikamiUitOpen | 0:6748e3332e85 | 98 | while (!menu.GetTouchedNumber(touch10)) |
MikamiUitOpen | 0:6748e3332e85 | 99 | ModifyFilter(drawerObj, lpHp, onOff, |
MikamiUitOpen | 0:6748e3332e85 | 100 | hn, ck, g0, filterOn); |
MikamiUitOpen | 0:6748e3332e85 | 101 | if (touch10 == 0) |
MikamiUitOpen | 0:6748e3332e85 | 102 | SelectFile(menu, selector, myLabel, fileName); |
MikamiUitOpen | 0:6748e3332e85 | 103 | } |
MikamiUitOpen | 0:6748e3332e85 | 104 | |
MikamiUitOpen | 0:6748e3332e85 | 105 | loopCount = SD_Open(sdReader, fileName, frameSize); |
MikamiUitOpen | 0:6748e3332e85 | 106 | while (!menu.Touched(1)) // PLAY がタッチされるまで待つ |
MikamiUitOpen | 0:6748e3332e85 | 107 | ModifyFilter(drawerObj, lpHp, onOff, |
MikamiUitOpen | 0:6748e3332e85 | 108 | hn, ck, g0, filterOn); |
MikamiUitOpen | 0:6748e3332e85 | 109 | } |
MikamiUitOpen | 0:6748e3332e85 | 110 | else |
MikamiUitOpen | 0:6748e3332e85 | 111 | loopCount = SD_Open(sdReader, fileName, frameSize); |
MikamiUitOpen | 0:6748e3332e85 | 112 | |
MikamiUitOpen | 0:6748e3332e85 | 113 | selector.Erase(BG_LEFT-4, 244); |
MikamiUitOpen | 0:6748e3332e85 | 114 | myLabel.Draw("IIR Butterworth filter"); |
MikamiUitOpen | 0:6748e3332e85 | 115 | drawerObj.DrawResponse(); |
MikamiUitOpen | 0:6748e3332e85 | 116 | menu.Inactivate(0); // OPEN 無効 |
MikamiUitOpen | 0:6748e3332e85 | 117 | menu.Activate(2); // PAUSE 有効 |
MikamiUitOpen | 0:6748e3332e85 | 118 | menu.Activate(4); // STOP 有効 |
MikamiUitOpen | 0:6748e3332e85 | 119 | |
MikamiUitOpen | 0:6748e3332e85 | 120 | playOk = false; |
MikamiUitOpen | 0:6748e3332e85 | 121 | bool stopOk = false; |
MikamiUitOpen | 0:6748e3332e85 | 122 | mySai.InitCodecOut(); // SAI の初期化 |
MikamiUitOpen | 0:6748e3332e85 | 123 | |
MikamiUitOpen | 0:6748e3332e85 | 124 | // IIR フィルタの内部の遅延器のクリア |
MikamiUitOpen | 0:6748e3332e85 | 125 | for (int k=0; k<ORDER/2; k++) hn[k].Clear(); |
MikamiUitOpen | 0:6748e3332e85 | 126 | |
MikamiUitOpen | 0:6748e3332e85 | 127 | for (int k=0; k<loopCount; k++) |
MikamiUitOpen | 0:6748e3332e85 | 128 | { |
MikamiUitOpen | 0:6748e3332e85 | 129 | int touch42 = -1; |
MikamiUitOpen | 0:6748e3332e85 | 130 | menu.GetTouchedNumber(touch42); |
MikamiUitOpen | 0:6748e3332e85 | 131 | if (touch42 == 4) break; // STOP |
MikamiUitOpen | 0:6748e3332e85 | 132 | if (touch42 == 2) // PAUSE |
MikamiUitOpen | 0:6748e3332e85 | 133 | { |
MikamiUitOpen | 0:6748e3332e85 | 134 | menu.Inactivate(2); // PAUSE 無効 |
MikamiUitOpen | 0:6748e3332e85 | 135 | menu.Activate(3); // RESUME 有効 |
MikamiUitOpen | 0:6748e3332e85 | 136 | mySai.Pause(); |
MikamiUitOpen | 0:6748e3332e85 | 137 | |
MikamiUitOpen | 0:6748e3332e85 | 138 | // PLAY か RESUME か STOP がタッチされるまで待つ |
MikamiUitOpen | 0:6748e3332e85 | 139 | int touch134 = -1; |
MikamiUitOpen | 0:6748e3332e85 | 140 | while (!menu.GetTouchedNumber(touch134)) |
MikamiUitOpen | 0:6748e3332e85 | 141 | ModifyFilter(drawerObj, lpHp, onOff, |
MikamiUitOpen | 0:6748e3332e85 | 142 | hn, ck, g0, filterOn); |
MikamiUitOpen | 0:6748e3332e85 | 143 | switch (touch134) |
MikamiUitOpen | 0:6748e3332e85 | 144 | { |
MikamiUitOpen | 0:6748e3332e85 | 145 | case 1: playOk = true; // 最初から PLAY |
MikamiUitOpen | 0:6748e3332e85 | 146 | break; |
MikamiUitOpen | 0:6748e3332e85 | 147 | case 3: mySai.Resume(); // PAUSE したところから PLAY 再開 |
MikamiUitOpen | 0:6748e3332e85 | 148 | menu.Activate(2); |
MikamiUitOpen | 0:6748e3332e85 | 149 | menu.Inactivate(3); |
MikamiUitOpen | 0:6748e3332e85 | 150 | menu.TouchedColor(1); |
MikamiUitOpen | 0:6748e3332e85 | 151 | break; |
MikamiUitOpen | 0:6748e3332e85 | 152 | case 4: stopOk = true; // STOP |
MikamiUitOpen | 0:6748e3332e85 | 153 | break; |
MikamiUitOpen | 0:6748e3332e85 | 154 | } |
MikamiUitOpen | 0:6748e3332e85 | 155 | } |
MikamiUitOpen | 0:6748e3332e85 | 156 | if (playOk || stopOk) break; |
MikamiUitOpen | 0:6748e3332e85 | 157 | |
MikamiUitOpen | 0:6748e3332e85 | 158 | ModifyFilter(drawerObj, lpHp, onOff, hn, ck, g0, filterOn); |
MikamiUitOpen | 0:6748e3332e85 | 159 | // 1フレーム分の信号処理 (IIR フィルタ) の実行 |
MikamiUitOpen | 0:6748e3332e85 | 160 | ProcessSignal(sdReader, mySai, sn, g0, hn, ORDER, filterOn); |
MikamiUitOpen | 0:6748e3332e85 | 161 | } |
MikamiUitOpen | 0:6748e3332e85 | 162 | mySai.Stop(); |
MikamiUitOpen | 0:6748e3332e85 | 163 | menu.Activate(0); // OPEN 有効 |
MikamiUitOpen | 0:6748e3332e85 | 164 | if (!playOk) menu.Activate(1); // PLAY 有効 |
MikamiUitOpen | 0:6748e3332e85 | 165 | for (int n=2; n<5; n++) // その他は無効 |
MikamiUitOpen | 0:6748e3332e85 | 166 | menu.Inactivate(n); |
MikamiUitOpen | 0:6748e3332e85 | 167 | sdReader.Close(); // SD のファイルのクローズ |
MikamiUitOpen | 0:6748e3332e85 | 168 | } |
MikamiUitOpen | 0:6748e3332e85 | 169 | } |
MikamiUitOpen | 5:4a99dabc9180 | 170 |