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

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Mon Apr 10 13:44:13 2017 +0000
Parent:
9:1221ba81a1bb
Commit message:
11

Changed in this revision

BSP_DISCO_F746NG.lib Show diff for this revision Revisions of this file
F746_GUI.lib Show annotated file Show diff for this revision Revisions of this file
LCD_DISCO_F746NG.lib Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/Biquad.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/Coefficients.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/Echo.hpp Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/EffectorInitializeGUI.hpp Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/GuiChanger.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/IIR_Cascade.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/InitializeGUI.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/ProcessingBase.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/ReverbUnit.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/ReverbUnitBase.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/Reverberator.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/WaveformDisplay.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/WeaverModulator.hpp Show annotated file Show diff for this revision Revisions of this file
TS_DISCO_F746NG.lib Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- 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
--- 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
--- 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
--- 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();
--- 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 変調器で使う低域通過フィルタの係数
--- 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
--- 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
--- /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
--- 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 
--- /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
--- 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
-
--- 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
--- /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
--- /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
--- 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& );
--- 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
--- 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
--- 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);   // 左右チャンネルに同じ信号を出力