Copyright (C) 2003-2011 デグレファクトリー
この資料は SNES SPC700 Player v2.12.4 以降に準拠しています。
4. 本家 SNESAPU.DLL から修正された不具合の一覧
改良版 SNESAPU.DLL は、保存しただけでは演奏できない SPC ファイルをなるべく演奏させるための拡張規格、 TimerTrick, Script700, Script700 SE に互換対応しております。
TimerTrick 互換機能は、木下氏が立案され、黒羽氏、 PEN@海猫氏が実装された TimerTrick 規格に互換性があります。
Script700 互換機能は、 41568k 氏が立案・実装された Script700 規格の一部の命令と、木下氏が立案・実装された Script700 SE 規格の一部の命令に互換性があります。
この資料では SNESAPU.DLL に搭載されている各 API 仕様と、TimerTrick, Script700 (SE) の互換機能を利用するための API 仕様、その他の独自拡張機能について説明しています。
この資料では、 SPC の演奏に最低限必要な API の解説のみを記載しています。 その他の API については本家サイト (Alpha-II Productions) のサンプル コードをご覧ください。
この資料で解説している API のバージョンは v2.x 系です。 v1.x 系や本家 v3.x 系の API は仕様が異なりますのでご注意ください。
1. サウンド デバイスを初期化します。
このとき、出力する波形データのチャンネル、ビット、サンプリング レートを決めておきます。
2. SetAPUOpt 関数で、演奏に関わる基本オプションを設定します。
基本的に、サウンド デバイスを初期化したときと同じ設定を使用します。
3. SPC ファイルを読み取り、メモリ上に格納します。
4. LoadSPCFile 関数で、読み取った SPC ファイルのメモリ内容を SNESAPU に転送します。
5. 必要であれば、 SetScript700, SetTimerTrick 関数で Script700 互換機能、または TimerTrick 互換機能を設定します。
6. EmuAPU 関数を呼び出して波形データを取得します。
7. 取得した波形データをサウンド デバイスへ転送して演奏を行います。
8. 手順 6 ~ 7 を繰り返します。
SPC700, DSP のエミュレーションを行い、波形データを生成します。
void* EmuAPU(void *pBuf, u32 len, u8 type);
引数
pBuf
[out] 波形データを格納するためのバッファへのポインタを指定します。
len
[in] 波形データを格納するためのバッファのサイズを指定します。
type
[in] 波形データを格納するためのバッファのサイズの単位を指定します。
0 | = APU のクロック数を基準としたサイズ。 24576000 で 1 秒分。 |
1 | = サンプル数。 サンプリング レートと同じ数で 1 秒分。 |
戻り値
pBuf で指定されたバッファに書き込まれた波形データの終端ポインタが返ります。
解説
この関数を呼び出す前に LoadSPCFile 関数を呼び出して、演奏の準備を行う必要があります。 その後はこの関数を続けて呼び出すことで、連続した波形データを取得できます。
通常、バッファ サイズの計算をしやすくするために type には 1 を指定します。 この場合、 len に指定する値はバイト数ではなくサンプル数であることに注意してください。 例えば 2ch, 16bit, 48kHz で 3 秒のバッファを出力する場合、バッファのサイズは 2 × 2 × 48000 × 3 = 576000 バイト必要ですが、 len に指定する値は 48000 × 3 = 144000 です。
参照
SPC ファイルのバッファを読み取り DLL 内部のメモリにコピーして、新しい SPC を演奏する準備を行います。
void LoadSPCFile(void *pFile);
引数
pFile
[in] SPC ファイルの内容が格納されたバッファへのポインタを指定します。 バッファのサイズは最低でも 66048 バイト必要です。
戻り値
ありません。
解説
pFile には、ファイル パスではなくファイルの内容を渡します。 この関数はファイル自体を読み込みません。 ファイルの読み込みはこの関数を呼び出す側 (プレイヤー側) で行う必要があります。
必ず 66048 バイト以上のメモリを確保して SPC ファイルの内容をバッファにコピーした後、そのバッファへのポインタを指定してください。 バッファ サイズが不足している場合は異常終了します。
この関数を呼び出した後すぐにバッファを解放、または書き換えができます。 演奏中もバッファを確保しておく必要はありません。
この関数を呼び出しても、 SetAPULength 以外の関数で行った設定は保持されたままです。 したがって、ファイルに応じて設定を変更する場合 (特に TimerTrick と Script700) は、別途設定関数を呼び出して再設定する必要があります。
参照
SetAPULength, SetScript700, SetTimerTrick
指定された時間だけシークして、演奏をスキップします (早送り)。
void SeekAPU(u32 time, u8 fast);
引数
time
[in] シークする時間を指定します。 単位は 1/64000 秒です。 64000 を指定すると 1 秒間シークします。
fast
[in] シークする際の処理を指定します。
0 | = シーク処理中 DSP エミュレーションを行います。 |
1 | = シーク処理中 DSP エミュレーションを行いません。 高速に動作します。 |
戻り値
ありません。
解説
この関数は早送りできますが、巻戻し (逆シーク) を行うことはできません。 逆シークを行うためには、 LoadSPCFile 関数を呼び出して最初の状態に戻してから、想定の位置にシークする必要があります。
例えば演奏開始から 10 秒後に 7 秒の位置へ戻したい場合、 LoadSPCFile 関数を呼び出して 0 秒の位置にした後、この関数を呼び出して 7 秒後に設定します。
ただし、この方法ではシーク位置が後になるほど処理に時間がかかります。 回避するためにはキャッシュ機構が必要です。 SNESAPU にはキャッシュ機構は実装されていません。
参照
演奏時間とフェードアウト時間を設定します。
void SetAPULength(u32 time, u32 fade);
引数
time
[in] 演奏時間を指定します。 単位は 1/64000 秒です。 64000 を指定すると 1 秒間演奏します。
fade
[in] フェードアウト時間を指定します。 単位は 1/64000 秒です。 64000 を指定すると 1 秒間フェードアウトします。
戻り値
ありません。
解説
全体の演奏時間は、 time と fade の合計値です。 例えば演奏時間が 120 秒、フェードアウト時間が 10 秒の場合、演奏時間は 130 秒です。
LoadSPCFile 関数を呼び出すと、この関数で設定した内容は解除され、フェードアウトが無効になります。
参照
SNESAPU エミュレーションの基本オプションを設定します。
void SetAPUOpt(u32 mix, u32 chn, u32 bits, u32 rate, u32 inter, u32 opts);
引数
mix
[in] ミキシング方法を指定します。
0 | = ミキシングを行いません。 出力結果は無音になります。 |
1 | = 内部的に 16bit-int でミキシングを行います。 (削除。 3 と同じ) |
2 | = 内部的に 16bit-int (MMX 使用) でミキシングを行います。 (削除。 3 と同じ) |
3 | = 内部的に 32bit-float でミキシングを行います。 最も高音質な出力が得られます。 |
chn
[in] チャンネル数を指定します。 1, 2 が指定できます。
1 | = モノラル |
2 | = ステレオ |
bits
[in] 量子化ビット数を指定します。 8, 16, 24, 32, -32 が指定できます。
-32 を指定すると 32bit-float (IEEE754) で出力します。
rate
[in] サンプリング レートを指定します。 8000~192000 の範囲で指定できます。
inter
[in] 補間処理の方法を指定します。
0 | = 補間処理を使用しません。 |
1 | = 線形補間を使用します。 |
2 | = 三次スプライン補間を使用します。 |
3 | = 実機ガウス分布補間を使用します。 |
4 | = シンク関数補間を使用します。 |
5 | = (予約。 現在は 7 と同じ) |
6 | = (予約。 現在は 7 と同じ) |
7 | = 高精度ガウス分布補間を使用します。 |
opts
[in] DSP エミュレーションのオプションを指定します。 複数指定する場合はすべての値を合計した値を指定してください。
0x1 | = アンチエイリアス処理を行います。 (削除) |
0x2 | = 古い BRR 復元プログラムを使用します。 |
0x4 | = 逆位相サラウンド効果を使用します。 |
0x8 | = 左右の出力を反転させます。 |
0x10 | = エコー機能を無効にします。 |
0x20 | = ピッチ モジュレーション機能を無効にします。 |
0x40 | = ピッチ ベンド機能を無効にします。 |
0x80 | = FIR フィルタ機能を無効にします。 |
0x100 | = BASS BOOST (低音強調) 機能を使用します。 |
0x200 | = エンベロープ機能を無効にします。 |
0x400 | = ノイズ機能を無効にします。 |
0x800 | = エコー時のメモリ確保処理を実機に近づけます。 |
0x1000 | = サラウンド機能を無効にします。 |
0x40000000 | = 出力レベル値を 32bit-float で出力します。 |
0x80000000 | = イヤー セーフ機能を無効にします。 |
戻り値
ありません。
解説
inter の 5 以上、 opts の 0x20 以上の値は独自拡張値です。 本家や互換性のない SNESAPU.DLL では使用できません。
LoadSPCFile 関数を呼び出しても、この関数で設定した内容は保持されます。
参照
演奏速度を設定します。
void SetAPUSmpClk(u32 speed);
引数
speed
[in] 演奏速度を指定します。 65536 が 1 倍を基準とした値を指定します。 32768 を指定すると半分の速度で演奏します。
戻り値
ありません。
解説
LoadSPCFile 関数を呼び出しても、この関数で設定した内容は保持されます。
参照
音量を設定します。
void SetDSPAmp(u32 amp);
引数
amp
[in] 音量を指定します。 65536 が 1 倍を基準とした値を指定します。 32768 を指定すると半分の音量で演奏します。
戻り値
ありません。
解説
LoadSPCFile 関数を呼び出しても、この関数で設定した内容は保持されます。
参照
ピッチ (音程) を設定します。
void SetDSPPitch(u32 pitch);
引数
pitch
[in] ピッチを指定します。 32000 が 1 倍を基準とした値を指定します。 64000 を指定すると 1 オクターブ上がります。
戻り値
ありません。
解説
LoadSPCFile 関数を呼び出しても、この関数で設定した内容は保持されます。
参照
Script700 互換機能を設定・解除します。
u32 SetScript700(void *pSource);
引数
pSource
[in] NULL 文字で終わる Script700 コマンドの文字列が格納されたバッファへのポインタを指定します。
NULL を指定すると、 Script700 互換機能を解除します。
戻り値
Script700 コマンドの解析結果が返ります。 1 以上の値が返ると Script700 は有効、 0 以下の値は無効です。
1 以上 | = DLL 内部で用意されたメモリを消費したサイズです。 |
0 | = pSource に NULL が指定されました。 |
-1 | = Script700 コマンドが多すぎるため、メモリに格納できません。 |
解説
Script700 コマンドはすぐに中間コード (バイナリ) に変換され、 DLL 内部で用意されたメモリ上に保持されますので、この関数を呼び出した後すぐにバッファを解放、または書き換えができます。 演奏中もバッファを確保しておく必要はありません。
LoadSPCFile 関数を呼び出しても、この関数で設定した内容は保持され、初期化を行いません。 無効の状態に戻すには、 pSource に 0 (NULL) を指定してこの関数を呼び出してください。
独自の Script700 エンジンを使用しているため、同じ Script700 コマンドでも他のプレイヤーと仕様や動作が異なる場合があります。
参照
TimerTrick 互換機能を設定・解除します。
void SetTimerTrick(u32 port, u32 wait);
引数
port
[in] ポート番号 (0 ~ 3、または 0xF4 ~ 0xF7) を指定します。
wait
[in] ウェイト タイム (1 ~ 0xFFFFFFFF) を指定します。
0 を指定すると、 TimerTrick 互換機能を解除します。
戻り値
ありません。
解説
TimerTrick 互換機能は Script700 互換機能を利用して実現していますので、この関数を呼び出した後に SetScript700 関数を呼び出すと、 TimerTrick 互換機能は自動的に無効化されます。
LoadSPCFile 関数を呼び出しても、この関数で設定した内容は保持され、初期化を行いません。 無効の状態に戻すには、 port に任意の値、 wait に 0 (NULL) を指定してこの関数を呼び出してください。
参照
SHVC-SOUND (実機のサウンドボード) にパラレル ポート経由で SPC の内容を転送します。
他プレイヤー用の SNESAPU.DLL に実装されています。 SNES SPC700 Player 付属の SNESAPU.DLL にはありません。
u32 TransmitSPC(u32 addr);
引数
addr
[in] パラレル ポートのデータ アドレスを指定します。 LPT1 を使用する場合、通常は 0x378 です。
戻り値
SHVC-SOUND への通信結果が返ります。 0 が返ると通信成功、それ以外の値は通信失敗です。
0 | = SHVC-SOUND との通信が成功しました。 |
1 | = SHVC-SOUND のリセットに失敗しました。 |
2 以上 | = SHVC-SOUND からの応答がありません。 |
-1 | = GiveIO がインストールされていません。 |
-2 | = パラレル ポートが双方向通信モードではありません。 |
-3 | = ブート ローダを格納できる空きがありません。 |
-4 | = DSP レジスタの転送に失敗しました。 |
-5 | = RAM の転送に失敗しました。 |
-6, -7 | = XRAM の転送に失敗しました。 |
解説
SHVC-SOUND への通信には、予め GiveIO のインストール、25pin パラレル ポート (双方向通信)、データ通信回路が必要です。 データ通信回路図は http://www.raphnet.net/electronique/snes_apu/snes_apu_en.php を参照してください。
この関数を呼び出す前に LoadSPCFile 関数で SPC ファイルを DLL へ転送して、演奏の準備を行ってください。
Script700 を動作させる場合には、この関数を呼び出す前に SetScript700 関数を呼び出してください。 その後、 EmuAPU 関数を非常に短い間隔で呼び出すことで、 Script700 が動作し SHVC-SOUND のポートへ書き込みが行われます。
EmuAPU 関数を呼び出す間隔が小さいほど細かなポート制御ができます。 単純な転送であれば 5ms 程度で十分ですが、多量のデータをやりとりする必要がある場合は非常に細かい間隔で実行する必要があります。
Script700 を使用しない場合は EmuAPU 関数を呼び出す必要はありません。 TransmitSPC を呼び出した後、自動的に演奏が開始されます。
参照
EmuAPU, LoadSPCFile, SetScript700
本家 SNESAPU.DLL v2.0 系で発生していたもののうち、修正された不具合の内容です。 () 内は修正されたバージョンです。
・ モノラル再生時に右側の音が入らない (v2.3.0)。
・ ステレオ再生時、 ReverseStereo モードが効かない (v2.3.0)。
・ 演奏中にエコーを無効にして再度エコーを有効にするとノイズが発生することがある (v2.4.3)。
・ エコーを使用する曲を演奏中、エコーが極端に弱くなったタイミングで CPU 使用率が異常に高くなる (v2.7.0)。
・ 32bit float (IEEE754) で出力すると、内部計算ミスにより音量が異常に高く音割れする (v2.8.2)。
・ シーク時に DSP レジスタ更新を行っていないため、シーク直後から演奏がおかしくなる (v2.9.2)。
・ シーク時にミキシング フラグが正常に初期化されない (v2.10.1)。
・ KON のタイミングが速すぎるため、特定の曲で発音時に音量異常になることがある (v2.11.1)。
・ DSP レジスタの ENDX フラグが KON 時に初期化されない (v2.11.3)。
・ スタック処理が間違っているため RET 命令で暴走し、特定の曲の演奏が進まない (v2.11.8)。
・ Gain DIRECT 処理のタイミングに問題があり、特定の曲で音抜けが発生する (v2.11.8)。
・ ADSR 処理のタイミングに問題があり、特定の曲でエンベロープが減衰しない (v2.13.3)。
・ オペコード処理の誤りにより、一部のゲームで効果音が鳴らないなど (v2.14.4)。