なお、このシリーズで扱うプログラミングの例題のビルドには、パソコンが必要です。OSは私が使っているMac OS X向けに解説を記述しますが、Linux(※ALSAに対応しているもの)やWindowsでも問題ありません。
今回は、VGS-SALについて解説します。
VGS-SAL
前回の記事で紹介した低レベルAPIのひとつひとつを解説すると、それだけで膨大な量の解説が必要になってしまいます。そこで、低レベルを直接叩くのではなく、VGSのSAL(Sound Abstraction Layout)を利用することにします。
VGS-SALは、Windows(DirectSound)、Linux(ALSA)、Mac、iOS、Androidの低レベルAPIを抽象化したものです。これを用いることで、全OS共通実装で「波形直書き」の実装ができます。
sal-sample
vgs2リポジトリの
このサンプルプログラムでは、VGS-SALを用いて440Hzのサイン波を鳴らし続けます。
サンプルプログラムは、ターミナルで以下のコマンドを実行すれば、ビルドできます。
(2)初期化:
(3)終了:
(4)バッファリング:
(5)バッファリング処理の内容
1行目
2行目
3行目
sample/sal-sample
ディレクトリにVGS-SALを用いたサンプルプログラムが格納されています。このサンプルプログラムでは、VGS-SALを用いて440Hzのサイン波を鳴らし続けます。
サンプルプログラムは、ターミナルで以下のコマンドを実行すれば、ビルドできます。
$ cd ~/vgs2/sample/sal-sample/ && make
sample/sal-sample
ディレクトリに格納されている makefile と saltest.c を見てみましょう。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: | |
make all-`uname` | |
all-Linux: | |
make build SOUNDLIB=-lasound | |
all-Darwin: | |
make build SOUNDLIB="-framework OpenAL" | |
build: | |
gcc -o saltest \ | |
-I$(VGS2_HOME)/template \ | |
saltest.c \ | |
$(VGS2_HOME)/template/vgs2sound.c \ | |
$(SOUNDLIB) \ | |
-lpthread |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <math.h> | |
#include "vgs2.h" | |
#define PI2 6.2831853071795864 | |
int main() | |
{ | |
char buf[1024]; | |
puts("Initialize sound-system"); | |
if(init_sound_cli()) { | |
puts("Failed!"); | |
return -1; | |
} | |
puts("Enter to finish program."); | |
while(fgets(buf,sizeof(buf),stdin)) { | |
break; | |
} | |
puts("Terminate sound-system."); | |
term_sound(); | |
return 0; | |
} | |
void sndbuf(char* buf,size_t size) | |
{ | |
static double r=0.0; | |
short* ptr=(short*)buf; | |
int i; | |
int size16=size/2; | |
lock(); | |
for(i=0;i<size16;i++,ptr++) { | |
*ptr=(short)(sin(r)*16384); | |
r += PI2 / (22050 / 440); /* 440Hz */ | |
} | |
unlock(); | |
} |
(1)makefile
- saltest.cをビルドする手続きが書かれています
(2)初期化: init_sound_cli
- SALの初期化をします
- cliとは Command Line
Interface(コマンド) の略です
- Windowsの場合、GUI用の初期化処理が別にありますが、その点についての解説は省略します
- UNIX系OSの場合、CLI用とGUI用の間に違いはありません
(3)終了: term_sound
- SALが用いているシステムリソースを解放します
- かならずプログラムの最後で呼び出すようにしてください
(4)バッファリング: sndbuf
- 一定間隔毎にSALからコールバックされるバッファリング処理です
- C++で実装する場合は、必ず
extern "C"
で宣言するようにしてください - 引数
buf
: 波形情報を格納するバッファです - 引数
size
: 波形情報を格納すべきサイズです buf
の内容を変更する処理は、必ずlock()
〜unlock()
で囲まなければなりません- 上記サンプルでは、440Hzのサイン音 が鳴り続けることになります
(5)バッファリング処理の内容
sndbuf
の lock()
〜 unlock()
で囲まれた範囲(バッファリング処理)の実装内容をもう少しブレイクダウンして見ていきましょう。1行目: for(i=0; i < size16; i++, ptr++) {
2行目: *ptr = (short)(sin(r) * 16384);
3行目: r += PI2 / (22050 / 440); /* 440Hz */
4行目: }
1行目
size16
は 引数buf
(8bit array) を 16bit array とした時の長さです- そして、
i
=0
〜size16-1
の間、ptr
をインクリメントしながらループすることになります ptr
は 引数buf
を 16bit array にしたものですptr
のインクリメントとは、__サンプリング周期のインクリメント(+1Hz)と等価ですね
2行目
sin(r)
を 16384倍 にした数値をptr
に代入していますsin
関数
の戻り値は-1.0
〜1.0
の範囲の実数です- なので、
ptr
に代入している値は-16384
〜16384
の範囲の値です - つまり、この
16384
というマジックナンバーは 鳴らす音の大きさ を意味しています - 16bitは
-32768
〜32767
の範囲の数値なので、限界音量の約
50%
がこのプログラムで鳴らす音の最大音量となります
3行目
r
を 2π ÷ ( 22050 ÷ 440 ) で加算していますr
は スタティック変数 なので、関数がreturn
しても値が維持され続けます- そのため、
sndbuf
が呼び出され続けると 440Hz のサイン波 が発音され続けることになります
追記
umm...
ここから先はコードベースの解説が多くなるのですが、bloggerだと結構辛いので、GitBook辺りを使ってイチから書き直すか。