Bonjour,
J'ai fait le portage pour Oric d'un procédé d'encodage viterbi utilisé pour faire jouer fidèlement au AY des échantillons audio.
Le procédé vient d'un développement initialement réalisé pour MSX.
J'ai mis les sources de l'encodeur (en python) et du lecteur pour Oric (en C et ASM) sur mon dépôt ayPlaySample.
La petite démo GROOVE.tap permet de se faire une idée de la qualité audio qui peut être atteinte avec cette méthode d'encodage.
Quatres choses à savoir sur cette petite démo:
- L'échantillon dure 3.6 secondes, il a fallu 4 heures de calcul pour l'encoder, et il occupe un peu plus de 40 Ko en mémoire une fois encodé.
- La place prise par l'échantillon encodé est si grande que ça consomme toute la mémoire de l'Oric jusqu'à corrompre la mémoire du charset standard. C'est pour cela que l'Oric doit être redémarrer après la démo.
- L'échantillon est joué dès le chargement de la démo et peut être arrêté en pressant une touche clavier.
- Les émulateurs ne rendent pas fidèlement l'audio de l'AY (et encore moins lorsque le AY est utilisé en mode PCM). Il faut donc exécuter cette démo sur un vrai Oric pour obtenir un rendu potable.
Salut,
Merci, je vais tester. En revanche, le python, ce n'est pas ce qu'il y a de plus performant.
En revanche, si tu peux me fournir un raw plus long (si tu en as un sous le coude), je peux tenter de le streamer sur sdcard pour voir ce que ça donne vu qu'il y a des débits assez importants, cela peut donner une idée de la qualité en streaming sur sdcard.
Sinon, je fais le raw moi même, mais cela sera mon choix de musique 🙂
J'ai une petite carte son/réseau qui traine depuis X temps sur laquelle je n'ai pas fait les drivers, un jour il faudra que je m'y colle.
- L'échantillon dure 3.6 secondes, il a fallu 4 heures de calcul pour l'encoder, et il occupe un peu plus de 40 Ko en mémoire une fois encodé.
Hello, vive le groove meme si c'est un peu répétitif avec ton sample de base. Bravo pour l'implémentation Oric. Sinon, vu ta productivité d'encodage, il est temps de changer de machine 😉
Hello, vive le groove meme si c'est un peu répétitif avec ton sample de base. Bravo pour l'implémentation Oric. Sinon, vu ta productivité d'encodage, il est temps de changer de machine 😉
Oui 🙂 Ce sont 3.6 secondes de son qui tournent en boucle .. ça donne vite envie de passer l'Oric par la fenêtre ... LOL !!
Le PC que j'utilise pour faire l'encodage est relativement puissant mais l'algorithme est hyper lourdingue !! à peu près une heure de calcul pour une seconde de son
le python, ce n'est pas ce qu'il y a de plus performant.
Carrément vrai .. je suis parti sur ce langage parce que c'est le plus pratique pour prototyper .. Si cette technologie d'encodage avait un intérêt à mes yeux, j'envisagerais bien de faire un version C de l'encodeur.
Mais pour l'instant je trouve que la place requise pour le stockage des échantillons est vraiment trop élevée et du coup je ne vois pas de débouché pour ce procédé actuellement.
Cela étant dit, s'il y a moyen de stocker les échantillons sur SD card, les potentialités deviennent intéressantes.
Je suis en train d'encoder quelques samples supplémentaires. A quel format faudrait-il que je te fournisse ces raw dont tu parles ?
si tu peux me fournir un raw plus long (si tu en as un sous le coude), je peux tenter de le streamer sur sdcard pour voir ce que ça donne
J'ai mis des échantillons pré-encodés sur le dépôt:
- Welcome c'est un mot extrait de Barbarian 2
- LetItWhip c'est une petite rythmique funky
- OneStep ic'est la fameuse phrase "That's one small step for men" d'Amstrong
- SuperFreak c'est une petit boucle funky bien connue.
- TheLargeMemory c'est la phrase "The large memory that stays large" extrait de la pub Oric de 1984
Pour les transformer en buffer il faut éditer le fichier util/genbuf.py pour changer la ligne
from LetItWhip import Out
afin de remplacer LetItWhip par une des valeurs citées plus haut.
Après il faut exécuter la commande
python util\genbuf.py
qui va générer les fichiers src\soundbuf.s et src/nbsample.h contenant les 3 raw buffers que le player va parcourir.
Dis moi si cela te permet de tester.
J'avoue ne pas bien voir comment il est possible de streamer ça d'une carte SD .. mais si c'est possible .. ça peut être délire!!
Cela étant dit, s'il y a moyen de stocker les échantillons sur SD card, les potentialités deviennent intéressantes.
Je suis en train d'encoder quelques samples supplémentaires. A quel format faudrait-il que je te fournisse ces raw dont tu parles ?
C'est surtout qu'il y a un débit de ouf, donc, c'est facilement "streamable", nous ne sommes pas loin d'une copie de ram à ram sur le hard. Je pourrais aller encore plus vite, mais il faudrait que ça passe par une upgrade du firmware (et que je le code 🙂
En fait, en format raw, j'ai juste besoin de ton format sans le header tap (que je peux retirer si besoin) et le player. Je modifie le player pour lire en streaming sur la carte.
Au niveau de la taille max, c'est "infini" puisque les sdcard 128go semblent marcher, et je pense que les 256go pourraient aussi (mais je n'ai pas testé car je n'en ai pas 🙂
L'idéal est de lire par bloc de X octets pour la vitesse, car octet par octet, cela baisse pas mal le débit ...
J'avoue ne pas bien voir comment il est possible de streamer ça d'une carte SD .. mais si c'est possible .. ça peut être délire!!
C'est tout simple, au lieu de lire en ram, je lis sur la sdcard et je balance au PSG (ou à la routine qui va balancer au PSG)
C'est comme cela que ça marche les vidéos "vidplay". Cela lit sur sdcard et cela balance directement en RAM hires. Sur vidplay, je pourrais aller un peu plus vite, mais c'était pour montrer à l'époque le débit.
D'ailleurs, je pense que cela te plairait de faire des algos de compressions vidéo spécifiques à l'oric, avec tout ce que tu fais déjà sur le son, la 3D, le raycasting.
Car il y a tellement de moyen de le faire ... (en mode texte, en hires compressé, en delta packing, etc )
en delta packing
Hello Jérome,
As tu dans ta collection de routines, une routine de compactage / décompactage pour CC65 ?
@didier_v Du deltapacking ? J'avais commencé, mais j'ai laissé en plan.
Si tu veux de la décompression, il y a gunzip qui est dispo en standard dans cc65.
Sinon, en cherchant sur github, on trouve souvent pleins de trucs pour cc65, donc cela ne m'étonnerait pas que cela puisse se trouver sur des repo git (mais il faut parfois pas mal chercher).
merci, je regarderais déjà gunzip
C'est tout simple, au lieu de lire en ram, je lis sur la sdcard et je balance au PSG (ou à la routine qui va balancer au PSG)
C'est comme cela que ça marche les vidéos "vidplay". Cela lit sur sdcard et cela balance directement en RAM hires. Sur vidplay, je pourrais aller un peu plus vite, mais c'était pour montrer à l'époque le débit.
Selon moi l'écriture dans les registres du PSG ne peut se faire qu'octet pas octet.
Par contre il doit pouvoir être possible de charger le buffer duquel sont lus les échantillons depuis la carte SD.
L'écriture dans les registres du PSG se fait dans un handler d'interruption à 4Hz et les échantillons sont tirés de trois buffer en mémoire.
Il faudrait voir si je peux charger ces buffers depuis la carte SD.
Mais je ne trouve pas le code source de vidplay dont tu parles.
@jibe https://github.com/jedeoric/vidplay
Je convertis en CA65 le code source écrit en xa pourquoi : Car à l'époque j'utilisais xa, et pour linker avec le c de cc65, je convertissais en co65.
En revanche, je vois que j'inclus des headers qui n'existent plus. En faisant en ca65, il faut inclure telestrat.inc. Le fopen est fait dans le code C, et la lecture est faite par la primitive kernel XFREAD
Est ce que tu veux que je te donne le squelette de code ? ainsi, il suffit juste de pointer au bon endroit. Cela me forcera à écrire mieux le code de vidplay 🙂
C'est sans doute plus simple car c'est du vieux code.
Mais en gros, c'est un fopen, et un appel XFREAD avec la taille en octet qu'on veut lire.
vidplay en vidéo :
L'écriture dans les registres du PSG se fait dans unhandler d'interruption à 4Hzet les échantillons sont tirés detrois buffer en mémoire.
Hello,
Ce que j'aime en regardant les codes des autres c'est apprendre. Je suis sur que tu maitrises une tonne de sujets Jibe et j'apprécie la lecture du handler multi fréquences. J'ai deux trucs qui m'interpellent :
- tu sauvegardes les registres dans la partie keyb_25hz, ce qui semble inutile puisque déjà fait
- c'est une question de gout, mais ayant appris à l'ancienne, avec les assembleurs de l'oric puis de mes autres machines, je suis assez dérouté par les instructions multiples sur une ligne et les macros qui rendent la lecture du code difficile.
- tu sauvegardes les registres dans la partie keyb_25hz, ce qui semble inutile puisque déjà fait
- c'est une question de gout, mais ayant appris à l'ancienne, avec les assembleurs de l'oric puis de mes autres machines, je suis assez dérouté par les instructions multiples sur une ligne et les macros qui rendent la lecture du code difficile.
Tu as totalement raison pour la sauvegarde/restauration des registres en entrée et sortie de la routine de gestion clavier. J'avais fait ça en me disant que c'était plus sûr mais effectivement cela fonctionne aussi sans cette sauvegarde/restauration.
Je viens de modifier le code pour prendre en compte ta remarque.
Par ailleurs, j'ai profité de cette modification de code pour prendre en compte une remarque de DBug concernant la ré-entrance du handler d'it qui n'était pas assurée par la méthode que j'utilisais. Je sauvegardais les registres en page zéro plutôt qu'en pile ce qui n'est pas ré-entrant (je ne m'explique d'ailleurs pas comment cela peux fonctionner autrement que par magie).
J'ai donc modifié la méthode de sauvegarde des registres dans le handler d'IT afin qu'il soit ré-entrant.
Concernant l'usage des instructions multiples et des macros, je peux comprendre que cela rende le code difficile à lire au premier abord. Mais je trouve qu'à l'usage, pour celui qui écrit le code et le parcours en long en large et en travers des centaines de fois, cela permet de naviguer plus facilement et de ne voir que l'essentiel. Typiquement, une fois que tu as lu et compris une ligne à instruction multiple ou une macro, tu n'as plus à la relire. Au bout d'un moment, en lisant le code, tu la reconnais et tu sais ce qu'elle fait . Alors OK on se prend la tête la première fois qu'on tombe dessus .. mais après cela permet de gagner en fluidité de lecture.
Par ailleurs, l'usage de la macro présente un autre avantage, il permet d'économiser un jsr/rts tout en :
- évitant de placer tout le code à l'endroit de la macro
- factorisant certaine partie de code qu'on peut retrouver à plusieurs endroits.
Le inline offre l'avantage d'une sous routine, sans avoir l'inconvénient du jsr/rts.
Cela dit, je suis tout à fait d'accord avec toi que ce n'est pas très "académique" et si j'avais les capacités intellectuelles de me passer de ce genre d'artifice je le ferais.
Mais vraiment, en ce qui me concerne, ça m'aide à y voir plus clair dans mon code. Des portions de code qui passent de 300 lignes à 50 lignes deviennent, à l'usage, plus facile à lire (tout en étant plus difficile d'accès au primo accédant .. nous sommes d'accord)
Mon sentiment sur le sujet c'est que ces artifices (instructions multiples et macro) rendent le code plus lisible à celui qui connaît le code .. au risque de le rendre plus difficile à lire à celui qui ne le connaît pas encore.
Encore merci pour ta remarque et je suis flatté que tu lises mon code.
Merci pour ce lien. J'avais cherché sur Oric-Software en n'avais rien trouvé.
J'ai regardé un peu le code et c'est vrai que la partie qui pourrait m'aider semble se trouver derrière les appels :
BRK_TELEMON(XFREAD)
J'en suis donc à chercher les fichiers
"../orix/src/include/orix.h"
"../orix/src/include/macro.h"
Pour voir ce qui se cache derrière ce XFREAD.
Ça doit être quelque part par là ..