Audio singal input and output example for DISCO-F746. Input: MEMS mic, Output: CN10 OUT, Acoustic effect: echo and frequency shift. DISCO-F746 によるオーディオ信号入出力.入力:MEMS マイク,出力:CN10 OUT,音響効果:エコー,周波数変換.
Dependencies: F746_GUI F746_SAI_IO
Revision 10:56f2f01df983, committed 2017-04-10
- Comitter:
- MikamiUitOpen
- Date:
- Mon Apr 10 13:44:13 2017 +0000
- Parent:
- 9:1221ba81a1bb
- Commit message:
- 11
Changed in this revision
diff -r 1221ba81a1bb -r 56f2f01df983 BSP_DISCO_F746NG.lib --- a/BSP_DISCO_F746NG.lib Fri Mar 17 01:26:25 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/ST/code/BSP_DISCO_F746NG/#5a395e126678
diff -r 1221ba81a1bb -r 56f2f01df983 F746_GUI.lib --- a/F746_GUI.lib Fri Mar 17 01:26:25 2017 +0000 +++ b/F746_GUI.lib Mon Apr 10 13:44:13 2017 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/MikamiUitOpen/code/F746_GUI/#d7f9f667fa68 +https://mbed.org/users/MikamiUitOpen/code/F746_GUI/#e6648167e8d3
diff -r 1221ba81a1bb -r 56f2f01df983 LCD_DISCO_F746NG.lib --- a/LCD_DISCO_F746NG.lib Fri Mar 17 01:26:25 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/ST/code/LCD_DISCO_F746NG/#d44525b1de98
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/Biquad.hpp --- a/MyAcousticEffector_MIC/Biquad.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/Biquad.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -9,7 +9,7 @@ // y[n] : output signal // b0 = 1 // -// 2016/11/08, Copyright (c) 2016 MIKAMI, Naoki +// 2017/03/26, Copyright (c) 2017 MIKAMI, Naoki //-------------------------------------------------------------- #ifndef IIR_BIQUAD_HPP @@ -25,9 +25,7 @@ public: struct Coefs { float a1, a2, b1, b2; }; - Biquad() {} // Default constructore - - Biquad(const Coefs ck) + Biquad(const Coefs ck = (Coefs){0, 0, 0, 0}) { SetCoefficients(ck); Clear();
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/Coefficients.hpp --- a/MyAcousticEffector_MIC/Coefficients.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/Coefficients.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -4,19 +4,25 @@ #include "Biquad.hpp" -using namespace Mikami; - //-------------------------------------------------------------- -// 直流分除去フィルタの係数 +// 帯域通過フィルタの係数 //-------------------------------------------------------------- -// 高域通過フィルタ -// バタワース特性 -// 次数 :2 次 +// 帯域通過フィルタ +// 連立チェビシェフ特性 +// 次数 :10 次 // 標本化周波数: 16.00 kHz -// 遮断周波数 : 0.05 kHz -const Mikami::Biquad::Coefs c1_ = - { 1.972234E+00f, -9.726140E-01f, -2.0f, 1.0f}; -const float g0_ = 9.862119E-01f; +// 遮断周波数1: 0.10 kHz +// 遮断周波数2: 6.90 kHz +// 通過域のリップル: 0.50 dB +// 阻止域の減衰量 :40.00 dB +const int ORDER_BPF_ = 10; // 次数 +const Biquad::Coefs ckBpf_[ORDER_BPF_/2] = { + { 5.650978E-01f, 3.238031E-01f, 0.000000E+00f, -1.0f}, // 1段目 + { -1.465572E+00f, -7.038566E-01f, 1.945920E+00f, 1.0f}, // 2段目 + { -1.773813E+00f, -9.479833E-01f, 1.890894E+00f, 1.0f}, // 3段目 + { 1.964750E+00f, -9.671182E-01f, -1.999561E+00f, 1.0f}, // 4段目 + { 1.993515E+00f, -9.950107E-01f, -1.999102E+00f, 1.0f} }; // 5段目 +const float g0Bpf_ = 4.930705E-01f; // 利得定数 //-------------------------------------------------------------- // Weaver 変調器で使う低域通過フィルタの係数
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/Echo.hpp --- a/MyAcousticEffector_MIC/Echo.hpp Fri Mar 17 01:26:25 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -//-------------------------------------------------------------- -// Echo generation system -// -// 2016/04/11, Copyright (c) 2016 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef ECHO_SYSTEM_HPP -#define ECHO_SYSTEM_HPP - -#include "ReverbUnit.hpp" -#include "ProcessingBase.hpp" - -using namespace Mikami; - -namespace Mikami -{ - class EchoSystem : public ProcessingBase - { - public: - EchoSystem(float gC = 0.8f, float gA = 0.6f) - : G0_(1.0f - gC), variableDelay_(6000) - { - cmF1_ = new CombFilter(gC, 887+1500); - cmF2_ = new CombFilter(gC, 1153+3000); - cmF3_ = new CombFilter(gC, 1499+6000); - apF1_ = new AllPassFilter(gA, 97); - apF2_ = new AllPassFilter(gA, 131); - } - - virtual float Execute(float sn) - { - float xn = G0_*sn; - float yn = cmF1_->Execute(xn, variableDelay_/4) - + cmF2_->Execute(xn, variableDelay_/2) - + cmF3_->Execute(xn, variableDelay_); - yn = apF2_->Execute(apF1_->Execute(yn)); - yn = yn + xn; // add direct input signal - return yn; - } - - void SetDelay(int n) { variableDelay_ = n; } - - private: - const float G0_; - int variableDelay_; - - CombFilter *cmF1_, *cmF2_, *cmF3_; - AllPassFilter *apF1_, *apF2_; - }; -} -#endif // ECHO_SYSTEM_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/EffectorInitializeGUI.hpp --- a/MyAcousticEffector_MIC/EffectorInitializeGUI.hpp Fri Mar 17 01:26:25 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -//-------------------------------------------------------------- -// 「MEMS マイクの入力に対して音響効果を与える」で使う GUI 等の初期化 -// -// 2017/03/17, Copyright (c) 2017 MIKAMI, Naoki -//-------------------------------------------------------------- - -#ifndef EFFECTOR_INIT_GUI_HPP -#define EFFECTOR_INIT_GUI_HPP - -#include "F746_GUI.hpp" -#include "WaveformDisplay.hpp" - -using namespace Mikami; - -void EffectorInitializeGUI( - ButtonGroup *(&onOff), ButtonGroup *(&menu), - SeekBar *(&barEcho), SeekBar *(&barFqCh), - NumericLabel<int> *(&frqLabel), - WaveformDisplay *(&dispIn), - WaveformDisplay *(&dispOut)) -{ - Label myLabel(240, 10, "Echo and frequency shifter", - Label::CENTER, Font16); - - // Button 用の定数 - const uint16_t BG_LEFT = 370; - const uint16_t BG_WIDTH = 100; - const uint16_t BG_HEIGHT = 45; - - // ButtonGroup: "ON", "OFF" - const string ON_OFF[2] = {"ON", "OFF"}; - onOff = new ButtonGroup(BG_LEFT, 40, BG_WIDTH/2, BG_HEIGHT, - 2, ON_OFF, 0, 0, 2, 1); - - // ButtonGroup: "THROUGH", "ECHO", "F_SHIFTER" - const string MENU[3] = {"THROUGH", "ECHO", "F_SHIFTER"}; - menu = new ButtonGroup(BG_LEFT, 110, BG_WIDTH, BG_HEIGHT, - 3, MENU, 0, 10, 1, 0); - - // SeekBar 用の定数 - const uint16_t SB_LEFT = BG_LEFT - 300; - const uint16_t SB_WIDTH = 256; - const uint16_t Y0_E = 192; - const uint16_t Y0_F = Y0_E + BG_HEIGHT + 5; - const uint16_t DY0 = 28; - - // エコー用 - barEcho = new SeekBar(SB_LEFT, Y0_E, SB_WIDTH, - 0, 6000, 0, "short", "", "long"); - barEcho->Inactivate(); - - // 周波数シフタ用 - barFqCh = new SeekBar(SB_LEFT, Y0_F, SB_WIDTH, - 0, 200, 100, "0", "", "200"); - barFqCh->Inactivate(); - frqLabel = new NumericLabel<int>(SB_LEFT+SB_WIDTH/2, Y0_F-DY0, "+%d Hz", - barFqCh->GetIntValue(), Label::CENTER); - frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT); - - // 波形表示用 - dispIn = new WaveformDisplay(GuiBase::GetLcd(), - SB_LEFT, 70, 256, 9, - LCD_COLOR_WHITE, LCD_COLOR_CYAN, - GuiBase::ENUM_BACK); - Label inLabel(SB_LEFT-40, 65, "IN"); - dispOut = new WaveformDisplay(GuiBase::GetLcd(), - SB_LEFT, 130, 256, 9, - LCD_COLOR_WHITE, LCD_COLOR_CYAN, - GuiBase::ENUM_BACK); - Label outLabel(SB_LEFT-40, 125, "OUT"); -} -#endif // #define EFFECTOR_INIT_GUI_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/GuiChanger.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyAcousticEffector_MIC/GuiChanger.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -0,0 +1,37 @@ +//-------------------------------------------------------------- +// 信号処理の種類に応じた GUI 部品の状態を変更する +// +// 2017/04/08, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef GUI_CHANGER_HPP +#define GUI_CHANGER_HPP + +// Through の場合 +void SetThrough(SeekBar *barReverb, SeekBar *barFqCh, + NumericLabel<int> *frqLabel) +{ + barReverb->Inactivate(); + barFqCh->Inactivate(); + frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT); +} + +// 残響生成の場合 +void SetReverb(SeekBar *barReverb, SeekBar *barFqCh, + NumericLabel<int> *frqLabel) +{ + barReverb->Activate(); + barFqCh->Inactivate(); + frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT); +} + +// 周波数シフトの場合 +void SetFrqShifter(SeekBar *barReverb, SeekBar *barFqCh, + NumericLabel<int> *frqLabel) +{ + barReverb->Inactivate(); + barFqCh->Activate(); + frqLabel->Redraw(GuiBase::ENUM_TEXT); +} + +#endif // GUI_CHANGER_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/IIR_Cascade.hpp --- a/MyAcousticEffector_MIC/IIR_Cascade.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/IIR_Cascade.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -1,49 +1,59 @@ //------------------------------------------------------------------------------ // 縦続形 IIR フィルタのクラス // -// 2016/04/12, Copyright (c) 2016 MIKAMI, Naoki +// 2017/04/07, Copyright (c) 2017 MIKAMI, Naoki //------------------------------------------------------------------------------ #ifndef IIR_CASCADE_HPP #define IIR_CASCADE_HPP #include "Biquad.hpp" +#include "Array.hpp" namespace Mikami { - template<int order> class IIR_Cascade + class IIR_Cascade { public: // コンストラクタ - IIR_Cascade(const Biquad::Coefs ck[], float g0) : g0_(g0) + IIR_Cascade(int order, const Biquad::Coefs ck[], float g0) + : ORDER2_(order/2), G0_(g0), hk_(ORDER2_) { + if ((order % 2) != 0) + { + fprintf(stderr, "\r\nOrder is not even number.\r\n"); + while (true) {} + } for (int n=0; n<order/2; n++) hk_[n] = Biquad(ck[n]); Clear(); } - + // デストラクタ - ~IIR_Cascade() - { - for (int n=0; n<order/2; n++) delete hk_[n]; - } - - // 過去の計算結果を格納する配列のクリア + ~IIR_Cascade() {} + + // 過去の計算結果を格納する遅延器のクリア void Clear() { - for (int k=0; k<order/2; k++) hk_[k].Clear(); + for (int k=0; k<ORDER2_; k++) hk_[k].Clear(); } // フィルタ処理の実行 float Execute(float xn) { - float yn = g0_*xn; - for (int k=0; k<order/2; k++) yn = hk_[k].Execute(yn); + float yn = G0_*xn; + for (int k=0; k<ORDER2_; k++) yn = hk_[k].Execute(yn); return yn; } private: - Biquad hk_[order/2]; // 2 次の IIR フィルタ - const float g0_; // 利得定数 + const int ORDER2_; // 次数/2 + const float G0_; // 利得定数 + + Array<Biquad> hk_; // 2 次の IIR フィルタのオブジェクトの配列 + + // disallow copy constructor and assignment operator + IIR_Cascade(const IIR_Cascade&); + IIR_Cascade& operator=(const IIR_Cascade&); }; } #endif // IIR_CASCADE_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/InitializeGUI.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyAcousticEffector_MIC/InitializeGUI.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -0,0 +1,67 @@ +//-------------------------------------------------------------- +// 「MEMS マイクの入力に対して音響効果を与える」で使う GUI 等の初期化 +// +// 2017/04/08, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef EFFECTOR_INIT_GUI_HPP +#define EFFECTOR_INIT_GUI_HPP + +#include "F746_GUI.hpp" +#include "WaveformDisplay.hpp" +using namespace Mikami; + +void InitializeGUI( + ButtonGroup *(&onOff), ButtonGroup *(&menu), + SeekBar *(&barReverb), SeekBar *(&barFqCh), + NumericLabel<int> *(&frqLabel), + WaveformDisplay *(&dispIn), + WaveformDisplay *(&dispOut)) +{ + Label myLabel(240, 8, "Reverberator and voice changer", + Label::CENTER, Font16); + + // ButtonGroup 用の定数 + const uint16_t BG_LEFT = 360; + const uint16_t BG_WIDTH = 110; + const uint16_t BG_HEIGHT = 45; + + // ButtonGroup: "ON", "OFF" + const string ON_OFF[2] = {"ON", "OFF"}; + onOff = new ButtonGroup(BG_LEFT, 40, BG_WIDTH/2, BG_HEIGHT, + 2, ON_OFF, 0, 0, 2, 1); + + // ButtonGroup: "THROUGH", "ECHO", "F_SHIFTER" + const string MENU[3] = {"THROUGH", "REVERB", "VOICE CHANGER"}; + menu = new ButtonGroup(BG_LEFT, 110, BG_WIDTH, BG_HEIGHT, + 3, MENU, 0, 10, 1, 0); + + // SeekBar 用の定数 + const uint16_t SB_LEFT = BG_LEFT - 300; + const uint16_t SB_WIDTH = 256; + const uint16_t Y0_E = 195; + const uint16_t Y0_F = Y0_E + BG_HEIGHT + 5; + + // リバーブ用 + barReverb = new SeekBar(SB_LEFT, Y0_E, SB_WIDTH, + 0, 6000, 0, "short", "", "long"); + barReverb->Inactivate(); + + // 周波数シフタ用 + barFqCh = new SeekBar(SB_LEFT, Y0_F, SB_WIDTH, + 0, 200, 100, "0", "", "200"); + barFqCh->Inactivate(); + frqLabel = new NumericLabel<int>( + SB_LEFT+SB_WIDTH/2, Y0_F-28, "+%d Hz", + barFqCh->GetIntValue(), Label::CENTER); + frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT); + + // 波形表示用 + Label inLabel(SB_LEFT-40, 55, "IN"); + dispIn = new WaveformDisplay( + GuiBase::GetLcd(), SB_LEFT, 60, 256, 9); + Label outLabel(SB_LEFT-40, 125, "OUT"); + dispOut = new WaveformDisplay( + GuiBase::GetLcd(), SB_LEFT, 130, 256, 9); +} +#endif // EFFECTOR_INIT_GUI_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/ProcessingBase.hpp --- a/MyAcousticEffector_MIC/ProcessingBase.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/ProcessingBase.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -1,23 +1,22 @@ //-------------------------------------------------------------- // 信号処理のための基底クラス // -// 2016/04/11, Copyright (c) 2016 MIKAMI, Naoki +// 2017/04/06, Copyright (c) 2017 MIKAMI, Naoki //-------------------------------------------------------------- #ifndef PROCESSING_BASE_HPP #define PROCESSING_BASE_HPP -using namespace Mikami; - namespace Mikami { class ProcessingBase { public: ProcessingBase() {} + virtual ~ProcessingBase() {} + virtual float Execute(float xn) { return xn; } }; } #endif // PROCESSING_BASE_HPP -
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/ReverbUnit.hpp --- a/MyAcousticEffector_MIC/ReverbUnit.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/ReverbUnit.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -1,106 +1,62 @@ //-------------------------------------------------------------- -// Reverb unit -// 2016/04/12, Copyright (c) 2016 MIKAMI, Naoki +// Reverb unit: comb filter and all-pass filter +// 2017/04/08, Copyright (c) 2017 MIKAMI, Naoki //-------------------------------------------------------------- #ifndef REVERB_UNIT_HPP #define REVERB_UNIT_HPP -#include "mbed.h" +#include "ReverbUnitBase.hpp" namespace Mikami { - // Base class for reverb unit - class Reverb - { - public: - // Constructor - Reverb(int delay) : ptr_(0), delay_(delay) - { - un_ = new float[delay]; - Clear(); - } - - ~Reverb() - { delete[] un_; } - - // Execute of filter (pure virtual function) - virtual float Execute(float x) = 0; - - // Clear internal delay elements - void Clear() - { for (int n=0; n<delay_; n++) un_[n] = 0; } - - protected: - float Get() { return un_[ptr_]; } - - float Get(int n) - { - int k = ptr_ + n; - if (k > delay_) k -= delay_; - if (k < 0) k += delay_; - return un_[k]; - } - - void Set(float x) - { - un_[ptr_] = x; - if (++ptr_ >= delay_) ptr_ = 0; - } - private: - int ptr_; - int delay_; - float *un_; // for delay - Reverb(const Reverb&); - Reverb& operator=(const Reverb&); - }; - // Reverb unit using comb filter - class CombFilter : public Reverb + class CombFilter : public ReverbBase { public: // Constructor CombFilter(float g, int delay) - : Reverb(delay), G0_(g) {} - - // Execute comb filter - virtual float Execute(float x) - { - float yn = Reverb::Get(); - Reverb::Set(x + G0_*yn); - return yn; - } + : ReverbBase(delay), G_C_(g) {} // Execute comb filter with variable delay float Execute(float x, int n) { - float yn = Reverb::Get(n); - Reverb::Set(x + G0_*yn); + float yn = Get(n); + Set(x + G_C_*yn); return yn; } private: - const float G0_; + const float G_C_; + + // disallow copy constructor and assignment operator + CombFilter(const CombFilter&); + CombFilter& operator=(const CombFilter&); }; // Reverb unit using allpass filter - class AllPassFilter : public Reverb + class AllPassFilter : public ReverbBase { public: // Constructor AllPassFilter(float g, int delay) - : Reverb(delay), G0_(g) {} + : ReverbBase(delay), G_A_(g) {} // Execute allpass filter - virtual float Execute(float x) + float Execute(float x) { - float un = x + G0_*Reverb::Get(); - float yn = -G0_*un + Reverb::Get(); - Reverb::Set(un); + float un = x + G_A_*Get(); + float yn = -G_A_*un + Get(); + Set(un); return yn; } + private: - const float G0_; + const float G_A_; + + // disallow copy constructor and assignment operator + AllPassFilter(const AllPassFilter&); + AllPassFilter& operator=(const AllPassFilter&); }; } #endif // REVERB_UNIT_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/ReverbUnitBase.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyAcousticEffector_MIC/ReverbUnitBase.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -0,0 +1,54 @@ +//-------------------------------------------------------------- +// Base class for Reverb unit +// 2017/04/04, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef REVERB_UNIT_BASE_HPP +#define REVERB_UNIT_BASE_HPP + +#include "mbed.h" +#include "Array.hpp" + +namespace Mikami +{ + // Base class for reverb unit + class ReverbBase + { + public: + // Constructor + ReverbBase(int delay) + : ptr_(0), delay_(delay), un_(delay) + { Clear(); } + + // Clear internal delay elements + void Clear() + { for (int n=0; n<delay_; n++) un_[n] = 0; } + + protected: + float Get() { return un_[ptr_]; } + + float Get(int n) + { + int k = ptr_ + n; + if (k > delay_) k -= delay_; + if (k < 0) k += delay_; + return un_[k]; + } + + void Set(float x) + { + un_[ptr_] = x; + if (++ptr_ >= delay_) ptr_ = 0; + } + + private: + int ptr_; + int delay_; + Array<float> un_; // for delay + + // disallow copy constructor and assignment operator + ReverbBase(const ReverbBase&); + ReverbBase& operator=(const ReverbBase&); + }; +} +#endif // REVERB_UNIT_BASE_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/Reverberator.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MyAcousticEffector_MIC/Reverberator.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -0,0 +1,51 @@ +//-------------------------------------------------------------- +// Reverberation generator +// +// 2017/04/10, Copyright (c) 2017 MIKAMI, Naoki +//-------------------------------------------------------------- + +#ifndef REVERBERATION_SYSTEM_HPP +#define REVERBERATION_SYSTEM_HPP + +#include "ReverbUnit.hpp" +#include "ProcessingBase.hpp" + +namespace Mikami +{ + class Reverberator : public ProcessingBase + { + public: + Reverberator(float gC = 0.8f, float gA = 0.6f) + : G0_(1.0f - gC), + DELAY_INIT_(6000), variableDelay_(6000), + cmF1_(gC, 887+1500), cmF2_(gC, 1153+3000), + cmF3_(gC, 1499+6000), + apF1_(gA, 97), apF2_(gA, 131) {} + + virtual float Execute(float sn) + { + float xn = G0_*sn; + float yn = cmF1_.Execute(xn, variableDelay_/4) + + cmF2_.Execute(xn, variableDelay_/2) + + cmF3_.Execute(xn, variableDelay_); + yn = apF2_.Execute(apF1_.Execute(yn)); + yn = yn + xn; // add direct input signal + return yn; + } + + void SetDelay(int n) { variableDelay_ = DELAY_INIT_ - n; } + + private: + const float G0_; + const int DELAY_INIT_; + int variableDelay_; + + CombFilter cmF1_, cmF2_, cmF3_; + AllPassFilter apF1_, apF2_; + + // disallow copy constructor and assignment operator + Reverberator(const Reverberator&); + Reverberator& operator=(const Reverberator&); + }; +} +#endif // REVERBERATION_SYSTEM_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/WaveformDisplay.hpp --- a/MyAcousticEffector_MIC/WaveformDisplay.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/WaveformDisplay.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -1,13 +1,13 @@ //----------------------------------------------------------- // Class for waveform display // -// 2015/12/15, Copyright (c) 2015 MIKAMI, Naoki +// 2017/04/06, Copyright (c) 2016 MIKAMI, Naoki //----------------------------------------------------------- #ifndef F746_WAVEFORM_DISPLAY_HPP #define F746_WAVEFORM_DISPLAY_HPP -#include "mbed.h" +#include "Array.hpp" namespace Mikami { @@ -16,72 +16,55 @@ public: WaveformDisplay(LCD_DISCO_F746NG &lcd, uint16_t x0, uint16_t y0, int nData, - uint16_t rShift, - uint32_t axisColor, uint32_t lineColor, - uint32_t backColor) - : X0_(x0), Y0_(y0), N_DATA_(nData), R_SHIFT_(rShift), - AXIS_COLOR_(axisColor), LINE_COLOR_(lineColor), - BACK_COLOR_(backColor), lcd_(lcd) { Axis(); } - - void Execute(const int16_t xn[]) + uint16_t rShift) + : X0_(x0), Y0_(y0), R_SHIFT_(rShift), + H1_(Y0_+LIMIT_+1), H2_(Y0_-LIMIT_-1), + lcd_(lcd) { Axis(nData); } + + void Execute(const Array<int16_t> &xn) { - static const uint16_t LIMIT1 = Y0_ + LIMIT2_; - static const uint16_t LIMIT2 = Y0_ - LIMIT2_; - Axis(); + lcd_.SetTextColor(GuiBase::ENUM_BACK); + lcd_.FillRect(X0_, Y0_-LIMIT_-1, + xn.Length(), (LIMIT_+1)*2+1); + Axis(xn.Length()); lcd_.SetTextColor(LINE_COLOR_); uint16_t x1 = X0_; uint16_t y1 = Clip(xn[0]); - for (int n=1; n<N_DATA_; n++) + for (int n=1; n<xn.Length(); n++) { uint16_t x2 = X0_ + n; uint16_t y2 = Clip(xn[n]); - if ( ((y2 == LIMIT1) && (y1 == LIMIT1)) || - ((y2 == LIMIT2) && (y1 == LIMIT2)) ) - { // Out of displaying boundaries - lcd_.SetTextColor(LCD_COLOR_RED); - lcd_.DrawHLine(x1, y1, 1); - lcd_.SetTextColor(LINE_COLOR_); - } - else - lcd_.DrawLine(x1, y1, x2, y2); - if ((y1 == LIMIT1) || (y1 == LIMIT2)) + lcd_.DrawLine(x1, y1, x2, y2); + if ((y1 == H1_) || (y1 == H2_)) lcd_.DrawPixel(x1, y1, LCD_COLOR_RED); x1 = x2; y1 = y2; } - lcd_.SetTextColor(BACK_COLOR_); } - + private: - const uint16_t X0_; - const uint16_t Y0_; - const int N_DATA_; + static const uint16_t LIMIT_ = 32; + static const uint32_t LINE_COLOR_ = LCD_COLOR_CYAN; + const uint16_t X0_, Y0_; const uint16_t R_SHIFT_; - const uint32_t AXIS_COLOR_; - const uint32_t LINE_COLOR_; - const uint32_t BACK_COLOR_; - static const int LIMIT_ = 32; - static const int LIMIT2_ = LIMIT_ + 1; - + const uint16_t H1_, H2_; + LCD_DISCO_F746NG& lcd_; - + // Clipping uint16_t Clip(int16_t xn) { int16_t x = xn >> R_SHIFT_; - if (x > LIMIT_ ) x = LIMIT2_; - if (x < -LIMIT_ ) x = -LIMIT2_ ; + if (x > LIMIT_ ) x = LIMIT_ + 1; + if (x < -LIMIT_ ) x = -(LIMIT_ + 1) ; return Y0_ - x; } - - void Axis() + + void Axis(int nData) { - lcd_.SetTextColor(BACK_COLOR_); - lcd_.FillRect(X0_, Y0_-LIMIT2_, N_DATA_, LIMIT2_*2+1); - - lcd_.SetTextColor(AXIS_COLOR_); - lcd_.DrawLine(X0_-5, Y0_, X0_+N_DATA_+5, Y0_); - } + lcd_.SetTextColor(LCD_COLOR_WHITE); + lcd_.DrawLine(X0_-5, Y0_, X0_+nData+5, Y0_); + } // disallow copy constructor and assignment operator WaveformDisplay(const WaveformDisplay& );
diff -r 1221ba81a1bb -r 56f2f01df983 MyAcousticEffector_MIC/WeaverModulator.hpp --- a/MyAcousticEffector_MIC/WeaverModulator.hpp Fri Mar 17 01:26:25 2017 +0000 +++ b/MyAcousticEffector_MIC/WeaverModulator.hpp Mon Apr 10 13:44:13 2017 +0000 @@ -4,54 +4,42 @@ // 帯域中央の周波数: 3.5 kHz // 低域通過フィルタの遮断周波数: 3.4 kHz // -// 2016/04/11, Copyright (c) 2016 MIKAMI, Naoki +// 2017/04/10, Copyright (c) 2016 MIKAMI, Naoki //-------------------------------------------------------------- - + #ifndef WEAVER_MODULATOR_HPP #define WEAVER_MODULATOR_HPP -#include "ReverbUnit.hpp" #include "ProcessingBase.hpp" #include "IIR_Cascade.hpp" -#include "Coefficients.hpp" // Coeffisients of LPF and DC-cut filter - -using namespace Mikami; +#include "Coefficients.hpp" // Coeffisients of BPF and LPF namespace Mikami { - class FrqShifter : public ProcessingBase + class WeaverMod : public ProcessingBase { public: - FrqShifter(float fS) - : FS_(fS), PI2_(3.1415926536f*2), F_B_(3500) - { - lpfC_ = new IIR_Cascade<ORDER_>(ck_, g0Lpf_); - lpfS_ = new IIR_Cascade<ORDER_>(ck_, g0Lpf_); - dcCut_ = new Biquad(c1_); - - lpfC_->Clear(); - lpfS_->Clear(); + WeaverMod(float fS, float fShift = 0) + : bpf_(ORDER_BPF_, ckBpf_, g0Bpf_), + lpfC_(ORDER_, ck_, g0Lpf_), lpfS_(ORDER_, ck_, g0Lpf_), + FS_(fS), PI2_(3.1415926536f*2), F_B0_(3500), + phi1_(0), dPhi1_(F_B0_*PI2_/FS_), phi2_(0) + { SetFrequency(fShift); } - dPhi1_ = F_B_*PI2_/FS_; - dPhi2_ = dPhi1_; - phi1_ = 0; - phi2_ = 0; - } - virtual float Execute(float xn) { - xn = dcCut_->Execute(xn); // DC 成分除去 - - float mpyC = xn*cosf(phi1_); - float mpyS = xn*sinf(phi1_); - - // LPF - float mpyC_Lpf = lpfC_->Execute(mpyC); - float mpyS_Lpf = lpfS_->Execute(mpyS); - + float un = bpf_.Execute(xn); // 帯域通過フィルタ(BPF) + + float mpyC = un*cosf(phi1_); + float mpyS = un*sinf(phi1_); + + // 低域通過フィルタ(LPF) + float mpyC_Lpf = lpfC_.Execute(mpyC); + float mpyS_Lpf = lpfS_.Execute(mpyS); + float mpyC_C = mpyC_Lpf*cosf(phi2_); float mpyS_S = mpyS_Lpf*sinf(phi2_); - + float yn = 2.0f*(mpyC_C + mpyS_S); phi1_ = phi1_ + dPhi1_; @@ -59,26 +47,29 @@ phi2_ = phi2_ + dPhi2_; if (phi2_ > PI2_) phi2_ = phi2_ - PI2_; - return yn; + return yn; } - + // 周波数のシフト量を設定 - void SetFrequensy(float fShift) - { dPhi2_ = (fShift + F_B_)*PI2_/FS_; } + void SetFrequency(float fShift) + { dPhi2_ = (fShift + F_B0_)*PI2_/FS_; } private: + // 帯域通過フィルタ + IIR_Cascade bpf_; // Weaver 変調器で使う低域通過フィルタ - IIR_Cascade<ORDER_> *lpfC_; - IIR_Cascade<ORDER_> *lpfS_; - // 直流分除去フィルタ - Biquad *dcCut_; - + IIR_Cascade lpfC_, lpfS_; + const float FS_; const float PI2_; - const float F_B_; // 中心周波数 - + const float F_B0_; // 中心周波数 + float phi1_, dPhi1_; float phi2_, dPhi2_; + + // disallow copy constructor and assignment operator + WeaverMod(const WeaverMod& ); + WeaverMod& operator=(const WeaverMod& ); }; } #endif // WEAVER_MODULATOR_HPP
diff -r 1221ba81a1bb -r 56f2f01df983 TS_DISCO_F746NG.lib --- a/TS_DISCO_F746NG.lib Fri Mar 17 01:26:25 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://developer.mbed.org/teams/ST/code/TS_DISCO_F746NG/#fe0cf5e2960f
diff -r 1221ba81a1bb -r 56f2f01df983 main.cpp --- a/main.cpp Fri Mar 17 01:26:25 2017 +0000 +++ b/main.cpp Mon Apr 10 13:44:13 2017 +0000 @@ -1,104 +1,89 @@ //-------------------------------------------------------------- // MEMS マイクの入力に対して音響効果を与える -// 音響効果:エコー生成,周波数シフト +// 音響効果:残響生成,周波数シフト // -// 2017/03/17, Copyright (c) 2017 MIKAMI, Naoki +// 2017/04/10, Copyright (c) 2017 MIKAMI, Naoki //-------------------------------------------------------------- -#include "EffectorInitializeGUI.hpp" +#include "InitializeGUI.hpp" #include "SAI_InOut.hpp" -#include "Echo.hpp" +#include "Reverberator.hpp" #include "WeaverModulator.hpp" -#include "Array.hpp" - +#include "GuiChanger.hpp" using namespace Mikami; int main() { - const int FS = AUDIO_FREQUENCY_16K; // 標本化周波数: 16 kHz - SaiIO mySai(SaiIO::BOTH, 256, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2); + const int FS = AUDIO_FREQUENCY_16K; // 標本化周波数: 16 kHz + // 入出力の準備 + SaiIO mySai(SaiIO::BOTH, 256, FS, + INPUT_DEVICE_DIGITAL_MICROPHONE_2); - ButtonGroup *onOff; // "ON", "OFF" - ButtonGroup *menu; // "THROUGH", "ECHO", "F_SHIFTER" - SeekBar *barEcho, *barFqCh; + ButtonGroup *onOff; // "ON", "OFF" + ButtonGroup *menu; // "THROUGH", "REVERB", "F_SHIFTER" + SeekBar *barReverb, *barFqCh; NumericLabel<int> *frqLabel; WaveformDisplay *displayIn, *displayOut; - - EffectorInitializeGUI(onOff, menu, barEcho, barFqCh, - frqLabel, displayIn, displayOut); - - ProcessingBase through; // 0: 信号処理なしで出力 - EchoSystem echo; // 1: エコー生成 - FrqShifter shifter(FS); // 2: 周波数シフト - ProcessingBase *func[3] = { &through, &echo, &shifter }; - shifter.SetFrequensy(100); // 周波数シフタの初期値:100 Hz + // GUI 部品の初期化 + InitializeGUI(onOff, menu, barReverb, barFqCh, + frqLabel, displayIn, displayOut); + // 処理に応じて GUI 部品の状態を変更する関数の割り当て + void (*fPtr[])(SeekBar*, SeekBar*, NumericLabel<int>*) + = { SetThrough, SetReverb, SetFrqShifter }; - int runStop = 1; - int menuNum = 0; + ProcessingBase through; // 0: 信号処理なしで出力 + Reverberator reverb; // 1: 残響生成 + WeaverMod shifter(FS, 100); // 2: 周波数シフト(シフトの初期値:100 Hz) + ProcessingBase *func[3] = { &through, + &reverb, + &shifter }; - // 入出力の波形表示で使用 - Array<int16_t> snIn(mySai.GetLength()); - Array<int16_t> snOut(mySai.GetLength()); + Array<int16_t> snIn(mySai.GetLength()); // 入力波形表示で使用 + Array<int16_t> snOut(mySai.GetLength()); // 出力波形表示で使用 - mySai.RecordIn(); - mySai.PlayOut(); - mySai.PauseOut(); + mySai.RecordIn(); // 入力開始 + mySai.PlayOut(); // 出力開始 + mySai.PauseOut(); // 出力一時停止 + int menuNum = 0; while (true) { // On/OFF の設定 int num; - - if ( (onOff->GetTouchedNumber(num)) && (runStop != num) ) + if (onOff->GetTouchedNumber(num)) { - if (num == 0) mySai.ResumeOut(); + if (num == 0) mySai.ResumeOut(); // 出力再開 else mySai.PauseOut(); - runStop = num; } - // エコーの長さを設定 - if ( (menuNum == 1) && (barEcho->Slide()) ) - echo.SetDelay(6000 - barEcho->GetIntValue()); + // 信号処理の種類の切り替えに対応する GUI 部品の状態の設定 + if (menu->GetTouchedNumber(menuNum)) + fPtr[menuNum](barReverb, barFqCh, frqLabel); + + // 残響の長さを設定 + if ( (menuNum == 1) && (barReverb->Slide()) ) + reverb.SetDelay(barReverb->GetIntValue()); // 周波数シフトの値の設定 if ( (menuNum == 2) && (barFqCh->Slide()) ) { frqLabel->Draw(barFqCh->GetIntValue()); - shifter.SetFrequensy(barFqCh->GetIntValue()); + shifter.SetFrequency(barFqCh->GetIntValue()); } - // 信号処理の種類の切り替え - if (menu->GetTouchedNumber(menuNum)) - switch (menuNum) - { - case 0: barEcho->Inactivate(); // Through - barFqCh->Inactivate(); - frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT); - break; - case 1: barEcho->Activate(); // Echo - barFqCh->Inactivate(); - frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT); - break; - case 2: barEcho->Inactivate(); // Frequency shifter - barFqCh->Activate(); - frqLabel->Redraw(GuiBase::ENUM_TEXT); - break; - } - //--------------------------------------------- // 1フレーム分の信号処理を行い,その結果を出力する - if ( mySai.IsCompleted()) + if (mySai.IsCompleted()) { for (int n=0; n<mySai.GetLength(); n++) { int16_t xL, xR; mySai.Input(xL, xR); int16_t xn = xL + xR; - snIn[n] = xn; // 表示用 + snIn[n] = xn; // 表示用 //------------------------------------------------------- - // 信号処理実行 - int16_t yn = (int16_t)func[menuNum]->Execute((float)xn); + int16_t yn = func[menuNum]->Execute(xn); // 信号処理実行 //------------------------------------------------------- mySai.Output(yn, yn); // 左右チャンネルに同じ信号を出力