レトロな音源にSCCなどの波形メモリ音源がありますが、そのちょっと豪華版を作ってみました。
仕様は以下の通り。

波形は8ビットx32サンプル
左右独立ボリューム(256段階)
サンプル間の補間あり(1/128サンプル単位)
同時発音数は64で、それぞれ独立に256音色の中から選べます。

波形にメモリを使わないPSGモードもあり、矩形波(デューティ比1/2,1/4,1/8)、三角波から選べます。

今回は、マイクロSDカードとスピーカーがあれば試せるようにTang Console 60k用に作りました。
使用する波形は、自作FM音源

https://github.com/kwhr0/FM-tone-generator

の出力を元に生成しました。
32サンプルで1周期になるように、fs=48kHzなら基音=1.5kHzで発音し、
全てのキャリアがサステインに移行し、さらに0.1秒経過した部分から32サンプルを取得します。

品質を向上させるため、以下のような処理をしています。
DCオフセットをキャンセルするため、32サンプルの平均値が0になるようにオフセット
アタックが急峻な場合にクリックノイズになるので、0に最も近いサンプルから始まるようにローテート
全音色の中で最大のものがフルスケールになるようにスケーリング

カード読み出し、MIDI解釈、サウンドドライバを担当するのはレトロっぽくMC6800バイナリ互換の

https://github.com/kwhr0/f6800wide

を使用しました。コンパイラは

https://github.com/zu2/chibicc-6800-v1

を使いました。

クロックについて:
1音の処理に8クロックかかるので、64音で512クロックかかります。
fs=96kHzだと49.152MHzが必要になります。
それよりちょっと低いのですが48MHzに設定しています。

マイクロSDカードは、FAT32でフォーマットし、ルートディレクトリにMIDIという名前のディレクトリを作ります。
その中にSMF0フォーマット、拡張子.MIDのファイルを入れておきます。階層ディレクトリもOKです。

表示・キー入力はUSBシリアルで行います。
Macの場合はコマンドラインで
screen /dev/tty.usbserial-*1 115200
とします。
操作は、主にテンキーを使うことを想定しています。
/	一つ後に
=	一つ前に
-	ボリューム下げる
+	ボリューム上げる
enter	再生/ディレクトリ下に
*	停止/ディレクトリ上に
他に、頭文字でそこに移動する機能があります。

以下のようなコンフィグが可能です。

アッテネータの調整
発音がオーバーフローする場合はクリッピングしているので歪みます。そのような場合はwtsg.vの
localparam ATT = 3;
を一つずつ大きくしてみて下さい。

PSGモード
snd.cの
#define WAVE	1
を0にし、wtsg.vの
localparam WAVE = 3;
を0にします。

ステレオモード
Tang Consoleはモノラルですが、ハードを追加するなどしてステレオにする場合はsnd.cの
#define STEREO	0
を1にします。

https://github.com/kwhr0/wavetable-tone-generator