Tag: PSG 8912

  • Compensation adaptative de la non-linéarité du convertisseur numérique analogique du modulateur d’amplitude du PSG AY-3-891x

    Quiconque souhaite adresser le sujet du modelage sonore sur Oric se verra tôt ou tard confronté à un des “défaut” de son générateur de son le AY-3-8912: la non linéarité du convertisseur numérique analogique utilisé dans le circuit d’enveloppe.

    Cet article présente un procédé de compensation de cette non linéarité capable de s’adapter à différents volumes sonores. Ce mécanisme de linéarisation, en plus de fournir une commande proportionnelle d’amplitude ouvre la porte à la génération d’enveloppe très précise dont la granularité s’adapte automatiquement au volume sonore choisi.

    Position du problème

    Avant de nous lancer dans le contournement d’un problème, commençons par en cerner l’essence. Quel est exactement le problème de non linéarité du machin truc ?

    Le schéma de principe ci-dessous illustre le fonctionnement de la génération sonore sur un Oric en même temps qu’il introduit les grandeurs dont il va être question dans la suite de l’article.

    Pour générer un son le PSG AY-3-891x utilise un générateur de signal carré dont il module l’amplitude proportionnellement à une tension issue de la conversion numérique analogique de la valeur d’enveloppe programmée dans le registre d’amplitude. Malheureusement, la conversion numérique vers analogique est entachée d’une non linéarité qui fait que la tension obtenue en sortie n’est pas proportionnelle à la valeur programmée dans le registre d’amplitude. Sur le schéma ci-dessus, on vois que la tension V a une forme arrondie là où la commande d’enveloppe E est en rampe rectiligne.

    Ce “problème” est clairement décrit dans les données techniques du composant AY-3-891x, à travers les figures 8 et 9 du document “PSG AY-3-8912 Data Manual” ou entre les figures 2 et 3 du datasheet du PSG AY 3 8912 reproduites ci-dessous:

    La figure ci-dessous montre clairement que, là où le générateur d’enveloppe ou la commande manuelle de l’amplitude demande un signal triangulaire (à gauche), la commande analogique en entrée du VCA (Voltage Controlled Amplifier) se trouve être d’aspect plutôt franchement parabolique (figure de droite). Et ce phénomène est pleinement assumée avec l’explication suivante:

    Since the primary use of the PSG is to produce sound for the highly imperfect amplitude detection mechanism of the human ear, the D/A conversion is performed in logarithmic steps with a normalized voltage range from 0 to 1 Volt.

    datasheet AY-3-8912

    Ce qui peut se traduire par:

    Puisque la fonction première du PSG est de produire un son à destination du mécanisme hautement imprécis qu’est l’oreille humaine, la conversion numérique analogique est effectuée à l’échelle logarithmique avec une plage de tension normalisée entre 0 et 1 volt.

    L’oreille humaine est indéniablement moins précise qu’un modem ou un oscilloscope mais elle est capable de faire la différence entre un violon qui joue un La et un piano qui joue un La .. Et la différence repose, en grande partie, sur l’enveloppe sonore dont cette phrase nous suggère qu’elle peut aisément s’accommoder d’une échelle logarithmique en lieux et place d’une échelle linéaire.

    Quelqu’un qui souhaite tenter de faire générer un son précis au AY-3-391x sera bien obligé de se poser la question suivante.

    Et dans cet article, je propose une solution qui consiste à linéariser la commande d’enveloppe par une pré-compensation logicielle de la déformation à laquelle on veut échapper.

    Pour obtenir une tension V qui soit le plus possible proportionnelle à une consigne d’enveloppe C, on peut élaborer une commande d’enveloppe E qui opère une déformation inverse à celle que va produire la conversion numérique analogique.

    Techniquement, cela consiste à appliquer une transformation à la donnée que nous voulons programmer dans le registre d’amplitude du AY-3-391x. Une transformation qui tente de compenser et d’anticiper les dégâts occasionnés lors de la conversion en analogique de notre souhait d’amplitude formulé numériquement.

    Identification de la déformation

    Dans la version General Instrument du datasheet du AY-3-391x, on trouve une version quotée de la déformation qui nous intéresse.

    Des quelques valeurs fournies sur ce graphique, on peut déterminer une tendance :

    • La valeur de 0.707V pour 14 correspond à 1/sqrt(2)
    • La valeur de 0.5 V pour 13 correspond à 1/sqrt(4)
    • La valeur de 0.25 V pour 11 correspond à 1/sqrt(16)

    Il vient assez naturellement que la tension V en sortie de convertisseur est exprimable par la formule suivante :

    V = 1 / SQRT(2(15-E))

    où :

    • E est le contenu du registre de contrôle de l’amplitude (valeur entière entre 0 et 15).
    • V est la tension (valeur réelle entre 0 et 1 V)

    Dans google, on peut vérifier que la courbe obtenue est proche de celle du modèle.

    Compensation de la déformation

    Pour inverser cette fonction (et donc compenser son effet) on devra calculer la commande d’enveloppe E par la formule suivante:

    E = 15-LOG2(1/(V2))

    où :

    • V est la tension (en volt) que nous voulons en sortie du convertisseur N/A
    • E est la commande d’enveloppe que nous devons programmer dans le PSG pour obtenir la tension V.

    La forme de cette fonction nous donne bien à penser qu’elle compensera la courbe précédente.

    Maintenant que nous avons une fonction permettant de compenser la non linéarité sur l’ensemble des valeurs possibles en sortie du convertisseur, nous allons voir comment il est possible d’adapter cette compensation à des situations où nous déciderions de limiter le volume maximum sur un canal tout en gardant la même dynamique du domaine d’entrée. Nous renoncerions aux valeurs hautes de la tension (car c’est là que les imprécisions sont les plus grandes) mais nous garderions toujours 16 valeurs possibles de consigne d’enveloppe. L’objectif est double:

    • gagner en précision absolue,
    • offrir la même expressivité d’un son quelque soit le volume sonore auquel on le restitue.

    Adaptation de la compensation en fonction du volume

    L’idée clé ici est d’associer à la consigne d’enveloppe maximale (15) un extremum de tension correspondent à un palier réel du composant physique. Ceci afin d’adapter au maximum la dynamique d’entrée au potentiel de sorti et bénéficier au maximum du surcroît de précision que nous offre le sacrifice des niveaux électriques élevés

    Nous avons vu au tout début que les paliers de tension du composant physique sont sous la forme: 1/sqrt(2^(15-E))

    En injectant cette expression dans l’équation vu précédemment, et en simplifiant, il apparaît que la commande d’enveloppe E à programmer dans le PSG s’exprime par:

    E = Volume + 2*LOG2(C)

    où :

    • Volume est une valeur entière entre 0 et 15,
    • C est la consigne d’enveloppe exprimée en 15ème du niveau électrique correspondant à Volume
    • E est la commande d’enveloppe que nous devons programmer dans le PSG pour obtenir la tension V = C*(15/Volume).

    Cette expression est d’une telle simplicité qu’elle m’a très fortement fait douter de mes calculs. J’ai donc écris un petit script python pour:

    • modéliser la déformation engendrée par le convertisseur numérique analogique,
    • calculer une table de compensation pour chaque volume sonore (de 0 à 15),
    • simuler l’effet de la pré-compensation,
    • comparer avec le cas sans compensation.

    Voilà les résultats obtenus pour le volume maximal de 15.

    Les points verts représentent la tension électrique obtenue lorsque le registre d’amplitude du circuit d’enveloppe n’est pas transformé. La valeur programmée est directement celle de l’axe des abscisses.

    La ligne en jaune représente la tension électrique idéale qui serait obtenue si la conversion numérique analogique était purement linéaire et que nous disposions d’un nombre infini de bit pour exprimer la consigne.

    Enfin, les point bleus représentent la tension électrique obtenue par la transformation de la consigne à travers une table de compensation générée par les équations fournies plus haut.

    Nous constatons que les points bleus et vert reposent bien tous sur les mêmes paliers réels du composant physique mais qu’ils sont arrangés de telle sorte que leur éloignement à la courbe idéal soit le minimum possible.

    L’effet de la linéarisation est indéniable. Voyons comment se comporte l’adaptation de la compensation pour le cas de volume maximum que nous fixerions à certains paliers du composant (paliers pour E=14 et E=12).

    L’adaptation de la compensation semble effective.

    Cette étude théorique a permis de:

    • démontrer la faisabilité mathématique d’une linéarisation acceptable du comportement du circuit d’enveloppe du PSG AY-3-391x,
    • exposer le matériel algorithmique nécessaire à mise en œuvre d’une compensation adaptative.

    Vous pouvez télécharger ci-dessous le script python qui m’a servi à générer la table de compensation, simuler son utilisation et vérifier les résultats.

  • Musique, Note, Octave, Fréquence et Période

    Rappels et précisions

    par André C.

    CE QU’IL Y A DERRIÈRE LE HAUT-PARLEUR

    Le PSG 8912, circuit intégré complexe, génère des sons sur la base de 14 paramètres qu’il faut lui fournir. Ce sont surtout les 6 premiers paramètres (en fait 3 paramètres sur 2 octets chacun) qui nous intéressent aujourd’hui. Ils définissent la période des sons qui seront respectivement générés par les canaux 1, 2 et 3.
    Lorsqu’on veut programmer des sons en langage machine, il faut envoyer ces 14 paramètres aux 14 registres du PSG 8912 à l’aide de la routine #FA86 (Atmos), après avoir renseigné X et Y pour qu’ils pointent sur l’adresse où se trouve le bloc des 14 paramètres. Heureusement ces 14 registres sont latchés (verrouillés) et gardent leur valeur tant qu’on ne la remplace pas par une autre. La plupart du temps il y a donc peu de changements et il est possible de modifier un seul registre à l’aide de la routine #F590 (Atmos), après avoir renseigné A avec le n° de registre (de 0 à 13) et X avec la valeur à y placer (A, X et Y sont les registres du microprocesseur 6502).

    VOUS PRÉFÉREZ LE BASIC ?

    Il n’empêche que le PSG 8912, ce n’est pas de la tarte, avec ses 14 paramètres dont certains sont complexes ! Mais les commandes PLAY, MUSIC et SOUND simplifient la vie de ceux qui sont effrayés par le langage machine. Le bel effort, qui a été fait pour programmer les commandes PLAY, MUSIC et SOUND, est handicapé par la pauvreté des manuels. A ce propos, je vous renvoie à l’excellent article “PLAY, MUSIC, SOUND”, paru dans le CEO-mag d’avril 2000, n°119-120, pages 35 à 39.
    Toujours est-il que ces 3 commandes Basic permettent de mettre en œuvre assez facilement les paramètres du PSG 8912.

    MUSIC

    Dans le cas de MUSIC, par exemple, il suffit d’indiquer le canal à activer (1 à 3), l’octave (0 à 7), la note (1 à 12) et le volume (1 à 15 pour le volume sonore ou 0 pour passer la main au contrôle par une enveloppe). Quoi de plus simple ? Soit dit en passant, la syntaxe de ce dernier paramètre est regrettable. Pourquoi ne pas avoir repris les valeurs qu’accepte directement le PSG 8912, à savoir 0 à 15 pour le volume et 16 (#10) pour le passage de contrôle à une enveloppe ?

    SOUND

    Mais MUSIC a les inconvénients (les limites) de son avantage (la simplicité) : Cette commande ne sait produire aucun son en dehors des notes standards. Pour ce genre de sons, il existe la commande SOUND, pour laquelle il faut indiquer le canal (1 à 6 avec 1 à 3 pour le canal et 4 à 6 pour ajouter du bruit blanc aux canaux 1 à 3), la période (de 0 à 65535) et le volume (idem MUSIC).
    Pas top la syntaxe du 3e paramètre (période). En français la hauteur d’une note est définie par sa fréquence. On ne parle jamais de la période d’une note. L’utilisation de la période était probablement plus simple d’un point de vue programmation, mais elle est contre culturelle et pas du tout intuitive (plus une note est haute plus sa période diminue).
    Toute valeur entre #0000 et #FFFF (0 et 65535) est acceptée et la valeur que l’on indique est directement envoyée au PSG 8912. Mais celui-ci ne prend pas en compte les 4 bits supérieurs de l’octet de poids fort. Les valeurs réellement injectées dans le PSG sont ra menées à l’espace #0000 à #0FFF (0 à 4095 en décimal). L’intervalle de 0 à 65535 est donc illusoire (mais les capacités du PSG 8912 et celles de l’oreille humaine sont quand même largement couvertes).

    PERIODE

    La période (en secondes) est l’inverse de la fréquence (en Hertz). En pratique, pour avoir des valeurs manipulables, on exprime la période en µs. Pour ce faire, il faut diviser 1 000 000 par la fréquence (il y a un million de µs dans une seconde). Par exemple pour le LA de l’octave 3 (le diapason qui sert de référence en musique), la fréquence officielle est 440 Hz. La période correspondante est de 1 000 000 / 440 = 2 272,73 µs, une valeur qui n’est jamais mentionnée, ni utilisée.

    LE TRUC INVISIBLE

    Le truc qui n’est pas explicité dans les divers documents disponibles (et il y en a un paquet !) est que dans le cas du PSG 8912, la période n’est pas exprimée en µs, mais en unités de 16 µs (ça sent le système binaire là-dessous). Il faut donc appliquer un facteur de conversion de 62 480 (car 1 000 000 / 62 480 = 16,00512164). Dans le cas du LA de l’octave 3 (440 Hz) la période exprimée en unité de 16 µs est de 62480 / 440 = 142 (soit #008E en hexadécimal). Les amateurs de langage machine pourront vérifier que #008E est bien la valeur indiquée dans la Rom par les tables de conversion en #FC5E (octet de poids fort) et #FC6B (octet de poids faible). Et c’est bien la valeur 142 qu’il faut indiquer à la commande SOUND pour obtenir un LA de l’octave 3.

    POUR EN REVENIR AU PSG 8912

    C’est bien sûr #008E qu’il faut aussi indiquer au PSG pour obtenir ce même LA de l’octave 3. Par exemple, pour obtenir ce son sur le canal 1, il faudra placer #8E dans le premier registre et #00 dans le second. D’une manière générale, pour produire un son de fréquence F, il faudra placer dans les registres du PSG une valeur de période P = 62480 / F. Ce n’est pas si compliqué, encore fallait-il le dire clairement. En complément pour ceux qui seraient intéressé, une table de conversion “Note-Frequence-periode.pdf” accompagne cet article.

  • Les enveloppes du PSG 8912

    par André C.

    Cet article fait suite à “PLAY, MUSIC, SOUND”, paru en avril 2000, dans le CEO-mag n°119-120 page 35 à 39. Mais il est plus particulièrement consacré aux enveloppes du PSG 8912.

    L’Oric permet de générer deux sortes de sons : Soit des sons continus dont on peut fixer (entre autre) le volume sonore, soit des sons complexes dont le volume évolue avec le temps selon un profil appelé “enveloppe”. Par exemple, l’enveloppe du fameux PING est une rampe descendante allant du volume maximum à zéro : \

    Problèmes de n° d’enveloppe

    Pour le registre “Numéro de l’enveloppe”, le PSG 8912 accepte des valeurs de #00 à #0F soit 16 possibilités (voir “L’Oric à nu” de Fabrice Broche, page 23). Mais certaines valeurs donnent des résultats identiques : d’une part #00, #01, #02, #03, #9 et d’autre part #04, #05, #06, #07, #0F. Cela ramène le nombre réel d’enveloppes à 8 (voir tableau page suivante).
    Mais 7 enveloppes seulement sont décrites dans le manuel de l’Oric-1 (page 111) et dans celui de l’Atmos (page 124). En fait les concepteurs de la commande PLAY ont fait un mauvais choix : La table pour de conversion des valeurs de 0 à 7 de la commande PLAY en valeurs de #00 à #FF à envoyer au PSG (soit : #00, #00, #04, #08, #0A, 0B, #0C et #0D) fait l’impasse sur l’enveloppe #0E, tandis que l’enveloppe #00 y figure (inutilement) deux fois ! (cf. “L’Oric à nu”, page 380).

    Problèmes de profils

    La forme de ces 16 enveloppes est un peu délicate à comprendre. Comme déjà indiqué, leur numéro va de #00 à #0F, soit en binaire, de 0000 0000 à 0000 1111. Ce numéro pilote en fait 4 paramètres correspondants aux bits b0 à b3 (actif lorsqu’ils sont mis à un) :
    ● Bit0 (HOLD) : Si 0 = répète indéfiniment le profil initial, si 1 = maintient (HOLD) indéfiniment le dernier son.
    ● Bit1 (ALT) : Si 0 = garde profil initial, si 1 = ALTerne front montant et front descendant.
    ● Bit2 (ATT) : Si 0 = ATTaque avec un front initial descendant, si 1 = ATTaque avec un front initial montant.
    ● Bit3 (CONT) : Si 0 = son limité dans la durée, si 1 = son CONTinu.
    En fait il n’y a que deux profils de base : Rampe descendante (ATT = 0, soit \) et rampe montante (ATT = 1, soit /). Le profil peut alors en rester là (CONT = 0) ou le son être prolongé (CONT = 1). Il y a deux manières de le prolonger : soit le dernier son est maintenu (HOLD = 1), soit le profil est répété (HOLD = 0). Enfin, si le profil est répété, il peut soit garder sa forme initiale (ALT = 0, la forme est répétée telle quelle et on a alors un résultat en dents de scie (//// ou \\\\), soit la forme est alternée (ALT = 1) et on a alors un résultat en \/\/\/ ou en /\/\/\ selon que l’on commence par un front descendant ou un front montant.
    Certaines enveloppes me laissent songeur (par exemple l’enveloppe #0B : rampe descendante qui se termine par un niveau sonore nul mais dont le niveau maintenu est haut ou à l’inverse l’enveloppe #0F : la rampe monte jusqu’au volume maximum, suivi par un niveau maintenu bas ! En fait ce niveau bas est inaudible et on est ramené à l’enveloppe #04 Le fichier ENVELOP.TAP qui accompagne cet article vous permettra d’étudier vous-même ce que cela donne. Dans cette démo, le PSG 8912 acceptant des valeurs de #00 à #0F j’ai retenu ces valeurs pour tester les 16 enveloppes. C’est le moment de vous faire l’oreille…
    Pour ma part, je suis arrivé à la conclusion suivante :

    n° pour
    le PSG
    n° pour PLAYDescription et profil
    #00 *0 & 1Rampe descendante puis arrêt \
    #04 *2Rampe montante puis arrêt /
    #083Répétition de la rampe descendante \\\\
    #0A4Rampe descendante, puis rampes alternées \/\/\
    #0B5Rampe descendante, puis plateau haut continu\ ͞
    #0C6Répétition de la rampe montante ////
    #0D7Rampe montante, puis plateau haut continu / ͞
    #0E **.Rampe montante, puis rampes alternées /\/\/
    Les différentes enveloppes gérée par le PSG 8912

    Note : Dans ce tableau, les numéros d’enveloppe à envoyer au PSG figurent en hexadécimal, tandis que les numéros destinés à la commande Basic PLAY figurent en décimal. Il s’agit seulement d’un artifice de présentation.
    Note *: Pour le PSG, les numéros d’enveloppe #00, #01, #02, #03 et #9 sont identiques. Idem pour les numéros #04, #05, #06, #07 et #15. Les enveloppes #09 \ _ et #0F /_ se terminent par un niveau bas continu donc inaudible et on est ramené aux enveloppes #00 et #04 respectivement.
    Note **: Cette enveloppe n’est pas accessible avec PLAY.

    Durée de l’enveloppe

    Dernière ombre au sujet des enveloppes : Le registre “Période de l’enveloppe” du PSG 8912. Ce terme de “période” entraîne une confusion avec le même terme utilisé pour la commande SOUND pour désigner la hauteur du son à générer.
    En fait, ce paramètre fixe la durée des enveloppes. Mais son usage n’est pas évident car sur les 8 enveloppes existantes, seules 2 ont une durée déterminée, les 6 autres durent sans fin (jusqu’à ce qu’on envoie de nouveaux paramètres au PSG).
    J’ai écrit plus haut “il n’y a que deux profils de base : Rampe descendante \ et rampe montante /” et justement le paramètre “durée” fixe la durée de ces rampes. Dans le cas où les rampes sont répétées sans fin, leur durée individuelle est celle indiquée par le paramètre “durée”.
    Dans “L’oric à nu” page 23, Fabrice Broche indique que ce paramètre “va de #0000 à #FFFF et qu’il faut multiplier par 16 pour avoir la période en µs, soit de 0 à 1 seconde environ”. En réalité, c’est par 256 qu’il faut multiplier. Comme tout un chacun peut le vérifier, la durée des enveloppes va de 0 à 16 secondes environ. Avec la durée maximum #FFFF, on a 65535×256 = 16776960 µs, soit un peu plus de 16 secondes. Et c’est bien cela qu’on obtient en pratique lorsqu’on envoie #FFFF au PSG 8912.
    C’est encore différent avec la commande Basic PLAY, qui permet (entre autres) de fixer la durée l’enveloppe à utiliser. PLAY accepte des valeurs de 0 à #7FFF (32767), ce qui génère des sons durant environ 16 s. Pour toute valeur supérieure à #7FFF, le PSG ne prend pas en compte le bit de poids le plus fort. Ainsi #8000 est ramené à #0000 et #FFFF est ramené à #7FFF, c’est-à-dire environ 16 s.

    Conclusion

    J’espère que cet article vous donne toutes les clefs pour utiliser des enveloppes dans la production de sons avec votre Oric. Il n’en reste pas moins que l’usage de ces enveloppes n’est pas évident et il faut tâtonner avant d’obtenir ce que l’on désire. Mais quel plaisir de combiner plusieurs enveloppes à la suite les unes des autres pour produire un son complexe, comme par exemple le lancement d’un missile, le sifflement de sa trajectoire et son explosion au contact de la cible ! Le PSG 8912 est un beau jouet, pour peu que l’on soit patient…