AOYAMA Koji's PROGRAMMING BLOG

サンプリング周波数視聴ツールのプログラミング

2025/02/10

 前回ご紹介しました、 サンプリング周波数が視聴できるツールのプログラミングの解説をします。



元データはサインカーブで再現


 まず、元になるデータとして、音源は波ですので、波の情報が必要です。 この波情報にはサインカーブを用いました。 JavaScriptでは以下のように書いて-1.0から1.0の値を取得することができます。
指定タイミングの音源データ = Math.sin( 角度 )

 多くのプログラミング環境で「=」(イコール)は、右辺の計算結果を、左辺の変数に代入することを意味します。

角度は時間で変化


 元データはラ音。 周波数は440Hz。 つまり1秒間に440回振動する波ですので、Math.sinに渡す角度は1秒間に440周します。 それを式にすると以下です。
角度 = 一周 * 周波数 * 時間

 プログラミングで「*」(アスタリスク)は乗算を表すことが多いです。掛け算ですね。「\( \times \)」の代わり。 時間の単位は秒です。

一周が\(2\pi\)になるラジアン表記


 プログラミングでは角度をラジアン(radian)と呼ばれる、一周を\(2\pi\) で表す形式で指定されることが多いです。 radと書かれたりします。\(\pi\)は円周率の\(\pi\)です。ぱい。3.14くらい。
 ちなみに私たち人間が普通に使う、一周を360度で表すのはディグリー(degree)と呼ばれます。 degとも書かれます。
形式一周
ディグリー(deg)360度
ラジアン(rad)\(2\pi\)

1秒間にサンプリング周波数ぶんのデータ


 時間については、1秒間にサンプリング周波数ぶんのデータになるように刻みます。 つまり1ステップごとに \( \frac{1}{サンプリング周波数}秒 \) 進みます。
時間 = ステップ数 / サンプリング周波数

 プログラミングで「/」(スラッシュ)は除算を表すことが多いです。割り算ですね。「\( \div \)」の代わり。

式をまとめます


 上記の式をまとめます。
角度 = \(2\pi\) * 周波数 * ステップ数 / サンプリング周波数


実際のコード抜き出し


 この部分の実際のJavaScriptコードも以下に記載しておきますね。
let iLength = Math.floor( iSamplingRate * iDuration / 1000.0 );
for ( let i = 0 ; i < iLength ; ++i ) {
  let fAngle = f2PI * fSoundFrequency * i / iSamplingRate;
  oSoundWave.aafWaveform[0][i] = Math.sin(fAngle);
}

iDurationはミリ秒指定


 本プログラムでは、再生時間を iDuration という変数名でミリ秒で指定しています。 今回の再生時間は1秒でしたので、iDuration には 1000 が入っています。
 秒数としては1000で割った値を使用します。 1000ミリ秒は1秒。

秒数にサンプリング周波数を掛けるとデータ量になる


 サンプリング周波数は変数 iSamplingRate に入っています。 これに秒数を掛けた結果がデータ量を表す変数 iLength に入ります。
 本プログラムでは Math.floor を利用し、小数点以下を切り捨てて整数にしています。

forループで全データ量処理


 データ量 iLength を求めたら、変数 i0 から (iLength-1) まで1ずつ増やして iLength回、 すなわち全データ量ぶん繰り返し処理します。

f2PIは\(2\pi\)、周波数はfSoundFrequency


 本プログラムでは変数 f2PI\(2\pi\) 相当の数値が入っています。 また変数 fSoundFrequency に再生すべき音の周波数が入っています。 それらを上記式に当てはめて計算し、角度を表す変数fAngleに代入します。

配列に代入


 最後に Math.sin の引数に角度を渡して波の高さを -1.0から1.0 の範囲で取得します。 変数 oSoundWave.aafWaveform音源データとなる波形データを格納する配列です。
 配列は配列変数[数字]の形で指定することで、同じ変数名で複数の値を扱えます。
 最初の [0] はチャンネル区分で、ステレオだと [0] か [1] になります。 本プログラムではモノラルなので oSoundWave.aafWaveform[0] 固定です。
 続く [i]各タイミングのデータ位置を指定しています。 この変数 i は上記の通り全データ量分だけ0から1ずつ増えていく繰り返し処理に使われます。
 つまり oSoundWave.aafWaveform[0][i] が、指定タイミングの音源データということになります。 実際には、oSoundWave.aafWaveform[0][0] に最初のデータが、 oSoundWave.aafWaveform[0][1] に次のデータが、…と順番に入っています。
 そしてもしサンプリング周波数が44.1KHzなら、音の長さは1秒ですので、 oSoundWave.aafWaveform[0][44099]に最後のデータが入っています。 0から4409944100個のデータです。

実際には工夫も


 基本的には以上の方式で音源データを生成しています。
 ただこれで実際に試してみると、再生時に指定するサンプリング周波数が低すぎると再生に失敗することがわかりました。 そのため15.6kHz以下のサンプリング周波数が指定された場合には、 再生時に指定するサンプリング周波数は十分に大きくして、 音源データを、数回同じ数値を繰り返してあえて階段状になるように生成して、低サンプリング周波数を再現しています。

まとめ


 前回紹介した、サンプリング周波数視聴ツールプログラミング解説を行いました。
 今回使用したsinなどの三角関数は応用範囲が広いので、本記事が間接的にでも何らかの参考になりましたら幸いです。

補足

・本記事で解説しているプログラミング言語は JavaScript です。
・ラジアンではなくディグリーで角度を指定するプログラミング環境もあるので注意は必要です。
・画像内のラスタライズ文字フォントにOpen Font LicenseNoto Sans Monoを使用しております。
・数式表現にMathJaxを使用しております。助かります!
カテゴリー:オーディオ推し,プログラミング,JavaScript
著者プロフィール
青山公士(あおやま こうじ)
中学2年生からゲームプログラミングに明け暮れる。ゲーム開発者としての代表作に「スーパー桃太郎電鉄II」(ハドソン)メインプログラマー、[PR]『ドラゴンクエストX オンライン』(スクウェア・エニックス)テクニカルディレクター/プロデューサーなどがある。[PR]「ドラゴンクエストXを支える技術」(技術評論社)著者。本ブログは今までの経験を活かしプログラミングが楽しいと感じる人が少しでも増えるようなものにしたい。 @kojibm
株式会社ロジック推し
推し情報を論理的にわかりやすく紹介することで「世の中をちょっと楽しく」をミッションに活動中。 HP X Instagram
privacy policy
ピックアップ
Loading...
最新記事
Loading...
関連記事
Loading...