エコーを使う
DSPのエコーを設定して、音に残響を付けます。
エコーの仕組み
エコーは、DSPの出力の一部をAPUのRAMにためておき、一定の時間(ディレイ)のあとで、もう一度出力に混ぜる機能です。
ためた音をフィルタに通してからもう一度ためる(フィードバック)ので、音が何度も繰り返しながら小さくなっていきます。
| 項目 | レジスタ | 内容 |
|---|---|---|
| ディレイの長さ | EDL | 16ミリ秒単位(0~15)。バッファの大きさは EDL × 2KB |
| バッファの場所 | ESA | バッファの先頭のページ(アドレスの上位8ビット) |
| フィードバックの量 | EFB | 符号付き8ビット。大きいほど長く残る |
| エコーの音量 | EVOLL・EVOLR | 左右の音量(符号付き8ビット) |
| エコーをかけるチャネル | EON | チャネルごとのビット |
| フィルタ | FIR0~FIR7 | 8つの係数(符号付き8ビット) |
| バッファへの書き込み | FLGのビット5 | 1で書き込みを禁止する |
バッファはAPUのRAMの中に取られ、エコーを使っている間、DSPが書き換え続けます。
プログラムや波形サンプルと重ならない場所に置いてください。EDLが15なら30KB(64KBのRAMのほぼ半分)を使います。
設定の手順
FLGの説明のとおり、次の順に設定します。
- FLGのビット5をセットして、バッファへの書き込みを禁止する。
- EDLとESAを設定する。
- バッファの全体を0で埋める。
- フィルタ・フィードバック・音量・EONを設定する。
- FLGのビット5をクリアして、書き込みを許可する。
バッファを0で埋めずに書き込みを許可すると、RAMに残っていた値が雑音として鳴ります。
また、EDLを変えても、新しい長さがすぐに使われるとは限りません。
手順2から手順5までの間は、EDLの最大の長さ(240ミリ秒)程度待つようにしておくと安全です。
; エコーを設定する(バッファは $C000~$DFFF、ディレイ64ミリ秒)
; 作業用: $20・$21
SetupEcho:
MOV A, #$6C
MOV Y, #$20
MOVW $F2, YA ; FLG: バッファへの書き込みを禁止する
MOV A, #$7D
MOV Y, #$04
MOVW $F2, YA ; EDL: 4 × 16ミリ秒(バッファ 8KB)
MOV A, #$6D
MOV Y, #$C0
MOVW $F2, YA ; ESA: バッファの先頭 = $C000
; バッファ($C000~$DFFF)を0で埋める
MOV $20, #$00
MOV $21, #$C0
MOV A, #$00
MOV Y, A
.clear
MOV ($20)+Y, A
INC Y
BNE .clear
INC $21
CMP $21, #$E0
BNE .clear
; フィルタ: 8つの係数をすべて $08 にする(合計 $40 で、全体の大きさは変わらない)
MOV A, #$0F ; FIR0
.fir
MOV Y, #$08
MOVW $F2, YA
CLRC
ADC A, #$10 ; FIR1~FIR7 は $1F, $2F, …, $7F
BPL .fir
MOV A, #$0D
MOV Y, #$40
MOVW $F2, YA ; EFB: フィードバック = 0.5倍
MOV A, #$2C
MOV Y, #$30
MOVW $F2, YA ; EVOLL
MOV A, #$3C
MOVW $F2, YA ; EVOLR(Yは$30のまま)
MOV A, #$4D
MOV Y, #$01
MOVW $F2, YA ; EON: チャネル0にエコーをかける
; 少し待ってから書き込みを許可する(タイマー0で約250ミリ秒)
MOV $FA, #80 ; 10ミリ秒ごと
MOV $F1, #$01 ; タイマー0を有効にする
MOV A, $FD ; カウンタを読んで0にしておく
MOV X, #25
.wait
MOV A, $FD
BEQ .wait
DEC X
BNE .wait
MOV A, #$6C
MOV Y, #$00
MOVW $F2, YA ; FLG: 書き込みを許可する(リセット・ミュートも解除)
RET
FIRの係数のレジスタは、FIR0が$0F、FIR1が$1F、…、FIR7が$7Fです。
$10ずつ増やし、$8Fになったところ(最上位ビットが1になる)でループを終えています。
タイマーの使い方はAPUのタイマーで間隔を作るを参照してください。
CONTROL($F1)にこの値を書き込むと、IPL ROMも見えなくなります。
フィルタとフィードバック
フィルタの係数は、ためた音のうち、どの周波数の成分をどれだけ残すかを決めます。
上の例のように、すべての係数を同じ値にすると、繰り返すたびに音がこもっていく(高い音が弱くなる)エコーになります。
係数の合計が$40(64)を超えると、繰り返すたびに音が大きくなることがあるので注意してください。
フィードバックを大きくすると、エコーが長く残ります。
フィルタと合わせて、繰り返すたびに音が大きくなるような設定にすると、音が止まらなくなります(ハウリング)。

矩形波を0.3秒鳴らしてキーオフしたときの音の大きさです(エコーありは上のSetupEchoの設定)。
エコーなしではキーオフですぐに消えますが、エコーありでは64ミリ秒ごとに音が繰り返し、だんだん小さくなっていきます。
鳴っている間も、エコーの分だけ音が大きくなっています。エミュレーターで鳴らした音の振幅を測ったものです。
コードから構造を読み取る
- DSPの$7D(EDL)・$6D(ESA)を設定したあと、広い範囲のRAMを0で埋めるループがあれば、エコーのバッファの準備です。ESAの値 × $100 から EDL × 2KB が、エコーに使われている(ほかのデータを置けない)領域です。
- $0F・$1F・…・$7Fに続けて値を書き込んでいれば、FIRフィルタの係数の設定です。
- サウンドドライバを解析するときは、エコーのバッファの位置と大きさを先に確かめておくと、残りのRAMのどこにデータを置けるかが分かります。