[MZ-700] Space Rally

Cette catégorie traite de développements récents pour nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

En tout cas pas simple. J'avais des raisons de penser que ce que j'ai codé n'est pas correct : le corps de l'ISR prenait plus de cycles qu'il n'en fallait quand il devait permuter la sortie audio. Du coup, l'ISR pouvait déborder au delà d'une période /HSYNC (environ 225 cycles au maximum pour ne pas déborder) et j'avais donc un nombre d'ISR pas si périodique que ça. Ajoutez à cela la programmation du compteur qui semble induire en erreur le décompte (je suis obligé de mettre 2 au lieu de 3 pour faire du ISR tous les 3 /HSYNC).

J'ai opté pour une lecture d'un tampon de 256 octets dans l'ISR pour tenir l'execution sous la période d'un /HSYNC. Il me faut donc dans la boucle du jeu, un algo qui va remplir ce tampon avec le code 'command' du PIT CTC0 que j'expliquerais. C'est cet algo qui m pose quelques difficultés et j'espère que l'un d'entre vous pourrait m'aider à y voir plus clair (spécialiste Z80).

Bien allons-y pour les détails :

Le corps d l'ISR :

Code : Tout sélectionner

		; prologue de l'ISR
		PUSH	HL
		PUSH	AF
		
	if DEBUG
		; incrémentation du nombre d'appel à cet ISR
		LD		HL,isr_count
		INC		(HL)
	endif
	
		; réarmement du compteur CTC2 (mode 0, période : 1)
		LD		HL,$E006
		LD		(HL),1
		
		; récupération de $20 (CTC0 mode 0 -> sortie audio haut)
		; ou de $28 (CTC0 mode 4 -> sortie audio bas)	
		LD		A,(sfx_buffer)
sfx_isr_buffer_index equ $-2

		; reprogrammation du CTC0
		LD		($E007),A
		
		; incrémentation de l'adresse du tampon, maintenue dans la page
		LD		HL,sfx_isr_buffer_index
		INC		(HL)
		
		; épilogue de l'ISR
		POP		AF
		POP		HL
		EI
		RET
Normalement, on se sert du mode 3 (square wave generator) sur le CTC0. Mais ici, j'alterne entre mode 0 (OUT0 = H initial) et mode 4 (OUT0 = L initial). A noter que la sortie audio est en faite l"inverse de OUT0.

Voici le détails des modes (traduction de l'anglais via DeepL) :
Modes de fonctionnement
Les bits D3, D2 et D1 du mot de contrôle définissent le mode de fonctionnement du timer. Il y a 6 modes au total ; pour les modes 2 et 3, le bit D3 est ignoré, donc les modes 6 et 7 manquants sont des alias pour les modes 2 et 3.

Tous les modes sont sensibles à l'entrée GATE, une GATE haute entraînant un fonctionnement normal, mais les effets d'une GATE basse dépendent du mode :

Modes 0 et 4 : Le comptage est suspendu lorsque GATE est basse, et repris lorsque GATE est haute.
Modes 2 et 3 : GATE bas force OUT haut immédiatement (sans attendre une impulsion d'horloge) et réinitialise le compteur (sur le front descendant de l'horloge suivante). Lorsque GATE repasse à l'état haut, le comptage reprend depuis le début.

Mode 0 (000) : Interruption sur le comptage des bornes
Le mode 0 est utilisé pour la génération d'une temporisation précise sous contrôle logiciel. Dans ce mode, le compteur commence à compter à partir de la valeur initiale COUNT chargée dans le compteur, jusqu'à 0. La vitesse de comptage est égale à la fréquence de l'horloge d'entrée.

La broche OUT est mise à un niveau bas après l'écriture du mot de contrôle, et le comptage commence un cycle d'horloge après la programmation du COUNT. La broche OUT reste basse jusqu'à ce que le compteur atteigne 0, auquel cas la broche OUT sera mise en haut jusqu'à ce que le compteur soit rechargé ou que le mot de contrôle soit écrit. Le compteur s'enroule jusqu'à 0xFFFF en interne et continue de compter, mais la broche OUT ne change plus jamais. Le signal Gate doit rester actif et élevé pour un comptage normal. Si Gate passe à l'état bas, le comptage est suspendu, et reprend lorsqu'il repasse à l'état haut.

Le premier octet du nouveau comptage, lorsqu'il est chargé dans le registre de comptage, arrête le comptage précédent.

Mode 2 (X10) : générateur de taux
Dans ce mode, le dispositif agit comme un compteur diviseur par n, qui est généralement utilisé pour générer une interruption d'horloge en temps réel.

Comme dans les autres modes, le processus de comptage commencera le prochain cycle d'horloge après l'envoi de COUNT. OUT restera alors élevé jusqu'à ce que le compteur atteigne 1, et deviendra faible pendant une impulsion d'horloge. Au cycle suivant, le compteur est rechargé, OUT passe à nouveau à l'état haut, et tout le processus se répète.

Le temps entre les impulsions hautes dépend du nombre prédéfini dans le registre du compteur, et est calculé à l'aide de la formule suivante :

Valeur à charger dans le compteur = {\displaystyle f_{\rm {input} \over f_{\rm {output}}{{{displaystyle f_{\rm {input}} \Nsur f_{\rm {output}}}

Notez que les valeurs du registre COUNT vont de {\displaystyle n}n à 1 ; le registre n'atteint jamais zéro.

Mode 3 (X11) : générateur d'ondes carrées
Ce mode est similaire au mode 2. Cependant, la durée des impulsions d'horloge haute et basse de la sortie sera différente du mode 2.

Supposons que {\displaystyle n}n soit le nombre chargé dans le compteur (le message COUNT), la sortie sera haute pour {\displaystyle \left\lceil {n \over 2}\right\rceil }{\displaystyle \left\lceil {n \over 2}\right\rceil } comptes, et faible pour {\displaystyle \left\lfloor {n \over 2}\right\rfloor }{\displaystyle \left\lfloor {n \over 2}\right\rfloor } comptes. Ainsi, la période sera de {\displaystyle n}n comptes, et si {\displaystyle n}n est impair, le demi-cycle supplémentaire est passé avec OUT haut.

Mode 4 (100) : Strobe déclenché par le logiciel
Après le chargement du mot de contrôle et de COUNT, la sortie restera haute jusqu'à ce que le compteur atteigne zéro. Le compteur génère alors une impulsion basse pendant 1 cycle d'horloge (un strobe) - après quoi la sortie redevient haute.

La GATE basse suspend le comptage, qui reprend lorsque la GATE redevient haute.
A l'initialisation je fais ceci :

Code : Tout sélectionner

		; CTC1 placé en mode 2 (rate generator, avec compteur LSB seulement)
		LD		HL,$E007		; $E007 - counter control
		LD		(HL),$54		; counter #1 - MODE 2 - set only LSB counter
		
		; CTC2 placé en mode 0 (interrupt on terminal count, avec compteur LSB seulement)
		LD		(HL),$90			; counter #2 - MODE 0 - set only LSB counter
		
		; CTC1 a pour période 3 /HSYNC [ 2 (OUT1->CLK2 : H) -> 1 (OUT1->CLK2 : H) -> 0 (OUT1->CLK2 : L) ]
		LD		L,$05			; $E005 - counter #1
		LD		(HL),2
		
		; CTC2 doit enclencher l'interruption à chaque passage de OUT1 à L
		LD		L,$06			; $E006 - counter #2
		LD		(HL),1

		; Activation de l'interruption du CTC2 (il n'y a pas d'autre source)
		EI
La sortie du CTC1 (son entrée est sur le signal BLNK) est connectée à l'entrée de CTC2. La division de fréquence est de 1 du coup.

Bon entrons dans le vif du sujet : je veux faire l'algo qui remplit ce tampon de 256 octets dans la boucle du jeu. J'ai codé un truc mais je pense que je n'arrive plus à réfléchir à ce stade.

Voici le son code actuel :

Code : Tout sélectionner

sfx_stop:
		; GATE0 à 0 -> coupure du son
		LD		L,$E008
		LD		(HL),0
		
		RET
sfx_start:
		; affectation initiale et courante de l'adresse du bloc de musique passé en HL 
		LD		(sfx_play_src_caddr-2),HL
		LD		(sfx_play_src_iaddr-2),HL
		
		; affectation initiale et courante de la taille du bloc de musique passé en BC 
		LD		(sfx_play_src_csize-2),BC
		LD		(sfx_play_src_isize-2),BC
		
		; remplissage du tampon
		CALL	sfx_play
		
		; CTC0 en mode 4 -> OUT0 -> 1 (signal audio à 0)
		LD		HL,$E007
		LD		(HL),$28

		; GATE0 à 1 -> reprise du son
		LD		L,$08
		LD		(HL),1
		
		RET
		
sfx_play:
		; address courante du tampon commence 128 octets plus loin
		LD		DE,sfx_buffer+128
sfx_play_dst_caddr:

		; lire l'index du tampon en cours dans l'ISR
		LD		A,(sfx_isr_buffer_index)
		
		; vérifier que l'on ne cherche pas à remplir sur la demi partie en cours de lecture par l'ISR
		XOR		E
		AND		$80
		
		; si oui, trop tôt pour remplir le tampon - attendons le frame suivant
		RET		Z
		
		; adresse courante du bloc de musique à lire
		LD		HL,0
sfx_play_src_caddr:

		; taille restante du bloc de musique à lire
		LD		IX,0
sfx_play_src_csize:

		; 128 octets à écrire dans le tampon et B contient le compteur d'ISR qui reste avant de basculer la sortie audio
		LD		BC,1:128
sfx_play_dst_csize:

		; on se cale sur un /HSYNC 
		HALT
		
		; et on entre directe pour traiter ce qui reste dans B
		JP		sfx_play_kernel
		
sfx_play_loop:
		; lire le compteur d'ISR dans le bloc de musique
		LD		B,(HL)
		
		; incrémenter l'adresse courante du bloc de musique
		INC		HL
		
		; le fichier binaire compte à partir de 0, nous on veut à partir de 1 ici
		INC		B
		
sfx_play_kernel:
		; décrémente la taille du bloc de musique
		DEC		IX
		
		; si on arrive à la fin du bloc de musique, il faut "rewind-er"
		LD		A,IXL
		OR		IXH
		CALL	Z,sfx_play_rewind
		
		; octet à mettre dans le tampon : $28 pour signal audio bas, $20 signal audio haut
		LD		A,$28
		
sfx_play_dst_cbyte:
		; écrire l'octet dans le tampon
		LD		(DE),A
		
		; incrémenter l'adresse de tampon tout en le maintenant dans un page
		INC		E
		
		; on sort si le tampon est remplie des 128 octets
		DEC		C
		JR		Z,sfx_play_eob
		
		; le compteur d'ISR lu dans le bloc de musique est décrémenté et on reboucle si non nul
		DJNZ	sfx_play_kernel
		
		; le compteur d'ISR est à 0 alors on bascule le signal audio et on reboucle
		XOR		$20
		LD		(sfx_play_dst_cbyte-1),A
		JP		sfx_play_loop
		
sfx_play_eob:
		; on sauvegarde le contexte pour le prochain appel à sfx_play
		DEC		B
		LD		(sfx_play_src_caddr-2),HL
		LD		(sfx_play_src_csize-2),IX
		LD		(sfx_play_dst_caddr-2),DE
		LD		A,B
		LD		(sfx_play_dst_csize-1),A
		RET
		
sfx_play_rewind:
		; on restaure l'adresse et la taille du bloc de musique à lire
		LD		HL,0
sfx_play_src_iaddr:
		LD		IX,0
sfx_play_src_isize:
		LD		(sfx_play_src_caddr-2),HL
		LD		(sfx_play_src_csize-2),IX
		RET
La routine est assez longue à lire et probablement erronée car je me retrouve sans son très vite et le tampon qui était rempli initialement avec 256 octets $20 se retrouve avec 256 octets $28 que je n'arrive pas à m'expliquer.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

GROGNEUGNEU !

je viens de voir que je fais un "XOR $20"... en d'autre terme, j'alterne entre $28 et $08 au lieu de $20 ! ça ne risquait pas de fonctionner car il me fallait un "XOR $08" en fait. Ok, j'ai du son en boucle mais pas toute la musique. Encore du boulot en perspective.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Bon ça se corse. Je n'arrive pas vraiment à savoir comment à quelle fréquence maximum on alterne la sortie audio. J'ai désactivé le remplissage du tampon avec les blocs de musique pour remplir avec une alternance à chaque appel ISR. J'ai donc là la période la plus courte ou la fréquence la plus haute que le jeu peut produire.

Ce faisant, je lance la capture du son depuis l'émulateur EmuZ-700 puis demande l'analyse du spectre via Audacity :
spectrum-one-toggle-per-isr.png
spectrum-one-toggle-per-isr.png (25.23 Kio) Consulté 4436 fois
Encore une fois, je ne suis pas spécialiste mais dans la littérature consacrée, il semblerait qu'une onde carrée est la somme d'harmoniques impaires.
xfourier_04.png
xfourier_04.png (15.57 Kio) Consulté 4436 fois
J'en déduis que le plus gros pic dans le spectre correspond à la fréquence fondamentale : aux alentours de 1954 Hz d'après l'export du fichier de spectre (je note que le pic suivant est au triple de la fréquence fondamentale).

Code : Tout sélectionner

...
1945.312500	-38.204800
1948.242188	-24.450636
1951.171875	-6.708512
1954.101563	-4.792348
1957.031250	-15.659689
1959.960938	-34.578064
...
Donc, dois-je conclure que l'ISR est enclenché à cette fréquence fondamentale !?

Pour comparaison, le spectre d'une onde sinusoïdale à 1954 Hz :
spectrum-1954Hz-sinewave.png
spectrum-1954Hz-sinewave.png (18.55 Kio) Consulté 4436 fois
Et celle d'une onde carrée à 1954 Hz :
spectrum-1954Hz-squarewave.png
spectrum-1954Hz-squarewave.png (18.01 Kio) Consulté 4436 fois
J'avoue que je suis un peu perdu là...
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Bon je reviens un peu sur ce que je disais précédemment.

J'ai enfin trouvé un diagramme qui m'apporte les éléments qui me manquaient à la compréhension du PIT :
8253ppt-10-1024.jpg
8253ppt-10-1024.jpg (128.85 Kio) Consulté 4399 fois
Donc d'après le diagramme, la fréquence fondamentale (il faut une paire d'ISR) devrait être :
Ff = 0.5 x 15KHz / ((PIT CNT2 + 1) x PIT CNT1) avec PIT CTC1 en mode 2 et PIT CTC2 en mode 0
Si je tente C1 = 1 et C2 = 2, j'obtiens théoriquement du ISR tous les trois lignes mais l'affichage ne suit pas (et on passe à du 25 fps).

Pourquoi ? parce que le déclenchement se fait quand le signal BLNK est sur le front descendant et non sur le front montant comme je supposais initialement. Or pour copier un block en VRAM je dois d'abord lire depuis une source (donc pendant que BLNK = 0) et écrire dans la VRAM (donc pendant que BLNK = 1)

Si je regarde les cycles nécessaires (environ 225 cycles par ligne) :
; SFX_ECS+ISR > 4 + 144 cycles => un ISR tous les 1 BLNK
; SFX_ECS+ISR+LBLK#1 > 4 + 144 + 94 cycles => un ISR tous les 2 BLNK ! <-- au final, c'est 2 BLNK minimum !
; SFX_ECS+ISR+LBLK#1+SBLK#1 > 4 + 144 + 94 + 81 cycles => un ISR tous les 3 BLNK (PUSH reprend sur le BLNK suivant)
; SFX_ECS+ISR+LBLK#1+SBLK#1+LBLK#2 > 4 + 144 + 94 + 81 + 119 cycles => un ISR tous les 3 BLNK
; SFX_ECS+ISR+LBLK#1+SBLK#1+LBLK#2+SBLK#2 > 4 + 144 + 94 + 81 + 119 + 81 cycles => un ISR tous les 4 BLNK (PUSH reprend sur le BLNK suivant)
; SFX_ECS+ISR+LBLK#1+SBLK#1+LBLK#2+SBLK#2+SFX_LCS > 4 + 144 + 94 + 81 + 119 + 81 + 10 cycles => un ISR tous les 4 BLNK.

ISR : l'interruption.
SFX_ECS : Enter Critical Session, un simple HALT pour laisser jouer la note avant d'attaquer les deux blocs "graphiques". A partir de là, il ne doit pas y avoir un autre ISR avant de quitter cette session car la pile est détournée de son usage normal.
SFX_LCS : Leave Critical Session. On restaure une pile "standard" pour que l'ISR prochain ne corrompt pas le bloc suivant.
LBLK#1 : lecture du premier bloc (se fait sous BLNK = 0 !)
SBLK#1 : écriture du premier bloc (se fait sous BLNK = 1 !)
LBLK#2 : lecture du deuxième bloc (se fait sous BLNK = 0 !)
SBLK#2 : écriture du deuxième bloc (se fait sous BLNK = 1 !)
Conclusion : le minimum est 4 BLNK entre chaque ISR avec C1 = 1 et C2 = 3 ------> fréquence fondamentale maximum jouable = 15KHz / 8.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

A partir d'aujourd'hui, je vais mettre en pause le son car je ne suis pas satisfait dans sa forme actuelle.

Je réfléchis à la façon de piloter le vaisseau. Actuellement j'utilise [<-] et [->] pour le déplacer dot par dot. Avec un défilement rapide et des dédales assez étroits, j'ai un peu peur que ne ce soit super jouable.

1) Je garde ce mode de déplacement et je gère un champ de protection qui s'enclenche au contact. L'énergie du champ diminue mais peut se régénérer lentement. Le vaisseau pourra alors continuer "en creusant" jusqu'à que le champ s'épuise. J'aimerais avoir la possibilité de pousser le vaisseau dans la direction inverse du choc. Super simple.

2) Le vaisseau garde le cap sur un couloir, une frappe sur [<-] ou [->] permet de choisir un autre couloir. Les chocs sont moindres mais on peut envisager des obstacles dans les couloirs de temps à autres pour forcer le joueur à changer de couloir. Un champ pour absorber les passages un peu abrupt du vaisseau d'un couloir à un autre sur une corniche en raison de l'algo utilisé pour garder le cap, qui n'est pas d'une précision suffisante pour assurer que TOUT le vaisseau ne va par arracher un bout de corniche. Mais un gros obstacle sera fatal au vaisseau.
Avatar de l’utilisateur
6502man
Messages : 12286
Inscription : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [MZ-700] Space Rally

Message par 6502man »

Pour les déplacements il n'y à pas de joystick sur les MZ ?

Tu produit la musique en 1 bits c'est ca ?

Si tu veux une onde carré il faut que le signal soit rapidement au niveau haut ou bas, je n'ai pas le schéma de la sortie son du MZ mais il doit y avoir des condensateurs ce qui risque de produire une courbe de réponse, mais je suis loin d'être un expert.

Sinon la solution utiliser un chip son 8 bits de type AY-3 pour avoir en même temps la musique et la gestion des joysticks :wink:
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Je ne gère pas le joystick bien que j'en ai un. Il est analogique et très RARE à trouver. Et quand on trouve, le prix est WTF. Il y a très peu de jeux qui l'utilisent. Et l'émulateur ne le gère pas. De plus, le mode MZ-700 ne gère pas ce joystick propriétaire donc un jeu l'utilisant ne sera pas compatible eb mode 700 du MZ-800.

Pour le son, j'ai deux manières :
- sortir le signal carré via le mode 3 et une période dans le compteur - ce que je prévoyais au début et ce que fait le player AT2.
- sortir 0 ou 1 en alternant le mode 0 et 2 sans affecter de période au compteur, via l'interruption d'un autre timer qui compte les blanc horizontaux de l'écran. C'est ce que je testais jusque-là.

Je mets ça en pause pour avancer sur d'autres points.
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [MZ-700] Space Rally

Message par Dmanu78 »

Merci @hlide pour ce partage. Je suis certain que tu trouveras une solution de contournement pour le son. Hâte de voir l’avancement de ce projet. :)
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Merci @Dmanu78. :)

Bon, j'ai repris la gestion du sons (parce que, euh, je suis tenace). J'utilise Audacity mais je ne suis pas sûr de bien l'utiliser.

Je suis parti sur un MP3 intitulé "Learn Soundation - Chip Music - Square Wave" (en suivant leur tutoriel) que j'ai chargé avec Audacity. J'ai fait un resample à 3903 Hz de cette "musique" puis un filtrage haute fréquence de 1952 Hz et enfin j'ai saturé à l'extrême pour pouvoir le passer à l'outil pcm2pwm (trouvable sur github) qui génère des octets représentants les périodes en unité d'ISR. 22Ko, ça passe entier dans le binaire.

L'ISR se contente de lire un octet dans un tampon cyclique d'une page de 256 octets pour mettre à l'état haut ou bas la sortie du son (principe du PWM). A chaque frame, j'appelle la routine qui va remplir les octets libres du tampon en transformant les 22 kilo de périodes en état haut et bas (si Période = N alors il faut remplir N états dans le tampon). C'est très similaire au LEP pour ceux qui connaissent.

Pour écouter, penser à bien baisser le son !!!

Donc voici la source :
Learn Soundation - Chip Music - Square Wave.zip
(342.21 Kio) Téléchargé 102 fois
(https://soundation.com/user/learnsounda ... uare-wave/)

Et ce que ça me donne sur l'émulateur EmuZ-700 :
2021-06-14_23-10-08.wav.zip
(117.68 Kio) Téléchargé 104 fois
Le fichier transformé qui a servi de source à pcm2pwm :
Sampler.zip
(22.89 Kio) Téléchargé 95 fois
P.S.: j'ai été obligé de zipper les mp3 et wav.
Avatar de l’utilisateur
rendomizer
Messages : 413
Inscription : 17 juin 2016 21:00
Contact :

Re: [MZ-700] Space Rally

Message par rendomizer »

Comment fais tu pour coder un sample sur 1bit ?

[Modération] Dérive à suivre ici [/Modération]
Je ne suis qu'un utilisateur pas un pro
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Oui, c'est un "loudspeaker" de 8 Ohm/1 W avec un amplificateur. Malheureusement, mon vrai MZ-700 est en panne. Au besoin, je fais tester sur un groupe FB sur une vraie machine. J'ai un autre émulateur qui jusqu'à présent s'est montré très fidèle au vrai MZ-700, en mode 700 : mz800emu mais je ne sais pas capturer le son (il semble meilleur).
mothbrd.jpg
mothbrd.jpg (278.63 Kio) Consulté 3917 fois
8253.png
8253.png (6.04 Kio) Consulté 3917 fois
mz8253.png
mz8253.png (28.63 Kio) Consulté 3897 fois
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Je suis actuellement en train d'expérimenter une approche pour créer un effet de volume. Plutôt que d'émettre un signal haut ou bas avec un duty à 100% tous les ISR, j'ai introduit (partiellement pour le moment) la notion de PCM 4-bit en remplacement du PCM 1-bit. Comment me direz-vous ? eh bien, je me suis aperçu que le mode 0 me permettait de créer un signal bas puis haut avec un duty "programmable". En effet, dès que le compteur atteint le seuil, il passe au signal haut et y reste jusqu'à reprogrammation de ce compteur.

Du coup je me suis dit que je pourrais m'amuser à créer un PCM 4-bit avec des duties de ce genre : 0/15, 1/15, 2/15, ..., 14/15, 15/15. Effectivement avec 1/15, le volume semble bien plus faible. En revanche, j'entend moins la différence de volume quand on approche le 15/15. Et je me dis que j'aimerais assez avoir plus faible que 1/15.

Bon maintenant la technique (et pourquoi du PCM 4-bit) :

Au lieu d'une page de 256 octets contenant les octets de programmation de mode du compteur 0 (utilisé pour la production de son carré jusqu'à 1.108404688 MHz), je détermine deux tables contiguës. La première continue de jouer le même rôle mais indirectement car elle contient des index sur la seconde page qui, elle, contient du code tous les 16 octets pour produire un signal carré avec un duty en rapport avec l'index de la période d'un ISR (un tous les 3.902825 KHz)

Voici la définition des deux pages :

Code : Tout sélectionner

	align 256
sfx_buffer:
		DS		256,$00
sfx_play_pwm_0:
		LD		HL,$E007 ; duty 0% !
		LD		(HL),$28
		JP		sfx_isr_ret
	align 16
sfx_play_pwm_1_15:
		LD		HL,$E007 ; 16-bit counter, duty 6,6...%
		LD		(HL),$30
		LD		L,$04
		LD		(HL),SFX_DUTY_1_15>>0
		LD		(HL),SFX_DUTY_1_15>>8
		JP		sfx_isr_ret
	align 16
...
sfx_play_pwm_14_15:
		LD		HL,$E007 ; 16-bit counter, duty 93,3...%
		LD		(HL),$30
		LD		L,$04
		LD		(HL),SFX_DUTY_14_15>>0
		LD		(HL),SFX_DUTY_14_15>>8
		JP		sfx_isr_ret
	align 16
sfx_play_pwm_15:
		LD		HL,$E007 ; duty 100% !
		LD		(HL),$20
		JP		sfx_isr_ret
J'ai pris 4-bit d'index car il ne me reste plus que 2 octets pour les 1/15 à 14/15. En passant à 5-bit, je ne serais plus en mesure de caser tous les duties dans une page de code.

Maintenant, il me faut adapter l'ISR :

Code : Tout sélectionner

sfx_isr:	PUSH	HL
		PUSH	AF
		
		LD		HL,$E006 ; réarme l'interruption pour déclencher un nouvel ISR dans les quatre BLNK à suivre
		LD		(HL),PIT_CNT2
		
		LD		HL,sfx_buffer ; on est où dans la première page ?
sfx_isr_buffer_index equ $-2
		LD		L,(HL) ; lit un octet $v0 où v est le "volume"
		INC		H ; passe à la page suivante
		JP		(HL) ; saute dans le code pour le bon "volume"
sfx_isr_ret:		
		LD		HL,sfx_isr_buffer_index ; on passe au "volume" suivant dans la page
sfx_isr_on_off:
		NOP ; on a ici $34 (INC [HL]) quand on joue sinon $00 (NOP) quand  on ne joue plus
		POP		AF
		POP		HL
		EI
		RET
L'ISR avait initialement 137 cycles d'exécution. Là de base on a 115 cycles auquel il faut ajouter soit 30 cycles ou 57 cycles selon le duty souhaité : 145 ou 172 cycles. L'écran semble toujours tourner à 50 fps.

La raison que j'ai voulu faire ça est double :

- voir si par ce jeu de duty, on pouvait créer un effet de volume et donc avoir la possibilité de mixer plusieurs sources.
- tester la possibilité de faire du MLI "intersective" : https://fr.wikipedia.org/wiki/Modulatio ... analogique.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Voici les spectres observés par valeur de duty :
duties_spectrums.png
duties_spectrums.png (123.73 Kio) Consulté 2712 fois
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

Actuellement voici ce que j'obtiens en "pure" 1-bit PCM -> PWM :
wavedrom_pwm@3.9KHz.png
wavedrom_pwm@3.9KHz.png (26.35 Kio) Consulté 2637 fois
Cela consiste à faire un duty à 0% ou 100%. Du coup, on tombe à une fréquence maximum de 1,9 KHz.

Mais je caresse l'espoir de doubler la résolution par un jeu de duty : 0%, 50% et 100%.

En effet, je peux par le biais du mode et de son compteur recréer un signal carré avec un duty 0%, 50% ou 100% au sein d'un ISR.
wavedrom_pwm@7.8KHz.png
wavedrom_pwm@7.8KHz.png (31.75 Kio) Consulté 2637 fois
Je ne l'ai pas encore testé car ça implique un changement dans le player ou dans les données à lire et à transformer.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Space Rally

Message par hlide »

A l'adresse des admins : pourriez-vous me déplacer tous les posts de "rendomizer" qui sont des hors sujets par rapport à la conception de ce jeu et les réponses à ce dernier pour assainir ce fil de discussion (enfin plutôt un train de pensée, d'échec et de réussite) ? merci !
Répondre