ras68k-ext 特設ページ



オールド PC のパラレルポートに接続して使う拡張音源インターフェース「ras68k-ext」についての特設ページです。
ラズベリーパイと組み合わせることで、ソフト音源として OPM/PSG/SCC/OPLL/(AD)PCM/MT-32/FluidSynth が鳴らせます。
元は X68000 用として開発されたものですが、プリンタポートのあるマシンであれば 8bit 機でも使えます。

ドライバの改造などは工夫する必要がありますが比較的低負荷なのが 8bit マシンには嬉しい所。
特に負荷の高い PCM 処理を簡単に扱えるのは魅力です。
これまで音源拡張にあまり縁のなかった機種でも豪華な音が鳴らせる(かも)。




■ 動作実例

実際の動作例として、戦闘力の低いマシンのひとつである PC-6001 初代機モード1 (Z80 4MHz / RAM 16K : 実機は mk2SR) での動画を載せておきます。


Z80 で動く MDX プレイヤーにより OPM 8 音のドライブを行い、プリンタポートに接続した ras68k-ext 経由の Raspberry Pi 3B+ から音を出しています。
MDX は「超連射 68k」より Pleasure Trip 〜君を乗せて By るざりん氏 です。


もう一つ、(AD)PCM 再生の実例として PC-8801MA2(8MHz-S) で再生した動画を紹介します。
no reverb の所にカーソルがありますが、実際は studio small リバーブがかかっています。ras68k のデフォルト設定が 2 なのを忘れていた…。
このドライバは↓で公開しています。

■ ras68k-ext の準備

[公式サイト]

http://opmregisters.web.fc2.com/ras68k/

このページ掲載時点での最新は v0.60 (20230521)です。
元は X68000 用なのですが、それ以外のマシンへの実例/覚書として幾つか情報を残しておきます。

ハード的な工作に関しては↓の「ホストマシン側」をご覧ください。

ラズパイ側 OS は新し目めのバージョンでも大丈夫でした。SD カードは高速な物の方がストレスなくて良いです。
筆者は Raspberry Pi 3B+ を使っていますが 4 でも使えるようです。
電源は余裕のあるものが良いです。low power 警告が頻発するようなのは実用の見地からも精神衛生上も×。



音声出力にはラズパイ本体の 3.5mm 端子がお手軽なのですが、この端子は 4 極(音声出力+入力)になっていて少し特殊なのと、伝統的にココから出る音は音質が悪いようです。
テストしてみて酷いようであれば USB オーディオ増設もアリでしょう。

いずれにせよ、最初にすべきことはラズパイからちゃんと音が出るか確認することです。
まずは aplay -l でオーディオデバイスを列挙してみましょう。



音声出力先デバイスとして 3.5mm 端子と Sound Blaster Play!3(USB 接続)と HDMI の三つが挙げられています。
このうち "card x" と "device y" という部分が大事なので覚えておきます。

次は amixer でミキサーコントロールを調べます。



ここでは 'PCM' というミキサーコントロール名を覚えておきます。
OS のバージョンによっては 'Headphone' という名前になっているかもしれません。

では実際に音が出るか確かめてみます。今回は 3.5mm 端子(card=0,device=0)からの出力とします。


$ speaker-test -D hw:0,0 -t sine -f 600  


これでサイン波の「ポー」という音が聞こえれば Ok です。"-D hw:" の後は aplay で調べた card 番号と device 番号です。
外部 USB 音源などでは -D の後を plughw:1,0 などとしなければならない環境もあるようです。
消音は CTRL+C です。

音が出ることが確認出来たら、ras68k-ext の設定ファイル pi68k.sh を編集して反映させておきます。



"hw:0,0" の部分を aplay で調べたカード番号、デバイス番号にします。今回は 3.5mm からの出力なので変更なし。
こちらも環境によっては "plughw:1,0" などのように書き換えます。



"-c" の後の "0" はカード番号、"sset" の後は amixer で調べたミキサーコントロール名にしておきます。
さきほど調べた結果 "PCM" だったのでここも変更なし。"Headphone" や "Speaker" だった場合は書き換えます。


$ sudo ./pi68k.sh start  


無事に起動できればずらずらっと流れて以下のようになります。
これでホスト側からの指示待ち受け状態に。



FluidSynth 対応バージョンあたりから色々ライブラリが足りなくて起動しない場合があるので、少し古いバージョンの方が良いかも…。
動作中に underrun occur メッセージが頻発するようなら再度環境を見直した方が良いかもしれません。

■ ホストマシン側

ras68k-ext からプリンタポートに繋ぐ MIL タイプ圧接コネクタは X1/X68k 用なので、ほかの機種で使うためにはコネクタ部分を置き換える必要があります。
このページの一番上の写真のようにコネクタを付け替えることで他機種にも繋げられるようになります。

仕様自体はセントロニクス準拠の当時よくあるタイプなので複雑な配線やパーツの追加は必要ありません。
ただし、MIL タイプとアンフェノールタイプではピンの並び方が違うので注意。
詳しくはこちら → http://www.cityfujisawa.ne.jp/~akitsura/connect/

本稼働前に各ピンが正しく接続されホストマシンとラズパイ側で通信が正常に行われているかチェックした方が良いでしょう。
筆者が所持している ras68k-ext インターフェース基板は「旧基板」とされているものなので、新基板では違う可能性があります。

ホストマシン側ピンRaspberry Pi 側ピン
STROBEPhisical.23(BCM 11)
bit 0Phisical.21(BCM 9)
bit 1Phisical.11(BCM 17)
bit 2Phisical.19(BCM 10)
bit 3Phisical.7(BCM 4)
bit 4Phisical.15(BCM 22)
bit 5Phisical.18(BCM 24)
bit 6Phisical.13(BCM 27)
bit 7Phisical.16(BCM 23)
BUSYPhisical.26(BCM 7)

ピン番号は物理ピン番号と BCM 番号とがあるので注意しましょう。
ラズパイ側でのピンの状態を見たり操作したりするのは gpio コマンド(Wiring Pi)があると便利だったのですが…
現行の OS(Bullseye) だと非推奨ということになったらしいです。困った。
とりあえず raspi-gpio というのが現状で代用できそう。今後また変わるかもしれないので筆者は gpio を引き続き使用します。。。


$ cd /tmp
$ wget https://project-downloads.drogon.net/wiringpi-latest.deb     
$ sudo dpkg -i wiringpi-latest.deb


一応 gpio インストール。ただし非推奨なので raspi-gpio のインストール方法と使い方を調べた方が今後の為にも良いかも。



このようにステータスを表示、各ピンの入出力を切り替えたり ON/OFF を操作したりできます。
"V" の項目が現在の ON/OFF です。

ホストマシンからは BASIC の OUT 文などで良いのでプリンタポートに向けて 1,2,4,8,16,32,64,128 を出力してラズパイ側のピンステータスを見ます。
bit0=1 なら 1, bit7=1 なら 128 です。PC88 なら OUT &H10,128 など。

反対にラズパイ側で変化させた BUSY をホストマシン側で読み取れるかもチェックしておくと良いでしょう。BUSY しか読めませんが。
上の画面で gpio -g write 7 1 というのがピン単位の操作です。
PC88 なら PRINT INP(&H40) で表示される数値の bit0=1 かどうかで判断します。


注意点として、各マシンのプリンタポート(パラレルポート)の入出力方法の違いがあります。
機種によって信号線が正論理だったり負論理だったりするため、何も考えずに入出力してしまうと信号が反転されて意図通りに動きません。
同じ NEC の機種の PC60 と PC88 でも以下のように違います。

PC60PC88Pi 側
busy(R) Port.$C0.bit1
0=busy
Port.$40.bit0
1=busy
Pi 側が 0 のとき PC88 側は 1
Pi 側が 0 のとき PC60 側は 0
strobe(W)Port.$93(8255)
0=off
1=on
Port.$40.bit0
0=on
1=off
PC88 が 0 のとき Pi 側は 0
PC60 が 0 のとき Pi 側は 1
データ書き込み後 on -> off とする
data(W)反転 そのまま PC88 が 0 のとき Pi 側は 0
PC60 が 0 のとき Pi 側は 1
※PC60 は反転して書き込む


動作を理解するために BASIC でのテストプログラムを掲載しておきます。

PC-8x01 での N88 BASIC テストプログラムは以下。PSG が発音されます。
"_SNDITPI" は送ると動かなかったのでコメントアウトしてあります。
何故か "_SENABLE" 等は受け付けます。なお、機械語の場合は初期化コマンドを送った後はしばらく待った方が良いです。

10 ' ras68k-ext TEST PC80/PC88
20 A$="_SNDITPI"
30 'FOR I=1 TO LEN(A$):DAT=ASC(MID$(A$,I,1)):GOSUB 500:NEXT
40 DAT=&HB0:GOSUB 500:DAT=&HDE:GOSUB 500
50 DAT=&HB1:GOSUB 500:DAT=&H1:GOSUB 500
60 DAT=&HB7:GOSUB 500:DAT=&H38:GOSUB 500
100 DAT=&HB8:GOSUB 500:DAT=15:GOSUB 500
110 DAT=&HF8:GOSUB 500:DAT=255:GOSUB 500
120 PRINT"PUSH SPACE TO STOP"
130 IF (INP(9) AND 64)<>0 THEN 130
140 DAT=&HB8:GOSUB 500:DAT=0:GOSUB 500
150 END
500 '
510 IF (INP(&H40) AND 1)=1 THEN 510
520 OUT &H10,DAT
530 ST=PEEK(&HE6C1) AND 254:POKE &HE6C1,ST:OUT &H40,ST
540 IF (INP(&H40) AND 1)=0 THEN 540
550 ST=PEEK(&HE6C1) OR 1:POKE &HE6C1,ST:OUT &H40,ST
560 IF (INP(&H40) AND 1)=1 THEN 560
570 RETURN

送信部分は PC88 機械語では以下のように書きます。

WriteRAS:
	out	($10),a		;data out to printer port
.wait1:
	in	a,($40)		;bit0:printer busy(0=ready)
	rrca
	jr	c,.wait1

	xor	a
	out	($40),a		;bit0:strobe(1=on)

.wait2:
	in	a,($40)		;bit0:printer busy(1)
	rrca
	jr	nc,.wait2

	ld	a,1
	out	($40),a		;bit0:strobe(1=on)

.wait3:
	in	a,($40)		;bit0:printer busy(0)
	rrca
	jr	c,.wait3
	ret

PC-6x01 での N60-BASIC テストプログラムは以下。PSG が発音されます。
こちらは最初に "_SENABLE" を送らないと駄目でした。
"_SNDITPI" は送信すると何故か鳴りません。
"(-1-D) AND 255" は XOR が無い PC60 の苦肉の策。機械語なら cpl で良いです。

10 REM ras68k-ext TEST PC60
20 A$="_SENABLE"
30 FOR I=1 TO LEN(A$):D=ASC(MID$(A$,I,1)):GOSUB 500:NEXT
40 D=&HB0:GOSUB 500:D=&HDE:GOSUB 500
50 D=&HB1:GOSUB 500:D=&H1:GOSUB 500
60 D=&HB7:GOSUB 500:D=&H38:GOSUB 500
100 D=&HB8:GOSUB 500:D=15:GOSUB 500
110 D=&HF8:GOSUB 500:D=255:GOSUB 500
120 PRINT"PUSH SPACE TO STOP"
130 IF INKEY$<>" " THEN 130
140 D=&HB8:GOSUB 500:D=0:GOSUB 500
150 END
500 REM
510 IF (INP(&HC0) AND 2)=0 THEN 510
520 OUT &H91,(-1-D) AND 255
530 OUT &H93,1
540 IF (INP(&HC0) AND 2)<>0 THEN 540
550 OUT &H93,0
560 IF (INP(&HC0) AND 2)=0 THEN 560
570 RETURN

公式サイトにある X68k 用プログラムソースを見ると、busy 待ちの部分にタイムアウトが設定されており
応答が無い場合には "_SENABLE" を送信するようになっていました。
万全を期すなら 8bit 機でもそのようにすべきかもしれません。

送信部分は PC60 機械語では以下のように書きます。

WriteRAS:
    cpl
    out         ($91),a         ;data out to printer port (8255 port.b)
.wait1:
    in          a,($C0)         ;bit1:printer busy(1=ready)
    and         2
    jr          z,.wait1

    rrca                        ;8255 bitset/reset mode -> bit0=1
    out         ($93),a         ;bit2:cgrom(1=off) bit1:crtkill(1=disp) bit0:strobe(1=on)

.wait2:
    in          a,($C0)         ;bit1:printer busy(0)
    and         2
    jr          nz,.wait2
                                ;8255 bitset/reset mode -> bit0=0
    out         ($93),a         ;bit2:cgrom(1=off) bit1:crtkill(1=disp) bit0:strobe(1=on)

.wait3:
    in          a,($C0)         ;bit1:printer busy(0)
    and         2
    jr          z,.wait3
    ret

最後の wait3 は省略できそうな気もしますが外すと鳴ってくれません。

指示の与え方は公式サイトの PCMD_TECH.TXT が詳しいです。
"_SENABLE" などの固定コマンド以外は基本的に、レジスタ番号+データの 2byte セットで送信します。
レジスタはターゲットとなる音源によって同じ番号でも機能が違い、そのため OPM + PSG のようなことはできません。
各音源の空きレジスタを利用して特殊な機能が実装されており、エフェクトや外部データのロードなどに対応しています。

プリンタポートから読み出せるビットが BUSY しかないため、仮想音源側のステータスなどは一切読めません。
つまりタイマー割込みなども本体のみで実装しなければならないので、従来のドライバを改造する場合工夫が必要です。


■ MXDRV for PC-8x01

mdxplay88_20230531.zip(ディスクイメージとソースコード)


mdx は THUNDER FORCE IV - STAFF ROLL (c) TECHNOSOFT やまちょ氏作 をサンプルとして収録させて頂いています。

ras68k-ext で多重 PCM 再生できるドライバのサンプルとして mxdrv + pcm8 を移植しました。
↑で PC88 のデモで動いているのがこの移植版です。
一応 mxdrv16y.x (2.06+16 Rel.3+25) 準拠ですが、いくつかの機能を省略しています。

8bit マシン故にメモリとファイルシステムの制限が厳しく、結局 2.06+16/02EX あたりとあまり変わらない気がします。
曲の差し替えも一仕事なので、ちょっとお試しで…というにはハードルが高いです。分かる人だけ使ってください。
一応、少し改造すれば HMB-20 や JMB-X1 でも動きます。

実装状況を以下に示します。

・ras68k-ext では仮想音源側のレジスタやステータスが読めず、割込みもかけられないのでタイマーなどは本体側 OPN(A) のものを使う
・PDX はヘッダ 768byte のみ PC88 メイン RAM 側にロードする必要がある
・PDX はファイルのアップローダーに不具合があるので(下項)Raspberry Pi に直接アップロード
・PCM8 は極一部の再生・停止などのコマンドを変換した上で実装
・PDX のヘッダテーブルから子テーブルを参照するファンクションは未実装
・68k コードを埋め込んで実行するファンクションは未実装

・拡張 MML コマンド1
[$E7][$00]〜[$E7][$06] 実装
[$E7][$02] PCM8 直接制御は再生・停止など極一部のみ対応

・拡張 MML コマンド2
[$E6][$00]〜[$E6][$06] 実装

・LFO コマンド(MP) / 特殊コマンドの新設
[$EC][$04]〜[$EC][$07] 振幅 256 倍実装
[$EC][$08][PMD][SPD][Bank][LFO#] NAMCO WAVE MEMORY 子テーブル参照なので未対応. 機能自体は実装.
[$EC][$09][PMD][SPD][Bank][LFO#] KONAMI WAVE MEMORY 子テーブル参照なので未対応. 機能自体は実装.
[$EC][$10][$00]〜[$EC][$10][$01] F-Num テーブル変換実装
[$EC][$11][Bank][LFO#][Len][0] Program MML(MP17) は埋め込まれた 68k コードを実行するので未対応
[$EC][$12][Bank][LFO#][0][0] Program LFO(MP18) は埋め込まれた 68k コードを実行するので未対応

・y コマンドの拡張
[$FE][$02][PMD] NAMCO/KONAMI Wave Memory LFO Depth 機能自体は実装
[$FE][$03][SPD] NAMCO/KONAMI Wave Memory LFO Speed 機能自体は実装
[$FE][$04][n] n/256 倍テンポ実装
[$FE][$05][n] フェードスイッチ実装
[$FE][$06][n] KONAMI ポルタメント実装
[$FE][$07][Spd] KONAMI LFO カウンターバグ修正
[$FE][$10][n]〜[$FE][$14][n] タイマーA/B の直接書き込みは OPN(A) のタイマー値に変換した上で機能


十分にテストしていないのでバグが残っている可能性があります。
さらに極めて無駄が多く低速です。PCM さえ鳴れば良かったので…。
無駄の一例をあげると

・対応データや MML コンパイラが無いと無意味な拡張コマンド類を実装してある。しかも動作未確認。
・未対応コマンドは無視するくせに、それなりに実装してある。
・巨大な OPN 系 の F-Num -> OPM 系 KC/KF 変換処理とテーブル 2048byte を積んである。
・乱数のためだけに 16bit * 16bit = 32bit 乗算を真面目に計算する。
・音量 LFO など最終結果が 8(7)bit の計算でも 32bit 演算を多用している。
・仮想レジスタ用にワーク 256byte を取ってあるがほとんど使っていない。
・未使用ワークが多数ある。

等々。

(AD)PCM を再生するためには PDX ファイル等を Raspberry Pi 側にアップロードする必要があります。
PC88 における Sound Boadrd II の ADPCM と同じ扱いで、仮想音源の外部メモリ的な扱いです。
さらに PDX ファイルのヘッダ部分 768byte は PC88 側の RAM 上にもロードする必要があります。
PCM ノート番号 (o0d+〜o8d) からアドレス・長さをテーブル参照して ras68k-ext に渡す必要があるためです。

しかし、結局サイズが大きい PDX ファイルを 2D(=320KB) 程度のディスクに収める方が大変なので、ディスクからのローダーおよび ras68k-ext へのアップローダーはあまり真面目に作っていません。
Raspberry Pi のストレージに一旦書き込んでしまえば、キャッシュファイルとして ras68k-ext 経由で読み込んでもらう方法が使えるのでこちらの方が現実的だと思います。



面倒くさいですが、メモリ・ストレージが厳しいのは 8bit マシンの宿命なので、諦めも肝心ということで。

PCMD_TECH.TXT を読めばわかりますが、X68k の OKI ADPCM だけでなく 8bit/16bit PCM なども鳴らせます。
再生もアドレス、長さとモードを指定するだけなので、ファイル形式も PDX に限らず独自形式でも Ok だと思います。


Z80 で動く mxdrv は MSX 版もあるのですが、こちらはコードも洗練されていてかなり高速です。
若干バージョンが低い (2.06+12) ことと、3.5MHz 系なのと、LFO 関連の謎挙動を除けば良い出来だと思います。

mxdrv は色々派生があるようですが、MXDRVg V2.00a が 2.06+17 Rel.X5-S 相当で、逆アセンブルしたコードを忠実に移植してあるようなので、これが事実上の標準ということで良いと思います。
再生環境が無いと、どれだけ凝ったデータ作ったところで無意味ですしね。

というか、うまく活用するなら mxdrv にこだわらず完全に新規のドライバを起こした方が良いと思いました(身も蓋もない)。


■ アップロードの不具合について

現状、ras68k-ext 経由で (AD)PCM データを Raspberry Pi 側にアップロードする機能は不具合があり機能しません。
アップロード自体は出来るのですが、数バイトの転送ミスが必ず起こります。
ADPCM の場合、前のデータとの差分なのですぐに破綻してしまい使い物になりません。

普通の演奏の場合はデータ転送ミスは起きていないようなので、アップロード特有の問題がありそうな気はしています。
幸い、ネットワーク経由などで /var/tmp/cache/ に直接 (AD)PCM データを格納すれば正しいデータが使えるので、当面はこの方法が良いと思います。

PC88 側からはバイトデータを送るだけなのでファイル名はラズパイ側で決定され、「16進数8桁小文字のファイル長_16進数8桁小文字のハッシュ値」となります。
ハッシュ値はファイル全てを 1byte ずつ足した値になります。


ras68k_uploader.zip(ディスクイメージとソースコード)

PC88 から転送するテストプログラムを置いておきます。
BOS.PDX を転送するものですが、ディスクイメージに BOS.PDX は含まれていないので、各自で書き込んでから起動してください。319,423バイトのものです。


> d88saver uploader.d88 bos.pdx 0 0 6  


で書き込んだ後、起動。実機 8MHz-S で転送完了に 4分24秒ほどかかりました。
最後に表示されるハッシュ値と実際に RasPi 側で表示される値が違う場合、転送ミスが発生したことになります。
0004dfbf_01c77a56 が正解。



■ その他

プリンタポートは割と空いている機種も多いのでは?
FM 音源系の拡張は割と選択肢が広がった感はあるけれど、事実上メモリ無尽蔵な PCM 音源は重宝する。
導入の難易度がやや高い。
今後に期待。

OPLL/MT-32/FluidSynth についてはほぼ未テスト。。。


▲ TOP