Logicielsmoto.com http://www.logicielsmoto.com/phpBB/ |
|
Driver son pour SN76489 et YM2413 (SMPS 6809) http://www.logicielsmoto.com/phpBB/viewtopic.php?f=3&t=647 |
Page 1 sur 1 |
Auteur: | Bentoc [ 23 Juin 2021, 16:43 ] |
Sujet du message: | Driver son pour SN76489 et YM2413 (SMPS 6809) |
Bonjour à tous, Dans ce fil je vous propose de suivre la mise au point d'un driver pour les cartes son de Dino : http://forum.system-cfg.com/viewtopic.php?f=18&t=11432 https://forum.system-cfg.com/viewtopic.php?f=18&t=12053 Pour l'instant ces 2 cartes sont au statut de prototypes : - SN76489 (construite) - YM2413 (pcb commandé) J'ai réalisé un premier driver adapté de PSGLib, mais celui ci est vraiment lié au SN76489, impossible d'étendre le format pour gérer d'autres puces. De plus il lit et transmet directement des ordres à la puce, impossible donc d'appliquer des effets au travers du logiciel ou de modifier le son. Choix du driver Après quelques recherches et tentatives autour du VGM, mon choix s'est arrété sur SMPS qui était le driver audio de Sega of Japan dans les années 80/90. https://hiddenpalace.org/News/Sega_of_J ... ource_Code L'objectif est donc de réaliser un portage de ce driver sur 6809 (TO8, mais il devrait être compatible avec d'autres machines). Pour tester mes développements j'utilise l'émulateur TO8D modifiée par Dino pour émuler les deux puces. SMPS existe pour Z80 et 68K et a été utilisé pour de nombreuses machines (Master system, Game Gear, Megadrive, Mega-CD, X32, ...). Il est largement documenté et de nombreux outils existent (conversion midi => smps, ...) Ce driver SMPS utilise un format de musique constitué de plusieurs pistes, il en existe trois types : - DAC (1 seule piste, généralement pour les sons de batterie) - FM (1 piste par channel, donc 9 dans le cas du YM2413) - PSG (1 piste par channel, donc 4 dans le cas du SN76489) Chaque piste définit une suite de notes avec une durée, il existe également un byte de controle qui permet des effets ou des boucles (imbriquées !) Le format est très compact, une musique avec une piste DAC, 6x FM et 3 PSG fait environ 1700 octets (hors samples évidement). Le format est donc assez "abstrait" pour ne pas être lié directement à une puce, c'est au driver de transformer les notes en données pour les puces FM ou PSG. Le driver gère aussi la définition des "voix" de chaque instrument. Ainsi dans ma première implémentation, la piste DAC déclenchera des sons FM ou PSG en lieu et place de samples. Objectifs Ce développement permettra donc de pouvoir lire des données musique des machines Sega (au hasard Sonic 2 ... ;-). Mais il permmettra également, via un outil de conversion, de lire des données midi. On pourra donc composer dans son DAW préféré et exporter les données midi sur Thomson au travers du format SMPS. La lecture se fera par un IRQ déclenché à la fréquence de 50Hz. Statut du projet Le projet a été initié il y a une grosse semaine. Ce qui fonctionne : - Lecture de la piste DAC et déclenchement des instruments Bass drum et Snare du YM2413 en lieu et place de samples - Boucle "simple" En cours : - Lecture des pistes FM du YM2413 - Effet de modulation - Déclenchement de sons PSG (Noise) et YM (mode drum off) sur piste DAC pour remplacer les sons de batterie du YM Non commencé : - Gestion PSG - Implémentation de nombreux "coordination flags" qui permettent de déclencher des effets et boucles - les SFX Au fur et à mesure de l'avancement je posterai ici du code pour partager et discuter optim ... Vous me verrez réapparaitre certainement quand j'aurai une lecture des pistes FM a peu près fonctionnelle. PS : Mon travail se base principalement sur la décompilation du driver son de Sonic 2, ainsi que sur le travail de Valley Bell's : https://forums.sonicretro.org/index.php ... rch.32473/ |
Auteur: | Bentoc [ 24 Juin 2021, 06:14 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Dans SMPS, pour réduire l'espace de stockage nécessaire aux données PCM, au lieu de stocker chaque sample comme un entier 8bits non signé, les samples sont encodés sur 4 bits, les 16 valeurs possibles sont ensuite utilisées comme index dans une table de correspondance : Code: DACDecodeTbl fcb 0,1,2,4,8,$10,$20,$40 fcb $80,$FF,$FE,$FC,$F8,$F0,$E0,$C0 La valeur retournée depuis la table est utilisée comme delta par rapport à la valeur de sample précédente. Le sample de départ est implicite à la valeur $80. L'espace de stockage est donc divisé par deux, moyennant une approximation du sample évidement. Une proposition de code pour lire les données encodées et restituer une valeur de sample qu'on peut envoyer au DAC : Code: Sample_data fdb 0 Sample_data_end fdb 0 Sample_value fcb $80 Sample_parity fcb 0 ; 0:hi nibble 1:lo nibble ... ldx Sample_data cmpx Sample_data_end beq DACEnd WriteToDAC tst Sample_parity bne @a lda ,x ; read sample and unpack value lsra lsra lsra lsra inc Sample_parity bra @b @a lda ,x+ ; read sample and unpack value stx Sample_data anda #$0F dec Sample_parity @b ldu #DACDecodeTbl ldb a,u addb Sample_value stb Sample_value ... Sur Thomson comme le DAC est sur 6bits, on ajustera les valeurs de la table de correspondance en conséquence. Evidement il faut faire un petit programme pour encoder les données ... mais rien de bien compliqué. Voilà c'est une petite parenthèse, issue de la lecture du code de SMPS, qui me semblait intéressante, même si pas directement liée à au YM et SN. |
Auteur: | Bentoc [ 25 Juin 2021, 21:52 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Avant de commencer à échanger sur le code, je vais présenter les structures de données. Chaque morceau de musique est un bloc de données commençant par un header dont voici la définition : SMPS Header Code: 2 bytes : Voice Top Address 1 byte : FM Total (nb of channels) 1 byte : PSG Total (nb of channels) 1 byte : Tempo 1 byte : Delay Il existe plusieurs formats pour le header, la différence porte sur le format des adresses : - relatif en big endian sur 68k - absolu en little endian sur z80 Pour la version 6809 on va utiliser le relatif en big endian Voice Top Address est l'offset par rapport au début du header, qui pointe sur les données de définition des instruments pour la puce FM. FM Total est le nombre de canaux / pistes FM utilisés dans le morceau PSG Total est le nombre de canaux / pistes PSG utilisés dans le morceau Tempo démultiplie la durée des notes de manière globale (si une durée de note est de 2 frames et le tempo vaut 3, la durée de note sera de 6 frames) Delay ajoute une temporisation: cumule le délai a chaque frame, s'il n'y a pas d'overflow on ajoute une frame aux notes en cours, sinon on n'ajoute pas de délai Ce délai permet de faire varier le rythme de lecture de manière plus fine que le tempo. Code: 2 bytes : PCM Drum Table Pointer 1 byte : Bias (dummy) - always 0 1 byte : Volm (dummy) - always 0 Si Bias et Volm valent 0 il s'agit de la piste dédiée à la lecture des samples, sinon c'est une piste FM ou PSG PCM Drum Table Pointer est l'offset par rapport au début du header, qui pointe sur la piste déclenchant les samples envoyés au DAC Remarque : dans ma version je déclencherai les sons de batterie du YM2413 en lieu et place des samples. Mon objectif est de conserver un appel tous les 1/50 s. Rien ne nous empêche de développer une version alternative qui utilise le DAC du TO8 ... mais ce n'est pas la priorité pour moi. Code: 2 bytes : FM ch Table Pointer 1 byte : Bias 1 byte : Volm répété n fois (n = FM Total) FM ch Table Pointer est l'offset par rapport au début du header, qui pointe sur une piste de notes FM Bias Transposition (décalage des notes + ou -) Volm Volume de départ du canal Code: 2 bytes : PSG ch Table Pointer 1 byte : Bias 1 byte : Volm 1 byte : Dummy - always 0 1 byte : Enve répété n fois (n = PSG Total) PSG ch Table Pointer est l'offset par rapport au début du header, qui pointe sur une piste de notes PSG Bias Transposition (décalage des notes + ou -) Volm Volume de départ du canal Enve id d'enveloppe de volume, chaque id pointe sur un tableau de données dans le driver son. |
Auteur: | Bentoc [ 25 Juin 2021, 22:02 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Voici maintenant la structure de donnée utilisée dans le driver, c'est encore sujet à modification, mais ça vous permettra de lire le code plus facilement. J'utilise les structures de données, ça permet de faire de faire des références de la manière suivante : Code: lda SongFM2.DurationTimeout Même si on utilisera le plus souvent la forme suivante pour pouvoir traiter chaque piste (dont l'adresse est chargée dans y) à tour de rôle : Code: lda DurationTimeout,y Code: Track STRUCT ; "playback control"; bits ; 1 (02h) seems to be "track is at rest" ; 2 (04h) SFX is overriding this track ; 3 (08h) modulation on ; 4 (10h) do not attack next note ; 7 (80h) track is playing PlaybackControl rmb 1 ; "voice control"; bits ; 0-3 (00h-0Fh) Channel number ; 7 (80h) PSG Track VoiceControl rmb 1 ; "note control"; bits ; 0-3 (00h-0Fh) Current Block(0-2) and FNum(8) ; 4 (10h) Key On ; 5 (20h) Sustain On NoteControl rmb 1 TempoDivider rmb 1 ; timing divisor; 1 = Normal, 2 = Half, 3 = Third... DataPointer rmb 2 ; Track's position Transpose rmb 1 ; Transpose (from coord flag E9) Volume rmb 1 ; (Dependency) Should follow Transpose - channel volume (only applied at voice changes) VoiceIndex rmb 1 ; Current voice in use OR current PSG tone VolFlutter rmb 1 ; PSG flutter (dynamically effects PSG volume for decay effects) StackPointer rmb 1 ; "Gosub" stack position offset (starts at 2Ah, i.e. end of track, and each jump decrements by 2) DurationTimeout rmb 1 ; current duration timeout; counting down to zero SavedDuration rmb 1 ; last set duration (if a note follows a note, this is reapplied to 0Bh) ; 0Dh / 0Eh change a little depending on track -- essentially they hold data relevant to the next note to play NextData rmb 2 ; DAC Next drum to play - FM/PSG frequency NoteFillTimeout rmb 1 ; Currently set note fill; counts down to zero and then cuts off note NoteFillMaster rmb 1 ; Reset value for current note fill ModulationPtr rmb 2 ; address of current modulation setting ModulationWait rmb 1 ; Wait for ww period of time before modulation starts ModulationSpeed rmb 1 ; Modulation Speed ModulationDelta rmb 1 ; Modulation change per Mod. Step ModulationSteps rmb 1 ; Number of steps in modulation (divided by 2) ModulationVal rmb 2 ; Current modulation value Detune rmb 1 ; Set by detune coord flag E1; used to add directly to FM/PSG frequency VolTLMask rmb 1 ; zVolTLMaskTbl value set during voice setting (value based on algorithm indexing zGain table) PSGNoise rmb 1 ; PSG noise setting VoicePtr rmb 2 ; custom voice table (for SFX) TLPtr rmb 2 ; where TL bytes of current voice begin (set during voice setting) LoopCounters rmb $A ; Loop counter index 0 ; ... open ... GoSubStack ; start of next track, every two bytes below this is a coord flag "gosub" (F8h) return stack ; ; The bytes between +20h and +29h are "open"; starting at +20h and going up are possible loop counters ; (for coord flag F7) while +2Ah going down (never AT 2Ah though) are stacked return addresses going ; down after calling coord flag F8h. Of course, this does mean collisions are possible with either ; or other track memory if you're not careful with these! No range checking is performed! ; ; All tracks are 2Ah bytes long ENDSTRUCT ; Track STRUCT Constants PlaybackControl equ 0 VoiceControl equ 1 NoteControl equ 2 TempoDivider equ 3 DataPointer equ 4 TransposeAndVolume equ 6 Transpose equ 6 Volume equ 7 VoiceIndex equ 8 VolFlutter equ 9 StackPointer equ 10 DurationTimeout equ 11 SavedDuration equ 12 NextData equ 13 NoteFillTimeout equ 15 NoteFillMaster equ 16 ModulationPtr equ 17 ModulationWait equ 19 ModulationSpeed equ 20 ModulationDelta equ 21 ModulationSteps equ 22 ModulationVal equ 23 Detune equ 25 VolTLMask equ 26 PSGNoise equ 27 VoicePtr equ 28 TLPtr equ 30 LoopCounters equ 32 GoSubStack equ 42 ****************************************************************************** Var STRUCT SFXPriorityVal rmb 1 TempoTimeout rmb 1 CurrentTempo rmb 1 ; Stores current tempo value here StopMusic rmb 1 ; Set to 7Fh to pause music, set to 80h to unpause. Otherwise 00h FadeOutCounter rmb 1 FadeOutDelay rmb 1 Communication rmb 1 ; Unused byte used to synchronise gameplay events with music QueueToPlay rmb 1 ; if NOT set to 80h, means new index was requested by 68K SFXToPlay rmb 1 ; When Genesis wants to play "normal" sound, it writes it here SFXStereoToPlay rmb 1 ; When Genesis wants to play alternating stereo sound, it writes it here SFXUnknown rmb 1 ; Unknown type of sound queue, but it's in Genesis code like it was once used VoiceTblPtr rmb 2 ; address of the voices FadeInFlag rmb 1 FadeInDelay rmb 1 FadeInCounter rmb 1 1upPlaying rmb 1 TempoMod rmb 1 TempoTurbo rmb 1 ; Stores the tempo if speed shoes are acquired (or 7Bh is played anywho) SpeedUpFlag rmb 1 DACEnabled rmb 1 MusicBankNumber rmb 1 IsPalFlag rmb 1 ENDSTRUCT ****************************************************************************** StructStart AbsVar Var tracksStart ; This is the beginning of all BGM track memory SongDACFMStart SongDAC Track SongFMStart SongFM0 Track SongFM1 Track SongFM2 Track SongFM3 Track SongFM4 Track SongFM5 Track SongFM6 Track SongFM7 Track SongFM8 Track SongFMEnd SongDACFMEnd SongPSGStart SongPSG1 Track SongPSG2 Track SongPSG3 Track SongPSGEnd tracksEnd ;tracksSFXStart ;SFX_FMStart ;SFX_FM3 Track ;SFX_FM4 Track ;SFX_FM5 Track ;SFX_FMEnd ;SFX_PSGStart ;SFX_PSG1 Track ;SFX_PSG2 Track ;SFX_PSG3 Track ;SFX_PSGEnd ;tracksSFXEnd StructEnd org StructStart fill 0,(StructEnd-StructStart) ; I want struct data to be in binary please ... Bon ça fait beaucoup d'un coup, pas la peine de trop s'attarder dessus, c'est juste pour avoir la définition des variables sous la main. Dans le prochain épisode on regardera comment est structurée une piste et comment on gère les boucles. PS: Pour ceux qui n'ont pas suivi mes derniers devs le compilateur est LWASM dont la doc est ici : http://www.lwtools.ca/manual/manual.pdf |
Auteur: | Samuel Devulder [ 26 Juin 2021, 10:24 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Quel est cet assembleur qui connait les struct ? |
Auteur: | Bentoc [ 26 Juin 2021, 14:49 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
C'est LWASM, regarde juste au dessus de ton message je le précise, avec en prime le manuel utilisateur. Je vous invite à lire ce manuel, je trouve cet assembleur vraiment complet. L'auteur est Canadien et répond rapidement. |
Auteur: | Bentoc [ 30 Juin 2021, 21:01 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Prenons un cas concret. On suppose que x est chargé avec l'adresse des données du morceau de musique. A l'adresse de x on retrouve donc le header: Code: | 05 f1 | 06 | 03 | 01 | b6 | 05 c6 | 00 00 | 01 e2 | 00 | 08 | ... -- -- -- -- -- -- -- -- -- -- -- -- -- -- | | | | | | | | | |_ volume piste FM0 | | | | | | | | | | | | | | | | | |_ transposition piste FM0 | | | | | | | | | | | | | | | |_ offset des données de la piste FM0 | | | | | | | | | | | | | |_ identifiant de piste DAC (valeur 0000) | | | | | | | | | | | |_ offset des données de la piste DAC | | | | | | | | | |_ delay | | | | | | | |_ tempo | | | | | |_ nb de pistes PSG | | | |_ nb de pistes FM | |_ offset des données de définition des instruments en position $01e2,x on retrouve les données de la piste FM0 : Code: ef 05 80 30 80 9b 0c a7 a5 08 a7 04 Les données sont encodées dans un octet de la manière suivante : Code: $00-7F : Durée $80 : Pause $81-$DF : Note $E0-$FF : Commande (Coordination flag) Les octets de commande peuvent être suivis de plusieurs octets de paramètres. Si on décode les données on a : Code: $EF $05 : SetVoice 05 => Sélection de l'instrument pour cette piste $80 : Pause $30 : durée 48 frames (démultiplié par le tempo) $80 : Pause - pas de durée - : on reprend la dernière durée lue soit 48 frames $9b : Note C#2 $0c : Durée 12 frames (démultiplié par le tempo) ... Subtilité Si on a : Une note, une durée, une durée On jouera deux fois la même note avec des durées différentes Si on a : Une note, une durée, une note, une note On jouera trois notes différentes de la même durée Fréquences et Notes de musique Le tableau ci dessous est une synthèse des notes et fréquences pour les puces YM2612 et YM2413 que j'ai réalisé et posté sur le forum de SonicRetro. On y retrouve les paramètres FNum et Block qui sont envoyés à la puce son pour paramétrer une fréquence d'instrument. Le driver smps gère les 95 notes C0-A#7 ce qui correspond aux notes midi 12-106 Fichier(s) joint(s): YM2612-YM2413 Freq&Notes.png [ 84.48 Kio | Vu 9442 fois ] Dans le code quand on lit les données de musique, on transforme donc une note en données FNum et Block à l'aide du code suivant : Code: FMSetFreq subb #$80 ; Test for a rest bne @a lda PlaybackControl,y ; Set bit 1 (track is at rest) ora #$02 sta PlaybackControl,y bra @b @a addb Transpose,y ; Add current channel transpose (coord flag E9) aslb ; Transform note into an index... ldu #Frequencies lda #0 ldd d,u std NextData,y ; Store Frequency @b ldb ,x ; Get next byte ... ; 95 notes (Note value $81=C0 $DF=A#7) Frequencies fdb $0000 ; padding for ($80=rest), saves a dec instruction fdb $00AD,$00B7,$00C2,$00CD,$00DA,$00E6,$00F4,$0102,$0112,$0122,$0133,$0146 ; C0 - B0 fdb $0159,$016D,$0183,$019A,$01B3,$01CC,$01E8,$0302,$0312,$0322,$0333,$0346 ; C1 - B1 fdb $0359,$036D,$0383,$039A,$03B3,$03CC,$03E8,$0502,$0512,$0522,$0533,$0546 ; C2 - B2 fdb $0559,$056D,$0583,$059A,$05B3,$05CC,$05E8,$0702,$0712,$0722,$0733,$0746 ; C3 - B3 fdb $0759,$076D,$0783,$079A,$07B3,$07CC,$07E8,$0902,$0912,$0922,$0933,$0946 ; C4 - B4 fdb $0959,$096D,$0983,$099A,$09B3,$09CC,$09E8,$0B02,$0B12,$0B22,$0B33,$0B46 ; C5 - B5 fdb $0B59,$0B6D,$0B83,$0B9A,$0BB3,$0BCC,$0BE8,$0D02,$0D12,$0D22,$0D33,$0D46 ; C6 - B6 fdb $0D59,$0D6D,$0D83,$0D9A,$0DB3,$0DCC,$0DE8,$0F02,$0F12,$0F22,$0F33 ; C7 - A#7 L'envoi d'une nouvelle fréquence à la puce YM2413 se fait ainsi : Code: FMUpdateFreq ldb Detune,y sex addd NextData,y ; apply detune but don't update stored frequency addd ModulationVal,y ; add modulation effect sta @dyn+1 lda #$10 ; set LSB Frequency Command adda VoiceControl,y ; get channel number ldu #YM2413_A0 sta ,u ; send Fnum update Command adda #$10 ; set Sus/Key/Block/FNum(MSB) Command(and used as 2 cycles tempo) nop ; total wait 4 cycles stb 1,u ; send FNum (b0-b7) _YMBusyWait17 ; total wait 24 cycles ldb NoteControl,y ; load current value (do not erase FNum MSB) (and used as 5 cycles tempo) sta ,u ; send command andb #$F0 ; clear FNum MSB (and used as 2 cycles tempo) @dyn addb #0 ; (dynamic) Set Fnum MSB (and used as 2 cycles tempo) stb 1,u ; send FNum (b8) and Block (b0-b2) stb NoteControl,y rts Il faut envoyer l'information en deux mises à jour de registre. Chaque mise à jour est composée : - d'un envoi de commande - d'une attente de 4 cycles (6809) - d'un envoi de valeur - d'une attente de 24 cycles (6809) avant de pouvoir envoyer une nouvelle commande Pour référence : Fichier(s) joint(s): YM2413 Freq Reg.png [ 35.51 Kio | Vu 9442 fois ] |
Auteur: | Bentoc [ 12 Juil 2021, 14:08 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Je commence à avoir quelque chose qui fonctionne plutôt bien. Voici un enregistrement de ce qui sort de de l'émulateur TO8D, branchez vos casques pour profiter des basses Mystic Cave Zone de Masato Nakamura (YM2413+SN76489) https://www.bento8.fr/wp-content/uploads/2021/07/MCZ.mp3 J'ai juste édité le fichier audio pour normaliser le signal et j'ai ajouté un fondu de fin. J'ai ajusté le mix des deux chips dans l'émulateur, le PSG est peut être un peu trop en retrait ... Dans la vrai vie il faudra ajuster le niveau de sortie du signal de la carte FM (elle nécessite ampli-op contrairement au chip PSG qui sort un signal suffisamment puissant). PS : Mes deux cartes sont construites, mais il reste à ajuster ce point du Mix, car actuellement la carte FM sort un signal bcp trop faible ... En pièce jointe le fichier binaire qui est lu par le driver SMPS du TO8. => 1535 octets pour 6 pistes FM et 3 pistes PSG Fichier(s) joint(s): Pour le moment je n'ai fait aucune optimisation, on tourne autour des 1200 cycles par frame (1/50s). Ce n'est pas extraordinaire. La première optim sur laquelle je vais devoir me pencher est la suivante : Les morceaux en provenance de la megadrive sont faits pour du 60hz, et dans le driver d'origine pour ajuster a 50hz: toutes les 5 frames on joue déclenche deux fois la lecture du morceau. Ce qui compense la vitesse de lecture mais induit une double charge de cycles. Il faudrait que je convertisse les durées directement dans le binaire pour récupérer ces 1200 cycles, ça vaut clairement le coup, mais ce n'est pas si facile a faire ... |
Auteur: | Samuel Devulder [ 12 Juil 2021, 19:49 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Ca sonne bien! Je regrette juste que ce ne soit pas en standard des chips pareils. Ca aurait changé la donne au niveau des jeux TO8 à l'époque. |
Auteur: | Bentoc [ 13 Juil 2021, 06:32 ] |
Sujet du message: | Re: Driver son pour SN76489 et YM2413 (SMPS 6809) |
Je suis d'accord avec toi ... Pour me consoler je me dit que ce qui n'a pas été fait à l'époque nous laisse de la place pour nous amuser aujourd'hui ! |
Page 1 sur 1 | Heures au format UTC + 1 heure |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |