YM2149Fでチップチューンメロディを再生するためのエミュレーターのエミュレーター







スペクトル上のテトリス2を覚えているのは誰ですか? 多くのレベル、一緒に演奏する能力、素晴らしい音楽がありました。



最近、 単純なゲーム用に8ビットコンピューターを作成しましたが、サウンド機能は提供していませんでした。 そして、そこにいくつかの8ビット音楽を追加したかったのです。 テトリス2のメロディを正確に覚えていたので(それよりも何時間も遅れて)、私はそれをいじり始めました。



私たちのコンピューターのATmega328Pプロセッサーは、ほとんどの場合、画像のレンダリングで忙しいため、通常の音楽を合成する時間はまったくありません。 そのため、ZX Spectrumや他のコンピューターと同じように、サウンドプロセッサYM2149F(別名AY-3-8910)が必要です。



YM2149FをArduinoに接続する



サウンドシンセサイザーをArduinoボードに接続し、簡単なノートを出力することから始めました。 YMは、15(実際には13を使用)レジスタの1つに値を書き込むことによって制御されます。 3つのチャネルのそれぞれの音の周波数、ノイズ周波数、音量レベル、周波数、およびエンベロープ形状がレジスタに記録されます。 アドレス指定とデータ送信には、8つの信号が使用されます。 バスモードを制御するには、レジスタの選択または値の読み込みという、さらに2つが必要です。





インターネット接続図



クロッキングのために、YMは分周器を備えた組み込みのプロセッサタイマーを使用します。 その結果、2 MHzがサウンドチップの入力に到達します。これは、オリジナルとの対応の観点からは間違っていますが、テストではそうなります。 私たちはプログラマであり、ハードウェア開発者ではありません。



クロックジェネレーターを初期化するコード
// Sets a 4MHz clock OC2A (PORTB3) void set_ym_clock(void) { // PB3 - output DDRB |= 0x01 << PORTB3; // Set Timer 2 CTC mode with no prescaling. OC2A toggles on compare match // // WGM22:0 = 010: CTC Mode, toggle OC // WGM2 bits 1 and 0 are in TCCR2A, // WGM2 bit 2 is in TCCR2B // COM2A0 sets OC2A (arduino pin 11 on Uno or Duemilanove) to toggle on compare match // TCCR2A = ((1 << WGM21) | (1 << COM2A0)); // Set Timer 2 No prescaling (ie prescale division = 1) // // CS22:0 = 001: Use CPU clock with no prescaling // CS2 bits 2:0 are all in TCCR2B TCCR2B = (1 << CS20); // Make sure Compare-match register A interrupt for timer2 is disabled TIMSK2 = 0; // Divide the 16MHz clock by 8 -> 2MHz OCR2A = 3; }
      
      









テストノートは正常に失われたため、先に進む必要がありました。



以前は、Spectrum自体とは別にSpectrumの音楽にはあまり興味がありませんでしたが、それでもAY形式について聞いたことがあります。 別の記事で、PSG形式について言及しました。 MP3のWAVに似ていますが、音楽コプロセッサーのレジスターとの一連のアクションが含まれています。 したがって、ファイルは大きく、ATmegaメモリに収まりません。



AYファイルはずっと小さくなります。 その秘密は何ですか? そして、実際には、これらはゲームをプレイするためのゲームまたはデモからのコードの一部であり、このコードのデータ配列でもあります。 通常、 プレーヤーはこのプログラムを実行してメロディーを再生するために、Spectrumの中央処理装置を単純にエミュレートします。



AVRでZ80をシミュレートしてみませんか?



... C80言語のZ80プロセッサ用のライブラリシミュレータを探して探しましたが、そのようなシミュレータが見つかりました 。 彼は、メモリと入出力ポートの読み取り/書き込み機能のみをスリップする必要がありました。



メモリに関して少し困難が生じました-結局のところ、ZX Spectrumには48キロバイトのRAMがあり、ATmega328Pには2つしかありません-読み書き機能用のメモリアレイを作成するために直接動作しません。 アドレスとセルの配列を作成し、プロセッサからアクセスするときに値を探す必要がありました。







(だれが考えたでしょう!)ある8ビットコンピューターを別の8ビットでエミュレートするのは良い考えではありませんでした。 いくつかの音は出力されますが、すべてがゆっくりと発生するため、メロディと呼ぶことは困難です。 次に、プレーヤーコードを把握し、Cに書き換えることにしました。



手動逆コンパイルまたは日没



コードは少しわかりにくいものでした。 音楽コプロセッサーを制御するバイトコードのインタープリターでした。 バイトコードはループとルーチンをサポートしています。 各YMチャネルは、個別のスタックを持つ個別のプログラムによって制御されます。 最初に、別の3プロセッサコンピューターをエミュレートするコンピューターをエミュレートしたことが判明しました。 プログラムは小さいことが判明しましたが(1秒に50回しか実行されませんでした)、それでも非常に低速でした。



このバイトコードのフォーマットをほとんど見通した後、偶然その説明を偶然見つけました。 それはFuxoft AY Languageでした。 それは、テトリス自身と彼のための音楽の両方を書いたフランティセック・フカ(Fuxoft)によって開発されました。 この言語は、数十の作曲で使用されています。 また、そのコードはゲームからFXMファイルとして抽出されます。 私がすでに分析したコードは、最初からやり直すために捨てられなければなりませんでした(しかし、それはまだリポジトリの変更の履歴で見ることができます )。







FXMプレーヤー



Bulbプレーヤーのソースコードで、フォーマットとそのデコーダーの簡単な説明がわかりました 。 逆アセンブルされたコードと比較すると、ほんのわずかな違いしか見つかりませんでしたが、データ構造のセマンティクスははるかに明確になりました。



これでプレイヤーは十分に高速になりました。 音楽が再生され、コンピューターとプログラマーを組み合わせることができます。 各曲は数キロバイトしか必要としないため、Arduino Mega(ATmega2560プロセッサー)を使用すると、FXM形式の既存の曲をすべてメモリに収めることができます。



次は?



正しい水晶発振器を追加して、チップの周波数がスペクトラムのとおりになるようにします。 他のトラッカー形式のデコーダーを作成し、SDカードを追加して、Spectrum音楽プレーヤーを取得することもできます。 そして、ゲームボックスに接続すると、実際のゲーム機が手に入ります。



確かに、何らかの理由で、スピーカーの音量が正常になるように機能しないため、すべてが非常に静かになりました。 たぶん、誰かがおもちゃの電話の音からそのようなスピーカーを作る方法を知っていますか? 中国の携帯電話はこれに対処しており、何らかの理由でYM2149Fの出力はあまり良くありません。 そのため、プレイヤーの動画は、アップロードしません。







UPD :アンプをはんだ付けし、すべてがどのように再生されるかをビデオに記録しました。





参照資料



  1. プレーヤーコードのリポジトリ
  2. 64x64 LEDディスプレイをArduinoに接続した方法
  3. ArduinoによるYM2149Fチップ制御
  4. CライブラリとしてのZ80プロセッサエミュレータ
  5. AYの音楽プレーヤー
  6. 音楽アーカイブ



All Articles