Synthesizer for Japanese five vowels with keyboard. 鍵盤と一緒になった日本語の5母音の合成器.
Dependencies: BSP_DISCO_F746NG_patch_fixed BUTTON_GROUP LCD_DISCO_F746NG TS_DISCO_F746NG mbed
Diff: main.cpp
- 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; + } + } +}