J'adore les vieux jeux informatiques. J'adore le vieux fer, mais pas assez pour le récupérer à la maison. Une autre chose est de choisir une ancienne puce et d'essayer de reproduire quelque chose vous-même, de combiner l'ancien avec le nouveau. Dans cet article, l'histoire raconte comment j'ai connecté le microcontrôleur AVR au YM3812, qui était utilisé dans des cartes son comme Adlib, Sound Blaster et Pro AudioSpectrum. Je n'ai pas créé quelque chose de fondamentalement nouveau, j'ai simplement combiné différentes idées. Peut-être que quelqu'un sera intéressé par ma mise en œuvre. Ou peut-être que mon expérience poussera quelqu'un à créer son propre projet rétro.

En me promenant sur Internet, un jour, je suis tombé sur un projet intéressant de carte audio OPL2 pour Arduino et Raspberry Pi . En bref: connectez une carte à Arduino ou Raspberry Pi, chargez un croquis ou un logiciel, respectivement, écoutez. L'idée tentante de choisir la puce OPL2, d'écouter son son et d'essayer de faire quelque chose de moi-même ne m'a pas quitté, et j'ai commandé, assemblé et commencé à comprendre comment cela fonctionne.
Quelques mots sur la gestion des puces YM3812
Pour que la musique puisse jouer, nous devons établir des registres. Certains sont chargés d'accorder les instruments, certains de jouer des notes, etc. L'adresse du registre est de 8 bits. La valeur du registre est de 8 bits. Une liste de registres est donnée dans la spécification .
Pour transférer les registres, il faut régler correctement les relevés sur les entrées de contrôle CS, RD, WR et A0 et sur le bus de données D0..D7.
Une entrée CS est nécessaire pour bloquer le bus de données lors de son installation. Réglez CS = 1 (désactivez l'entrée), réglez D0..D7, réglez CS = 0 (activez).
L'entrée RD doit être une unité logique
Pour écrire l'adresse du registre, réglez WR = 0, A0 = 0
Pour écrire la valeur du registre, définissez WR = 0, A0 = 1
Carte audio OPL2 pour Arduino et Raspberry Pi

Procédure de transfert de registre:
- Lors de l'initialisation, définissez PB2 = 1 pour bloquer l'entrée de
YM3812
- Nous passons l'adresse du registre
2.1 PB1 = 0 (A0 = 0)
2.2 Nous transmettons les octets d'adresse de registre via l'interface SPI. Les données sont stockées dans le registre à décalage 74595
2,3 PB2 = 0 (WR = 0, CS = 0). La puce 7404 inverse le signal et fournit 1 à l'entrée de ST_CP 74595
, qui commute ses sorties Q0..Q7. YM3812
écrit l'adresse du registre
2,4 PB2 = 1 (WR = 1, CS = 1) - Nous transmettons la valeur du registre
3.1 PB1 = 1 (A0 = 1)
3.2 Nous transférons les octets de données via l'interface SPI de la même manière que p.2.2
3,3 PB2 = 0 (WR = 0, CS = 0). YM3812
écrit des données
3.4 PB2 = 1 (WR = 1, CS = 1)
Un onduleur 7404
et quartz XTAL1
met en œuvre un générateur d'impulsions rectangulaire avec une fréquence de 3,579545 MHz, qui est nécessaire au fonctionnement du YM3812
.
YM3014B
convertit un signal numérique en un signal analogique, qui est amplifié par l'amplificateur opérationnel LM358
.
L'amplificateur audio LM386
nécessaire pour pouvoir connecter des haut-parleurs passifs ou un casque à l'appareil, comme LM358
puissance du LM358
n'est pas suffisante.
Essayons maintenant d'extraire le son de tout cela. La première chose à laquelle j'ai (et probablement pas seulement moi) pensé était de savoir comment faire fonctionner tout cela dans DosBox. Malheureusement, jouer hors de la boîte avec le matériel Adlib ne fonctionnera pas, car DosBox ne sait rien de notre appareil et ne sait pas comment transmettre les commandes OPL2 n'importe où (jusqu'à présent, il ne le sait pas).
L'auteur du projet propose un sketch pour Teensy, fonctionnant comme un appareil MIDI. Naturellement, le son sera composé d'instruments précompilés et le son sera différent, nous obtiendrons une émulation d'un appareil MIDI sur une puce OPL2. Je n'ai pas Teensy et je n'ai pas pu essayer cette option.
Fonctionnement du port série
Il y a un croquis SerialPassthrough . Avec lui, nous pouvons transmettre des commandes via le port série. Il ne reste plus qu'à implémenter le support dans DoxBox. J'ai utilisé la version de SVN: svn://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk
Dans le src/hardware/adlib.cpp
nous modifions l'implémentation d'OPL2:
#include "serialport/libserial.h" namespace OPL2 { #include "opl.cpp" struct Handler : public Adlib::Handler { virtual void WriteReg( Bit32u reg, Bit8u val ) {
Avant l'assemblage, remplacez le numéro de port COM par celui actuel.
Si vous supprimez le commentaire dans la ligne //adlib_write(reg,val);
, le son sera lu simultanément via l'émulateur et l'appareil.
Dans la configuration DosBox, vous devrez spécifier l'utilisation d'OPL2:
[sblaster] oplemu=compat oplmode=opl2
Voici comment je l'ai obtenu:
Il semble assez volumineux. Même si vous utilisez Arduino au lieu de la maquette, vous devez connecter les fils. Le numéro de port sur le système peut changer et vous devrez reconstruire la DosBox. Je voulais vraiment tout apporter à un aspect concis, supprimer les pièces inutiles et assembler le tout sur une seule planche.
OPL2-USB
Une idée est venue, et pourquoi ne pas créer un appareil indépendant avec un minimum de composants et de problèmes lorsqu'il est connecté. Tout d'abord, vous pouvez retirer le 74595
et utiliser les ports atmega. Ici, il est utilisé uniquement pour réduire le nombre de fils. Deuxièmement, vous pouvez utiliser un oscillateur à cristal prêt à l'emploi et vous débarrasser de la puce 7404
. Un amplificateur audio n'est également pas nécessaire si vous connectez l'appareil aux haut-parleurs. Et enfin, vous pouvez vous débarrasser de USB-UART si vous connectez directement l'atmega à USB, par exemple en utilisant la bibliothèque V-USB: https://www.obdev.at/products/vusb/index.html . Afin de ne pas vous embêter à écrire des pilotes et à les installer, vous pouvez faire du microcontrôleur un appareil HID personnalisé.

Les ports B et C sont partiellement occupés à se connecter au programmateur FAI et au quartz. Le port D est resté totalement libre, nous l'utilisons pour le transfert de données. J'ai attribué les ports restants dans le processus de conception de PCB.
Le schéma complet peut être étudié ici: https://easyeda.com/marchukov.ivan/opl2usb
LED1
avec sa résistance est optionnelle et lors du montage je ne les ai pas installés. Le fusible U4 est nécessaire pour ne pas brûler accidentellement le port USB. Il ne peut pas non plus être réglé, mais remplacé par un cavalier.
Pour rendre l'appareil compact, j'ai décidé d'essayer de l'assembler sur des composants SMD.
Cartes de circuits imprimés et appareil fini Partie numérique à gauche, analogique à droite.
Pour moi, c'était la première expérience dans la conception et l'assemblage d'un appareil fini et ne pouvait pas me passer de jambages. Par exemple, les trous dans les coins de la planche doivent avoir un diamètre de 3 mm pour les racks, mais ils se sont avérés être de 1,5 mm.
Le firmware peut être consulté sur github . Dans la version précédente, une commande était envoyée dans un paquet USB. Ensuite, il s'est avéré que sur les pistes dynamiques, DosBox commence à ralentir en raison de la surcharge et de la faible vitesse de l'USB 1.0, DosBox se bloque lors de l'envoi d'un paquet et de la réception d'une réponse. J'ai dû faire une file d'attente asynchrone et envoyer des commandes par lots. Cela a ajouté un léger retard, mais ce n'est pas perceptible.
Configuration V-USB
Si nous avons déjà compris l'envoi de données au YM3812 plus tôt, alors l'USB devra bricoler.
Renommez usbconfig-prototype.h
en usbconfig.h
et ajoutez-le (ci-dessous ne sont que les modifications):
Dans le fichier main.c
, nous définissons les structures de données des parcelles
Déclarez une poignée pour HID
PROGMEM const char usbHidReportDescriptor[] = {
Gestionnaires d'événements:
Je recommande ces articles en russe sur V-USB:
http://microsin.net/programming/avr-working-with-usb/avr-v-usb-tutorial.html
http://we.easyelectronics.ru/electro-and-pc/usb-dlya-avr-chast-2-hid-class-na-v-usb.html
Prise en charge de DosBox
Le code de DosBox peut être consulté dans le même référentiel .
Pour travailler avec le périphérique côté PC, j'ai utilisé la bibliothèque hidlibrary.h
(malheureusement, je n'ai pas trouvé de liens vers l'original), qui a dû être un peu modifiée.
J'ai décidé de ne pas toucher l'émulateur OPL, mais d'implémenter ma propre classe séparée. Le passage à l'USB dans les configurations ressemble maintenant à ceci:
[sblaster] oplemu=usb
Dans le constructeur du module Adlib dans adlib.cpp
ajoutez la condition:
else if (oplemu == "usb") { handler = new OPL2USB::Handler(); } else {
Et dans dosbox.cpp
nouvelle option de configuration:
const char* oplemus[]={ "default", "compat", "fast", "mame", "usb", 0};
L'exe compilé peut être récupéré ici: https://github.com/deadman2000/usb_opl2/releases/tag/0.1
Vidéo
Appareil prêt en actionConnexion:
Son enregistré via une carte son:
Résultats et plans
J'étais satisfait du résultat. Il est facile de connecter l'appareil, aucun problème. Bien sûr, mes modifications DosBox n'entreront jamais dans la version officielle et les branches populaires, comme Il s'agit d'une solution très spécifique.
La prochaine étape consiste à choisir l'OPL3. Il y a encore une idée pour construire un tracker sur les puces OPL
Projets similaires
VGM Player
Carte son OPL2 sur bus ISA