T'SoundSystem Manual

# T'SoundSystem Spec

## Waht's New

・Programer's Manualを追加

・相対音量命令「(」「)」追加

・相対音量命令「~[n]」「_[n]」追加

・GAMEBOYモード更新中

・「p」命令の意味を変更（＊重要＊）

・相対オクターブ・音量命令のスワップ機能追加

## 基本機能

> 同時発音数 | 制限なし（コンパイラの仕様上の制限で26）。
> 音色表現力 | チェンネル毎に任意のモジュールを動的に選択可能。加えて、チャンネル間のFM変調機能搭載。ステレオ出力。
> 音程解像度 | 3種類から選択可能。
> 音量解像度 | 2種類から選択可能。
> タイマー | テンポ制御用とエンベロープ制御用の２本の擬似タイマー割り込みを内部に持つ。

### モジュール

> 0 | PSG | 矩形波音源。もっとも単純な音色しか出せないが、処理はもっとも軽い。
> 1 | FC | デューティ比を調節できる矩形波。ファミコンレベルの音色表現が可能。処理も軽い。
> 2 | NOISE | ノイズ音源。
> 3 | SIN | サイン波。FM変調をすることで、FM音源同様の表現が可能。若干重い。
> 4 | SCC | ウェーブテーブル音源。コナミ往年のSCC音源を再現可能。テーブルサイズは32。

### 音程解像度

> 0 | Hz | Hz単位での表現が可能。デフォルトのモード。
> 1 | MSX | MSXで使用されていたPSGと同等の解像度。高音域になると、音程が荒くなる。
> 2 | FM | FM音源等で使用されているような指数的な解像度。半音を64等分できる解像度を持つ。

### 音量解像度

> 0 | 線形 | 線形的な音量変化。
> 1 | 非線型 | FM音源などで採用されている音楽的な音量変化。

# T'SoundSystem MML Manual

## 制御文

> #TITLE <[title]> | 曲名を登録する。'\'を使えば、'>'等も含めることができる。 GAMEBOYモードでは意味を持たない。 (例)#TITLE <RISING ZAN \<THE SAMURAI GUNMAN\>>
> #CHANNEL [n] | 曲のなかで使う最大音色数を指定する。 (例)#CHANNEL 3
> #PRAGMA [key] | GameBoy用の曲データを作る際に使用する。keyとしてGAMEBOYを指定すること。 (例)#PRAGMA GAMEBOY
> #WAV [n], <[table]> | SCC用の波形テーブル n にデータを設定する。signed char×32。パラメータの詳細は後述。 GAMEBOYモードの時は０〜15しかパラメータに含めることが出来ない。 (例)#WAV 0, <(0, 127),16, (-128, 127),16>0〜255の256個登録できる。
> #TABLE [n], <[table]> | エンベロープ用の波形テーブル n にデータを設定する。siged char の任意長。パラメータの詳細は上に同じ。0〜255の256個登録できる。
> #OCTAVE [key] | keyはNORMALとREVERSEが指定可能。REVERSEを指定した場合は、相対オクターブ命令「>」「<」の機能が入れ替わる。 (例)#OCTAVE REVERSE
> #VOLUME [key] | keyはNORMALとREVERSEが指定可能。REVERSEを指定した場合は、相対音量命令「)」「(」の機能が入れ替わる。
> #A〜#Z | 各チャンネルのMMLデータを記述する。
> #END | MMLの終了を示す。これ以降はコメントとして扱われる。

### テーブルパラメータ

要素の数だけ、「,」で区切ってパラメータを列挙する。

(l, m),n の書式で、lからmまでの値をn個のパラメータで線形補完する。例えば、(1,5),5 は、1,2,3,4,5 と同じ。

## MMLコマンド

### 制御関連

(*)対応モード : N = 通常モード、 G = ゲームボーイモード

> コマンド | 有効範囲 | 解説 | (*)
> t[n] | 1≦n(120)≦512 | テンポ指定。テンポ制御用のタイマーの値を操作するので全チャンネルに影響が及ぶ。 | N/G
> $ |  | 無限ループ開始位置指定。これが指定されると、チャンネルデータが最後まで演奏された時、この位置に戻る。 | N/G
> [[n] ... | ] | 2≦n(2)≦255 | ループ擬似命令。'['から']'の間をn回繰り返す。最終ループの時は、'|'まで来たらループを抜ける。'|'は省略可能。コンパイルの段階で展開される。そのため、バイナリサイズは大きくなってしまう。が、相対命令も有効。ネストは不可。 (例)[3c<] …(展開)→ c< c< c< | N/G
> /:[n] ... / ... :/ | 2≦n(2)≦255 | ループ命令。'/:'から':/'の間をn回繰り返す。最終ループの時は、'/'まで来たらループを抜ける。'/'は省略可能。ドライバレベルのループ機能なので、コンパイル時に展開される相対命令の類は繰り返されない。ネストは16重まで可能。 (例)/:2cde/fgab<:/c:/ …(展開)→ cdefgab cde <c | N
> { ... } |  | コメント。'{'から'}'で囲まれた部分をコメントとして扱う。ネストも可能。 | N/G

### 音色関連

> s[n] | 0≦n(0)≦255 | サスティン。キーオフ後にいきなり音を消さずに減衰させる。0の時はOFF。値が大きいほど減衰も急。 | N
> s[n],[m] | 0≦n(0)≦255, -128≦m(0)≦127 | 拡張サスティン。キーオフ後に、音量だけではなく、音程も同時に連続的に変化させる。mに対する音程の変化分は、音程モードにより、異なる。 | N
> % | 0≦n(0)≦255 | モジュール変更。モジュール指定に使う数値は後述。 | N
> @ | 0≦n(0)≦255 | 音色変更。変更の方法・有効範囲はモジュール毎に異なり、そのパラメータの有効性はコンパイル時にはチェックされないので注意。 | N/G

### 音程関連

> o[n] | 1≦n(4)≦8 | オクターブの指定。大きいほど高い。 | N/G
> > |  | オクターブ・相対ダウン。コンパイラ擬似命令。 | N/G
> < |  | オクターブ・相対アップ。コンパイラ擬似命令。 (例)cdrfgab<c | N/G
> a[n]〜g[n] | 1≦n(L)≦1024 | ラ〜ソにそれぞれ対応した音を出す。Lはl[n]で指定された値。 | N/G
> +(#)/- |  | a〜gの直後に記述することで、音程を半音単位で上げ/下げする。 | N/G
> r[n] | 1≦n(L)≦1024 | 休符指定。 | N/G
> k[n] | -128≦n(0)≦127 | ディチューン。 | N/G
> mp[a], [b], [c], [d], [e] | 0≦a≦65535, 0≦b≦255, 0≦c≦255, -128≦d≦127, 0≦e≦255 | ピッチモジュレーション。a : Delay, b : Depth, c : Width, d : Height, e : Delta。発声後、a 単位時間後にモジュレーション開始。width 単位時間おきに height 単位音程ずつ変化する。変化量の絶対値が depth に達したら、変化の方向を逆転する。以上の処理を、delta 回繰りかえしたら、depth は 1 増える。任意のパラメータを省略可能。これを使用すると s コマンドの第 2 パラメータは無効になる。 | N
> p[n] | 0≦n(0)≦3 | パンポットの指定。v[n]系のモノラル指定を使って音量指定した時だけ意味がある。0:mute, 1:left, 2:right, 3:center。 | N/G

### 音長関連

> q[n] | 0≦n(MG)≦MG | 実際に演奏する音調の割合。ある長さだけ音を伸ばそうとしたとき、実際にはその長さのn/MGが演奏され、残りの時間は休符になる。（現在はMG=16で固定） | N/G
> l[n] | 1≦n(4)≦1024 | 省略時の音調指定 | N/G
> . |  | 音長指定の直後に付加することで、長さを1.5倍にする。続けて複数付加できる。 | N/G
> ^ |  | タイ。音長のあとにさらに音長を追加する。 (例)c4^16 | N/G

### 音量関連

> v[n] | 0≦n(10)≦15 | 音量を指定する。数値が大きいほど音も大きい。この方法で指定すると、パンポットで指定の位置に音がふられる。 | N/G
> v[n], [n] | 0≦n≦15 | 音量を指定する。始めの値が左、次の値が右のチャンネルの音量を示す。任意のパラメータを省略可能。 (例)v15,0 c v10, c v0,10 c v,15 c | N
> @v[n] | 0≦n(10)≦255 | 音量を細かく指定する。モノラル。 | N
> @v[n],[n] | 0≦n(10)≦255 | 音量を細かく指定する。ステレオ。 | N
> ) |  | 音量・相対ダウン。コンパイラ擬似命令。直前にvを使ったか、@vを使ったかで変化単位が変わる。 (例)v0 /:c)d)e:/ …(展開)→ v0c v1d v2e c v1d v2e | N/G
> ( |  | 音量・相対アップ。コンパイラ擬似命令。直前にvを使ったか、@vを使ったかで変化単位が変わる。 | N/G
> _[n] | 0≦n(1?)≦255 | 音量を相対的に、256段階指定単位でnだけダウンする。nの値は最初に省略された時は1、それ以外で省略された時は前回の値が使用される。ドライバプリミティブ命令。 (例)@v32 l16 c_8d_e_f_g …(展開)→ @v32 c16 @v24 d16 @v16 e16 @v8 f16 @v0 g16 | N
> ~[n] | 0≦n(1?)≦255 | 音量を相対的に、256段階指定単位でnだけアップする。nの値は最初に省略された時は1、それ以外で省略された時は前回の値が使用される。前回の値は「_」と「~」ではそれぞれ別々に管理される。 | N
> na[n],[m] | 0≦n(0)≦255, 0≦m(0)≦255 | 音量エンベロープ。テーブルn番のデータでエンベロープをかける。mは1回の変化が起こるまでの時間。mが大きいほど変化はゆっくりになる。いずれかの省略は不可。共に省略、またはmが0の時は機能をOFFにする。 | N
> x[n],[m] | 0≦n(0)≦1, 0≦m(0)≦3 | 音量モード(n)、音程モード(m)の設定。 | N

### FM変調関連

> @i[n],[m] | 0≦n(0)≦8, 0≦m(0)≦3 | FM変調入力モードを設定する。nが0の時OFF。1〜8は変調の感度を表す。mは変調に使用するパイプ番号。 | N
> @o[n],[m] | 0≦n(0)≦2, 0≦m(0)≦3 | FM変調出力モードを設定する。nが0の時OFF。1の時は上書モード、2の時は加算モード。mは変調に使用するパイプ番号 | N

## モジュール

モジュール指定に使うIDは以下の通り。ただし、128以降のIDは過去の仕様との互換性のために存在するもので、通常はモジュール変更のあとにpコマンドを使用して音程モードを変更して下さい。

後のversionでは音程モードについては%コマンドでは変化しないような仕様に変更する可能性があります。

> > ID | 音源 | 音程モード | 変調（IN/OUT）
> > --- | --- | --- | ---
> > 0 | PSG | Hzモード | ×/×
> > 1 | FC | Hzモード | ×/×
> > 2 | NOISE | Hzモード | ×/×
> > 3 | SIN | Hzモード | ○/○
> > 4 | SCC | Hzモード | ○/○
> > 128 | PSG | MSXモード | ×/×
> > 129 | FC | MSXモード | ×/×
> > 130 | NOISE | MSXモード | ×/×
> > 131 | SIN | MSXモード | ○/○
> > 132 | SCC | MSXモード | ○/○
> > 256 | PSG | FMモード | ×/×
> > 257 | FC | FMモード | ×/×
> > 258 | NOISE | FMモード | ×/×
> > 259 | SIN | FMモード | ○/○
> > 260 | SCC | FMモード | ○/○

## FM変調

以前は、SINモジュールの時にのみ、@コマンドを使って変調を指定していましたが、以後は@i/@oコマンドを使用して下さい。

やはり、こちらも以前の方法は廃止される可能性があります。

### 変調出力モード

出力モードがONになると、そのチャンネルの波形データは、スピーカへは出力されず、パイプへ出力されます。パイプに出力されたデータはそれ以降のチャンネルに影響を与えることができます。

まず上書モードですが、このモードではすでにパイプにデータがあった場合でも、現在の出力でデータを上書きします。

加算モードでは、逆にパイプにあるデータと、現在の出力の合成波をパイプに出力します。

パイプのデータは自動に初期化されることはないので、パイプへ最初に出力するチャンネルは上書モードである必要があります。

### 変調入力モード

入力モードがONになると、パイプからの入力データを位相に反映させます。この時の反映の度合いは感度によります。

あるチャンネルからの出力を入力に利用する際、出力側のチャンネル番号を入力側のチャンネル番号よりも若いものにして、双方で同じ番号のパイプに出力/入力する必要があります。

### 例

>     Ａ→Ｂ→Ｃ♪

> >     #A @i0,0 @o1,0 { 最初のチャンネル。パイプ0に新規に出力 }
> >     #B @i1,0 @o1,0 { #Aの出力をパイプ0経由で位相に反映させたものを再度パイプ0に出力 }
> >     #C @i1,0 @o0,0 { #A->#Bをパイプ0経由で位相に反映させスピーカーへ出力 }

>     Ａ―＋→Ｃ♪
>     Ｂ―＋

> >     #A @i0,0 @o1,0 {パイプ0に新規出力 }
> >     #B @i0,0 @o2,0 {パイプ0に加算出力 }
> >     #C @i1,0 @o0,0 {#A+#Bをパイプ0経由で位相に反映させスピーカーへ出力 }

# Programer's Manual

## 概要

T'SoundSystemをプログラムから利用する方法は、大きくわけて２つあります。１つはin_tss.dllを利用する方法、もう１つはNPTSS.DLLを利用する方法です。前者はWinAmpのPlug-in、後者はNetscapeのPlug-inとして機能しますが、それぞれ別のプログラムから利用しやすいように独自インターフェースを備えています。結論から言えば、サウンドストリームに対して、より綿密な制御がしたい場合はin_tss.dll、簡単に高機能なライブラリを使いたいのならNPTSS.DLLを使うべきです。NPTSS.DLLはまた、効果音の多重再生のサポートします。

## in_tss.dllのインターフェース

### void DSP_WRITE(void *buffer, unsigned int size);

T'SoundSystemからの出力をバッファに受け取ります。つまり、再生時には常にこの関数を定期的に呼び出し、受け取ったデータをなんらかの方法で再生する必要があります。よっしん氏の超連射ではPCM再生の遅延を限界まで減らすために自前のサウンドループに、ここで得た出力を合成する、といった手法をとっています。

### BOOL PlayMusicBuffer(char *data, int length);

既にメモリ上に読み込んだ、TSS,TSDデータを再生します。上記のとおり、このルーチンをコールしただけでは再生されず、DSP_WRITEを使って出力を取り出す必要があります。

### BOOL PlayMusic(char *filename);

上記コールのファイル名渡し版です。

### void StopMusic(void);

（再生中ならば）再生を停止します。（すでに再生中の場合に、再生系の呼び出しをした場合には、内部でまずStopMusicを呼び出してから次の再生を開始します）

### サンプル

`

    #include <Windows.h>
    #include <stdio.h>
    #include "in_tss.h"

    int main(int argc, char **argv)
    {
    	/* 最初の引数で渡されたデータの先頭1Mbyteぶんのサンプリング出力を標準出力に書き出す */
    	char buf[1024];
    	if (!PlayMusic(argv[1])) fprintf(stderr, "PlayMusic: failed\n") && exit(1);
    	for (int i = 0; i < 1024; i++) {
    		DSP_WRITE(buf, 2048);
    		write(STDOUT_FILENO, buf, 2048);
    	}
    	StopMusic();
    	return 0;
    }

`

## NPTSS.DLLのインターフェース

### void TSGL_Init(HWND hwnd);

ライブラリを初期化します。必ず最初に呼び出してください。HWNDにNULLを渡した場合にはMultiMedia APIが、正しいウィンドウハンドルを渡した場合にはDirectSoundが使用されます。

### void TSGL_Trash(void);

ライブラリの後処理をします。最後に呼び出してください。

### void TSGL_PlayMusicBuffer(char *data, int length);

すでにメモリ上に読み込んだTSS,TSDデータを再生します。呼び出すだけで、別スレッドで自動的に再生されます。

### void TSGL_PlayMusic(char *filename);

上記コールのファイル名渡し版です。

### void TSGL_StopMusic(void);

演奏を停止します（音楽演奏のみ）。

### void TSGL_PlaySound(int channel, char *data, long size, long bytesPerSample, long channelCount, long samplingRate);

チャンネルを指定し、効果音を再生します。チャンネルは0-7まで有効です。再生中のチャンネルを指定した場合には、再生中の効果音を取り消して再生します。また、再生が終わるまで、渡したメモリは開放してはいけません（メモリ管理が厳密なNT系列のkernelではクラッシュします）。

### void TSGL_StopSound(int channel);

チャンネルを指定し、効果音を停止します。

### void TSGL_PlaySoundAuto(char *data, long size, long bytesPerSample, long channelCount, long samplingRate);

チャンネルを自動的に割り振り、効果音を再生します。空いているチャンネルが無い場合には、古いデータから順に取り消し、再生します。

### void TSGL_StopSoundAll(void);

すべての効果音を停止します。

### int TSGL_Check(int channel);

チャンネルを指定し、効果音が再生中かチェックします。

### void TSGL_PlaySoundLocal(char *data, long size, long bytesPerSample, long channelCount, long samplingRate);

データを内部にコピーした上で、効果音を再生します。このコールは、再生中に渡したメモリを開放してもかまいません。ただし、コピーの際にオーバーヘッドが生じるので、多用は禁物です。再生終了後に内部のコピーは自動的に破棄されます。このコール用に内部に専用のチャンネルを持っています。

### void TSGL_StopSoundLocal(void);

PlaySoundLocalで再生中の効果音を停止します。

based on ver.0.85 / Last update: $Date: 2000/12/02 08:17:22 $