読者です 読者をやめる 読者になる 読者になる

ActionScript で波形メモリ音源向け波形編集ツール

ActionScript3 SiON wonderfl


Wave Shape Editor | Si+ (wonderfl.net)
7ヶ月ぶりに wonderfl りました。ついでに日記は9ヶ月ぶりの更新。今回は、波形メモリ音源向け波形編集ツール、という著しくニッチなモノを作ってみました。
ちなみにSiON ネタは実に1年2ヶ月ぶり。
ほぇー。最近、歳月が過ぎるのが早すぎて困る。
かなりマニアックなネタですが、いざ作って触ってみると波形と音の実験ツールとして中々面白いポテンシャルを持ってそうだと感じました。そこで今回は少し趣向を変えて、いつもの技術ネタではなく、簡単な音実験をしながら操作方法のチュートリアルを書いてみようと思います。

イントロダクション:波形メモリ音源って?

wikipedia:波形メモリ音源
平たく言えば、1周期分の波形データだけ持っておいて音階をつけて鳴らす音源方式です。
演算がシンプル かつ 省メモリで 多様な音が作れたため、1980年代前半のいくつかのアーケードゲーム基板に搭載され、それまで矩形波一辺倒だったゲーム音楽の世界に新たな風を起こしました。またファミコンMSX では、わざわざカードリッジに波形メモリ音源チップを搭載して音楽を鳴らすゲームが登場し、ゲーム音楽の一時代を築きました。以降のハード、ファミコンディスクシステムゲームボーイPCエンジンなどでは波形メモリ音源が標準搭載されており、この時代のゲーム音楽においていかに重要な存在だったかを垣間見ることが出来ます。
MMLTalks にこの時代の波形メモリ音源を使用した力作データが沢山ありますので聴いてみると良いかも知れません。
[BUBBLESYSTEM] | MMLTalks
[wsg] | MMLTalks
[scc] | MMLTalks
1980年代終盤以降における FM 音源チップの台頭によりお役御免となりますが、ゲーム黎明期の名作に数多く使用されたため、懐古的な音楽シーンでは今でもよく使われているようです。

イントロダクション:SiON の波形メモリ音源

基本的な使い方は、SiONDriver.setWaveTable() メソッドで Vector. 形式の波形データを登録して、波形メモリ音源モジュール(4番)を指定した mml 又は SiONVoice で呼び出す、という形になります。
(現在 RC 版のSiON ver.0.65では SiONVoice.setWaveTable() メソッドが追加されており SiONVoice が直接波形情報を持てるようになっています。)

// 波形設定(エントリ数は2の累乗)
var waveShape:Vector.<Number> = new Vector.<Number>(256); 
// たとえばサイン波
for (var i:int=0; i<256; i++) {
    waveShape[i] = Math.sin(Math.PI * 2 * i / 256);
}
// 波形登録
var sion:SiONDriver = new SiONDriver();
// 音声番号=0 に waveShape を登録
sion.setWaveTable(0, waveShape);
...
// "%4@0" でモジュール=4、音声番号=0 を指定
sion.play("%4@0 cde");  // mml を使って登録した波形の音を鳴らす。
... or ...
// モジュール=4、音声番号=0 を指定
var waveMemoryVoice:SiONVoice = new SiONVoice(4, 0);
sion.noteOn(60, waveMemoryVoice); // SiONVoice を使って登録した波形の音を鳴らす。

波形メモリ音源は演算が非常にシンプルなので、低負荷で多様な音を出力することができる優秀な音源方式です。SiON では公開時からエミュレータが搭載されており、単純な矩形波と同等の低負荷で音を出す事ができます。
にもかかわらず、MMLTalks以外では、今までほとんど扱ってきませんでした。

波形と聴感:概論

波形メモリ音源では波形を直接設定するため、一見とても直感的に見えますが、実際には波形と聴感の間に認識できる相関はほとんどありません(中には波形から音が想像できる変態さんも居るかもしれませんが、普通はせいぜい頭の中で近い典型的な波形に分解して、その合成音を考える程度)。このため、思い通りの波形を作るにはトライアンドエラーの繰り返しとなり、様々な波形編集を試せるツールが必要になります。しかし、残念ながら波形メモリ音源はロストテクノロジのため、有用なツールはなかなか見つかりません(TSSCP や mck 界隈でいくつかツールはありますが、自分には波形を加工するのに機能不十分と感じました)。
結局、波形メモリ音源を扱うためにはまずはその波形編集用のツールが必要で、しかしなかなか有用なものが無かったため、強力な音源方式であるにも関わらず扱えなかった、という感じです。で、無いなら作ってしまえというのが、今回の波形メモリ音源向け波形編集ツールを作った直接のモチベーションです。
以降、実際にツールを使いながらの操作説明と、簡単な実験を行ってみたいと思います。
(参照)オペレーションマニュアル

波形と聴感:基本的な波形の音

先ほど、波形と聴感の間に認識できる相関はほとんど無いと書きましたが、典型的な波形の音を覚えておくことで指針を得ることは可能です。まず、その典型的な波形の音をツール上で聴いてみましょう。

sin波

ツール上で [SELECT_ALL] -> [sin] -> [check sound]
一番基本的な音です。人間の耳は共鳴によって音を分解して認識するため、特定周波数で最も共鳴が起きやすいこの波形が純粋な音と認識されるようです。

三角波

ツール上で [SELECT_ALL] -> [triangle] -> [check sound]
sin波に似てますが、奇数倍音成分が含まれているため、少し明るい音と認識される傾向があります。

矩形波

ツール上で [SELECT_ALL] -> [square] -> [check sound]
デジタル上で一番演算が簡単な波形で、典型的なファミコン音やBEEP音はこの波形で、いわゆるピコピコ音とはこの波形を指すことが多いようです。sin波や三角波で極端にボリュームを上げた場合、-1と1で飽和するため究極的にはこの矩形波になります。このため強い音と認識される傾向があります。

鋸(ノコギリ)波

ツール上で [SELECT_ALL] -> [linear] -> [check sound]
アナログシンセで擬似ストリングスとして重宝されていた波形で、バイオリンなど撥弦楽器の波形に近いといわれています。1/周波数の強さで全整数倍音を含んでいるためフィルターで加工しやすく、明るい音と認識される傾向があります。

短周期乱数波

ツール上で [SELECT_ALL] -> [random] -> [check sound]
純粋な乱数波はホワイトノイズと呼ばれ、テレビやラジオの砂嵐音です。しかし、波形メモリ音源では基音が決まっておりランダムな倍音を含む音になります。同じ振幅では高い音のほうが耳障りになるため、ランダムに等しく倍音を含むこの音は耳障りな音と認識される傾向があります。
実際には、波形サンプル数が64と非常に荒いことによる高周波ノイズ成分がのった音になっていますが、この波形は大体こんな音、という位には判ると思います。

波形と聴感:波形の変形

次に波形を少し変形して音がどのように変化するか試してみます。上述の典型的な波形の音を覚えておくとその合成である程度音の予想がつくカナ?というのが何となくわかると思います。

sin波⇔三角波

一番基本的な波形合成方法は加算合成です。画像処理で言う Alpha 合成を想像してもらえばよいと思います。各サンプル値を一定比率で加算したもので、単純に二つの音を同時に鳴らしてボリュームを変えているのと理論的には同じになります。
やり方は、まず上述の方法で sin 波を設定後[>>Operator]で合成波形に sin 波を読み込みます([>>Operator]ボタンの隣のアイコンに sin 波が表示されればok)。次に、同様に三角波を設定後[blend...]ボタンを押します。あとは波形編集画面中央の青線をドラッグすることで加算合成比率をコントロールすることが出来ます。
聴いてみると、まさにブレンドという感じです。波形が中間くらいの形だと中間くらいの音が鳴るのが判ると思います。

sin波⇔矩形波

上述の加算合成で波形の補間は出来ますが、あえて別の方法で変形させてみます。sin 波を読み込み後[Inflate...]を選択してください。同様に青線をドラッグすると波形が膨らむ/萎むように変形します。処理としては中間の数値を1又は-1に近づける/遠ざけるような演算をしています。画像処理でいう覆い焼きと焼き込みが近いでしょうか。この変形でもsin波と矩形波の間を別の方法で補間することが出来ます。聴いてみるとやはり中間くらいの音が鳴るのが判ると思います。ただし、ほんの少しの変形で大分矩形波に近づく印象があります。
また別の方法で変形させてみます。sin 波読み込みから[Scale...]を選択して値を変更すると sin 波の振幅が変わります。ただし1,-1で飽和するため値を上げていっても頭打ちになります。コントラストを上げていって白とびするイメージです。波形の頭が切れて台形になるにつれ音が矩形波に近づいていく様子がわかります。

sin波⇔ノコギリ波

さらに別の方法で変形させてみましょう。sin 波を読み込み後[Pinch...]を選択してください。青線をドラッグすると波形が左右に偏ります。処理としては時間軸方向に波形歪めています。この方法では完全にノコギリ波に近づけることは出来ませんが、ある程度波形が偏ってくるとノコギリ波っぽい雰囲気が出てくると思います(少しムリがあります、厳密には「ノコギリ波にフィルターを掛けた音」に近づくのであんまり似てない)。

波形と聴感:波形の変形2

他にも様々な変形方法がありますが、典型的なものをいくつか紹介しておきます。

multiple

周波数を整数倍します。波形を作ったら[>>Operator]で合成波形として登録。青線を+1までめいっぱい上げてから、[>>Operator]ボタンの隣の[m=1]と書いてあるスライダーを動かすと周期を変更できます。ただしサンプル数が少ないため高いmultipleでは波形を再現できません。
[Stretch...]を使っても周波数を操作できますが、整数倍でないと両端を切った波形になってしまうので注意が必要です。

半波整流波、全波整流波

詳細はwikipedia参照。波形の半分を0に設定すると半波整流、もう半分からコピーすると全波整流です。半波整流は波形の右半分を選択後[fill zero]でok。全波整流は波形の左半分を選択して[COPY]後、右半分を指定して[PASTE]。

位相操作

[SELECT_ALL] -> [Rotate...]で位相を変更できます。やってみると判りますが聴感上の違いはありません。ただ、上述の加算合成や、これから説明するリングモジュレーション・周波数変調は位相によって違った効果がでます。

波形と聴感:2波形の合成

さて、先ほど加算合成について説明しましたが、そのほかにも典型的な波形合成方法を2種類搭載しています。ただし、これらはとても複雑でトライアンドエラーで音の変化を確かめていくのが基本スタンスになります。ここでは操作方法のみ説明します。

リングモジュレーション(乗算合成)

乗算合成です。演算方法もシンプルで掛け算を行います。上述の加算合成と同じ方法で合成波形を設定して[Ring mod...]で操作します。

FM合成(周波数変調)

いわゆるヤマハFM音源の合成方式です。周波数を変調するのではなく位相の微分値を変調するので、厳密な周波数変調ではありませんが、演算が軽く、倍音成分を簡単に制御できるため、音源においてはこの方式をFM合成と呼ぶことが多いです。他の合成と同様[Freq mod...]で操作します。
まずは、sin波を合成波形に設定してmultiple=5位でsin波を変調してみると、倍音が増して明るい音になると思います。ここら辺になると波形と音の相関がほとんどない事がわかると思います。

波形と聴感:作った波形を使う

ツールで作った波形をどうやって使うかについてですが、[Hex Window]で波形を HEX 文字列として出力して、それをMML又はプログラム上で展開する形になります。HEX 文字列は単純な 1byte singed int 値なので

// ただし length は 2の累乗
var length:int = hexString.length / 2;

var samples:Vector.<Number> = new Vector.<Number>(length);
for (var i:int=0; i<length; i++) {
    var value:int = parseInt(hexString.substring(i*2, 2));
    samples[i] = ((value < 128) ? value : (value - 256)) / 128;
}

で展開できます。MMLから呼び出す場合は "#WAVB" コマンドでHEX文字列をそのまま記述すればOKです。
また、[Hex Window] では [Update data from HEX] ボタンで逆にHEX文字列から波形データを読み込む事も出来ます。

最後に

波形メモリ音源の音つくりは結局トライアンドエラーだと思います。
MMLTalks の MML から波形データを引っ張ってくれば、往年の名作ゲームの波形データを覗くなんて事も可能です。
興味あれば色々いじってみると面白いかもしれません。