OPMでCSM音声合成・その1(1slotのみを使用した音声合成)
まず、Speaking Pianoで行っているであろう手法をそのまま模倣し、1slotのみを使用したサイン波を使って16チャンネルの鍵盤を叩き、同等の音声合成を行うことを第一目標に掲げました。
処理の流れの概略は以下のとおりです。
- (前段階処理)PCMを処理時間単位で分割する
- 分割したPCMデータを離散フーリエ変換(DFT)にかける
- HiPass/LoPassフィルタ等をかける
- 計算結果を評価する
- 上記の処理をPCMデータの終わりまで繰り返す
PCMを処理時間単位で分割する
CSMモードを使用しない場合はドライバの時間管理を利用します。ドライバの最短処理時間をテンポ・タイムベース、そしてPCMサンプルのサンプリングレートから算出し、実時間に相当する長さでPCMを分割します。計算式は以下のとおりです。
Rate ÷ (BPM ÷ 60) ÷ TimeBase × Step
仮に作る曲のテンポ(BPM)が120・ドライバの四分音符分解能(TimeBase)が48・用意したPCMデータのサンプリングレート(Rate)が44.1kHz・ドライバ分解能の7Stepごとに処理する場合は 44100 ÷ (120 ÷ 60) ÷ 48 × 7 = 3215.625 となります。この場合、PCMデータを3215個もしくは3216個を読み込んで、その単位ごとにフーリエ変換および評価を行ないます。
ちなみにWAVはヘッダ等がくっついていてちょっと扱いづらいので、筆者は生のPCMに変換してから処理をしました。WAV→PCMのコンバートにはrun68.exeと、NOZ.氏作のpcm3pcm.xを使用しました。以前からMDXの作成などでもお世話になっています。ありがとうございます。
CSMモードを使用する場合は、割り込みタイミングの実時間ごとに分割します。
分割したPCMデータを離散フーリエ変換(DFT)にかける & HiPass/LoPassフィルタ等をかける
処理時間短縮のため、高速フーリエ変換(FFT)を使用します。この変換で周波数値に対する出力量が求められます。
高速フーリエ変換を使った場合、得られるデータは2のn乗個になります。最終データがPCMのサンプリングレートの周波数になるので、x個目のデータが示すおおよその周波数は「(x ÷ FFTのサイズ) × サンプリングレート」で算出できます。
結果は左右対称になります。意味のあるデータは半分だけです。また、低周波数帯/高周波数帯は窓関数等の影響で意味のないデータになることが多いようです。人の声の再生が目的ですので、適当な範囲のデータ以外を削除することはそれなりに意味がある・・・はずです。
今回はHiPass=400Hz・LoPass=7000Hzで処理した・・・と思います(記憶が曖昧・・・)。この数値も特に理由もなく、適当に決めたものです。
計算結果を評価する
ココが肝です。
まず評価する前に、離散フーリエ変換で得られた周波数値を、鍵盤の持つ周波数値と比較し、最も近似の周波数値にあてはめて、出力量を集計し直します。
離散フーリエ変換の結果、厳密に周波数成分が解析できるわけではありません。出力結果の周波数値も離散しているので、「このへんの周波数帯がこのくらい強く現れてます」ということしかわかりません。(詳しくはFFTとは?〜本当は正しくないFFTの周波数特性〜を参照してください。)そこで、改めて「鍵盤の周波数値」を基準に再集計します。
これで、おおよその周波数値に対する絶対量が、鍵盤に対する絶対量に置き換わります。出力量の多いデータを上位から必要個数取得して、鍵盤データと音量データを保存します。
ちなみに筆者はこの時の音量値の扱いが未だによくわかっていません。音量は対数変化するので、アレコレいじってなんとなく変換できた気がする・・・という状態にはできたのですが・・・この部分は識者の意見を伺いたいところです^-^;;;
結果例
http://nrtdrv.sakura.ne.jp/mp3/csmtest_20100522_16.mp3
これは1slot×16chで処理したものです(窓関数なし・ほぼLoPass/HiPassを適用せず)。なお、申し訳ありませんが、音量に注意してください(汗)。かなりデカイです(汗)