音を鳴らすには、様々なハードウェア機能を使って実現します。DirectSoundはその極地といっても過言ではありません。ここでは非常に面倒ではありますけれど、ガチガチに決まったらルールに従ってサンプルコードを追いかける形になります。窮屈ではありますがご容赦願います。さて、音とは何かというところから始めます。
普段何気なく聞いている音楽。その記録媒体の1つCDディスクは、バイナリデータの集まりです。円盤の1秒は44100分割されていて、1分割分の音の高さは2バイトであり、ステレオの2チャンネルで構成されています。これをwavファイルフォーマットに置き換えると以下になります。
44100(Hz) * 2バイト(16bit) * 2(ステレオ)* 1(秒) + 44(ヘッダ) = 176,444バイト
wavファイルの中身はヘッダ部とデータ部に分かれています。ヘッダは0x00-0x43までの44バイト。残りのデータは0x0000で埋まり、ファイルサイズは176,444バイトとなっています。音の高さ2バイト(16bit)の中身は、符号付きsigned(-32768 ~ +32767, 無音は0)となっています。
次に音を人工的に作ってみましょう。以下にpythonのソースコードを載せますが読まなくて結構です。
import numpy as np import wave import struct from matplotlib import pylab as plt fname = '1sec_440Hz.wav' fs = 44100 f = 440 sec = 1 A = 32767 samples = sec * fs t = np.linspace(0, sec, samples) s = A * np.sin(2 * np.pi * f * t) s = s.astype(np.int16) data = struct.pack("h" * samples , *s) wf = wave.open(fname, 'w') wf.setnchannels(1) wf.setsampwidth(2) wf.setframerate(fs) wf.writeframes(data) wf.close() plt.plot(s[0:441]) plt.show()
このプログラムは440Hzのドレミファでいうラ音を1秒間モノラル出力したものです。以下のグラフは横軸0〜441(44100 / 100)。縦軸は繰り返しの説明になりますが、2バイト(16bit)、符号付きsigned(-32768 ~ +32767, 無音は0)です。
The Sample Rate The GBA hardware does internally re-sample all sound output to 32.768kHz (default SOUNDBIAS setting). It'd thus do not make much sense to use higher DMA/Timer rates. Best re-sampling accuracy can be gained by using DMA/Timer rates of 32.768kHz, 16.384kHz, or 8.192kHz (ie. fragments of the physical output rate).
適当翻訳すると「GBAは32.768kHzで音が鳴るんで32.768kHz, 16.384kHz, 8.192kHz」の
どれかにしといた方がいいぜ、とアドバイスしてくれてます。
例でいえば、画像ファイルのアスペクト比を無視して
縮小をするんじゃないぞ、と忠告してもらっているようなものです。
音の中身はモノラルであり、音単位は8bit singed(符号付き)となっています。
サンプルのsrc\res\Makefileの抜粋を見てみましょう。
.wav.s: $(WAVFILES) @echo \# converting $< @./sox $< -r 16384 -c 1 -B -s -1 $*.raw @padbin 4 $*.raw @bin2s $*.raw > $@ @rm $*.raw
データはsox(音フォーマット変換ツール)、padbin(バイト境界調整ツール)、
bin2s(アセンブリテキスト変換ツール)、に掛けていき、GBAのプロジェクトと結合します。
soxのコマンドオプションを詳しく見てみましょう。
soxのコマンドオプションはこのようになっています。
-r RATE sample rate of audio -c CHANNELS number of channels of audio data; e.g. 2 = stereo -B force endianness to big/little -s sample encoding: signed -1 sample size in bytes
コマンドプロンプトで打ち込んだ結果を以下に表します。
> sox 1sec.wav -r 16384 -c 1 -B -s -1 1sec.raw > > dir 1sec.raw > > 2019/01/05 xx:xx 16,384 1sec.raw
0x00で埋まった16,384サイズのファイルが出来上がりました。
GBAは「16384Hz モノラル 8bit(符号付き)」形式で鳴らす予定なので
ヘッダがない、素のデータのみ、ということがわかると思います。