SD card player with variable cotoff frequency lowpass and highpass IIR filter. SD カードの *.wav ファイルのオーディオ信号を,遮断周波数可変 IIR 低域通過および高域通過フィルタを通して,ボードに搭載されているCODEC で出力する.このプログラムについては,CQ出版社インターフェース誌 2018年8月号で解説している.
Dependencies: F746_GUI F746_SAI_IO FrequencyResponseDrawer SD_PlayerSkeleton
MyVariableFilter/BtwthDesignerDrawer.cpp@11:399670d24ed9, 2017-04-10 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Mon Apr 10 01:44:22 2017 +0000
- Revision:
- 11:399670d24ed9
- Parent:
- 10:3532c05aa1a9
12
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 2:dcaee06f6ccb | 1 | //------------------------------------------------------------------- |
MikamiUitOpen | 10:3532c05aa1a9 | 2 | // IIR フィルタを双1次 z 変換で設計し,その周波数特性を描画するためのクラス |
MikamiUitOpen | 2:dcaee06f6ccb | 3 | // |
MikamiUitOpen | 10:3532c05aa1a9 | 4 | // 2017/03/27, Copyright (c) 2017 MIKAMI, Naoki |
MikamiUitOpen | 2:dcaee06f6ccb | 5 | //------------------------------------------------------------------- |
MikamiUitOpen | 2:dcaee06f6ccb | 6 | |
MikamiUitOpen | 2:dcaee06f6ccb | 7 | #include "BtwthDesignerDrawer.hpp" |
MikamiUitOpen | 2:dcaee06f6ccb | 8 | |
MikamiUitOpen | 2:dcaee06f6ccb | 9 | namespace Mikami |
MikamiUitOpen | 2:dcaee06f6ccb | 10 | { |
MikamiUitOpen | 2:dcaee06f6ccb | 11 | // Constructor |
MikamiUitOpen | 2:dcaee06f6ccb | 12 | BtwthDesignerDrawer::BtwthDesignerDrawer( |
MikamiUitOpen | 2:dcaee06f6ccb | 13 | uint16_t x0, uint16_t y0, float db1, |
MikamiUitOpen | 2:dcaee06f6ccb | 14 | int fs, int order, float fc, |
MikamiUitOpen | 2:dcaee06f6ccb | 15 | uint16_t fL, uint16_t fH, BilinearDesign::Type lpHp) |
MikamiUitOpen | 5:82b24bd280ce | 16 | : lcd_(GuiBase::GetLcd()), |
MikamiUitOpen | 2:dcaee06f6ccb | 17 | X0_(x0), Y0_(y0), ORDER_(order), |
MikamiUitOpen | 2:dcaee06f6ccb | 18 | CURSOR_Y0_(y0+1-db1*60), CURSOR_LENGTH_(db1*60-1), |
MikamiUitOpen | 2:dcaee06f6ccb | 19 | MIN_F_(fL), MAX_F_(fH), |
MikamiUitOpen | 2:dcaee06f6ccb | 20 | CURSOR_COLOR_(0xFFE000D0), CURSOR_TOUCHED_COLOR_(0xFFFF80FF), |
MikamiUitOpen | 2:dcaee06f6ccb | 21 | coefs_(order/2), ck_((Array<Biquad::Coefs>&)coefs_), |
MikamiUitOpen | 2:dcaee06f6ccb | 22 | drawerObj_(x0, 100.0f, 20000.0f, 140, |
MikamiUitOpen | 2:dcaee06f6ccb | 23 | y0, -60, 0, db1, 10, fs), |
MikamiUitOpen | 2:dcaee06f6ccb | 24 | designObj_(order, fs), |
MikamiUitOpen | 2:dcaee06f6ccb | 25 | tp_(drawerObj_.X(MIN_F_), drawerObj_.X(MAX_F_), CURSOR_Y0_, y0), |
MikamiUitOpen | 4:eae45f4cfeed | 26 | lblFrq_(x0+70, 38, "Cutoff frequency = %4d Hz") |
MikamiUitOpen | 2:dcaee06f6ccb | 27 | { |
MikamiUitOpen | 10:3532c05aa1a9 | 28 | // 双1次 z 変換による IIR フィルタの設計 |
MikamiUitOpen | 2:dcaee06f6ccb | 29 | fC_ = fc; // 最初に与える遮断周波数 |
MikamiUitOpen | 2:dcaee06f6ccb | 30 | designObj_.Execute(fC_, lpHp, coefs_, g0_); |
MikamiUitOpen | 2:dcaee06f6ccb | 31 | frqResp_.SetParams(ORDER_, g0_, ck_); |
MikamiUitOpen | 2:dcaee06f6ccb | 32 | |
MikamiUitOpen | 2:dcaee06f6ccb | 33 | lp_ = lpHp; |
MikamiUitOpen | 2:dcaee06f6ccb | 34 | cursorRedraw_ = false; |
MikamiUitOpen | 2:dcaee06f6ccb | 35 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 36 | |
MikamiUitOpen | 2:dcaee06f6ccb | 37 | // フィルタの再設計と周波数特性の再描画 |
MikamiUitOpen | 2:dcaee06f6ccb | 38 | bool BtwthDesignerDrawer::ReDesignAndDraw(Biquad::Coefs ck[], float &g0, |
MikamiUitOpen | 2:dcaee06f6ccb | 39 | BilinearDesign::Type lpHp) |
MikamiUitOpen | 2:dcaee06f6ccb | 40 | { |
MikamiUitOpen | 2:dcaee06f6ccb | 41 | bool changed = (lpHp != lp_) ? true : false; |
MikamiUitOpen | 2:dcaee06f6ccb | 42 | bool tch = tp_.IsTouched(cursorX_, cursorX_); |
MikamiUitOpen | 2:dcaee06f6ccb | 43 | if (tch || changed) |
MikamiUitOpen | 2:dcaee06f6ccb | 44 | { |
MikamiUitOpen | 2:dcaee06f6ccb | 45 | int newFc = Frq10(drawerObj_.PosToFrq(cursorX_)); |
MikamiUitOpen | 2:dcaee06f6ccb | 46 | newFc = (newFc > MAX_F_) ? MAX_F_ : newFc; |
MikamiUitOpen | 2:dcaee06f6ccb | 47 | if ((abs(newFc - fC_) >= 1) || changed) |
MikamiUitOpen | 2:dcaee06f6ccb | 48 | { |
MikamiUitOpen | 2:dcaee06f6ccb | 49 | fC_ = newFc; |
MikamiUitOpen | 4:eae45f4cfeed | 50 | lblFrq_.Draw(newFc); |
MikamiUitOpen | 2:dcaee06f6ccb | 51 | designObj_.Execute(newFc, lpHp, coefs_, g0_); |
MikamiUitOpen | 2:dcaee06f6ccb | 52 | GetCoefficients(ck, g0); |
MikamiUitOpen | 2:dcaee06f6ccb | 53 | |
MikamiUitOpen | 2:dcaee06f6ccb | 54 | frqResp_.SetParams(ORDER_, g0_, ck_); |
MikamiUitOpen | 2:dcaee06f6ccb | 55 | drawerObj_.Erase(); |
MikamiUitOpen | 2:dcaee06f6ccb | 56 | drawerObj_.DrawAxis(); // 目盛線の描画 |
MikamiUitOpen | 2:dcaee06f6ccb | 57 | drawerObj_.DrawGraph(frqResp_); // 周波数特性のグラフのカーブを描画する |
MikamiUitOpen | 2:dcaee06f6ccb | 58 | |
MikamiUitOpen | 2:dcaee06f6ccb | 59 | if (tch) // カーソルの移動 |
MikamiUitOpen | 2:dcaee06f6ccb | 60 | { |
MikamiUitOpen | 5:82b24bd280ce | 61 | lcd_.SetTextColor(CURSOR_TOUCHED_COLOR_); |
MikamiUitOpen | 5:82b24bd280ce | 62 | lcd_.DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 10:3532c05aa1a9 | 63 | lcd_.DrawVLine(cursorX_-1, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 10:3532c05aa1a9 | 64 | lcd_.DrawVLine(cursorX_+1, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 2:dcaee06f6ccb | 65 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 66 | cursorRedraw_ = true; |
MikamiUitOpen | 2:dcaee06f6ccb | 67 | oldCursorX_ = cursorX_; |
MikamiUitOpen | 2:dcaee06f6ccb | 68 | lp_ = lpHp; |
MikamiUitOpen | 2:dcaee06f6ccb | 69 | return true; |
MikamiUitOpen | 2:dcaee06f6ccb | 70 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 71 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 72 | |
MikamiUitOpen | 2:dcaee06f6ccb | 73 | if (!tch && cursorRedraw_) // カーソルを元の色に戻す |
MikamiUitOpen | 2:dcaee06f6ccb | 74 | { |
MikamiUitOpen | 5:82b24bd280ce | 75 | lcd_.SetTextColor(CURSOR_COLOR_); |
MikamiUitOpen | 5:82b24bd280ce | 76 | lcd_.DrawVLine(oldCursorX_, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 10:3532c05aa1a9 | 77 | lcd_.DrawVLine(oldCursorX_-1, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 10:3532c05aa1a9 | 78 | lcd_.DrawVLine(oldCursorX_+1, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 2:dcaee06f6ccb | 79 | cursorRedraw_ = false; |
MikamiUitOpen | 2:dcaee06f6ccb | 80 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 81 | return false; |
MikamiUitOpen | 2:dcaee06f6ccb | 82 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 83 | |
MikamiUitOpen | 2:dcaee06f6ccb | 84 | // 周波数特性の描画 |
MikamiUitOpen | 2:dcaee06f6ccb | 85 | void BtwthDesignerDrawer::DrawResponse() |
MikamiUitOpen | 2:dcaee06f6ccb | 86 | { |
MikamiUitOpen | 4:eae45f4cfeed | 87 | lblFrq_.Draw(fC_); |
MikamiUitOpen | 2:dcaee06f6ccb | 88 | drawerObj_.DrawAxis(); // 目盛線の描画 |
MikamiUitOpen | 2:dcaee06f6ccb | 89 | FrqRespDrawer::AxisX_Char numX[] = // 横軸の目盛値を描画する際に使う構造体の配列 |
MikamiUitOpen | 2:dcaee06f6ccb | 90 | {{ 100, "0.1"}, { 200, "0.2"}, { 500, "0.5"}, { 1000, "1"}, |
MikamiUitOpen | 2:dcaee06f6ccb | 91 | { 2000, "2"}, { 5000, "5"}, {10000, "10"}, {20000, "20"}}; |
MikamiUitOpen | 2:dcaee06f6ccb | 92 | drawerObj_.DrawNumericX(numX, 8, 6, "Frequency [kHz]"); // 横軸の目盛 |
MikamiUitOpen | 2:dcaee06f6ccb | 93 | drawerObj_.DrawNumericY(-24, -6, 20, "%3d"); // 縦軸の目盛は 20 dB 間隔 |
MikamiUitOpen | 2:dcaee06f6ccb | 94 | drawerObj_.DrawGraph(frqResp_); // 周波数特性のカーブの描画 |
MikamiUitOpen | 2:dcaee06f6ccb | 95 | |
MikamiUitOpen | 2:dcaee06f6ccb | 96 | cursorX_ = drawerObj_.X(fC_); |
MikamiUitOpen | 5:82b24bd280ce | 97 | lcd_.SetTextColor(CURSOR_COLOR_); |
MikamiUitOpen | 5:82b24bd280ce | 98 | lcd_.DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 10:3532c05aa1a9 | 99 | lcd_.DrawVLine(cursorX_-1, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 10:3532c05aa1a9 | 100 | lcd_.DrawVLine(cursorX_+1, CURSOR_Y0_, CURSOR_LENGTH_); |
MikamiUitOpen | 2:dcaee06f6ccb | 101 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 102 | |
MikamiUitOpen | 2:dcaee06f6ccb | 103 | // フィルタ係数の取得 |
MikamiUitOpen | 2:dcaee06f6ccb | 104 | void BtwthDesignerDrawer::GetCoefficients(Biquad::Coefs c[], float &g0) |
MikamiUitOpen | 2:dcaee06f6ccb | 105 | { |
MikamiUitOpen | 2:dcaee06f6ccb | 106 | for (int k=0; k<ORDER_/2; k++) c[k] = ck_[k]; |
MikamiUitOpen | 2:dcaee06f6ccb | 107 | g0 = g0_; |
MikamiUitOpen | 2:dcaee06f6ccb | 108 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 109 | |
MikamiUitOpen | 2:dcaee06f6ccb | 110 | // 周波数を 10, 20, 50, 100 Hz の倍数にする |
MikamiUitOpen | 2:dcaee06f6ccb | 111 | int BtwthDesignerDrawer::Frq10(float f) |
MikamiUitOpen | 2:dcaee06f6ccb | 112 | { |
MikamiUitOpen | 2:dcaee06f6ccb | 113 | if (f < 1000) |
MikamiUitOpen | 2:dcaee06f6ccb | 114 | return ((int)(f/10.0f + 0.5f))*10; |
MikamiUitOpen | 2:dcaee06f6ccb | 115 | if (f < 2000) |
MikamiUitOpen | 2:dcaee06f6ccb | 116 | return ((int)(f/20.0f + 0.5f))*20; |
MikamiUitOpen | 2:dcaee06f6ccb | 117 | if (f < 3000) |
MikamiUitOpen | 2:dcaee06f6ccb | 118 | return ((int)(f/50.0f + 0.5f))*50; |
MikamiUitOpen | 2:dcaee06f6ccb | 119 | else |
MikamiUitOpen | 2:dcaee06f6ccb | 120 | return ((int)(f/100.0f + 0.5f))*100; |
MikamiUitOpen | 2:dcaee06f6ccb | 121 | } |
MikamiUitOpen | 2:dcaee06f6ccb | 122 | } |