2016年2月14日日曜日

vgs-spuで始めるサウンドプログラミング

サウンドプログラミングは割と敷居が高いと思われがちですが、その原因は音を鳴らすまでがやたらと難しいためだと思います。これは今も昔も変わらないことです。昔はパソコンに搭載されている石の仕様を理解する必要があったので、実際かなり大変でした。

しかし、今のパソコンやスマートフォンであれば、少なくとも石(H/W)の違いを意識する必要はありません。Windows、Mac OS X、Linux、UNIX、Android、iOSなどで、音を鳴らす基本的な仕組みは全部同じですが、それぞれのOSが提供する「音を鳴らす方法」が以下のように多様にあります。
  • Windows: WaveMapper や DirectSound
  • Mac OS X, iOS: AudioUnit や OpenAL
  • Linux: ALSA; Advanced Linux Sound Architecture
  • Android: OpenSL/ES (他)
  • UNIX: OSS; Open Sound System
全部覚えるのは面倒臭いです。全部どころか、一つマスターするのも結構大変かもしれません。(やれる事はだいたい全部同じなので、一つマスターするだけで全部マスターするのは容易いですが)

VGSではこの辺りの実装を Sound Abstraction Layer (SAL) という形で抽象化しましたが、今回、その SAL を更に汎用的な形で独立させてみました。

VGS - Sound Processing Unit (SPU)
https://github.com/suzukiplan/vgs-spu

まだこの記事を書いている段階では WIP にしていますが、とりあえず Windows と Mac OS X では動きました。VGS-SPUは、全OS共通の「音を鳴らす方法」を提供します。これを使えば、敷居が高いと思われがちな サウンドプログラミング の敷居が幾分か低くなります。

どの程度低いかは、VGS-SPUの example を見ていただければ分かると思います。
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include "vgsspu.h"
#ifdef _WIN32
static void usleep(int usec)
{
Sleep(usec / 1000);
}
#endif
static unsigned int hz;
static unsigned int pw = 22050;
static void buffering(void* buffer, size_t size)
{
short* sbuf = (short*)buffer;
size_t s2 = size >> 1;
size_t s1;
for (s1 = 0; s1 < s2; s1++, sbuf++, hz++) {
if (hz % 440 < 220) {
*sbuf = (short)((16384 * pw) / 22050);
} else {
*sbuf = (short)((-16384 * pw) / 22050);
}
if (pw) pw--;
}
}
int main(int argc, char* argv[])
{
void* context = vgsspu_start(buffering);
if (NULL == context) {
puts("failed");
return -1;
}
usleep(1000000);
vgsspu_end(context);
return 0;
}

この example では、buffering というコールバック関数で波形(440Hz = ラ の矩形波)を書き、main関数で VGS-SPU を起動、スリープ、停止という手続きを実行しています。

「音を鳴らす」というのは要するに波形データの変化(PCM)を書くことです。その辺のことは情報処理の教科書的なもので見たことがあると思いますが、「そのデータを何処に書くの?」ということは恐らく情報処理の教科書的なものには書いてないと思います。「何処に書くのか」は、前述の各OSが提供しているサウンドAPI毎に異なるし、また、あまり纏まった資料も無い(個々のAPI毎にかなり無駄に分厚い専門書とかなら少ないがある)ので、実際に音(PCM)を書くところまで辿り着くのが結構大変です。

しかし、VGS-SPUなら「vgsspu_startを呼ぶ」「コールバックで音を書く」「vgsspu_endで終わる」という極めてシンプルな3ステップだけでサウンドプログラミングの入り口に辿り着くことができます。

そして、VGS-SPUを通して音の鳴らし方のイメージが掴めてきたら、VGS BGM Decoderを見てみると良いです。

VGS BGM Decoder
https://github.com/suzukiplan/vgs-bgm-decoder

VGS-SPUは音を書くための方法で、VGS BGM Decoderは書く音を生成するコーデックと呼ばれるものです。コーデックという言葉はマルチメディア系に詳しい方なら聞いたことがあるかもしれませんが、サウンドの世界では符号化されたデータ(VGSなら .BGM形式)をリニアPCMへ変換するもの(デコーダ)や、何がしかのデータを符号化するもの(エンコーダ)があります。

VGS BGM Decoderにとってのエンコーダは MML(テキスト)を .BGM形式に変換するMMLコンパイラのことですね。VGSのMMLコンパイラについても独立したリポジトリに切り出してみました。

VGS MML Compiler (encoder)
https://github.com/suzukiplan/vgs-mml-compiler

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...