PSGPCM再生時のクロックの話、再び

  • 投稿日:
  • 更新日:2015/03/09
  • by
  • カテゴリ: ,

性懲りもなくPSGPCMと格闘しています。

PSGによるPCM再生は、以前11kHz/9ビット相当の比較的高音質の再生を成功させましたが、マシンパワーおよびメモリを非常に消費する方法でした。

そのため、来るべき(?)画像と音声の同時再生に向け、いかに「軽く」発音させるかについても少し検討してみることにしました。 まずはテストとして、PSG 1チャネルで8kHz/4ビットの再生を試しました。

すると、またしてもクロック数計算が合わない事象に出くわしてしまいました。 以前はI/Oウェイトの考慮漏れが原因でしたが、今回はそうでもない感じです。

データはpacked 4bit(1バイトの上位4ビット、下位4ビットにそれぞれ音量データを格納する方式)で作成しました。 再生ルーチンの中心部は次のようになっています。

	; 割り込みは禁止、DMA OFF
	; あらかじめ音量や周波数は設定しておく
	; ポート0xa0に8を出力しておく(出力チャネルのラッチ)
	; HL=データ開始アドレス、BC=データ長
_loop:
	ld      a, (hl)		;8
	ld	d, a		;5
	and	a, #0xf0	;8
	rra			;5
	rra			;5
	rra			;5
	rra			;5
	; output high nibble
	out     (#0xa1), a	;13 -> 54 (a)
	call	_wait	 	;18 + _wait
	inc	hl		;7
	dec     bc		;7
	ld	a, d		;5
	and	a, #0x0f	;8
	; dummy
	inc	hl		;7
	dec	hl		;7
	ld	d, #1		;8
	ld	d, #1		;8
	nop			;5
	; output low nibble
	out     (#0xa1), a	;13 -> 75 (b)
	call	_wait	 	;18 + _wait
	ld      a, b		;5
	or      c		;5
	jp      nz, _loop	;11 -> 21 (c)
	; 終了処理(省略)

_wait:
   	ld      e, #24		;8
_wait_loop:			; 16 per loop
	dec	e		;5
	jp      nz, _wait_loop	;11
	ret			;11
  

ニーモニックのあとに表記しているのは実行クロックです。 M1 waitおよびI/O waitを考慮した数値です。 CB/DD/ED/FD修飾のある命令は存在せず、すべてRAM上で実行させるので、これ以外のウェイトは入らないと思います。

元 データを壊してもいいならrldを使えばもっと高速になったりしますが、今回は単に実験なのであまり深く考えず、上位/下位のそれぞれが同じ時間で再生さ れるようにします。 同じwaitルーチンを使うために、処理の速いlow nibbleはダミーを入れています。 これで

  high nibble = (a) + (c) + wait(w/ call) = 75 + wait(w/ call)
   low nibble = (b) +       wait(w/ call) = 75 + wait(w/ call)
  

と、同じ時間で処理できます。

これだと高速すぎるので、waitルーチン内においてeレジスタの設定値で時間調整をします。 クロック周波数3993600Hzで8000Hzの再生をするためには、 1サンプルあたり、

  3993600 / 8000 = 499.2

となり、ひとつのサンプルがおよそ499クロックになるようにウェイト時間を調整すればいいことがわかります。 callに18クロック、ウェイトのループ以外の処理に19クロック、ループ1回に16クロックなので、逆算すると、

  (499.2 - (75 + 18 + 19)) / 16 = 24.2

となり、eレジスタの値を24にしています。

これを再生させると、7.25秒分のサンプルの再生に実測でおよそ11秒かかってしまいます。 当然音程も低くなります。

ひとつのサンプルにかける時間を350クロック程度にすると、おおよそ原音に近い時間と音程になります。 なぜでしょうね...??

実験はエミュレータ(PC-6001VW ver 205c)で行いました。 いま分解ですごいことになっているので、実機では試験できていません。

こちらもよく読まれています