Synthesizer for Japanese five vowels with keyboard. 鍵盤と一緒になった日本語の5母音の合成器.
Dependencies: BSP_DISCO_F746NG_patch_fixed BUTTON_GROUP LCD_DISCO_F746NG TS_DISCO_F746NG mbed
main.cpp@0:a98746e7a170, 2016-02-24 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Wed Feb 24 13:00:12 2016 +0000
- Revision:
- 0:a98746e7a170
1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 0:a98746e7a170 | 1 | //------------------------------------------------------------ |
MikamiUitOpen | 0:a98746e7a170 | 2 | // 合成母音発生器+キーボード |
MikamiUitOpen | 0:a98746e7a170 | 3 | // Vowel synthesizer with keyboard |
MikamiUitOpen | 0:a98746e7a170 | 4 | // タッチしている母音に対応する音が出る |
MikamiUitOpen | 0:a98746e7a170 | 5 | // 黒鍵はサポートしていない |
MikamiUitOpen | 0:a98746e7a170 | 6 | // |
MikamiUitOpen | 0:a98746e7a170 | 7 | // 2016/02/24, Copyright (c) 2016 MIKAMI, Naoki |
MikamiUitOpen | 0:a98746e7a170 | 8 | //------------------------------------------------------------ |
MikamiUitOpen | 0:a98746e7a170 | 9 | |
MikamiUitOpen | 0:a98746e7a170 | 10 | #include "button_group.hpp" |
MikamiUitOpen | 0:a98746e7a170 | 11 | #include "sai_io_o.hpp" |
MikamiUitOpen | 0:a98746e7a170 | 12 | #include "Rosenberg.hpp" // 合成声帯波用 |
MikamiUitOpen | 0:a98746e7a170 | 13 | #include "Resonator.hpp" // 共振器用 |
MikamiUitOpen | 0:a98746e7a170 | 14 | #include "Radiator.hpp" // 放射の効果用 |
MikamiUitOpen | 0:a98746e7a170 | 15 | |
MikamiUitOpen | 0:a98746e7a170 | 16 | using namespace Mikami; |
MikamiUitOpen | 0:a98746e7a170 | 17 | |
MikamiUitOpen | 0:a98746e7a170 | 18 | const uint32_t N_DATA_ = 300;//1400; |
MikamiUitOpen | 0:a98746e7a170 | 19 | |
MikamiUitOpen | 0:a98746e7a170 | 20 | SaiIO_O mySai_(N_DATA_, I2S_AUDIOFREQ_16K); |
MikamiUitOpen | 0:a98746e7a170 | 21 | |
MikamiUitOpen | 0:a98746e7a170 | 22 | const int N_VWL_ = 5; // 母音の種類の数 |
MikamiUitOpen | 0:a98746e7a170 | 23 | const int N_RSN_ = 3; // 共振器の数 |
MikamiUitOpen | 0:a98746e7a170 | 24 | |
MikamiUitOpen | 0:a98746e7a170 | 25 | // フォルマント周波数,帯域幅のデータ:{周波数, 帯域幅} |
MikamiUitOpen | 0:a98746e7a170 | 26 | const Resonator::FrBw FORMANT_[N_VWL_][N_RSN_] = |
MikamiUitOpen | 0:a98746e7a170 | 27 | {{ {654, 50}, {1060, 55}, {2375, 60} }, // ア |
MikamiUitOpen | 0:a98746e7a170 | 28 | { {302, 40}, {2057, 60}, {3004, 65} }, // イ |
MikamiUitOpen | 0:a98746e7a170 | 29 | { {375, 45}, {1208, 55}, {2165, 60} }, // ウ |
MikamiUitOpen | 0:a98746e7a170 | 30 | { {541, 50}, {1784, 60}, {2452, 60} }, // エ |
MikamiUitOpen | 0:a98746e7a170 | 31 | { {458, 45}, { 807, 50}, {2379, 60} }}; // オ |
MikamiUitOpen | 0:a98746e7a170 | 32 | |
MikamiUitOpen | 0:a98746e7a170 | 33 | int main() |
MikamiUitOpen | 0:a98746e7a170 | 34 | { |
MikamiUitOpen | 0:a98746e7a170 | 35 | const float FS = I2S_AUDIOFREQ_16K; // 標本化周波数: 16 kHz |
MikamiUitOpen | 0:a98746e7a170 | 36 | const float F0 = 125.0f; // 基本周波数:125 Hz |
MikamiUitOpen | 0:a98746e7a170 | 37 | const float A0 = 10000.0f; // 声帯波の振幅 |
MikamiUitOpen | 0:a98746e7a170 | 38 | const float A0M[N_VWL_] = // 声帯波の倍率 |
MikamiUitOpen | 0:a98746e7a170 | 39 | { 1.0f, 3.0f, 2.0f, 1.0f, 1.0f }; |
MikamiUitOpen | 0:a98746e7a170 | 40 | |
MikamiUitOpen | 0:a98746e7a170 | 41 | Rosenberg gs(F0, FS, A0); // 声帯波発生用オブジェクト初期化 |
MikamiUitOpen | 0:a98746e7a170 | 42 | Resonator rs[N_RSN_]; // 共振器用オブジェクト配列の宣言 |
MikamiUitOpen | 0:a98746e7a170 | 43 | Radiator rd(0.8f); // 放射の効果用オブジェクトの初期化 |
MikamiUitOpen | 0:a98746e7a170 | 44 | |
MikamiUitOpen | 0:a98746e7a170 | 45 | LCD_DISCO_F746NG lcd; // LCD 用オブジェクト |
MikamiUitOpen | 0:a98746e7a170 | 46 | const uint32_t BACK_COLOR = 0xFF006A6C; // Teal green |
MikamiUitOpen | 0:a98746e7a170 | 47 | const uint32_t TOUCHED_COLOR = 0xFF7F7FFF; |
MikamiUitOpen | 0:a98746e7a170 | 48 | const uint32_t ORIGINAL_COLOR = 0xFF0068B7; |
MikamiUitOpen | 0:a98746e7a170 | 49 | |
MikamiUitOpen | 0:a98746e7a170 | 50 | lcd.Clear(BACK_COLOR); |
MikamiUitOpen | 0:a98746e7a170 | 51 | lcd.SetBackColor(BACK_COLOR); |
MikamiUitOpen | 0:a98746e7a170 | 52 | lcd.SetTextColor(LCD_COLOR_WHITE); |
MikamiUitOpen | 0:a98746e7a170 | 53 | lcd.SetFont(&Font20); |
MikamiUitOpen | 0:a98746e7a170 | 54 | lcd.DisplayStringAt(0, 10, (uint8_t *)"Vowel Synthesizer", CENTER_MODE); |
MikamiUitOpen | 0:a98746e7a170 | 55 | |
MikamiUitOpen | 0:a98746e7a170 | 56 | TS_DISCO_F746NG ts; // タッチパネル用オブジェクト |
MikamiUitOpen | 0:a98746e7a170 | 57 | const string FIVE_VOEWLS[N_VWL_] = {"a", "i", "u", "e", "o"}; |
MikamiUitOpen | 0:a98746e7a170 | 58 | ButtonGroup vowel(lcd, ts, 10, 40, 50, 40, |
MikamiUitOpen | 0:a98746e7a170 | 59 | ORIGINAL_COLOR, BACK_COLOR, |
MikamiUitOpen | 0:a98746e7a170 | 60 | N_VWL_, FIVE_VOEWLS, 0, 5, 1, Font20); |
MikamiUitOpen | 0:a98746e7a170 | 61 | vowel.Draw(0, TOUCHED_COLOR); |
MikamiUitOpen | 0:a98746e7a170 | 62 | |
MikamiUitOpen | 0:a98746e7a170 | 63 | // 白鍵用 |
MikamiUitOpen | 0:a98746e7a170 | 64 | const string NO_CHAR[8] = {"", "", "", "", "", "", "", ""}; |
MikamiUitOpen | 0:a98746e7a170 | 65 | const int X0S = 90; |
MikamiUitOpen | 0:a98746e7a170 | 66 | const int Y0S = 120; |
MikamiUitOpen | 0:a98746e7a170 | 67 | const int WIDTH = 43; |
MikamiUitOpen | 0:a98746e7a170 | 68 | ButtonGroup scale(lcd, ts, X0S, Y0S, WIDTH, 140, |
MikamiUitOpen | 0:a98746e7a170 | 69 | LCD_COLOR_WHITE, BACK_COLOR, |
MikamiUitOpen | 0:a98746e7a170 | 70 | 8, NO_CHAR, 5, 0, 8); |
MikamiUitOpen | 0:a98746e7a170 | 71 | |
MikamiUitOpen | 0:a98746e7a170 | 72 | const float F_DO = 110.0f*powf(2, 3.0f/12.0f); |
MikamiUitOpen | 0:a98746e7a170 | 73 | const float F_OCTAVE[8] = |
MikamiUitOpen | 0:a98746e7a170 | 74 | { F_DO, F_DO*powf(2, 2.0f/12.0f), |
MikamiUitOpen | 0:a98746e7a170 | 75 | F_DO*powf(2, 4.0f/12.0f), F_DO*powf(2, 5.0f/12.0f), |
MikamiUitOpen | 0:a98746e7a170 | 76 | F_DO*powf(2, 7.0f/12.0f), F_DO*powf(2, 9.0f/12.0f), |
MikamiUitOpen | 0:a98746e7a170 | 77 | F_DO*powf(2, 11.0f/12.0f), F_DO*2}; |
MikamiUitOpen | 0:a98746e7a170 | 78 | |
MikamiUitOpen | 0:a98746e7a170 | 79 | // 黒鍵用(音は出ない) |
MikamiUitOpen | 0:a98746e7a170 | 80 | const int H0 = 70; |
MikamiUitOpen | 0:a98746e7a170 | 81 | const int X0B = X0S+WIDTH/2+5; |
MikamiUitOpen | 0:a98746e7a170 | 82 | const int WB = WIDTH-5; |
MikamiUitOpen | 0:a98746e7a170 | 83 | const int MPOS = WIDTH + 5; |
MikamiUitOpen | 0:a98746e7a170 | 84 | lcd.SetTextColor(LCD_COLOR_BLACK); |
MikamiUitOpen | 0:a98746e7a170 | 85 | lcd.FillRect(X0B, Y0S, WB, H0); |
MikamiUitOpen | 0:a98746e7a170 | 86 | lcd.FillRect(X0B+MPOS, Y0S, WB, H0); |
MikamiUitOpen | 0:a98746e7a170 | 87 | lcd.FillRect(X0B+MPOS*3, Y0S, WB, H0); |
MikamiUitOpen | 0:a98746e7a170 | 88 | lcd.FillRect(X0B+MPOS*4, Y0S, WB, H0); |
MikamiUitOpen | 0:a98746e7a170 | 89 | lcd.FillRect(X0B+MPOS*5, Y0S, WB, H0); |
MikamiUitOpen | 0:a98746e7a170 | 90 | |
MikamiUitOpen | 0:a98746e7a170 | 91 | // 男声,女声 |
MikamiUitOpen | 0:a98746e7a170 | 92 | const string MF[2] ={"M", "F"}; |
MikamiUitOpen | 0:a98746e7a170 | 93 | ButtonGroup mf(lcd, ts, X0S, 40, 60, 40, |
MikamiUitOpen | 0:a98746e7a170 | 94 | ORIGINAL_COLOR, BACK_COLOR, |
MikamiUitOpen | 0:a98746e7a170 | 95 | 2, MF, 5, 0, 2, Font20); |
MikamiUitOpen | 0:a98746e7a170 | 96 | mf.Draw(0, TOUCHED_COLOR); |
MikamiUitOpen | 0:a98746e7a170 | 97 | |
MikamiUitOpen | 0:a98746e7a170 | 98 | mySai_.InitCodecOut(); |
MikamiUitOpen | 0:a98746e7a170 | 99 | mySai_.OutPause(); |
MikamiUitOpen | 0:a98746e7a170 | 100 | |
MikamiUitOpen | 0:a98746e7a170 | 101 | float f0 = 1; |
MikamiUitOpen | 0:a98746e7a170 | 102 | int mf0 = -1; |
MikamiUitOpen | 0:a98746e7a170 | 103 | int sw0 = -1; |
MikamiUitOpen | 0:a98746e7a170 | 104 | // 共振器の準備 |
MikamiUitOpen | 0:a98746e7a170 | 105 | for (int k=0; k<N_RSN_; k++) |
MikamiUitOpen | 0:a98746e7a170 | 106 | rs[k] = Resonator(FORMANT_[0][k], FS); |
MikamiUitOpen | 0:a98746e7a170 | 107 | // 声帯波の振幅設定 |
MikamiUitOpen | 0:a98746e7a170 | 108 | gs.SetAmplitude(A0*A0M[0]); |
MikamiUitOpen | 0:a98746e7a170 | 109 | |
MikamiUitOpen | 0:a98746e7a170 | 110 | int dore0 = -1; |
MikamiUitOpen | 0:a98746e7a170 | 111 | while (true) |
MikamiUitOpen | 0:a98746e7a170 | 112 | { |
MikamiUitOpen | 0:a98746e7a170 | 113 | int mfNow; |
MikamiUitOpen | 0:a98746e7a170 | 114 | if (mf.GetTouchedNumber(mfNow, TOUCHED_COLOR)) |
MikamiUitOpen | 0:a98746e7a170 | 115 | { |
MikamiUitOpen | 0:a98746e7a170 | 116 | if (mfNow != mf0) |
MikamiUitOpen | 0:a98746e7a170 | 117 | { |
MikamiUitOpen | 0:a98746e7a170 | 118 | // 男声,女声の切り替え |
MikamiUitOpen | 0:a98746e7a170 | 119 | f0 = (mfNow == 0) ? 1.0f : 2.0f; |
MikamiUitOpen | 0:a98746e7a170 | 120 | mf0 = mfNow; |
MikamiUitOpen | 0:a98746e7a170 | 121 | } |
MikamiUitOpen | 0:a98746e7a170 | 122 | } |
MikamiUitOpen | 0:a98746e7a170 | 123 | |
MikamiUitOpen | 0:a98746e7a170 | 124 | int sw; |
MikamiUitOpen | 0:a98746e7a170 | 125 | if (vowel.GetTouchedNumber(sw, TOUCHED_COLOR)) |
MikamiUitOpen | 0:a98746e7a170 | 126 | { |
MikamiUitOpen | 0:a98746e7a170 | 127 | if (sw != sw0) |
MikamiUitOpen | 0:a98746e7a170 | 128 | { |
MikamiUitOpen | 0:a98746e7a170 | 129 | // 共振器の準備 |
MikamiUitOpen | 0:a98746e7a170 | 130 | for (int k=0; k<N_RSN_; k++) |
MikamiUitOpen | 0:a98746e7a170 | 131 | rs[k] = Resonator(FORMANT_[sw][k], FS); |
MikamiUitOpen | 0:a98746e7a170 | 132 | // 声帯波の振幅設定 |
MikamiUitOpen | 0:a98746e7a170 | 133 | gs.SetAmplitude(A0*A0M[sw]); |
MikamiUitOpen | 0:a98746e7a170 | 134 | |
MikamiUitOpen | 0:a98746e7a170 | 135 | sw0 = sw; |
MikamiUitOpen | 0:a98746e7a170 | 136 | } |
MikamiUitOpen | 0:a98746e7a170 | 137 | } |
MikamiUitOpen | 0:a98746e7a170 | 138 | int dore; |
MikamiUitOpen | 0:a98746e7a170 | 139 | if (scale.GetTouchedNumber(dore)) // キーがタッチされている場合 |
MikamiUitOpen | 0:a98746e7a170 | 140 | { |
MikamiUitOpen | 0:a98746e7a170 | 141 | if (dore != dore0) // タッチするキーが変わった場合 |
MikamiUitOpen | 0:a98746e7a170 | 142 | { |
MikamiUitOpen | 0:a98746e7a170 | 143 | // 音階に対応する基本周期に設定 |
MikamiUitOpen | 0:a98746e7a170 | 144 | gs.SetPeriod(F_OCTAVE[dore]*f0); |
MikamiUitOpen | 0:a98746e7a170 | 145 | dore0 = dore; |
MikamiUitOpen | 0:a98746e7a170 | 146 | mySai_.OutResume(); |
MikamiUitOpen | 0:a98746e7a170 | 147 | } |
MikamiUitOpen | 0:a98746e7a170 | 148 | |
MikamiUitOpen | 0:a98746e7a170 | 149 | if (mySai_.IsXferred()) |
MikamiUitOpen | 0:a98746e7a170 | 150 | { |
MikamiUitOpen | 0:a98746e7a170 | 151 | for (int n=0; n<mySai_.GetLength(); n++) |
MikamiUitOpen | 0:a98746e7a170 | 152 | { |
MikamiUitOpen | 0:a98746e7a170 | 153 | float gn = gs.Execute(); // 合成声帯波発生 |
MikamiUitOpen | 0:a98746e7a170 | 154 | float vn = gn; // 声帯波を声道へ入力 |
MikamiUitOpen | 0:a98746e7a170 | 155 | for (int k=0; k<N_RSN_; k++) |
MikamiUitOpen | 0:a98746e7a170 | 156 | vn = rs[k].Execute(vn); // 声道の効果 |
MikamiUitOpen | 0:a98746e7a170 | 157 | float yn = rd.Execute(vn); // 放射の効果 |
MikamiUitOpen | 0:a98746e7a170 | 158 | |
MikamiUitOpen | 0:a98746e7a170 | 159 | mySai_.Output(yn, gn); |
MikamiUitOpen | 0:a98746e7a170 | 160 | } |
MikamiUitOpen | 0:a98746e7a170 | 161 | mySai_.ResetXferred(); |
MikamiUitOpen | 0:a98746e7a170 | 162 | } |
MikamiUitOpen | 0:a98746e7a170 | 163 | } |
MikamiUitOpen | 0:a98746e7a170 | 164 | else // キーがタッチされていない場合 |
MikamiUitOpen | 0:a98746e7a170 | 165 | { |
MikamiUitOpen | 0:a98746e7a170 | 166 | mySai_.OutPause(); |
MikamiUitOpen | 0:a98746e7a170 | 167 | mySai_.ClearOutBuffer(); |
MikamiUitOpen | 0:a98746e7a170 | 168 | dore0 = -1; |
MikamiUitOpen | 0:a98746e7a170 | 169 | } |
MikamiUitOpen | 0:a98746e7a170 | 170 | } |
MikamiUitOpen | 0:a98746e7a170 | 171 | } |