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

Committer:
MikamiUitOpen
Date:
2016-02-24
Revision:
0:a98746e7a170

File content as of revision 0:a98746e7a170:

//------------------------------------------------------------
//  合成母音発生器+キーボード
//  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;
        }
    }
}