Synthesizer for Japanese five vowels with keyboard. 鍵盤と一緒になった日本語の5母音の合成器.

Dependencies:   BSP_DISCO_F746NG_patch_fixed BUTTON_GROUP LCD_DISCO_F746NG TS_DISCO_F746NG mbed

Revision:
0:a98746e7a170
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Feb 24 13:00:12 2016 +0000
@@ -0,0 +1,171 @@
+//------------------------------------------------------------
+//  合成母音発生器+キーボード
+//  Vowel synthesizer with keyboard
+//      タッチしている母音に対応する音が出る
+//      黒鍵はサポートしていない
+//      
+//  2016/02/24, Copyright (c) 2016 MIKAMI, Naoki
+//------------------------------------------------------------
+
+#include "button_group.hpp"
+#include "sai_io_o.hpp"
+#include "Rosenberg.hpp"    // 合成声帯波用
+#include "Resonator.hpp"    // 共振器用
+#include "Radiator.hpp"     // 放射の効果用
+
+using namespace Mikami;
+
+const uint32_t N_DATA_ = 300;//1400;
+
+SaiIO_O mySai_(N_DATA_, I2S_AUDIOFREQ_16K);
+
+const int N_VWL_ = 5;   // 母音の種類の数
+const int N_RSN_ = 3;   // 共振器の数
+
+// フォルマント周波数,帯域幅のデータ:{周波数, 帯域幅}
+const Resonator::FrBw FORMANT_[N_VWL_][N_RSN_] =
+    {{ {654, 50}, {1060, 55}, {2375, 60} },     // ア
+     { {302, 40}, {2057, 60}, {3004, 65} },     // イ
+     { {375, 45}, {1208, 55}, {2165, 60} },     // ウ
+     { {541, 50}, {1784, 60}, {2452, 60} },     // エ
+     { {458, 45}, { 807, 50}, {2379, 60} }};    // オ
+
+int main()
+{
+    const float FS = I2S_AUDIOFREQ_16K; // 標本化周波数: 16 kHz
+    const float F0 = 125.0f;    // 基本周波数:125 Hz
+    const float A0 = 10000.0f;  // 声帯波の振幅
+    const float A0M[N_VWL_] =   // 声帯波の倍率
+        { 1.0f, 3.0f, 2.0f, 1.0f, 1.0f };
+    
+    Rosenberg gs(F0, FS, A0);   // 声帯波発生用オブジェクト初期化
+    Resonator rs[N_RSN_];       // 共振器用オブジェクト配列の宣言
+    Radiator rd(0.8f);          // 放射の効果用オブジェクトの初期化
+
+    LCD_DISCO_F746NG lcd;       // LCD 用オブジェクト
+    const uint32_t BACK_COLOR          = 0xFF006A6C;    // Teal green
+    const uint32_t TOUCHED_COLOR       = 0xFF7F7FFF;
+    const uint32_t ORIGINAL_COLOR      = 0xFF0068B7;
+
+    lcd.Clear(BACK_COLOR);
+    lcd.SetBackColor(BACK_COLOR);
+    lcd.SetTextColor(LCD_COLOR_WHITE);
+    lcd.SetFont(&Font20);
+    lcd.DisplayStringAt(0, 10, (uint8_t *)"Vowel Synthesizer", CENTER_MODE);
+    
+    TS_DISCO_F746NG ts;         // タッチパネル用オブジェクト
+    const string FIVE_VOEWLS[N_VWL_] = {"a", "i", "u", "e", "o"};
+    ButtonGroup vowel(lcd, ts, 10, 40, 50, 40,
+                      ORIGINAL_COLOR, BACK_COLOR,
+                      N_VWL_, FIVE_VOEWLS, 0, 5, 1, Font20);
+    vowel.Draw(0, TOUCHED_COLOR);
+                      
+    // 白鍵用
+    const string NO_CHAR[8] = {"", "", "", "", "", "", "", ""};
+    const int X0S = 90;
+    const int Y0S = 120;
+    const int WIDTH = 43;
+    ButtonGroup scale(lcd, ts, X0S, Y0S, WIDTH, 140,
+                      LCD_COLOR_WHITE, BACK_COLOR,
+                      8, NO_CHAR, 5, 0, 8);
+                      
+    const float F_DO = 110.0f*powf(2, 3.0f/12.0f);
+    const float F_OCTAVE[8] =
+        { F_DO, F_DO*powf(2, 2.0f/12.0f),
+          F_DO*powf(2, 4.0f/12.0f), F_DO*powf(2, 5.0f/12.0f),
+          F_DO*powf(2, 7.0f/12.0f), F_DO*powf(2, 9.0f/12.0f),
+          F_DO*powf(2, 11.0f/12.0f), F_DO*2};
+                        
+    // 黒鍵用(音は出ない)
+    const int H0 = 70;
+    const int X0B = X0S+WIDTH/2+5;
+    const int WB = WIDTH-5;
+    const int MPOS = WIDTH + 5;
+    lcd.SetTextColor(LCD_COLOR_BLACK);
+    lcd.FillRect(X0B, Y0S, WB, H0);
+    lcd.FillRect(X0B+MPOS, Y0S, WB, H0);
+    lcd.FillRect(X0B+MPOS*3, Y0S, WB, H0);
+    lcd.FillRect(X0B+MPOS*4, Y0S, WB, H0);
+    lcd.FillRect(X0B+MPOS*5, Y0S, WB, H0);
+    
+    // 男声,女声
+    const string MF[2] ={"M", "F"};
+    ButtonGroup mf(lcd, ts, X0S, 40, 60, 40,
+                   ORIGINAL_COLOR, BACK_COLOR,
+                   2, MF, 5, 0, 2, Font20);
+    mf.Draw(0, TOUCHED_COLOR);
+
+    mySai_.InitCodecOut();
+    mySai_.OutPause();
+
+    float f0 = 1;
+    int mf0 = -1;
+    int sw0 = -1;
+    // 共振器の準備
+    for (int k=0; k<N_RSN_; k++)
+        rs[k] = Resonator(FORMANT_[0][k], FS);
+    // 声帯波の振幅設定
+    gs.SetAmplitude(A0*A0M[0]);
+
+    int dore0 = -1;
+    while (true)
+    {
+        int mfNow;
+        if (mf.GetTouchedNumber(mfNow, TOUCHED_COLOR))
+        {
+            if (mfNow != mf0)
+            {
+                // 男声,女声の切り替え
+                f0 = (mfNow == 0) ? 1.0f : 2.0f;
+                mf0 = mfNow;
+            }
+        }
+
+        int sw;
+        if (vowel.GetTouchedNumber(sw, TOUCHED_COLOR))
+        {
+            if (sw != sw0)
+            {
+                // 共振器の準備
+                for (int k=0; k<N_RSN_; k++)
+                    rs[k] = Resonator(FORMANT_[sw][k], FS);
+                // 声帯波の振幅設定
+                gs.SetAmplitude(A0*A0M[sw]);
+
+                sw0 = sw;        
+            }
+        }
+        int dore;
+        if (scale.GetTouchedNumber(dore))   // キーがタッチされている場合
+        {
+            if (dore != dore0)  // タッチするキーが変わった場合
+            {
+                // 音階に対応する基本周期に設定
+                gs.SetPeriod(F_OCTAVE[dore]*f0);
+                dore0 = dore;
+                mySai_.OutResume();
+            }
+            
+            if (mySai_.IsXferred())
+            {
+                for (int n=0; n<mySai_.GetLength(); n++)
+                {
+                    float gn = gs.Execute();    // 合成声帯波発生
+                    float vn = gn;              // 声帯波を声道へ入力
+                    for (int k=0; k<N_RSN_; k++)
+                        vn = rs[k].Execute(vn); // 声道の効果
+                    float yn = rd.Execute(vn);  // 放射の効果
+
+                    mySai_.Output(yn, gn);
+                }
+                mySai_.ResetXferred();    
+            }
+        }
+        else                                // キーがタッチされていない場合
+        {
+            mySai_.OutPause();
+            mySai_.ClearOutBuffer();
+            dore0 = -1;
+        }
+    }
+}