Rebol le nouvel émulateur Old school ? | |
guest2 | 30-Jan-2007/19:40:52+1:00 |
A l'origine était le 'verbe' , puis Rebol est apparu... Bon sérieux, à l'origine je voulais développer des outils en Rebol pour développer des jeux sur MSX. Le MSX est une machine 8bit des années 80 chère à mon coeur. D'ailleurs si le coeur vous en dit, vous pouvez tester la bête avec de zolis émulateurs comme BlueMsx et OpenMSX. Donc j'avais dans l'idée d'écrire des outils pour développeur en assembleur sur proceseur Z80. Il y'a 3 semaines, j'ai donc commencé à écrire un parseur minimaliste pour émuler du code Z80 désassemblé. En gros à partir de quelque chose comme ça: #4017: 4017 2100e0 ld hl,#e000 401a 1101e0 ld de,#e001 401d 01fe0f ld bc,#0ffe 4020 3600 ld (hl),#00 4022 edb0 ldir 4024 3100e7 ld sp,#e700 4027 cd3801 call #0138 402a e6cf and #cf 402c 4f ld c,a 402d e60c and #0c 402f 87 add a,a 4030 87 add a,a 4031 b1 or c 4032 cd3b01 call #013b 4035 cdad59 call #59ad 4038 3ec3 ld a,#c3 403a 214c40 ld hl,#404c 403d 329afd ld (#fd9a),a 4040 229bfd ld (#fd9b),hl 4043 fb ei #4044: 4044 0101e2 ld bc,#e201 4047 cd4700 call #0047 J'ai écrit un parseur qui permet d'exécuter pas à pas chaque instruction Z80 en Rebol. De là, comme j'avancais bien, je me suis dit, pourquoi ne pas tester ça en grandeur nature sur un vrai programme ? J'ai donc récupéré la ROM d'un jeu pas trop gros GALAGA (32ko) et je me suis mis en tête d'émuler la puce graphique du MSX pour voir si j'arrivais à produire un truc acceptable( pas trop lent donc) Et j'ai donc abouti à ça: http://momupload.com/files/13793/galaga.r.html [url=http://momupload.com/files/13793/galaga.r.html]galaga.r[/url] (désolé pour le lien, je le mettrais sur mon site ftp, plus tard) Laissez tourner la demo, jusqu'au bout, vous verrez votre vaisseau se faire capturer, pour ceux qui se souviennent de ce jeu. Pour l'instant, je ne gère pas encore le clavier donc on peut pas jouer mais ça vaut quand même le coup d'oeil. Et pis apparement , j'ai quelque embêtements avec les dessins des vaisseaux ennemis, mon interpreteur n'est donc pas encore au point. Alors , je vois déjà des mains se lever. - A quand le son ? Surement jamais, vu qu'émuler une puce sonore en Rebol, même rudimentaire, c'est une autre paire de manche et pis j'y connais rien. - A quand un Emulateur 100% Rebol permettant de jouer à n'importe que jeu MSX1. Là c'est faisable mais c'est beaucoup de boulot et ce n'était pas vraiment mon projet de départ. De plus on remarque quand même que c'est super LENT. Même si mon code n'est pas optimisé, on voit bien que le moteur grapique de Rebol rame un max quand on zoom, alors que franchement, y'a pas de raison (en tout cas la vitesse de mon code n'est pas en jeu). J'affiche juste une image 256x192 plus 32 sprites (souvent moins) de 16x16. | |
guest2 | 30-Jan-2007/20:14:45+1:00 |
Juste pour dire que le programme boucle, même quand vous fermez la fenêtre. Donc faut penser à killer la tâche. | |
guest2 | 30-Jan-2007/20:30:12+1:00 |
Juste pour dire que le programme boucle, même quand vous fermez la fenêtre. Donc faut penser à killer la tâche. | |
GreG | 31-Jan-2007/3:00:10+1:00 |
Je n'arrive pas a chopper ton fichier Pourtant, j'aurais bien teste! --> FTP ! | |
guest2 | 31-Jan-2007/4:06:36+1:00 |
et vala ! http://perso.orange.fr/rebol/galaga.r y'a qu'à demander !!!! En plus c'est une version jouable, jusqu'à ce que ça plante ! hin hin ! Attention ! Pour démarrer le jeu, il faut appuyer sur "Demo", pas sur la touche SPACE, sinon ça bug. Ensuite les touches pour jouer sont: espace= pour tirer flèches droite et gauche pour vous savez quoi. Vous remarquerez que votre vaisseau est touijours en déplacement sauf quand vous tirez, ça c'est à cause de Rebol qui ne sait pas gérer les touches enfoncées/pas enfoncées. Enfin, j'me comprends. Le jeu fonctionne jusqu'à ce qu'il rencontre une adresse inconnue. Elle est inconnue parce qu'il ne l'a encore jamais rencontrée. Et comme il vous manque mon parseur pour traduire les nouvelles routines assembleur à la volée, ben du coup, le jeu s'arrête. Et Oh ! , je vais pas tout vous filer le premier jour | |
guest2 | 31-Jan-2007/4:41:32+1:00 |
Hum, en même temps, je me dis que si rebcode était diponible on pourrait faire un émulateur vraiment rapide donc exploitable. Mais reste le problème du rendu, Actuellement Draw est incapable de raffraichir à une cadence de 50Mhz tout en laissant le temps d'exécuter le code du programme plus un wait d'une durée raionnobale pour intercepter les evennements claviers. Actuellement je ne rafraichi l'écran qu'une fois sur 3 et ça reste lent ... ... ... ... ... | |
dubman | 31-Jan-2007/10:25:42+1:00 |
Guest2 ton idée est trés bonne et originale , c'est pas mal du tout , il est incroyable ce rebol ! | |
Goldevil | 31-Jan-2007/13:13:26+1:00 |
Très sympa. Haaa... Galaga (ou Galaxian). Un petite larme nostalgique me vient au coin de l'oeil. Moi j'ai commencé l'informatique avec un MPF-II, un clone d'AppleII. Le processeur est un 6502 (le même que le Commodore 64 si mes souvenirs sont bons) Je suis impressionné par le boulot. Je suis surtout impressionné par le fait que cela n'est même pas encore plus lent. Même si le Z80 est un vieux processeur 8 bits, écrire un émulateur demande tout de même du travail ainsi qu'une connaissance fine de la machine à émuler. Tu pourrais peut-être dissocier l'aspect émulation Z80 et l'émulation MSX (le bios en autre). Ainsi, ton code serait réutilisable pour écrire un émulateur ZX-81 ou ZX-Spectrum. Félicitation ! C'est une petite perle à publier sur rebol.org Je n'avais jamais pensé à utiliser rebol pour faire de l'émulation, mais c'est vrai que c'est faisable même pour émuler des processeurs plus modernes. Je pense au 8086 ou encore au 68000. A mon avis, la gars qui fait un émulateur Amiga500 en Rebol recevra un SDK gratuit de la part de Carl même s'il tourne 20x moins vite que la machine originale. Bonne chance pour émuler les processeurs graphiques PS: Je suppose que tu parlais d'un rafraîchissement à 50Hz et pas 50MHz. | |
coccinelle | 31-Jan-2007/13:45:52+1:00 |
Bravo, c'est assez génial tout ça. Et si tu émullais parfaitement le Z80, je pourrais faire tourner mon tout premier programme, un traitement de texte écrit en basic (mBasic sous CPM) | |
coccinelle | 31-Jan-2007/14:03:45+1:00 |
Bravo, c'est assez génial tout ça. Et si tu émullais parfaitement le Z80, je pourrais faire tourner mon tout premier programme, un traitement de texte écrit en basic (mBasic sous CPM) | |
guest2 | 31-Jan-2007/14:52:25+1:00 |
Merci pour vos encouragements. Effectivement, il est possible d'émuler à peu près toutes les machines à base de processeur Z80. Même si ce projet évolue bien, je continuerais de me co centrer sur la partie émulation du hardware MSX, donc pour les autres machines, faudra trouver des volontaires. J'ai re-re-reflechi au son, c'est vraiment dommage de pas l'avoir et finalement je pense que ça ne ralentirait pas tant que ça le jeu. J'ai fait une petite recherche dans Rebol.org et j'ai trouvé le script "Sintezar PM-101 - Phase Manipulation Digital Synthesizer" de Boleslav Brezovsky. Je pense que ça serait une bonne base de travail, malheureusement je suis un peu pommé par rapport aux notions utilisées et il me semble que le PSG du MSX est beaucoup plus simple. Les spés de la puce sonnore (PSG) du MSX sont là: http://www.xs4all.nl/~ronholst/map/resources/sound/generalinstrument_ay-3-8910.pdf Si une bonne âme voulait se donner la peine d'adapter le script de Boleslav. Je tiens à préciser que le PSG du MSX et la même que l'amstrad. Donc, le boulot serait réutilisable. //Goldevil, le bios du MSX (ou de n'importe quel autre machine Z80) est aussi écrit en assembleur donc on pourrait tout simplement l'émuler au lieu de réécrire comme je l'ai fait des API en Rebol. Mais l'émulation serait beaucoup plus lente. | |
Goldevil | 1-Feb-2007/9:38:58+1:00 |
Si mes souvenirs sont bons, le programme de Boleslav crée à la volée des fichiers WAV qui sont joués par rebol. Si tu veux reprendre le même système, tu va devoir en temps réel créer un forme d'onde et générer le fichier wav et puis seulement faire jouer le son. D'après la datasheet du PSG, il possède 3 canaux, c'est à dire 3 sons de base. Les sons sont générés un peu comme sur une chaîne de montage -D'abord un Tone Generator qui te sort une onde carrée à une fréquence bien précise (définie sur 12bits). -On y mélange éventuellement (avec le MIXER) du "bruit" : une onde carrée pseudo-aléatoire dont la fréquence est définie sur 5 bits. -On définit l'amplitude avec le Amplitude Controler (infos sur 4 bits). - Ce dernier peut-être lui-même contrôlé par un Enveloppe Generator. Ce dernier permet de faire varier l'amplitude de manière programmée (Fig 1 schéma avec les lignes en dents de scie) -En fin de compte le canal nous produit un son sur 4 bits qui passe dans le convertisseur analogique digital pour devenir un son analogique. ce dernier à une réponse logarithmique (voir Fig 3 de la doc). Attention, la manière dont est conçu le circuits audio influence aussi le son dans l'étage analogique lui-même. Souvent, il y a un amplificateur opérationnel et quelques composants (condensateur, diodes et résistance) qui monte le voltage pour le faire correspondre à une sortie casque ou Line par exemple. Mais ce traitement modifie également un peu le son. Il est souvent plus "lissé". Autre chose. Si Rebol est incapable de jouer plusieurs sons simultanément, il faudra en plus mixer les 3 canaux en un seul. Comment on programme le PSG ? Il y a trois modèles mentionnés dans la doc avec 0,1 ou 2 ports de communication I/O. Mais les 3 modèles peuvent être aussi interfacés avec un bus et dans ce cas, le processeur de l'ordi voit les registres du PSG comme de simples emplacement mémoire. Il faudrait déjà savoir quel PSG est utilisé et comment il est interfacé avec le CPU. Le gros problème avec l'émulation du son, c'est qu'il faut émuler un autre type de processeur en même temps. l'avantage du PSG est qu'il est capable de jouer un son en continu. Le CPU change les registres et le PSG joue le son tant que le CPU ne lui demande pas de s'arrêter. Générer les formes d'ondes, c'est pas compliqué. C'est du calcul sur des entiers et c'est assez rapide. Par contre, j'ai peur du temps de traitement pour générer le wav et demander à rebol de le jouer. Il y a plusieurs pistes pour améliorer le système : 1)Quand un son est généré, il a un signature bien précise qui est les valeurs des 16 regitres du PSG. On peut le conserver en mémoire et/ou sur disque. Lors du premier "boum" de votre vaisseaux dans Galaga, le jeu ralenti mais à la perte de vos deux autres vaisseaux la vitesse reste optimale. 2) On génère à l'avance plusieurs types de sons que le PSG peut créer. On prépare des wav à l'avance quoi. Je suis certains que la plupart des softs utilisent qu'un nombre limités de sons courant. Par exemple, les musiques sont souvent faites Voilà, j'espère t'avoir un peu aidé. | |
guest2 | 1-Feb-2007/14:49:04+1:00 |
Salut Goldevil, merci pour tes infos. En fait, dans le MSX, on dispose de ports pour modifier directement les registres du PSG. Dans le jeu Galaga, c'est encore plus simple, il appelle une routine du bios en lui passant en parametre le numero du registre à modifier et sa nouvelle valeur. J'ai déjà tracé la modifications des registres et j'obtiens une série de 19 registres à modifier à chaque interruption (c'est à dire 50 fois par seconde). par exemple, la musique jouée au lancement du jeu commence par cette série: (seuls les registres R0 à R15 nous intéressent) R0 R1 R2 R3 R4 R5 R7 R10R11R12R13R14R15R16R17R18 PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 9A 0A 31 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 31 0A 5C 0D 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 31 0A 5C 0D 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 31 0A 5C 0D 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 31 0A 5C 0D 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 31 0A 5C 0D 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 31 0A 31 0A 5C 0D 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 14 09 E7 0B E7 0B 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 5C 0D 14 09 02 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 5C 0D 14 09 02 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 5C 0D 14 09 02 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 5C 0D 14 09 02 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 5C 0D 14 09 02 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 5C 0D 14 09 02 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF PSG: 16 08 5C 0D 9A 0A 00 B8 0D 0D 0F 00 00 00 00 CF Dans un premier temps ont pourrait essayer de ne prendre en compte que les 6 premiers registres (la fréquence de la note pour les 3 canaux, si je ne me trompre pas) et y appliquer dessus une simple onde sinusoidale et mixer les 3 canaux, pour voir si ça sort un son) En fait si le son final est différent du son original, c'est pas bien grave, du moment que ça sort quelque chose Mais je garde ton idée de sauvegarder dans une table en temps réel , les données des registres du PSG et d'y associer là séquence de son correspondante. Mais j'aimerais quand même être capable de générer le son à la volée plutot que de faire appel à des fichiers WAV samplés par un autre programme. //sinon pour le prog de Boslav, d'après ce que j'ai vu, il'y a 2 modes de fonctionnement: Création d'un fichier wav ou envoie directe des infos au format PCM sur le port sound:// C'est evidemment le 2nd cas qui m'intéresse. | |
guest2 | 1-Feb-2007/15:09+1:00 |
Autres infos: Sur ce site vous trouver tout un tas de programmes permettant d'émuler le PSG du MSX: http://bulba.at.kz/progr_e.htm Dont celui là: http://bulba.at.kz/YMEmuWithFilters.src.rar qui est le source d'un convertisseur AY->WAV écrit en pascal. Des volontaires ???? | |
guest2 | 1-Feb-2007/17:52:05+1:00 |
Bon finalement j'ai fait des tests avec le port sound:// et je crois avoir quelques résultats:REBOl [] ; Set up the sound sample parameters: sample: make sound [ rate: 8000 channels: 1 bits: 8 volume: 1 data: #{} ] ; build a wave at a frequency during a time (time from 1 to 50, 50 = 1 sec) make-tone: func [freq time] [ pitch: freq * 360 / sample/rate note: make binary! to integer! 360 / pitch for phase 1 360 pitch [ val: 128 + to integer! 127 * sine phase insert tail note to-char val ] rep: freq / 50 * time ret: make binary! rep * length? note head insert/dup tail ret note rep ] ; fréquence 200 Hz pendant 1/2 secondes note1: make-tone 200 25 wait 0 ; nécessaire pour que le port sound fonctionne sound-port: open sound:// sample/data: note1 insert sound-port sample probe now/time/precise wait sound-port probe now/time/precise close sound-port halt Mais comment interpréter ce qui suit ? J'ai bien compris que les registres ne contiennent pas directement la fréquence à appliquer mais je me perds dans l'interprétation du texte (mon anglais est vraiment mauvais) ******* Tone Generator Control (registers R0,R1,R2,R3,R4,R5) The frequency of each square wave generated by the three Tone Generators (one each for Channels A, B and C) is obtained in the PSG by first counting down the input clock by 16, then by further counting down the result by the programmed 12-bit Tone Period value. ********* | |
Franck | 1-Feb-2007/23:55:50+1:00 |
Vraiment excellent super boulot, niveau vitesse c'est tout à fait acceptable (à mon goût) | |
Goldevil | 2-Feb-2007/15:37:35+1:00 |
Si j'ai bien compris tout est géré sur 4 bits. Chaque canal est un son sur 4 bits dont l'amplitude varie entre -7 et 7 (4 bits signés). Dans le PSG, il y a deux blocs séparés : 1) Le génération de la note qui peut-être un mélange d'un son pur et d'un "bruit". 2) Le contrôle du volume qui peut varier au cours du temps. 1) TONE GENERATOR Le paramètre freq de la fonction 'make-tone se calcule à partir de registres différents pour chaque canal. Canal A : 4 bits de poids faible de R1 + les 8 bits de R0 Canal B : 4 bits de poids faible de R3 + les 8 bits de R2 Canal C : 4 bits de poids faible de R5 + les 8 bits de R4 La période (l'inverse de la fréquence) est donc sur 12 bits (0 à 4093). De plus, le PSG utilise la fréquence de base comme étant 1/16ème de la fréquence d'horloge. D'après la doc le PSG est peut être cadencé entre 1MHz et 2MHz. Le modèle AY-3-8913 peut monter à 2,5 MHZ. (J'ai bien écrit MHz et pas GHz ! C'est une autre époque les gars) Calcul de la fréquence à partir de la valeur du registre : horloge_du_psg / 16 / valeur_registre Autre détail, le tone generator produit une onde carrée et non sinusoidale. Donc la boucle "for phase 1 360 pitch..." doit faire son calcul différement. J'ai fait une propose donc une réécriture du code ou la fonction 'make-tone prend comme paramètre la valeur du registre et produit une onde carrée au lieu d'une sinusoide. A l'audition le son est plus coupant. Il y a des aigus car une onde carrée implique des autre fréquences. Dans l'exemple donné, on génère un son digital avec une fréquence d'échantillonage de 8Khz (sample/rate). Je l'ai changé en 44.1Khz, qualité CD. Chose amusante, le PSG peut sortir des fréquences supérieure à 50Khz. Soit de bon ultrasons qui ne sont même plus audibles par un chien. 2) NOISE GENERATOR Alors là je sèche un peu. Le noise generator fonctionne sur le même principe que le tone generator à l'exception qu'il génère un bruit pseudo aléatoire. Il prend sa fréquence sur 5 bits du registre R6. Le seul problème étant de savoir ce qu'on entend par "bruit pseudo-aléatoire" d'une fréquence particulière. 3) MIXER Le principe est très simple. Les bits du registre R7 jouent comme des interrupteurs. Pour les trois canaux, on choisi le son, le bruit ou les deux. Par contre je ne sais pas comment il mélange son + bruit mais je suppose qu'un s'agit d'une simple addition des deux. 4) AMPLITUDE CONTROL Il s'agit du contrôle du volume. Il prend sa valeur sur 4 bits faibles d'un registre (valeurs de 0 à 15). Canal A : Registre R10 Canal B : Registre R11 Canal C : Registre R12 Le truc bizare c'est le 5ème bit le plus significatifs du registre qui défini le "Amplitude Mode". Je pense que cela détermine 2 modes de fonctionnement possible. 0 = fonctionnement de base. Sa valeur est commandée par le "Envelope Generator". Je suppose que les 4 bits sont alors ignorés. 5) ENVELOPPE GENERATOR L'enveloppe est un contrôle de l'amplitude programmée. Selon 4 bits faibles du registre R15, il va produire une enveloppe d'une forme différente. Dans la doc, la Figure 1 montre les différentes combinaisons possibles. Imaginez simplement que vous jouer avec le curseur volume de la chaîne hifi. L'amplitude de ce contrôle de volume est donnée sur 4 bits qui servent à controler le "Amplitude Control" En résumé. Soit on garde le volume au même niveau, soit on demande au Enveloppe Generator de le changer selon une schéma précis. Notez qu'il semble que le Enveloppe Generator contrôle le volume des 3 canaux ensemble. On ne peut donc pas appliquer des enveloppes différentes selon le canal. 6) D/A CONVERTER Pour chaque canal, ce module agit comme un simple multiplicateur sur le signal. Il multiplie le signal sorti du Mixer par le signal sorti du "Amplitude Genrator". Il s'agit de la dernière étape qui transform des bits en un signal qui va de 0 à 1V. On pourrait ce dire qu'on s'en fout car nous on veut obtenir un signal digital qu'on a déjà à ce stade. Mais il a une sortie logarithmique. Il faut donc effectuer en plus un exposant sur le signal pour(cfr fig 3) Bon, c'est bien joli tout ça mais comment faire cela. En fait je pense qu'il faut faire une fonction make-tone qui génère en une seule boucle le signal pour une durée de quelques seconde. On joue le son et lorsque l'émulateur rencontre une modification du registre, il recrée un nouveau signal et lance le son à la place de celui qui est en train d'être joué. Je pense qu'il n'est pas envisageable de créer le son par plusieurs étapes successives (trop lent) REBOl [] ; Set up the sound sample parameters: sample: make sound [ rate: 44100 channels: 1 bits: 8 volume: 1 data: #{} ] psg_clock: 1000000 ; build a wave at a frequency during a time (time from 1 to 50, 50 = 1 sec) make-tone: func [ tune_register [integer!] time [integer!] /local freq ] [ freq: psg_clock / 16 / tune_register pitch: freq * 360 / sample/rate note: make binary! to integer! 360 / pitch for phase 1 360 pitch [ val: 128 + to integer! 127 * sine phase insert tail note to-char val ] rep: freq / 50 * time ret: make binary! rep * length? note head insert/dup tail ret note rep ] ; On teste avec la valeur du registre à 50 pendant 1/2 seconde note1: make-tone 50 25 wait 0 ; nécessaire pour que le port sound fonctionne sound-port: open sound:// sample/data: note1 insert sound-port sample probe now/time/precise wait sound-port probe now/time/precise close sound-port | |
guest2 | 2-Feb-2007/17:56:19+1:00 |
Merci Goldevil j'ai enfin trouvé la fréquence du PSG: Sur le MSX, c'est la fréquence du Z80 divisé par 2, soit: psg_clock: 3579545 / 2 et j'ai trouvé une description un peu plus accessible des registres du PSG The AY-3-8910 is a I/O chip whith 3 sound generators. It controls the three MSX std. audio channels, joystick and cassette. Function/register table: Frequency, audio channel A-C: 0...5 Noise freq.: 6 Mixer: 7 Volume: 8 ...10 Envelope: 11...13 Joystick and cassette: 14 Paddle,joystick sel,touchpad: 15 For register summary, see note 6a1 (port A0). For SOUND A,B (register write) example, see note 6b1 (port A1). For register read example, see note 6c1 (port A2). For joystick read example, see note 6c1 (port A2). Note 6a1: PORT.A0 I AY-3-8910 PSG Register select ------- Port A0h WRITE = PSG register select. This port selects the current PSG register (0-15). Registers are: 0 = Fine freq. channel A (0-255) 1 = Freq. channel A (0-15) 2 = Fine freq. channel B (0-255) 3 = Freq. channel B (0-15) 4 = Fine freq. channel C (0-255) 5 = Freq. channel C (0-15) Output frequency (tone): f = 3.579M/2 T ------------------- 16*(256*fine+coarse) Where "coarse" are one of the coarse frequency setting registers, 1,3 or 5 and "fine" are one of the fine frequency setting registers, 1,2 or 4. 6 = Noise period (0-31) Output frequency (noise): f = 3.579M/2 N -------------- 16*NoisePeriod Where "NoisePeriod" are register 6. 7 = Mixer bit Expl. 0 = Channel A tone enable (0=Enable,1=Disable) 1 = Channel B tone enable (0=Enable,1=Disable) 2 = Channel C tone enable (0=Enable,1=Disable) 3 = Channel A noise enable (0=Enable,1=Disable) 4 = Channel B noise enable (0=Enable,1=Disable) 5 = Channel C noise enable (0=Enable,1=Disable) 6 = I/O port A mode (0=input, 1=Output) 7 = I/O port B mode (0=input, 1=Output) 8 = Volume channel A (0-15, 16=Envelope) 9 = Volume channel B (0-15, 16=Envelope) 10= Volume channel C (0-15, 16=Envelope) 11= Envelope fine freq. (0-255) 12= Envelope freq. (0-255) Envelope frequency (tone or noise): f = 3.579M/2 E ---------------------- 256*(256*ECoarse+EFine) Where "ECoarse" are the coarse envelope frequency setting register 12 and "EFine" are the fine envelope frequency setting register 11. Note that the envelope period is 1 ----- f E 13= Envelope shape (0-15) C A A H O T L L N T T D T 0 0 X X \________ 0 0 1 X X /________ 4 1 0 0 0 \\\\\\\\\ 8 (Repeating, see figure) 1 0 0 1 \________ 9 1 0 1 0 \/\/\/\/\ 10 (Repeating, see figure) 1 0 1 1 \ 11 (See figure) 1 1 0 0 ///////// 12 (Repeating) 1 1 0 1 / 13 1 1 1 0 /\/\/\/\/\ 14 (Repeating) 1 1 1 1 / 15 Sinon, tu parlais de générer une onde carrée, c'est pas l'urgence à mon avis. Je vais plutôt essayer d'adapter le script pour gérer le mixer, l'amplitude et l'enveloppe, ça me parait faisable assez vite, le plus dûr est passé... Je ferai ça ce week, sauf si tu veux t'en charger | |
guest2 | 2-Feb-2007/18:02:45+1:00 |
ah au fait ! J'ai déjà testé l'idée de faire durer le son entre 2 interruptions, puis de clearer le port et de réinjecter le son suivant. Ben... ça marche pas trop bien. déjà l'émulateur est très lent donc la musique original ne ressemblera plus à rien et puis j'entends de désagréables crachottis lorsque je clear le port sound. Donc va falloir repartir sur l'idée de pré-construire tous les sons en utilisant le générateur AY sur lequel on bosse ou alor d'envoyer les sons avec un décalage de 1 à plusieurs secondes, pour laisser le temps à l'émulateur de fabriquer la séquence sonore complète. je me tate... | |
guest2 | 2-Feb-2007/18:12:03+1:00 |
Arghhhhh !!! j'étais complètement passé à côté du script KurtSynth de Kurt Sassenrath. http://www.rebol.net/demos/1B5E455C332A1F7C/kurtsynth.r Si je l'avais trouvé avant j'aurais moins galéré. Son code n'est pas très optimisé mais ça marche. Bon sinon, une ptite question Goldevil... Pour le mixage des 3 canaux a b c, je fais une bête moyenne ou pas ? F = Fa/3 + Fb/3 + Fc/3 | |
guest2 | 2-Feb-2007/18:14:25+1:00 |
Euh evidemment, je divise pas par 3 si il n'y que 1 ou 2 canaux en fonction. (je précise) | |
guest2 | 3-Feb-2007/18:59:21+1:00 |
Bon vala, j'ai fait un script pour jouer la musique d'intro de Galaga: la chanson contient un liste de 15 valeurs correspondant aux registres du PSG, rafraichis tous les 1/50 de seconde. J'ai uniquement tenté de mixer les fréquences des 3 premiers canaux, sans toucher au reste (amplitude, enveloppe et noise). D'ailleurs on devrait obtenir un résultat assez proche de l'original, vue que dans cette musique, le volume des 3 canaux est pratiquement le même et que la musique n'utilise pas d'envelopes ni le canal noise. On reconnait bien le tempo mais malheureusement les notes jouées ne correspondent pas du tout. Apparement ça ne vient pas du Mixer, j'ai fait des tests, le problème c'est la fréquence des notes contenues dans les canaux A,B et C, ça ne correspond pas du tout aux fréquences réelles attendues par le format PCM (celui du port sound://). Y'a probablement une conversion suplémentaire à faire. ici, j'ai mis le wav généré par l'émulateur BlueMSX, c'est donc le but à atteindre: http://perso.orange.fr/rebol/GALAGA_01.wav REBOL [] clock: 3579545 / 32 inter: 50 ; nombre d'interruptions par seconde wait 0 ; nécessaire pour que le port sound fonctionne sound-port: open sound:// ; Set up the sound sample parameters: sample: make sound [ rate: 44100 / 4 channels: 1 bits: 8 volume: 1 data: #{} ] cache: make list! 100 ; build a wave at a frequency and store it for reuse make-tone: func [freq /local note rep ret pitch phase] [ if not note: select head cache freq [ pitch: freq * 360 / sample/rate note: make binary! to integer! 360 / pitch phase: 0 while [phase <= 360][ val: 128 + to integer! 127 * sine phase insert tail note to char! val phase: phase + pitch ] insert cache freq insert cache note ] cp note ] ; Mix 3 channels A,B,C mix: func [/local tone len][ tone: make binary! len: to-integer sample/rate / inter tone: head change/dup tone to char! 0 len loop len [ if tail? toneA [toneA: head toneA] if tail? toneB [toneB: head toneB] if tail? toneC [toneC: head toneC] val: to integer! toneA/1 + toneB/1 + toneC/1 / 3 change tone to char! val tone: next tone toneA: next toneA toneB: next toneB toneC: next ToneC ] head tone ] ; une ligne correspond au son joué pendant 1/50 de seconde song: [ 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 154 10 49 10 0 184 13 13 15 0 0 0 0 207 49 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 49 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 49 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 49 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 49 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 49 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 20 9 231 11 231 11 0 184 13 13 15 0 0 0 0 207 92 13 20 9 2 10 0 184 13 13 15 0 0 0 0 207 92 13 20 9 2 10 0 184 13 13 15 0 0 0 0 207 92 13 20 9 2 10 0 184 13 13 15 0 0 0 0 207 92 13 20 9 2 10 0 184 13 13 15 0 0 0 0 207 92 13 20 9 2 10 0 184 13 13 15 0 0 0 0 207 92 13 20 9 2 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 92 13 154 10 0 184 13 13 15 0 0 0 0 207 22 8 49 10 92 13 0 184 13 13 15 0 0 0 0 207 22 8 49 10 92 13 0 184 13 13 15 0 0 0 0 207 22 8 49 10 92 13 0 184 13 13 15 0 0 0 0 207 22 8 49 10 92 13 0 184 13 13 15 0 0 0 0 207 22 8 49 10 92 13 0 184 13 13 15 0 0 0 0 207 22 8 49 10 92 13 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 49 10 22 8 241 7 0 184 13 13 15 0 0 0 0 207 49 10 22 8 241 7 0 184 13 13 15 0 0 0 0 207 49 10 22 8 241 7 0 184 13 13 15 0 0 0 0 207 49 10 22 8 241 7 0 184 13 13 15 0 0 0 0 207 49 10 22 8 241 7 0 184 13 13 15 0 0 0 0 207 49 10 22 8 241 7 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 154 10 234 8 0 184 13 13 15 0 0 0 0 207 92 13 49 10 92 13 0 184 13 13 15 0 0 0 0 207 92 13 49 10 92 13 0 184 13 13 15 0 0 0 0 207 92 13 49 10 92 13 0 184 13 13 15 0 0 0 0 207 92 13 49 10 92 13 0 184 13 13 15 0 0 0 0 207 92 13 49 10 92 13 0 184 13 13 15 0 0 0 0 207 92 13 49 10 92 13 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 231 11 231 11 231 11 0 184 13 13 15 0 0 0 0 207 2 10 20 9 2 10 0 184 13 13 15 0 0 0 0 207 2 10 20 9 2 10 0 184 13 13 15 0 0 0 0 207 2 10 20 9 2 10 0 184 13 13 15 0 0 0 0 207 2 10 20 9 2 10 0 184 13 13 15 0 0 0 0 207 2 10 20 9 2 10 0 184 13 13 15 0 0 0 0 207 2 10 20 9 2 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 92 13 154 10 0 184 13 13 15 0 0 0 0 207 154 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 154 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 154 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 154 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 154 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 154 10 49 10 92 13 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 231 11 234 8 0 184 13 13 15 0 0 0 0 207 231 11 234 8 19 7 0 184 13 13 15 0 0 0 0 207 231 11 234 8 19 7 0 184 13 13 15 0 0 0 0 207 231 11 234 8 19 7 0 184 13 13 15 0 0 0 0 207 231 11 234 8 19 7 0 184 13 13 15 0 0 0 0 207 231 11 234 8 19 7 0 184 13 13 15 0 0 0 0 207 231 11 234 8 19 7 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 106 8 224 11 0 184 13 13 15 0 0 0 0 207 60 11 234 8 127 7 0 184 13 13 15 0 0 0 0 207 60 11 234 8 127 7 0 184 13 13 15 0 0 0 0 207 60 11 234 8 127 7 0 184 13 13 15 0 0 0 0 207 60 11 234 8 127 7 0 184 13 13 15 0 0 0 0 207 60 11 234 8 127 7 0 184 13 13 15 0 0 0 0 207 60 11 234 8 127 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 106 8 0 184 13 13 15 0 0 0 0 207 92 13 60 11 234 8 0 184 13 13 15 0 0 0 0 207 92 13 60 11 234 8 0 184 13 13 15 0 0 0 0 207 92 13 60 11 234 8 0 184 13 13 15 0 0 0 0 207 92 13 60 11 234 8 0 184 13 13 15 0 0 0 0 207 92 13 60 11 234 8 0 184 13 13 15 0 0 0 0 207 92 13 60 11 234 8 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 231 11 2 10 0 184 13 13 15 0 0 0 0 207 145 8 92 13 60 11 0 184 13 13 15 0 0 0 0 207 145 8 92 13 60 11 0 184 13 13 15 0 0 0 0 207 145 8 92 13 60 11 0 184 13 13 15 0 0 0 0 207 145 8 92 13 60 11 0 184 13 13 15 0 0 0 0 207 145 8 92 13 60 11 0 184 13 13 15 0 0 0 0 207 145 8 92 13 60 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 145 8 231 11 0 184 13 13 15 0 0 0 0 207 60 11 231 11 145 8 0 184 13 13 15 0 0 0 0 207 60 11 231 11 145 8 0 184 13 13 15 0 0 0 0 207 60 11 231 11 145 8 0 184 13 13 15 0 0 0 0 207 60 11 231 11 145 8 0 184 13 13 15 0 0 0 0 207 60 11 231 11 145 8 0 184 13 13 15 0 0 0 0 207 60 11 231 11 145 8 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 60 11 127 7 0 184 13 13 15 0 0 0 0 207 127 7 2 10 224 11 0 184 13 13 15 0 0 0 0 207 127 7 2 10 224 11 0 184 13 13 15 0 0 0 0 207 127 7 2 10 224 11 0 184 13 13 15 0 0 0 0 207 127 7 2 10 224 11 0 184 13 13 15 0 0 0 0 207 127 7 2 10 224 11 0 184 13 13 15 0 0 0 0 207 127 7 2 10 224 11 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 234 8 60 11 127 7 0 184 13 13 15 0 0 0 0 207 60 11 92 13 234 8 0 184 13 13 15 0 0 0 0 207 60 11 92 13 234 8 0 184 13 13 15 0 0 0 0 207 60 11 92 13 234 8 0 184 13 13 15 0 0 0 0 207 60 11 92 13 234 8 0 184 13 13 15 0 0 0 0 207 60 11 92 13 234 8 0 184 13 13 15 0 0 0 0 207 60 11 92 13 234 8 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 2 10 241 7 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 231 11 2 10 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 231 11 20 9 231 11 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 231 11 234 8 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 22 8 154 10 0 184 13 13 15 0 0 0 0 207 234 8 20 9 231 11 0 184 13 13 15 0 0 0 0 207 234 8 20 9 231 11 0 184 13 13 15 0 0 0 0 207 154 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 154 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 154 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 154 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 154 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 154 10 20 9 231 11 0 184 13 13 15 0 0 0 0 207 ] pcm: clear #{} Fa': Fb': Fc': 0 foreach [A0 A1 B0 B1 C0 C1 noise mixer volA volB volC Ev0 Ev1 Shape JoyA JoyB] song [ Fa: to integer! 0.5 + clock / (A0 and 15 * 256 + A1) Fb: to integer! 0.5 + clock / (B0 and 15 * 256 + B1) Fc: to integer! 0.5 + clock / (C0 and 15 * 256 + C1) ;print [Fa Fb Fc] if Fa' <> Fa [toneA: make-tone Fa] if Fb' <> Fb [toneB: make-tone Fb] if Fc' <> Fc [toneC: make-tone Fc] insert tail pcm mix Fa': Fa Fb': Fb Fc': Fc ] sample/data: pcm insert sound-port sample halt | |
Goldevil | 3-Feb-2007/19:23:16+1:00 |
Pour l'onde carrée. C'est plus simple que l'onde sinusoïdale car tu ne dois pas faire de calcul de sinus. La moitié de la période, la valeur est au maximum (+7) et l'autre moitié au minimum (-7). Et puis le son ressemblera plus à ce que fait le PSG. Pour mixer les 3 canaux, tu additionne les 3 canaux (en vérifiant de ne pas sortir des limites). Je pense que tu peux créer des sons sur 2 canaux sans devoir mixer toi-même. Dans ton 1er script, dans les paramètres du son, tu détermine le nombre de canaux. Et je ne sais pas comment doivent être encodées les données dans ce cas. La doc sur le support du son en Rebol est dispo dans celle du SDK : http://www.rebol.com/docs/sound.html J'ai écrit un petit script fonctionnel. C'est comme cela que je vois un générateur de son émulant le PSG. Le code est particulièrement peu optimisé pour des raisons didactiques (chaque registre est un object!) mais c'est pour montrer comment les différent registres influent sur le calcul de l'onde résultante de chaque canal. Seul le Enveloppe Generator n'est pas du tout émulé rebol [] psg_emulator: make object! [ ; PARAMETERS psg_clock: 3579545 / 2 psg_period: 1 / psg_clock sampling_frequency: 16000 time_slot_size: to-integer (psg_clock / sampling_frequency) sample_channel_A: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] sample_channel_B: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] sample_channel_C: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] sample_channel_mixed: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] ; REGISTERS register: make object! [ bits: reduce [true true true true true true true true ] ; B0 B1 B2 B3 B4 B5 B6 B7 init: does [ bits: reduce bits ] get_bit: func [ bit_number [integer!] ] [ return pick bits bit_number ] getvalue: func [ /limit ; pour limiter le nombre de bits significatifs nb_bits_limit /local bit i ] [ value: 0 either limit [nb_limit: nb_bits_limit] [nb_limit: 7] for i 0 nb_limit 1 [ if (pick bits (i + 1)) = TRUE [ value: value + ( 2 ** i )] ] return value ] B0: does [ return first bits] B1: does [ return second bits ] B2: does [return third bits] B3: does [return fourth bits] B4: does [return fifth bits] B5: does [return sixth bits] B6: does [return seventh bits] B7: does [return pick bits 8] ] ; Tone generator channel A R0: make register [] R1: make register [] ; Tone generator channel B R2: make register [] R3: make register [] ; Tone generator channel C R4: make register [] R5: make register [] ; Noise R6: make register [] ; Mixer control R7: make register [] ; Amplitude control channel A R10: make register [] ; Amplitude control channel B R11: make register [] ; Amplitude control channel C R12: make register [] ; Envelope generator frequency R13: make register [] R14: make register [] ; Envelope generator shape R15: make register [] ; SOUND GENERATION init: does [ R0/init R1/init R2/init R3/init R4/init R5/init R6/init R7/init R10/init R11/init R12/init R13/init R14/init R15/init time_slot_size: psg_clock / sampling_frequency tone_generator/init noise_generator/init enveloppe_generator/init sample_channel_A: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] sample_channel_B: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] sample_channel_C: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] sample_channel_mixed: make sound [ rate: sampling_frequency channels: 1 bits: 8 volume: 1 data: #{} ] ] generate_sound: func [ duration [integer!] /local nb_cycles noise_level ] [ time_slot: 0 duration: to-decimal duration nb_cycles: to-integer (duration * psg_clock) init print ["Duration in seconds:" duration] print ["Duration in cycles:" nb_cycles] print ["Sound channel A :" r7/B0] print ["Sound channel B :" r7/B1] print ["Sound channel C :" r7/B2] print ["Noise channel A :" r7/B3] print ["Noise channel B :" r7/B4] print ["Noise channel C :" r7/B5] print ["Volume channel A :" r10/getvalue/limit 4] print ["Volume channel B :" r11/getvalue/limit 4] print ["Volume channel C :" r12/getvalue/limit 4] print "Calculating..." for time_slot 0.001 duration ( 1 / sampling_frequency ) [ channel_A: 0 ; Channel A channel_B: 0 ; Channel B channel_C: 0 ; Channel C ; TONE GENERATOR + NOISE GENERATOR ; noise level noise_level: noise_generator/getvalue time_slot ; sortie du mixer pour channel A if r7/B0 [channel_A: channel_A + tone_generator/getvalue time_slot #"A"] if r7/B3 [channel_A: channel_A + noise_level] if not all [r7/B0 r7/B3] [channel_A: channel_A * 2] ; sortie du mixer pour channel B if r7/B1 [channel_B: channel_B + tone_generator/getvalue time_slot #"B"] if r7/B4 [channel_B: channel_B + noise_level] if not all [r7/B1 r7/B4] [channel_B: channel_B * 2] ; sortie du mixer pour channel C if r7/B2 [channel_C: channel_C + tone_generator/getvalue time_slot #"C"] if r7/B5 [channel_C: channel_C + noise_level] if not all [r7/B2 r7/B5] [channel_C: channel_C * 2] ;print [channel_A channel_B channel_C noise_generator/current_level] ; AMPLITUDE GENERATOR either r10/B4 [ channel_A: channel_A * enveloppe_generator/getvalue #"A" ] [ channel_A: channel_A * (r10/getvalue/limit 4) / 15 ] either r11/B4 [ channel_B: channel_B * enveloppe_generator/getvalue #"B" ] [ channel_B: channel_B * (r11/getvalue/limit 4) / 15 ] either r12/B4 [ channel_C: channel_C * enveloppe_generator/getvalue #"C" ] [ channel_C: channel_C * (r12/getvalue/limit 4) / 15 ] ;print [channel_A channel_B channel_C noise_generator/current_level] channel_mixed: channel_A + channel_B + channel_C channel_mixed: max channel_mixed -10 channel_mixed: min channel_mixed 10 ; DA CONVERTIONS ; Logarithmic amplification channel_A: to-integer (channel_A * abs channel_A) + 128 channel_B: to-integer (channel_B * abs channel_B) + 128 channel_C: to-integer( channel_C * abs channel_C) + 128 channel_mixed: to-integer( channel_mixed * abs channel_mixed) + 128 ;print [channel_A channel_B channel_C] append sample_channel_A/data to-char channel_A append sample_channel_B/data to-char channel_B append sample_channel_C/data to-char channel_C append sample_channel_mixed/data to-char channel_mixed ; Mix the 3 channels output: channel_A + channel_B + channel_C ] return output ] tone_generator: make object! [ freq_channel_A: freq_channel_B: freq_channel_C: 0 period_channel_A: period_channel_B: period_channel_C: 0 halfperiod_channel_A: halfperiod_channel_B: halfperiod_channel_C: 0 ; Initialisation à partir des registres init: does [ freq_channel_A: psg_clock / 16 / (((R1/getvalue/limit 4) * 256) + R0/getvalue ) freq_channel_B: psg_clock / 16 / (((R3/getvalue/limit 4) * 256) + R2/getvalue ) freq_channel_C: psg_clock / 16 / (((R5/getvalue/limit 4) * 256) + R4/getvalue ) period_channel_A: 1 / freq_channel_A period_channel_B: 1 / freq_channel_B period_channel_C: 1 / freq_channel_C halfperiod_channel_A: period_channel_A / 2 halfperiod_channel_B: period_channel_B / 2 halfperiod_channel_C: period_channel_C / 2 print "TONE GENERATOR" print ["Frequency channel A : " freq_channel_A "Hz (Period: " (period_channel_A * 1000) "ms)"] print ["Frequency channel B : " freq_channel_B "Hz (Period: " (period_channel_B * 1000) "ms)"] print ["Frequency channel C : " freq_channel_C "Hz (Period: " (period_channel_C * 1000) "ms)"] ] ; Donne valeur signal pour un moment donné getvalue: func [ time_slot channel [char!] /local time_position ] [ switch channel [ #"A" [ either (modulo time_slot period_channel_A) > halfperiod_channel_A [ return -5] [ return 5] ] #"B" [ either (modulo time_slot period_channel_B) > halfperiod_channel_B [ return -5] [ return 5] ] #"C" [ either (modulo time_slot period_channel_C) > halfperiod_channel_C [ return -5] [ return 5] ] ] return value ] ] noise_generator: make object! [ freq_channel_noise: 0 period_channel_noise: 0 current_level: 0 last_slot: -1 init: does [ freq_channel_noise: psg_clock / 16 / R6/getvalue/limit 5 period_channel_noise: 1 / freq_channel_noise last_slot: -1 print ["Frequency noise channel : " freq_channel_noise "Hz (Period: " (period_channel_noise * 1000) "ms)"] ] getvalue: func [ timeslot ] [ slot: to-integer timeslot / period_channel_noise ;print slot if slot <> last_slot [ either (random 2) = 1 [current_level: -5] [current_level: 5] ;print ["change to" current_level] last_slot: slot ] return current_level ] ] enveloppe_generator: make object! [ init: does [] getvalue: func [ channel [char!] ] [ return 1 ] ] ] ; Noise frequency psg_emulator/R6/bits: [true true true true true false false false] ; Channel A frequency psg_emulator/R0/bits: [true true true true false false false false] psg_emulator/R1/bits: [false false false false false false false false] ; Channel B frequency psg_emulator/R2/bits: [true true true true true true true true] psg_emulator/R3/bits: [true false false false false false false false] ; Channel C frequency psg_emulator/R0/bits: [true true true true true true true true] psg_emulator/R5/bits: [true false false false false false false false] ; Mixer psg_emulator/R7/bits: [true true true false false true false false] psg_emulator/R10/bits: [true true true true false true true true] psg_emulator/R11/bits: [true true true true false true true true] psg_emulator/R12/bits: [true true true true false true true true] psg_emulator/generate_sound 2 wait 0 ; nécessaire pour que le port sound fonctionne sound-port: open sound:// print "Sound A" insert sound-port psg_emulator/sample_channel_A wait sound-port print "Sound B" insert sound-port psg_emulator/sample_channel_B wait sound-port print "Sound C" insert sound-port psg_emulator/sample_channel_C wait sound-port print "Sound Mixed" insert sound-port psg_emulator/sample_channel_mixed wait sound-port close sound-port halt | |
guest2 | 3-Feb-2007/20:09:35+1:00 |
Ok, j'ai utilisé une onde carré et j'applique ta manip du DAA donc je fais 128 + (7 * 7) la moitié de la phase et 128 - (7 * 7) l'autre moitié Mais ça résoud pas le problème de fond, ce ne sont pas les bonnes notes qui sont jouées. | |
guest2 | 3-Feb-2007/21:30:14+1:00 |
On avance, on avance j'ai juste modifié 2 routines: là pour générer une onde carrée ; build a wave at a frequency ans store it make-tone: func [freq /local note rep ret pitch phase] [ if not note: select head cache freq [ pitch: to integer! sample/rate / freq / 2 + 0.5 note: make binary! pitch * 2 insert/dup tail note to char! 128 + 25 pitch insert/dup tail note to char! 128 - 25 pitch insert cache freq insert cache head note ] head note ] et là , j'ai juste appliqué un coeff multiplicateur sur les fréquences des canaux pour changer d'octave, j'ai fait ça au jugé: pcm: clear #{} Fa': Fb': Fc': 0 foreach [A0 A1 B0 B1 C0 C1 noise mixer volA volB volC Ev0 Ev1 Shape JoyA JoyB] song [ Fa: to integer! 20 * to integer! 0.5 + clock / (A1 and 15 * 256 + A0) Fb: to integer! 20 * to integer! 0.5 + clock / (B1 and 15 * 256 + B0) Fc: to integer! 20 * to integer! 0.5 + clock / (C1 and 15 * 256 + C0) print [Fa Fb Fc] chg?: false if Fa' <> Fa [toneA: make-tone Fa chg?: true] if Fb' <> Fb [toneB: make-tone Fb chg?: true] if Fc' <> Fc [toneC: make-tone Fc chg?: true] insert tail pcm either chg? [prevmix: mix][prevmix] Fa': Fa Fb': Fb Fc': Fc ] sample/data: pcm insert sound-port sample halt 2 remarques: - Y'a un bruit de fond désagréable, je sais pas si c'est à cause du générateur d'ondes carrées ou d'un autre bug. - On se rapproche de la musique originale mais ça joue encore faux, probablement que multiplier les fréquences pour changer d'octave c'est trop simple, y'a encore un truc qui m'échappe. | |
Goldevil | 4-Feb-2007/11:00:42+1:00 |
Tu avances. Le bruit de fond est certainement du à l'onde carrée. Dans une onde carrée, y'a des plus hautes fréquences. En fait c'est comme s'il y avait des notes plus hautes jouées en même temps mais à un volume inférieur. Je suppose que l'étage analogique du MSX devait lisser le son avec quelques condensateurs et se rapprocher plus d'une onde sinusoïdale. Mais ça c'est difficile à simuler. Si tu remets une onde sinusoïdale, tu arriveras à un son plus beau mais moins proche de l'original. Personnellement, je ne trouve pas cela plus mal. Quand on y pense simuler, la génération du son d'un vieux circuit comme le PSG demande plus de travail qu'émuler des simples sons échantillonés d'une soundblaster de première génération. | |
guest2 | 4-Feb-2007/18:36:37+1:00 |
Bon alors en fait ça marche, c'est juste les valeurs extraites des régistres qui étaient fausses, donc mon élulateur Z80 est loin d'être au point. Là j'intègre la gestion de l'amplitude, enveloppes et noise, et je prépare une demo | |
coccinelle | 4-Feb-2007/21:41:54+1:00 |
Pour revenir au sujet de départ, si j'ai bien compris, tu n'interprete pas directement le code binaire du Z80 mais tu le convertis d'abord en instruction Rebol. Est-ce bien pour çà que tu n'as pas l'air de parser le code du programme binaire ? | |
guest2 | 4-Feb-2007/21:57:05+1:00 |
oui j'interprete pas directement les opcodes du Z80, je passe par une espèce de phase de parsing/compilation qui traduit de séquences ou carrément des routines entières en instructions Rebol. Si je faisais pas ça mais de la vrai émulation ce serait encore plus lent. Avec Rebcode je pourrais surement me permettre de faire de l'interprétation temps réelle mais j'ai pas testé. | |
coccinelle | 6-Feb-2007/8:49:47+1:00 |
Je ne suis pas aussi convaincu que toi en ce qui concerne la vitesse. Si tu générais du RebCode alors je serais vraiment d'accord mais sinon, j'ai un doute. Faudrait faire la comparaison pour se rendre compte du gain ou de la perte. Je vais y penser. | |
Login required to Post. |