Nouveau procédé d'e...
 
Notifications
Retirer tout

Nouveau procédé d'encodage audio pour Oric.

32 Posts
5 Utilisateurs
0 Likes
793 Vu
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 

@jibe Soit tu passes en ca65/cc65 ce code et donc tu fais l'inclusion de telestrat.inc qui est standard dans cc65. Soit tu fais la macro XA65 pour que :

BRK_TELEMON soit fait tel que :

.byte $00, val ; val est l'argument de BRK_TELEMON.

La table de mapping de XFREAD : https://github.com/cc65/cc65/blob/master/asminc/telestrat.inc

L'idéal est de builder avec cc65, comme cela, cela rajoute le header. Sinon avec xa, il faut rajouter le header orix à la main

donc cl65 -ttelestrat main.c te génère un binaire orix avec le header tout fait.

Si le programme doit être fait à 100% en assembleur, Assinie a un repo orix-sdk qui permet d'accéder à des macros toutes faites pour les malloc, les fopen, fclose etc.

la macro pour les appels du kernel sont déclarés aussi dans telestrat.inc : https://github.com/cc65/cc65/blob/master/asminc/telestrat.inc#L537

Le build de binaire Orix se fait avec la target telestrat de cc65 tout simplement car le kernel orix est une grosse évolution de Telemon.

La vidéo vidplay avec le lapin fait 10mo pour info, mais il n'y a pas de limite si ce n'est les 4go de la FAT32 par fichier, dans ce cas il suffit de basculer sur un autre fichier de data.

 


RépondreCitation
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 

Allez plus simple, convertion du code en cc65/ca65 pour que cela fonctionne : https://github.com/orix-software/vidplay

Donc, il suffit de cloner, puis si on veut lire un header passer : dans A et Y la longueur du header à lire, sinon supprimer le XFREAD :

https://github.com/orix-software/vidplay/blob/master/src/play.asm#L18

dans PTR_READ_DEST (page zero) mettre le pointeur de chargement de la data :

https://github.com/orix-software/vidplay/blob/master/src/play.asm#L14

Donc :

1) mettre dans PTR_READ_DEST  l'adresse où seront loadées les données : PTR_READ_DEST   est modifié à la lecture donc, il faut le sauvegarder

2) appeler XFREAD avec dans A et Y le nombre d'octet à lire avant

3) appeler la routine qui va balancer les octets dans le PSG

Orix a besoin des adresses entre $00 et $7F en page 0, tout le reste au dessus de $80 peut être utilisé par le programme. En revanche, actuellement, seulement 16 octets de la zp sont sauvegardés par processus (si multitasking, il y a un jour 🙂

Sur émulateur, la vitesse est presque la même qu'en réel (normalement)

 

 


RépondreCitation
JiBe
 JiBe
(@jibe)
Membre
Inscription: Il y a 3 ans
Posts: 111
Début du sujet  
Posté par: @jede

 

1) mettre dans PTR_READ_DEST  l'adresse où seront loadées les données : PTR_READ_DEST   est modifié à la lecture donc, il faut le sauvegarder

2) appeler XFREAD avec dans A et Y le nombre d'octet à lire avant

3) appeler la routine qui va balancer les octets dans le PSG

Merci pour ces éclaircissements salutaires .. je crois que je commence à comprendre.

Il me vient une question/remarque/crainte :

La routine qui balance les octets dans le PSG c'est un handler d'interruption à 4kHz (tous les 250 cycles si mes calculs sont bons) qui effectue trois écritures à chaque IT.

Les écritures sont espacés de 50 cycles et globalement le passage dans le handler d'IT consomme à peu près 200 cycles.

Si mes calculs sont bons, ça ne laisse que 50 cycles au processeur pour vaquer à d'autres occupations.

La routine XFREAD est-elle interruptible ? combien d'octet peut-on espérer quelle copie en 50 cycles (dont il faut qu'on défalque les cycles liés à la commutation de contexte)?

PS: le délai de 50 cycles entre deux écritures dans le PSG peut être réduit (mais pas non plus jusqu'à l'extrême)

Pour l'instant j'ai encore des inquiétudes sur la faisabilité du truc.


RépondreCitation
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 

@jibe Alors s'il ne reste que 50 cycles, il ne faut pas passer par le kernel, car l'appel au kernel prend déjà plus de 50 cycles.

Quand tu fais un brk XX, le kernel (mais comme telemon), se prend une IRQ, mais il a déjà une routine de switch de banque pour arriver sur le kernel (le vecteur d'IRQ est en page 2, mais il appelle la page 4 pour basculer et sauver certains trucs si besoin).

Il teste ensuite si c'est une IRQ de brk, si oui (ce qui est notre cas) il va manipuler la stack pour récupérer le param après brk, sauvegarder les registres, calculer l'offset de la routine. L'appeler, puis à l'execution, va repasser la main, en restaurant les registres avant appel, en  rebasculant sur la ROM précédente. L'appel à  XFREAD n'est pas interruptible, enfin elle pourrait, mais cela partirait en vrille car il faudrait sauver son contexte pendant son execution, et ça même si techniquement, c'est possible, ce n'est pas prévu.

Tout cela pour dire qu'avant même d'avoir executé la routine de lecture, les 50 cycles sont déjà pris par le calcul de tous les offset, les sauvegardes, le switch.

C'est pour cela que vidplay, j'avais indiqué que je pouvais aller plus vite, car en bypassant le kernel, je pouvais accélérer la vitesse car je désactivais les IRQ, et je tapais sur le hard directement. Seulement, cela ne va pas dans le sens que je voudrais pour le player de video, c'est pour cela que j'appelle les primitives du kernel.

Pour taper sur le hard directement, il faut coller ce genre de routine de lecture. C'est à dire qu'àprès le fopen, le code minimaliste pour taper sur le controleur sdcard/usb est ici : https://github.com/orix-software/kernel/blob/master/src/functions/files/xread.asm

Mais même avec cela, je pense que les 50 cycles seront dépassés (je ne me suis pas amusé à calculer). Mais cela se tente. On doit attendre que le chip usb réponde avec wait_response.

Normalement, on n'aurait pas besoin de faire un wait_response, mais je n'ai pas cablé la broche IRQ du chip (c'est prévu dans d'autres version du hard), donc on ne fonctionne qu'en pull et ce wait_response est du temps perdu, car on pourrait faire autre chose pendant ce temps là. Mais normalement, c'est assez rapide.

Donc, cela se tente sans le kernel, ou alors, il faut envisager de perdre en qualité de son pour rentrer dans le timing.

En tous les cas, c'est une limite du cpu du 6502 car on est bridé par ses megahertz ici. Sur cpc, ils montent en 100 ko/sec avec le même controleur, et c'est le Z80 qui est limitant aussi.

 

 

 


RépondreCitation
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 

En revanche, s'il faut taper sur le hard, il vaut mieux faire un .tap qui s'execute dans la rom basic plutôt que de faire un binaire Orix dans ce cas (juste parce que parce que taper sur le hard rendrait le systère dans un état non normal à la fin de l'execution). Mais cela peut se faire déjà.

 


RépondreCitation
assinie
(@assinie)
Membre
Inscription: Il y a 3 ans
Posts: 49
 

@jibe la principale difficulté que je vois et que tu utilises 3 buffers qui doivent être remplis simultanément.

Ce qui signifie que, en l'état actuel, il faut pouvoir lire 3x256 octets pendant que ta routine ne va s'exécuter que 256 fois ce qui me parait un peu difficile.

En 50 cycles, on ne pourra lire que 3 octets si on utilise une boucle, ce qui pourrait suffire si la lecture de la carte SD pouvait se faire en continu mais ce n'est pas le cas.

La lecture de 256 octets se fait en deux temps, une première lecture de 254 octets et une seconde de 2 octets, et pour chacun de ces deux blocs il faut faire un appel à la routine WaitResponse dont parle @jede. C'est ça qui va ralentir un peu le débit (on doit pouvoir calculer la lantence induite par WaitResponse mais elle sera probablement dépendante du matériel et de la carte SD).

Une solution pourrait être d'utiliser 3 jeux de buffers pour compenser le retard.

Au démarrage, le programme charge les deux premiers avant de lancer les interruptions, et on commence à charger le troisième au moment où tu actives les interruptions.

Ensuite on boucle sur les trois jeux de buffers, de cette façon, la lecture du fichier devrrait rester en avance sur la reproduction sonore.

Peut-être que seulement deux jeux de buffers feraient aussi l'affaire, dans tous les cas il faudra vérifier si la théorie est validée par la pratique.

Je pense qu'on peut doubler la vitesse de lecture mais au détriment de la taille du programme, mais ce ne serait pas nécessairement une bonne idée parce que ce serait trop rapide par rapport à la reproduction du son.

Dans l'idéal, la lecture du fichier doit se faire globalement à la même vitesse que la reproduction du son. On peut être plus rapide mais dans ce cas, il faut utiliser un système de water mark de façon à ce que la lecture du fichier ne se fasse que lorsque c'est nécessaire.


RépondreCitation
JiBe
 JiBe
(@jibe)
Membre
Inscription: Il y a 3 ans
Posts: 111
Début du sujet  

Merci Jede et Assinie pour vos réponses.

En l'état actuel de ma compréhension du sujet , il me paraît hasardeux de me lancer dans cette aventure pour de l'audio.

Mais il s'avère que je travaille actuellement à un autre sujet qui pourrait tout à fait tirer profit du XFREAD.

C'est un projet dans lequel il faudrait pouvoir copier 32k de donnée de la carte sd vers la mémoire de l'Oric en un seul bloc.

Je vais tâcher de faire un prototype de mon idée avec OSDK .. et si ca donne bien .. je l'implémenterai en cc65/ca65 pour bénéficier du XFREAD.

Entre temps je vous montrerai de quoi il s'agit pour que vous me disiez si vous pensez que ça a un intérêt et si c'est possible.

Je vous tiens au courant.

 


RépondreCitation
assinie
(@assinie)
Membre
Inscription: Il y a 3 ans
Posts: 49
 

Juste une petite précision, le fait de ne pouvoir lire que 3 octets dans le temps imparti (50 cycles) n'est pas lié à l'utilisation du ch376 mais uniquement à la boucle de lecture (si on attaque directement le hard):

        ldy #$00
loop:
        lda CH376_DATA		[4]
        sta (PTR),Y		[6]
        iny			[2]
        dex			[2]
        bne loop		[3/2]

X contient le nombre d'octets à lire et Y sert d'index pour la copie en mémoire.

La durée d'exécution de la boucle est de 17 cycles ce qui donne 3 parcours en 50 cycles (51)

On peut accélerer cette boucle de différentes manières:

  • suppression de l'utilisation de l'un des registres (nécessite que les données soient écrites à l'envers dans le fichier par bloc de 256 octets: ie le premier octet dans le fichier est le 256ième en ram, le second est le 255ième,..., elles seront dans le bon ordre en mémoire)
    • gain: 2 cycles par boucle
  • utilisation de l'instruction sta PTR,Y au lieu de sta (PTR),y
    • gain: 1 cycle par boucle
  • dérouler complètement la boucle en mettant:
    • 	lda CH376_DATA		[4]
      	sta PTR			[4]
      	lda CH376_DATA		[4]
      	sta PTR+1		[4]
      	...	
    • on descend alors à 8 cycles par octets soit 6 octets transférés en 48 cycles
  • la même, mais PTR=0 et donc un chargement en page 0, ce qui n'est probablement pas envisageable mais permet de gagner encore 1 cycle par octets soit 7 cycles et donc un transfert de 7 octets en 49 cycles.

Les deux premières optimisations combinées permettent de passer à 14 cycles par boucle soit un gain près de 18% sans augmentation de la taille du programme.

Il reste toujours le délai de WaitResponse qui est relativement incompressible et est exécuté deux fois pour 256 octets transférés si je ne dis pas de bêtise. Je n'ai pas mesuré sa durée moyenne et je pense qu'elle dépend de la carte SD/USB utilisée.

C'est peut être possible en passant par le noyau Orix pour la lecture du fichier en utilisant le truc des trois ou quatres jeux de buffers comme expliqué dans mon post précédent, il faudrait vérifier.mais ça ne me parait pas infaisable.


RépondreCitation
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 
Posté par: @jibe

Merci Jede et Assinie pour vos réponses.

En l'état actuel de ma compréhension du sujet , il me paraît hasardeux de me lancer dans cette aventure pour de l'audio.

Mais il s'avère que je travaille actuellement à un autre sujet qui pourrait tout à fait tirer profit du XFREAD.

C'est un projet dans lequel il faudrait pouvoir copier 32k de donnée de la carte sd vers la mémoire de l'Oric en un seul bloc.

Je vais tâcher de faire un prototype de mon idée avec OSDK .. et si ca donne bien .. je l'implémenterai en cc65/ca65 pour bénéficier du XFREAD.

Entre temps je vous montrerai de quoi il s'agit pour que vous me disiez si vous pensez que ça a un intérêt et si c'est possible.

Je vous tiens au courant.

 

Salut,

De toutes manières, passer par le Kernel est forcément plus long puisque cela fait des checks à droite à gauche et j'ai prévu de faire du mapping de device. C'est à dire qu'un fopen pourrait aussi se faire sur vrai drive disquette (ainsu qu'un XFREAD) si on monte un drive dans /mnt. Cette partie n'est pas faite, mais j'ai déjà le squelette pour gérer les points de montages.

Tout cela pour dire que le kernel est conçu pour tout faire, mais pas nécessairement pour aller le plus vite possible. C'est pour cela que je propose le format .tap qui peut profiter du hardware de la carte sans interférer avec le kernel ou bien avoir une utilisation non prévue (c'est à dire qu'on pourrait très bien dans orix monter une vraie K7 sur un vrai magneto, et lire à partir de là avec le fopen/fread : puisque le device sera masqué par l'OS).

Concernant OSDK, tu peux facilement utiliser les primitives du kernel avec xa.

Il suffit de déclarer la macro BRK_KERNEL dans xa, et l'appeler avec le bon param.

Je n'utilise plus xa car j'utilise beaucoup de structures en asm et cela devenait trop compliqué à gérer avec xa65. Et surtout je peux facilement remapper avec les includes de cc65 car le code du kernel essaie de garder les mêmes errno etc.

 


RépondreCitation
JiBe
 JiBe
(@jibe)
Membre
Inscription: Il y a 3 ans
Posts: 111
Début du sujet  

Coucou @jede 

Je bosse sur une idée de 3D sur Oric à base de photosphère style réalité virtuelle.

Dans le principe, ça devrait donne un truc un peu dans ce style:

ATTENTION : Overclock x 16

Dans cette image, le décor est mappé sur une photosphère qui pèse 32ko en mémoire (256*128 px) et mon idée c'était d'ouvrir la porte à des jeux d'aventure en 3D où on pourrait se déplacer d'endroit en endroit en chargeant ces 32 Ko lorsqu'on change d'endroit.

Mais pour l'instant je cherche encore à produire des images qui offrent un bon rendu à une si faible résolution et ce n'est pas facile. Celle que j'affiche là est une des plus jolie que je suis parvenu à obtenir pour l'instant.

Je ne suis pas vraiment un artiste 2D/3D et donc je galère un peu ..

Mais si j'arrive à faire des photosphères correctes, ça voudra dire que le procédé peut avoir de l'intérêt. Surtout s'il est possible de charger rapidement ces 32ko entre deux scènes du jeu.

Bref, il faut d'abord que je m'assure qu'il y ait un réel intérêt / potentiel esthétique avant de me lancer dans un développement plus avancé.

 

 

Ce message a été modifié Il y a 12 mois parJiBe

RépondreCitation
didier_v
(@didier_v)
Reputable Member Admin
Inscription: Il y a 3 ans
Posts: 268
 

@jibe : toujours aussi impressionnant

Personnellement, je réduirais la taille de la fenetre pour réduire la consommation de mémoire. 32ko pour l'image, cela laisse peu de marge pour le software ; trop peu je pense pour avoir un moteur de jeu d'aventure correct

Cela compliquera un peu mais pas tant que ca la tache du graphiste

Ce message a été modifié Il y a 12 mois pardidier_v

RépondreCitation
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 
Posté par: @didier_v

@jibe : toujours aussi impressionnant

Personnellement, je réduirais la taille de la fenetre pour réduire la consommation de mémoire. 32ko pour l'image, cela laisse peu de marge pour le software ; trop peu je pense pour avoir un moteur de jeu d'aventure correct

Cela compliquera un peu mais pas tant que ca la tache du graphiste

Salut,

 

Cela dépend si Jibe veut le faire tournant sur la carte, dans ce cas, le pb de ram est moindre, puisqu'on a disposition 512KB de RAM en banking.Je n'ai pas prévu qu'un programme fasse plus de deux banques, mais cela pourrait s'envisager


RépondreCitation
jede
 jede
(@jede)
Honorable Member Admin
Inscription: Il y a 3 ans
Posts: 373
 

@jibe Dans le même style, on m'avait suggéré de faire un "Dragon's lair" même si techniquement c'est possible avec la carte, ce n'était pas quelque chose qui m'intéressait de faire.

Sinon, cela m'a fait penser à quelque chose d'autre, sur cpc, il y a une démo qui streame à partir de la disquette (regarder après la 2ème minute) : En revanche, je ne sais plus trop comment cela marche

 

Dans le même style, il serait possible de faire la démo STNICCC : comparaison snes/megadrive

Bref, tout cela n'est pas le même principe que ce que tu veux faire, mais cela m'y a un peu fait penser.


RépondreCitation
JiBe
 JiBe
(@jibe)
Membre
Inscription: Il y a 3 ans
Posts: 111
Début du sujet  
Posté par: @didier_v

Personnellement, je réduirais la taille de la fenetre pour réduire la consommation de mémoire. 32ko pour l'image, cela laisse peu de marge pour le software ;

C'est une bonne idée .. il faut que je rende paramétrable la taille du "viewport".

Pour l'instant j'utilise une image en 256*128 pixels car cette image doit couvrir 360° avec une résolution écran de 78*64 texels.

Si je réduis le nombre de texels à l'écran (et donc la largeur de l'angle de vue), je dois effectivement pouvoir diminuer la taille de l'image .. 🙂

A suivre ..


RépondreCitation
JiBe
 JiBe
(@jibe)
Membre
Inscription: Il y a 3 ans
Posts: 111
Début du sujet  
Posté par: @jede

Bref, tout cela n'est pas le même principe que ce que tu veux faire, mais cela m'y a un peu fait penser.

Ce que tu me montres là est époustouflant !!

Je ne me sens pas (encore) capable de faire ce genre de chose.

Mais c'est clair que ça fait envie ...


RépondreCitation
Page 2 / 3
Share: