【This Web Policy】
You should make JavaScript available to read this page.
Please enable the execution of JavaScript!



























μ-iVoice Text-To-Speech API

JavaScriptだけで実現した音声合成エンジン

  【リンクフリー】 私設研究所ネオテックラボ Neo-Tech-Lab.co.uk
【記載者】 私設研究所Neo-Tech-Lab.com 上田智章 ☆Tomoaki Ueda☆ NTLMMD
  ●【Neo-Tech-Lab】トップページ  ●【Google音声合成Text-To-Speech】  ●【WebGL】  ●【MikuMikuDance関連】記事メニュー
 
ここにチェックボックス型外部コンテンツ・メニューが入ります。

■記載日2011年01月21日■08:00頃記載
【μ-iVoiceについて】
μ-iVoiceは、現状のブラウザでプラグインなしにJavaScriptだけで動作させることを想定したコンパクトな音声合成エンジンです。
現在、Version 0.09Cのμ-iVoiceを公開中です。
対象ブラウザは、Google Chrome, Mozilla Fire Fox, Apple Safariになります。
Text-To-Speech API(テキスト読み上げAPI)ですが、抑揚コントロールのための簡易なスクリプトを実装しています。
さらに、元がシンセサイザーなので、シンセサイザー演奏モードと簡易ボカロの機能があります。
ローカルに音声データファイルを用意すれば、ドラッグドロップで組込が行えるので、任意の話者で発声が可能です。
レンダリング速度を重視した結果、音声合成アルゴリズムは、変形DDS (Direct Digital Synthesizser)を用いることにしました。
HTML5で導入されたaudioタグのソースにBase64形式のData URIを与えて、Data Schemeを使って再生を行っています。
IEは、.wav形式のData Schemeに対応していないようなので使えません。
波形レンダリング・アルゴリズムをMPEGに対応させれば、解決するのでしょうが、
まだMPEGエンコーダを自力コーディングする能力が不足しているのと、
ブラウザ側の処理能力も低いので、Native Clientが標準実装される頃に再考してみたいと思います。
μ-iVoiceは、JavaScriptだけで記述されているので、『ソースを表示』すればソース閲覧が可能です。
このページではその他の詳細情報をメモしておきます。(私はすぐに忘れるので.....)

【μ-iVoice】『Webで使える音声合成/シンセサイザAPI』

μ-iVoiceは私設研究所Neo-Tech-Lab.com特製の音声合成APIです。現在、Version0.09Cです。
0.5秒スパン、135音の音声データ(モノラル, 16bit, 22.050kHz)を使って発声を行います。
但し、ソースは子音等の扱いに関して処理をはしょったレンダリング速度最優先の音質劣化バージョンとさせていただいています。是非、本家Ⅱのレンダリング速度とJavaScript DDS方式を比べてみて下さい。
初回のアクセスは少しお待ちいただく必要があります。
スタートまでの時間がかかるのは、90秒分のメッセージと2分21秒分のシンセサイザー演奏デモのレンダリングを行っているためです。デモの初期化部分を外せば短時間で立ち上がります。
(自分の声はいくらエディットしてもなんか癖を感じ、やっぱりキモイのでアップしませんが。)
音声データ記録ツール(Excel VBA)を使って音声データの作成・編集を行うことができます。
音声データの交換により、任意話者による発声を行うことができます。
将来目標は、『あいうえお』の5音登録だけで任意話者に対応することです。
現在のところ、ひらがなのみ発声可能です。漢字⇒かな変換は開発中です。文字数の制約はありません。
簡単な半角英数字のスクリプトによる制御コードを挟めば、アクセントやイントネーション、歌唱が可能です。自動抑揚付与も開発中です。
発声原理は、変形DDS(Direct Digital Synthesizer)アルゴリズムを用いています。
今後は、波形レンダリング処理にもう少し手を加えて、音質の向上を行います。

【サイト埋め込み方法の例】
【1】 <iframe border="0" src="http://www.geocities.jp/ivoiceapi/index.htm" width=720px height="1150px"></iframe>

【2】 <iframe border="0" src="http://neotechlab.web.fc2.com/index.htm" width=800px height="1200px"></iframe>


【Version0.09までの実装機能履歴】

【第1次試作】/2011/08/09/~/2011/08/12/
 【Version0.01】/2011/08/09/
   ●DDS(Direct Digital Synthesizer)によるMIDIデータ演奏(ステレオ,16bit,44.1kHz)
 【Version0.02】/2011/08/09/
   ●アタック、消退
 【Version0.03】/2011/08/10/
   ●ドラムパートの追加
 【Version0.04】/2011/08/10/
   ●内部データ形式の変更と1秒単位の波形レンダリングに変更
 【Version0.05】/2011/08/12/
   ●音声パートの追加
 【Version0.06】/2011/08/12/
   ●スピーチ機能の追加
【第2次試作】/2011/12/29/~/2012/01/19/
 【Version0.07】/2012/01/02/
   ▼ブラウザ改訂の悪影響で1MBを超えるBase64⇒Binaryに問題が発生したので、これを解決。
    ●音声データ及びドラムデータを疑似JSONPからBase64形式.wavファイルに変更
   ●ステレオ, 16bit, 44.1kHz⇒モノラル, 16bit, 22.05kHz(読込速度の問題で劣化)
   ●抑揚(音階、長さ、強さ)を制御するScriptを実装
 【Version0.08】/2012/01/10/
   ●音声データのレンダリング方式の変更(1000倍の時間分解能でスムージング)
   ●ローカルの.wav形式音声データファイルをセレクトあるいはドラッグドロップでNTL_Voiceに組込み可能
    録音ツールで録音・編集した音声データを使って任意話者での音声合成を行うことができます。
   ●応答メッセージ読み上げ機能
 【Version0.09】/2012/01/15/
   ●カナ、漢字や数字の音読み、訓読み機能の追加
    (膨大な量のデータベース構築が必要なので小学校レベルで徐々に拡充の予定)
    熟語については今後対応の予定
   ●漢字辞書に読み替えひらがなを登録しているが、制御スクリプトも書き込めるので抑揚自動付与が可能

【開発中の機能】

【第3次試作】/2012/01/20/~
  ■子音と母音の抽出速度制御
  ■任意話者の『あいうえお』の5音のサンプル音だけからの物真似発声(ターミネーター音声ハック機能)

【μ-iVoice開発予定】

【Version1.0】/2012/06/14/~
漸くμ-iVoice Version1.0の女性ナレーターが内定しそう。
音声チャット会議でオリジナル・キャラ(PMDモデル)と合わせて開発開始という事になった。
モデル案はリアルとバーチャルの2案があるのでどちらに決まるかはわからないが、
キャラ設定は次回リアル会議で決定の予定。

【シンセサイザの各音階の周波数の設定について】

■記載日2012年1月13日■23:58頃記載
シンセサイザの各音階の周波数は
 1) 基準となる周波数はA4[ラ]で440Hzである。
 2) 12平均律(右隣の半音は2^(1/12)=1.0594630943593倍の周波数である。)を使う。
の2点だけを知っていれば簡単に求めることができる。
下表は、Excelで計算した各音階の周波数リストである。

  

【どうして別人の物真似ができるのか?:標準子音と任意母音の合成】

■記載日2012年1月14日■02:45頃記載
どうして、ものまね芸人は他人の声をうまくまねることができるのか考えてみた。
『子音はきっと誰の声でもそんなに差異がないのでは?』あるいは『子音は広帯域スペクトルなので特徴認識しにくいのでは?』との考えに至った。
MikuMikuDanceの作者、樋口優さんのホームページにある優れものツール『MikuMikuVoice』(1.5 なんちゃってツール)を使って、自分の音声と初音ミクの音声について、幾つかの子音部分だけを聴き比べてみたら、やはり区別することはできなかった。
私の耳で確認した範囲では、子音には音の高低を判断できる成分(線スペクトル)が含まれていないように思われる。子音だけでは男女の区別もつかないようだ。
それではと考え、私の『か』の音の子音部分の後ろに初音ミクの『あ』の音を接続して聞いてみたところ、ちゃんと初音ミクが『か』と発音しているように聞き取れるではないか。
人間の聴力では、細かな差異は認識しにくく、線スペクトルの何本かの特徴で人の声を聞き分けているのだろう。
だから、予め、Aさんの子音のデータベースを作り、Bさんの『あ』『い』『う』『え』『お』の5音の声で合成すれば、Bさんの声に聞こえるはずだ。
多分、任意の話者Bさんの『あ』『い』『う』『え』『お』の5音を採録するだけで、ほぼBさんそっくりの声が出せるはずだ。
普段の会話の一部でも録音できれば、母音を5音とも抽出することができる。映画のターミネーターのように他人の声をハックすることができるわけだ。
これは相当な工数削減が望めそうだし、データ圧縮が期待できる。
加えて、母音の音声データだけなら、2.5次元FDTDによる解析ができ、MRIスライスデータがあれば演算で求めることもできる。
つまり3次元人体構造が判明していれば、その人物の声を聴かずに、声を再現することができるわけだ。

  
  【図】子音と母音の合成

  
  【図】MikuMikuVoiceによる選択部分の再生
    44.1kHz, 16bitの.wav形式ファイルが読み込める。+ボタンで拡大ができ、マウスドラッグで領域選択した部分を『再生』で聞き取ることができる。

【子音、母音と音階の関係について】

■記載日2012年1月14日■22:37頃記載
子音は一般に広帯域スペクトルを持った過渡応答波形であるので、線スペクトルを殆ど有していない。
このため、音階として認識されるのは、母音の成分の方であるはずだ。
実際に、『か』でドレミファソラシドを発声してみた。
MikuMikuVoiceで子音の部分だけを聞いてみたが、やはり音階は持たなかった。
従って、過渡応答波形である子音部分は音階によらず、録音時のサンプリングレートで再生し、
母音だけを音階に対応した周波数で再生すればよいことがわかる。



【音声データ補間法について】

■記載日2012年1月18日■21:50頃記載
既に20年以上前の技術なので記載しておく。
音声データのサンプリング速度は、Version0.006で44.1kHz、Version0.007~0.009で22.05kHzである。
DDS (Direct Digital Synthesizer)では、この音声データが再生周波数で決まる時間幅で読みだされる。
再生周波数がサンプリング周波数に近ければそれほど問題は生じないが、
周波数が低いと、同じデータが複数回連続して読み出され、周波数が高いと、間が飛んでしまう。
つまり、時刻分解能が劣化してしまうので、音質劣化につながる。
これを回避するために、サンプリング関数(sinx/x)による補間と直線補間を組み合わせた方法を採用している。
1968年に出版された電気学会の『測定値の統計処理』にサンプリング関数による補間法が記載されている。
採用方法では、4つのサンプル(w0,w1,w2,w3)を使い、両端の2点(w0,w3)を使って直線補間を行う。
中央2個のサンプル位置での直線補間値をw1とw2から取り除き、残りの量に対してサンプリング補間を行う。
サンプリング関数は最初に1000倍程度の時間分解能で求めておけば、テーブル参照だけで補間を行うことができる。
参考までにExcel VBAでのコーディング例を示す。
補間処理実行時には、加減算と乗算だけで曲線補間を行うことができる。
この方法は非常に便利で、ノイズ除去やサンプリング速度変換等、様々な応用が可能だ。
3Dグラフィックスの場合には、Phong Shading等でベクトル補間の演算負荷を圧縮することができる。
波形データの場合にはデータ圧縮などにも応用が可能だ。



【Excel VBAの場合】

Public Iwave() As Single           '【サンプリング関数】0~π
Public Const nIwave As Long = 1000 '【補間配列の個数】サンプル間の分割数 実際のサイズはnIwave+1
Public w0, w1, w2, w3, w4, w5, w6 As Single 'w4:1/3 w5:nIwave w6:1/nIwave

'************************************************
'【CreateConstants】補間係数テーブル作成【Version0.08】+α
'************************************************
'●DDS劣化現象低減の為、補間演算で、より滑らかなデータを発生する
Public Sub CreateConstants()
   Dim Pi As Single, a As Single, x As Single, i As Long
   ReDim Iwave(nIwave)
   Pi = Atn(1#) * 4#
   a = Pi / nIwave
   Iwave(0) = 1#
   For i = 1 To nIwave
      x = i * a
      Iwave(i) = Sin(x) / x
   Next i
   w4 = 1# / 3#
   w5 = CSng(nIwave)
   w6 = 1# / nIwave
End Sub

'************************************************
'【CreateConstants】簡易曲線補間演算【Version0.08】+α
'************************************************
'●平成元年頃に産総研(当時は電子技術総合研究所)の基礎計測部 計測基礎研究室の
'葛西直子主任研究官が上田の特許2071969に関して改善提案された補間方法に基づく。
'ここでは4サンプル値(y0,y1,y2,y3)からy1~y2間の補間値を得る。
Public Function CalculationValue(ByRef buf() As Single, n As Long, x As Single) As Single
' buf(): 補間対象のデータ配列 n:配列要素数 x:小数点以下を補間
   Dim i, j As Long
   
   i = Int(x) '小数点以下を切り捨てて整数化
   '4サンプルを取得 w0, w1, w2, w3
   If i > 0 Then w0 = buf(i - 1) Else w0 = 0#
   w1 = buf(i)
   If (i + 1) < n Then w2 = buf(i + 1) Else w2 = 0#
   If (i + 2) < n Then w3 = buf(i + 2) Else w3 = 0#
   '補間処理
   i = Int((x - CSng(i)) * w5) 'xの小数点以下を補間関数のレンジにマッピング
   j = nIwave - i
   w3 = (w3 - w0) * w4
   w0 = w0 + w3
   w1 = w1 - w0
   w2 = w2 - w0 - w3
   w3 = w3 * w6
   CalculationValue = w0 + CSng(i) * w3 + w1 * Iwave(i) + w2 * Iwave(j)
End Function

【音声データ補間法について その2】データ圧縮

■記載日2012年1月21日■06:57頃記載
試に上記アルゴリズムを使ってデータ圧縮を試みた。 『あ』と『え』と『か』の変換結果を下に示す。
115200bpsというのは、8bitのデータを11.52kHzで非同期シリアル通信で伝送することを想定している。
圧縮後の結果を見る限り、ホームコンピュータ側で音声合成処理をかけた後で、
ZigBee(無線通信インターフェース)でサイボーグインターフェースまでデータを送信するのには十分使えそうだ。
母音は高周波成分を殆ど含まないから簡単だ。
ターミネーター音声ハックには十分使えそうに思える。
『か』の子音部分では流石にデータの劣化が見て取れる。まあなんとか使える範囲か?
子音の圧縮率は抑えて、時間の大半を占める母音部分の圧縮率を高めれば1/30位のデータ圧縮は届きそうに思える。
音声フォルマント周期を拾うエンコーダに手を出すべきか? 迷うところだ。

←『あ』の変換結果

←『え』の変換結果

←『か』の変換結果

【現状の問題点について】

■記載日2012年1月16日■00:47頃記載
Version0.09でローカル音声データの組み込みを試したところ、うまく機能した。但し、以下の点が課題として残る。
1.子音の長さと音階を揃えて録音しないと、少し違和感のある発声になる。
2.母音だけを周期音扱いして子音をドラムと同じ過渡音としていないので、音域が狭い。
3.ブラウザ側の制約で、音声データサイズが少し大きい。
  処理速度的にはデータ転送量を1/8程度に落とす事が好ましい。
4.漢字ボキャブラリが少ない。(今後拡充予定)
5."ー"(長音記号)に対応させる必要性
6.な行、ま行と'ん'については課題が残るが、ターミネータ音声ハックの子音/母音ブレンド機能の追加


子音先頭への位置合わせも自動化したいところ

■記載日2011年8月9日■23:54頃記載
【Web シンセサイザ/ボーカロイドを一から製作してみよう】
Vocaloid2エディタをインストールしていたノートパソコンが壊れたので、
別のパソコンにインストールしようとしたらインストールできない。
  (LANに接続しているのに『接続できない』とメッセージが出てそのせいかアクティベートできない!)
頭にきたので、シンセサイザとボーカロイド(正確には真似ロイド)を一から製作してみようと思い立つ。
JavaScriptだけでブラウザ上で音を合成し、再生できるように考えてみた。
前からMIDIコンポーザとVocaloid2エディタの往復はとても不便だった。どうせなら機能を統合してみよう。
  (かなり飽きっぽい性格なので、どうせ途中で飽きるだろうけど。)
取り敢えず、Google Chrome12, Mozilla FireFox5, Apple Safari5.1で動作するシンセサイザのコアを製作してみた。
FireFox5以外で動作することからわかるようにAudio出力API (audioタグの事ではない。) は使っていない。
【追記】DirectXのDirectSoundをブラウザから使えるようにしたらしいWeb Audioと言うのも使っていない。
今回はシンセサイザをハードウェア(CPLD)設計技術の一つであるDDS(Direct Digital Synthesizer)で構成してみたら、
思ったより短いコードで済んだ。あっさり動作した。こんなに簡単だとは思わなかった。

【Web MIDI】
  ●【Finland民謡】『Ieavan Polkka』 (スタンダード・ドラム・セット使用)
    波形データを演算(rendering)して、音が出るまで10秒~20秒程かかります。

まさかこんなにシンセサイザを作るのが簡単だとは思わなかったので、少しやる気が出たかも。
で、次はボーカロイドの方に着手。どうせなら、喋りと歌の両方ができるのを作ってみたい。
ただし、7月30日の記事で書いたYouTube動画の学習型発話器をソフトウェアで実行させる方式だ。
ミクの音源データを学習させて、ミクっぽい声を出させてみたい。
将来的には、3次元立体音響ホロフォニクス・コンポーザと統合する予定です。これは音波の頭部表面での反射によって発生する回折波を考慮した音波を演算することで音源位置を容易に把握できる音を演算する技術です。バイノーラル録音を行わずに演算だけで同一の効果を実現する事に対応しています。現在、Excel VBA程度で実行できるアルゴリズムを開発済みです。

■記載日2011年8月12日■09:21頃記載
【Web シンセサイザ/ボーカロイドを一から製作してみた】(第1次試作)
前はあんなに苦労していたのに、結構あっさりとカーネル(Kernel)の試作が完了してしまった。シンセサイザとボーカロイドの発声(なんちゃって初音ミク)と歌唱のコーディングを行い、取り敢えず、Google Chrome12, Mozilla FireFox5, Apple Safari5.1で動作する
シンセサイザ/ボーカロイドのカーネルを製作してみた。

【Web Vocaloid】
  【ロボティックな初音ミク風スピーチのサンプル】
   ●『なんちゃって初音ミク声でごあいさつ』(5~6秒の短いスピーチならすぐ)
    ☆ブラウザで『ソースを表示』すれば、JavaScriptのコードを見る事ができます。
    【注】現在、ブラウザ側のメモリリーク改定に伴って、文字列読込速度がフリーズする現象が出ております。(Localでは再生可能なのですが)Google Chrome, Apple Safari, Fire Foxで同じ現象がでています。Cross Domainに関するセキュリティー関連の改定が影響している可能性もあります。なので近いうちに書きなおします。

   ●【Finland民謡】『Ieavan Polkka』 (ドラム、なんちゃって初音ミク声付き)
   ■波形データを1曲分演算(rendering)して、再生まで10秒~20秒程かかります。
   ■stringや型付き変数のメモリリークの影響を受けるようだ。
    何回かページを連続表示するとクラッシュする場合がある。
    これはJavaScriptエンジンの問題なのでどうしようもない。
    再度ブラウザを起動してください。

【YouTube】サンプル音 テスト結果


■記載日2011年12月04日■10:37頃記載
【現在の作業と今後の予定】
 ●喉頭がんで声帯を失った人用のサイボーグ・インターフェース(音声再建)に応用展開中。
  ハードウェアはそのうち公開の予定。まずは音声合成部分からかな?
 ●現在、Web Agentにさせているサンプル音のAI学習は処理が遅いので、簡単なアルゴリズムに変更予定。
 ●20年程前に開発したアルゴリズムを使ってDDSアルゴリズムを改良中。
  データを圧縮しつつも、より自然な発声に近づくはず。
 ●毎回サウンドレコーダーやiTuneでファイル変換(.wma⇒.wav)するのが面倒になったので、
  Excel VBAで録音ツール製作開始。 古い手だが、Win32APIのWaveInを使う方法。
  44.1kSPS, 2ch, 16bitで音声入力をExcel Sheetに記録。学習用サンプルデータを保存。
   【Excel VBAツール】Win32APIのWaveInを使った録音ツール Version 0.01

【YouTube動画】

【実験用サイボーグインターフェース】


【実験用音声アドバイス機能付き浴槽心電計】
入浴者の心電図を湯水を介して無拘束で計測。虚血性心疾患の兆候や呼吸などをモニタしてアドバイスを行うエージェント・システム。

【動作原理について】(第1次試作)
FireFox5以外のブラウザで動作することからわかるようにAudio Data API(audioタグの事ではない。)は使っていない。
最近、Chromeで使えるようになったWeb Audio(DirectXのDirectSoundをJavaScriptで使えるようにしたもの?)も利用していない。
まだまだ改善するべき点は多いが、かなり短いコードで済んだ。とにかく動作原理の確認には成功した。
次は、初音ミクやその他のボーカロイドのサンプル音を本格的にWeb Agent Mikuを使ってAI学習させてみようと思う。
本家YAMAHAでは1000パターン以上のサンプルが必要らしいが、Web AgentにはAI学習機能でそんな必要はない。
合わせて、今回、子音と母音を分離しなかったので次は分離してデータを小さく抑えるつもりだ。
任意の話者で録音したサンプル音で学習すれば、音声合成、歌唱が可能だ。
ツール類は現在のところWindows上でしか動作させることができない。
もっと滑らかに喋れるように学習させる必要があるが、これをブラウザに実装するのは負荷的にちょっと無理か。
だが、今回採用した方式は、Vocaloid2のように音程に左右されない。自由に滑らかにフォルマント周波数を変更させることができる。リアルタイムAI学習だけが課題となる。但し、現状、Web Agent Mikuの負荷はMiku.netを起動していないのであまりあてにはならない。Miku.netの安定な制御方法が確立していないので当分専用サーバーを用意するしか方法はない。リアルタイムAI学習:これは音声入力をリアルタイムAI学習させてミク音声にリアルタイム変換する処理を実現しようとしているのだが、音素の切り替わりをうまく検出するアルゴリズムを思いついていないので現状うまく動作しない。勿論、iSpeech APIのようにAI学習済み単語/文章例データベースをCloudサービスで提供する方法もあるが、まねはしたくないし、あれは大規模過ぎる。もっとシンプルであるべきだ。)
音素から連続的に別の音素に切り替わる際の補間も発声モデルに戻って実行すれば滑らかに繋がるのだが、ブラウザでは処理負荷が重過ぎる。将来的にはWebGLが普及した時点でGPUに実行させればリアルタイムに演奏/歌唱/発声が可能となるだろう。(WebGLでは任意Shaderスクリプトのダウンロード実行が可能なのだ。)
フィルターバンクを用意すれば、任意曲の耳コピ・モードも実現可能かもしれないし、テキスト読み上げ機能、任意言語通訳機能など、今秋に発売予定とされるVocaloid3以上の機能を搭載することも可能かもしれない。実際、今現在はGoogle Text-To-Speechに依存しているため、Google Chrome12でしか実行できないが、音声認識と音声合成を組み合わせたプログラムもこんなに簡単だ。(iSpeech APIを使えばブラウザの制約は無くなるが考え中。)
それと試作中に実施した音声サンプルのAI学習処理で、いい声を持った歌手の声の成分がある特徴をもっているらしい事が判明。成程、こんな法則が!

■記載日2011年11月21日■08:37頃記載
【音を出す仕組みについて】
このページで紹介しているJavaScriptでは、.wav形式の音源ソースデータをブラウザ側で生成して
Base64形式のテキストデータに変換して、それをAudioタグのsrcとして与える方法を用いています。
Audio Data API[オーディオ出力API]は、現状Fire Foxにしか実装されていないので使っていません。
Base64形式とはバイナリーデータを3バイト単位に英数字と+及び/からなる64文字を用いた4バイトに変換する方法です。
殆どのブラウザでは、imgやaudioタグのsrcとしてBase64形式を使うことができます。
アルゴリズムを簡素化するため、バイト数が3の倍数となるように工夫しています。
残念ながらIEは作成が簡単な.wav形式に対応していないので再生することができません。

   function createBase64Header(typ) { return "data:"+typ+";base64,"; }
   function encodeBase64(buf,nByte) {
      var code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      var a,b,c,d;
      for(var j=0,s="";j>6);
         b=((a&3)<<4)|(b>>4);a=a>>2;
         s+=code.charAt(a)+code.charAt(b)+code.charAt(c)+code.charAt(d);
      }
      return s;
   }

【.wav形式音声ファイルのバイト構造】
処理速度を若干でも速くするためにWebGLで導入された型付き配列を使っていますが、普通のArrayでも動作します。
NTL_audioDataという配列をバイト配列と考えて、.wav形式ファイル構造で波形データを作成します。
   //************************************************
   //【Audio File】'.wav'形式(16bit/44.1kHz/Stereo)固定
   //************************************************
   //【参考URL】http://www.kk.iij4u.or.jp/~kondo/wave/
   var NTL_audioSampleBits=16;      //【ビット数】        16bit
   var NTL_audioSamplingRate=44100; //【サンプリング速度】44.1kHz
   var NTL_audioChannels=2;         //【チャンネル数】    2ch
   var NTL_audioDataBlockSize=4;    // 2*2
   var NTL_audioDataLength=176400;  // 44100*2*2
   var NTL_audioData;               //【バッファ】1秒分
   var NTL_audioSource;             //【base64形式ソース】

   function initializeWaveFile(TimeLength) {
      NTL_audioData = new Uint8Array(NTL_audioDataLength); //【WebGL】*******************************
      var nSample=Math.round(TimeLength)*NTL_audioSamplingRate+1;
      var nBytesOfData=nSample*NTL_audioDataBlockSize;
      var filelength=44+nBytesOfData;
      createDDSFrequencyData();     //【DDS増分deltaを初期化】
      createDDSWaveTemplete();      //【DDS1波分sin波テンプレートデータを作成】
      createDDSAmplitudeTemplete(); //【DDS Amplitudeを作成】AttackとCutting
      setStringData(NTL_audioData, 0,'RIFF');                 //【RIFFヘッダー】
      setUint32Data(NTL_audioData, 4,filelength-8);           //【以降のファイルバイトサイズ】filesize-8
      setStringData(NTL_audioData, 8,'WAVE');                 //【WAVEヘッダー】
      setStringData(NTL_audioData,12,'fmt ');                 //【fmt チャンク】
      setUint32Data(NTL_audioData,16,16);                     //【fmt チャンクのバイト数】リニアPCMの場合16
      setUint16Data(NTL_audioData,20,1);                      //【Format ID】1:リニアPCM
      setUint16Data(NTL_audioData,22,NTL_audioChannels);      //【Channel数】1:モノラル, 2:ステレオ
      setUint32Data(NTL_audioData,24,NTL_audioSamplingRate);  //【SamplingRate】44.1kHz
      setUint32Data(NTL_audioData,28,NTL_audioDataLength);    //【DataLength】44100×2Channel×2byte
      setUint16Data(NTL_audioData,32,NTL_audioDataBlockSize); //【BlockDataSize】2Channel×2byte
      setUint16Data(NTL_audioData,34,NTL_audioSampleBits);    //【Bits/Sample】16bit
      setStringData(NTL_audioData,36,'data');                 //【dataチャンク】
      setUint32Data(NTL_audioData,40,nBytesOfData);           //【波形データのbyte数】
      setUint16Data(NTL_audioData,44,0);                      //【R】先頭データ
      setUint16Data(NTL_audioData,46,0);                      //【L】先頭データ
      return nSample; //【書込ポインタは1から開始の事】
   }
   function setStringData(buf,st,sD)
   { for(var i=0,e=sD.length; i<e; i++) { buf[i+st]=sD.charCodeAt(i); } }
   function setUint32Data(buf,st,v)
   { var y=v,x=y&255;buf[st]=x;y=y>>8;x=y&255;buf[st+1]=x;y=y>>8;x=y&255;buf[st+2]=x;y=y>>8;x=y&255;buf[st+3]=x; }
   function setUint16Data(buf,st,v)
   { var y=v,x=y&255;buf[st]=x;y=y>>8;x=y&255;buf[st+1]=x; }

■記載日2011年12月04日■03:11頃記載
【Win32APIのWaveInを使って音声を録音するExcel VBAツール】
今までWindowsのサウンドレコーダーを使って録音し、iTuneでwaveファイルに変換してきたが、
毎回処理が面倒なのでExcel VBAでシートに読み込むツールを製作開始した。
Microsoft社のKinect SDK betaと干渉してC#が調子悪いので、DirectSoundが使えない。半日かけたがどうにも進まないのでC#は諦めた。
   【Excel VBAツール】Win32APIのWaveInを使った録音ツール Version 0.01
発声開始時刻合わせや発声音階を調べてチューニングする部分等はこれから製作の予定。
プログラムを作らず、Web Agentに処理の細かな指示を出したいがどうにもうまく表現できない。
自分で作れって事だよね。しょうがないか.....

【使い方】
 ●まず、マイクを接続した状態で『WaveIn有効デバイス情報を取得する』ボタンをクリックし、利用可能なデバイスを調べる。
 ●情報欄のszPnameを見て、使うDeviceID (マイク) をセルB13に入力する。
 ●『録音 (0.7秒間』ボタンをクリックして、『発音する語』で指定された語を発音する。
 ●暫く待つと波形が表示されるので、良ければ『進む(データ保存)』ボタンをクリックする。
 ●取り直すときはもう一度『録音 (0.7秒間』ボタンをクリックする。
 ●保存したデータを取りなおすときは『戻る』ボタンを何回かクリックして戻る。
VBAなので処理速度は遅い。



Sheet1の処理

Private nWaveInDevice As Long     ' 利用可能なWaveInデバイス数
Private WICaps() As WAVEINCAPS    ' WaveInデバイスの情報
Private hWaveIn As Long           ' ハンドル番号
Private uWaveInID As Long         ' ID番号
Private fmtWaveIn As WAVEFORMATEX ' WaveInのWAVEFORMATEX構造体
Private hdrWaveIn As WAVEHDR      ' WaveInのWAVEHDR構造体
Private mT As MMTIME              ' WaveInのMMTIME構造体(記録時間確認用)
Private Buf() As Integer          ' Waveデータ一時保存用バッファ

'*********************************************************************
'***【利用可能な録音デバイスを調べる】
'*********************************************************************
Private Sub CommandButton1_Click()
  Dim i As Long, j As Long
  
  nWaveInDevice = waveInGetNumDevs() ' 利用可能なWaveInデバイス数を取得する
  Sheet1.Cells(2, 2) = nWaveInDevice ' セルに取得結果を表示
  Range("B4:C9").Select              ' デバイス情報欄を消去する
  Selection.ClearContents            '   :
  ReDim WICaps(nWaveInDevice - 1)
  For i = 0 To nWaveInDevice - 1
     j = waveInGetDevCaps(i, WICaps(i), 46) ' 第3引数はWAVEINCAPS構造体の総バイト数
     Sheet1.Cells(4, 2 + i) = WICaps(i).wMid
     Sheet1.Cells(5, 2 + i) = WICaps(i).wPid
     Sheet1.Cells(6, 2 + i) = WICaps(i).vDriverVersion
     Sheet1.Cells(7, 2 + i) = WICaps(i).szPname
     Sheet1.Cells(8, 2 + i) = Hex$(WICaps(i).dwFormats)
     Sheet1.Cells(9, 2 + i) = WICaps(i).wChannels
  Next i
End Sub

'*********************************************************************
'***【1秒分録音してシートに読み込む】44.1kSPS, 2ch, 16bit
'*********************************************************************
Private Sub CommandButton8_Click()
   Dim i As Long
   fmtWaveIn.wFormatTag = WAVE_FORMAT_PCM '
   fmtWaveIn.nChannels = 2                ' チャンネル数 1:モノラル 2:ステレオ
   fmtWaveIn.nSamplesPerSec = 44100       ' サンプリング速度(1秒あたりのサンプル数)
   fmtWaveIn.wBitsPerSample = 16          ' 1サンプルのビット数
   fmtWaveIn.nAvgBytesPerSec = fmtWaveIn.nSamplesPerSec * fmtWaveIn.nChannels * (fmtWaveIn.wBitsPerSample \ 8)
   fmtWaveIn.nBlockAlign = fmtWaveIn.nChannels * (fmtWaveIn.wBitsPerSample \ 8)
   fmtWaveIn.cbSize = 0
   i = waveInOpen(hWaveIn, 0, fmtWaveIn, 0, 0, WAVE_FORMAT_DIRECT) '【デバイスを開く】
   If i <> 0 Then
      MsgBox "何かエラーが発生した模様です。", vbOKOnly
      GoTo LExit
   End If
   hdrWaveIn.dwBufferLength = 44100 * 2& * 2&  ' 1秒分のバッファを用意(バイト数)
   ReDim Buf(hdrWaveIn.dwBufferLength \ 2 - 1)
   hdrWaveIn.lpData = VarPtr(Buf(0)) ' Wave保存バッファへのポインタを渡す
   
   i = waveInPrepareHeader(hWaveIn, hdrWaveIn, 32) '【ヘッダー情報を準備】
   i = waveInAddBuffer(hWaveIn, hdrWaveIn, 32)     '【バッファを準備する】
   
   waveInStart hWaveIn '【録音開始】
   
L1:
   If hdrWaveIn.dwFlags And 1 = 0 Then
      DoEvents
      GoTo L1
   End If
   
   For i = 0 To 32000 - 1
      Sheet1.Cells(20 + i, 1) = i
      Sheet1.Cells(20 + i, 2) = Buf(2 * i)
      Sheet1.Cells(20 + i, 3) = Buf(2 * i + 1)
   Next i
   
LExit:
   i = waveInClose(hWaveIn) '【デバイスを閉じる】
End Sub

Private Sub CommandButton9_Click()
   Dim i As Long
   i = Sheet1.Cells(18, 4)
   If i > 4 Then
      Sheet1.Cells(18, 4) = i - 1
      Sheet1.Cells(18, 2) = Sheet1.Cells(19, i - 1)
   End If
End Sub

Private Sub CommandButton10_Click()
   Dim i As Long, j As Long
   i = Sheet1.Cells(18, 4)
   For j = 0 To 44100 - 1
      Sheet1.Cells(20 + j, i) = Buf(2 * j)
   Next j
   Sheet1.Cells(18, 4) = i + 1
   Sheet1.Cells(18, 2) = Sheet1.Cells(19, i + 1)
End Sub

win32api(標準モジュール)の定義

'****************************************************************
'【Win32API】WaveIn利用の為の定義
'****************************************************************
Public Const MAXPNAMELEN = 32     '  max product name length (including NULL)
Public Const MAXERRORLENGTH = 128 '  max error text length (including final NULL)

'【MMTIME構造体】
' ●記録経過時間を調べる為の構造体
Type MMTIME
   wType As Long
   u As Long
End Type
' ●MMTIME構造体の変数wTypeの値
Public Const TIME_MS = &H1     '  time in Milliseconds
Public Const TIME_SAMPLES = &H2     '  number of wave samples
Public Const TIME_BYTES = &H4     '  current byte offset
Public Const TIME_SMPTE = &H8     '  SMPTE time
Public Const TIME_MIDI = &H10    '  MIDI time


'  Multimedia Window Messages
Public Const MM_WIM_OPEN = &H3BE  '  waveform input
Public Const MM_WIM_CLOSE = &H3BF
Public Const MM_WIM_DATA = &H3C0
' String resource number bases (internal use)
Public Const MMSYSERR_BASE = 0
Public Const WAVERR_BASE = 32
Public Const MIDIERR_BASE = 64
Public Const TIMERR_BASE = 96   '  was 128, changed to match Win 31 Sonic
Public Const JOYERR_BASE = 160
Public Const MCIERR_BASE = 256
' General error return values
Public Const MMSYSERR_NOERROR = 0                         '  no error
Public Const MMSYSERR_ERROR = (MMSYSERR_BASE + 1)         '  unspecified error
Public Const MMSYSERR_BADDEVICEID = (MMSYSERR_BASE + 2)   '  device ID out of range
Public Const MMSYSERR_NOTENABLED = (MMSYSERR_BASE + 3)    '  driver failed enable
Public Const MMSYSERR_ALLOCATED = (MMSYSERR_BASE + 4)     '  device already allocated
Public Const MMSYSERR_INVALHANDLE = (MMSYSERR_BASE + 5)   '  device handle is invalid
Public Const MMSYSERR_NODRIVER = (MMSYSERR_BASE + 6)      '  no device driver present
Public Const MMSYSERR_NOMEM = (MMSYSERR_BASE + 7)         '  memory allocation error
Public Const MMSYSERR_NOTSUPPORTED = (MMSYSERR_BASE + 8)  '  function isn't supported
Public Const MMSYSERR_BADERRNUM = (MMSYSERR_BASE + 9)     '  error value out of range
Public Const MMSYSERR_INVALFLAG = (MMSYSERR_BASE + 10)    '  invalid flag passed
Public Const MMSYSERR_INVALPARAM = (MMSYSERR_BASE + 11)   '  invalid parameter passed
Public Const MMSYSERR_HANDLEBUSY = (MMSYSERR_BASE + 12)   '  handle being used simultaneously on another thread (eg callback)
Public Const MMSYSERR_INVALIDALIAS = (MMSYSERR_BASE + 13) '  "Specified alias not found in WIN.INI
Public Const MMSYSERR_LASTERROR = (MMSYSERR_BASE + 13)    '  last error in range
Public Const MM_MOM_POSITIONCB = &H3CA                    '  Callback for MEVT_POSITIONCB
Public Const MM_MCISIGNAL = &H3CB
Public Const MM_MIM_MOREDATA = &H3CC                      '  MIM_DONE w/ pending events
Public Const MIDICAPS_STREAM = &H8                        '  driver supports midiStreamOut directly

'【waveInOpen内の変数dwFlagsの値】 ※waveOutOpen()でも使用
Public Const WAVE_ALLOWSYNC = &H2
Public Const WAVE_VALID = &H3     '  ;Internal

'【WAVEHDR構造体】録音時に使用される
Type WAVEHDR
   lpData As Long          ' Audioデータ格納バッファのポインタ
   dwBufferLength As Long  ' バッファ長(バイト数)
   dwBytesRecorded As Long ' 記録されたバイト数
   dwUser As Long          '
   dwFlags As Long         ' 状態フラグ
   dwLoops As Long         '
   lpNext As Long          '
   Reserved As Long        '
End Type
' ●WAVEHDR構造体のdwFlagsの値(状態を示す)
Public Const WHDR_DONE = &H1      '  done bit
Public Const WHDR_PREPARED = &H2  '  set if this header has been prepared
Public Const WHDR_BEGINLOOP = &H4 '  loop start block
Public Const WHDR_ENDLOOP = &H8   '  loop end block
Public Const WHDR_INQUEUE = &H10  '  reserved for driver
Public Const WHDR_VALID = &H1F    '  valid flags      / ;Internal /

'【WAVEINCAPS構造体】
Type WAVEINCAPS
   wMid As Integer
   wPid As Integer
   vDriverVersion As Long          ' ドライバーのバージョン番号
   szPname As String * MAXPNAMELEN ' デバイスの名称
   dwFormats As Long               ' 記録フォーマット(利用可能なビット位置が1になっている)
   wChannels As Integer            ' チャンネル数
End Type
'  defines for dwFormat field of WAVEINCAPS and WAVEOUTCAPS
Public Const WAVE_INVALIDFORMAT = &H0  '  invalid format
Public Const WAVE_FORMAT_1M08 = &H1    '  11.025 kHz, Mono,   8-bit
Public Const WAVE_FORMAT_1S08 = &H2    '  11.025 kHz, Stereo, 8-bit
Public Const WAVE_FORMAT_1M16 = &H4    '  11.025 kHz, Mono,   16-bit
Public Const WAVE_FORMAT_1S16 = &H8    '  11.025 kHz, Stereo, 16-bit
Public Const WAVE_FORMAT_2M08 = &H10   '  22.05  kHz, Mono,   8-bit
Public Const WAVE_FORMAT_2S08 = &H20   '  22.05  kHz, Stereo, 8-bit
Public Const WAVE_FORMAT_2M16 = &H40   '  22.05  kHz, Mono,   16-bit
Public Const WAVE_FORMAT_2S16 = &H80   '  22.05  kHz, Stereo, 16-bit
Public Const WAVE_FORMAT_4M08 = &H100  '  44.1   kHz, Mono,   8-bit
Public Const WAVE_FORMAT_4S08 = &H200  '  44.1   kHz, Stereo, 8-bit
Public Const WAVE_FORMAT_4M16 = &H400  '  44.1   kHz, Mono,   16-bit
Public Const WAVE_FORMAT_4S16 = &H800  '  44.1   kHz, Stereo, 16-bit
'以降の定義は不明
'Public Const WAVE_FORMAT_4M16 = &H1000  '  48   kHz, Mono,   16-bit(DVDの音質)
'Public Const WAVE_FORMAT_4S16 = &H2000  '  48   kHz, Stereo, 16-bit(DVDの音質)
'Public Const WAVE_FORMAT_4M16 = &H4000  '  96   kHz, Mono,   16-bit(スタジオの音質)
'Public Const WAVE_FORMAT_4S16 = &H8000  '  96   kHz, Stereo, 16-bit(スタジオの音質)

'  flags for wFormatTag field of WAVEFORMAT
Public Const WAVE_FORMAT_PCM = 1  '  Needed in resource files so outside #ifndef RC_INVOKED
'
Public Const WAVE_FORMAT_QUERY = &H1
Public Const SND_PURGE = &H40               '  purge non-static events for task
Public Const SND_APPLICATION = &H80         '  look for application specific association
Public Const WAVE_MAPPED = &H4
Public Const WAVE_FORMAT_DIRECT = &H8
Public Const WAVE_FORMAT_DIRECT_QUERY = (WAVE_FORMAT_QUERY Or WAVE_FORMAT_DIRECT)

'【WAVEFORMATEX構造体】WaveInOpen時に指定する
Type WAVEFORMATEX
   wFormatTag As Integer
   nChannels As Integer
   nSamplesPerSec As Long
   nAvgBytesPerSec As Long
   nBlockAlign As Integer
   wBitsPerSample As Integer
   cbSize As Integer
End Type

'【利用可能なデバイス数を取得する】
Public Declare Function waveInGetNumDevs Lib "winmm.dll" () As Long
'【指定デバイスIDのデバイス情報を取得する】※uSizeは構造体WAVEINCAPSをコピーするバイト総数を示す。
Public Declare Function waveInGetDevCaps Lib "winmm.dll" Alias "waveInGetDevCapsA" _
                (ByVal uDeviceID As Long, lpCaps As WAVEINCAPS, ByVal uSize As Long) As Long
'【デバイス・オープン】指定WAVEFORMATEXで開く
Public Declare Function waveInOpen Lib "winmm.dll" _
                (lphWaveIn As Long, ByVal uDeviceID As Long, lpFormat As WAVEFORMATEX, ByVal dwCallback As Long, _
                 ByVal dwInstance As Long, ByVal dwFlags As Long) As Long
'【デバイス・クローズ】
Public Declare Function waveInClose Lib "winmm.dll" (ByVal hWaveIn As Long) As Long
'【ヘッダー情報を準備する】        ※uSizeは構造体WAVEHDRをコピーするバイト総数を示す。
Public Declare Function waveInPrepareHeader Lib "winmm.dll" _
                (ByVal hWaveIn As Long, lpWaveInHdr As WAVEHDR, ByVal uSize As Long) As Long
'【記録データを格納するバッファを指定する】※uSizeは構造体WAVEHDRをコピーするバイト総数を示す。
Public Declare Function waveInAddBuffer Lib "winmm.dll" _
                (ByVal hWaveIn As Long, lpWaveInHdr As WAVEHDR, ByVal uSize As Long) As Long
'【録音開始】
Public Declare Function waveInStart Lib "winmm.dll" (ByVal hWaveIn As Long) As Long
'【録音停止】中断
Public Declare Function waveInStop Lib "winmm.dll" (ByVal hWaveIn As Long) As Long
'【録音ポインタ初期化】バッファをクリアし、格納ポインタを先頭に戻す
Public Declare Function waveInReset Lib "winmm.dll" (ByVal hWaveIn As Long) As Long
'【記録済みのデータ位置、時刻を調べる】
Public Declare Function waveInGetPosition Lib "winmm.dll" _
                (ByVal hWaveIn As Long, lpInfo As MMTIME, ByVal uSize As Long) As Long
'【以下は未使用】
Public Declare Function waveInGetErrorText Lib "winmm.dll" Alias "waveInGetErrorTextA" _
                (ByVal err As Long, ByVal lpText As String, ByVal uSize As Long) As Long
Public Declare Function waveInUnprepareHeader Lib "winmm.dll" _
                (ByVal hWaveIn As Long, lpWaveInHdr As WAVEHDR, ByVal uSize As Long) As Long
'...【Openしているハンドル番号のデバイスIDを取得する】
Public Declare Function waveInGetID Lib "winmm.dll" _
                (ByVal hWaveIn As Long, lpuDeviceID As Long) As Long
Public Declare Function waveInMessage Lib "winmm.dll" _
                (ByVal hWaveIn As Long, ByVal msg As Long, ByVal dw1 As Long, ByVal dw2 As Long) As Long

【過去のメモ】

『対象ブラウザ:Google Chrome12 & Mozilla FireFox5 & Apple Safari5.1』

このページでは、ブラウザにプラグインを使わずに、JavaScriptだけでMIDIデータから音楽演奏を行ったり、音声合成あるいはVocaloidを実装しようとする試みを紹介します。つまり、ソフトウェアをインストールすることなく、ブラウザだけで作曲・演奏や音声合成、読み上げ等を行う方式の確立を目指しています。サーバーはApacheです。レンタルサーバーでも可能です。
Mozilla FireFox5にはHTML5のAudio APIが既に実装されているため、この機能を使ってシンセサイザを実装する事は比較的容易ですが、利用可能なブラウザがFireFox5に限られてしまう欠点があります。そこで、大抵のブラウザに実装されるようになったHTML5のaudioタグに着目してみました。調査してみたところ、audioタグを使えば、『.wav』形式のオーディオファイルの再生がIE9を除いて可能でした。さらに、base64形式の.wavは、Google Chrome12, Mozilla FireFox5, Apple Safariで再生することができました。以下のデモでは、MIDIファイルをテキスト変換して得た数値データ(楽譜)に基づいて波形を生成し、再生しています。ドラムパートはまだ作成していません。

1.【Direct Digital Synthesizer】

  ■【対象ブラウザ】Google Chrome12, Mozilla FireFox5, Safari5.1
    但し、rendering処理に時間を要するので、再生までに10秒~30秒程度かかります。
  ■【非対応ブラウザ】Opera11.5, IE9(.wav再生不可能)
  ●MIDIファイルをテキストファイルに変換して時刻、チャンネル、音階、音の長さ、音の強さの配列データとする。
  ●多チャンネルの演奏データをsin波を重ねて作成したテンプレート音源で演奏する。
  ●但し、ドラムパートはWindowsのMIDI標準ドラムセット音源のテンプレートを用いた。
  ●16bit/44.1kHz/Stereo形式。自動再生。再生時間45秒。
  ●base64エンコードでテキスト形式に変換する。
  ●HTML5のaudioタグにsrc(source)として貼り付ける。
  ●HTML5のaudioタグに対応しており、.wav形式のファイルの再生が可能なブラウザであれば、WebAudioで音楽演奏が可能です。
  ●C1→C10まで再生したが、前後1オクターブはPC性能の問題有。
  ●但し、pianoは88鍵なのでその範囲はカバーできた。clockが44.1kHzの為限界有。
  【注意】
  ■IE9は.wav形式に対応していないので再生できません。
  ■Opera11.5ではbase64形式に対応していないらしく再生できません。

1.1 【フィンランド民謡】『Ieavan Polkka』(ドラム有) (Version 0.01)
1.2 【バッハ】『フーガ ト短調』 (Version 0.01)
1.3 【モーツアルト】『トルコ行進曲』 (Version 0.01)
1.4 【リスト】『ラ・カンパネラ』 (Version 0.01)

2.【シンセサイザ/なんちゃってロイド】

2.1 【フィンランド民謡】『Ieavan Polkka』(ドラム有) (Version 0.05)
2.2 【フィンランド民謡】『Ieavan Polkka』(ドラム、ミク音声有) (Version 0.06)

■記載日2011年8月16日■17:58頃記載
【子音の謎解明】(第1次試作)
まだコーディングには反映できていないが、子音に関する声楽的な謎が解けた。なんと母音と異なり、子音には音階が無いのだ。面白い! ここにこれ以上詳しく書く事はないだろうが、音響FDTDシミュレータで人間の発声シミュレーションを実施する中で浮上していた疑問だった。
本日、知り合いの声楽をやっている人に質問して確認できた。子音が殆ど目立たない発声方法を練習するのだそうだ。 こういう視点で音楽を習っていたら楽しかったろうに。
実際に聞き比べて初めてわかった。ボーカロイドを製作する上でかなり重要な事項だと思う。修正しなくては。
ちなみに音痴にも2種類あるようだ。基本周波数だけ一致してもダメなんだ。人間って凄い。普段会話のときのスペクトルと違って、微妙にスペクトルが変化してきれいに調和するスペクトルを出している!
もう少し詳しく書くと、人間の声は単音階ではなく、様々な線スペクトルが含まれている。ピアノで言えば複数の鍵盤を叩いて和音を出している。だから歌の音階に合わせて主音階のスペクトルだけじゃなく、他の線スペクトルも調和させないと不協和音となり、音痴になってしまうのだ。自動制御という視点で人間の発声を理解すると、想像を超えて、凄い複雑なものだったようです。だから難聴で上手に歌うのはこの微妙なフィードバックが作用せず不可能に近いことなのだ。改良後にコメントします。

■記載日2011年8月17日■17:58頃記載
【そろそろ開発コードを決めようかな?】(第2次試作開始?)
Google翻訳で使われているText-To-Speech APIに興味を持って調べ始めたのが2011年5月の事。一度はその大元のiSpeech APIを使おうかと思ったが、Googleのサーバー負荷が時刻によって安定しておらず、応答時間が不安定だった。Google Text-To-Speech APIには日本語を喋らせる上で微調整ができないので不具合も多い。それ以前に実施したMedia Playerとかswfobjectは全然だったので、今回真似ロイド(なんちゃってボーカロイド)を作り始めたわけだ。この真似ロイド(なんちゃってボーカロイド)にはシンセサイザも実装しているので、これはなんと表現したらいいのか? 何かいい名称はないかなぁ。
.......ところで英語も喋れるようにしとかないと。ルカの声をサンプルにして子音をAI学習させて、母音をミックスする方法もある。母音の方の声に聞こえるから不思議だ。
当初、パターンAI学習の繰返し回数は100万回に設定したが、過学習になっていることが判明した。1000回~1万回程度がよさそうだ。

■記載日2011年8月20日■00:10頃記載
【知り合いより専門書を借りて読み始める】
子音と母音、音階、協和音、不協和音などに関する疑問が噴出してきたために、知り合いより専門書を借りて読み始めた。『新装版 楽典 理論と実習』石桁真礼生ら 音楽之友社

【音の種類】

1. 純音 単一周波数の音。音叉、sin波。
2. 楽音 規則性、周期性のある複数の倍音スペクトルを含んだ音。(人間の声では母音に相当する。)
3. 噪(そう)音 規則性のない、過渡的な音。打楽器の接触音。ピアノが弦を叩いた瞬間の音。(人間の声では子音に相当する。)
4. 騒音 ノイズ(通常は聞きたくない音)

通常の楽器の音は噪音と楽音からなる。ギターでは弦をはじく瞬間の音が噪音。その後の共鳴音が楽音である。
打楽器では、木琴は噪音と楽音があるが、ドラムは噪音主体と考えていいだろう。
厳密にはメロディック・タムタムとかでは噪音だけでなく楽音もある。
人間の声も子音を噪音。母音を楽音と見なせば理解し易い。
楽音は基音(基本周波数の音)と複数の倍音を持つ。2倍、3倍、4倍、5倍、6倍、7倍、8倍、9倍、.....
2倍音、4倍音、8倍音は1オクターブずつ上の音なのであまり目立たないが、3倍音、5倍音、6倍音、7倍音、9倍音は聞き取り易い。
理系の人間にはここまでで子音が基音(音階)に無関係であること、母音が音階に依存して変化する成分であることがはっきりと認識できる。なるほどやっぱりそうだったか。

【純正律による音階 と 十二平均律による音階】

人間の聴覚は純音2音の周波数比が簡単な整数比になっている場合に協和音として知覚する性質がある。
C: 1 D:9/8 E:5/4 F:4/3 G:3/2 A:5/3 B:15/8 C:2
この音階で調律すると、協和音で構成されるので美しい音色となるそうだが、反面移調が行えず、利便性に欠ける。
現在、通常使われている音階は十二平均律による音階である。十二平均律では1オクターブを2^1/12=1.059463094359....で分割する。
つまり、A4(=440Hz)の半音上の音は440Hz*1.059463094359... = 466.1637...Hzというように決まる。
この調律はシンプルだが、完全な協和音で構成されないので音色の美しさは劣る。反面、どの移調を行ってもそれなりに協和音との誤差が小さい利点がある。
さて、ここで次の疑問が湧いてくる。
 ●歌声の母音や楽器の楽音は協和音を発しているのに、音階の方は十二平均律だから音色によっては不協和音が目立たないだろうか?
  裏を返せば、不協和音が目立ちにくい倍音成分の声の歌は美しく聞こえるはずだ。音痴と美しい歌声の本質に関係していそうだ。
  歌手で言えば、ハスキーボイスの歌手の方がヒットを飛ばし易い傾向がある。
  バイオリンの名器『ストラディバリウス』の音色の秘密もこういったことに関係しているかもしれない。
ああ、嫌だ。何でこんな事が気になるんだろうか?