[Thomson] Son 1 bit PWM en streaming

Cette catégorie traite de développements récents destinés à 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

Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

[Thomson] Son 1 bit PWM en streaming

Message par Daniel »

Après mes essais de sons 1 bit sur MO5 (voir http://forum.system-cfg.com/viewtopic.php?f=25&t=4499 ) j'ai voulu faire encore plus difficile : du PWM en streaming à partir d'une carte SD, pour jouer de la musique sur le buzzer du MO5.

Je ne crois pas que l'on puisse tirer grand chose de cette expérience, car la lecture de la carte SD est trop lente, elle prend plus de cycles que la génération de la musique. Je voulais seulement vous faire écouter le résultat. Attention aux oreilles, c'est insupportable :
http://dcmoto.free.fr/tmp/elvis_pwm.mp3

Les échantillons sur la carte SD sont sur 2 bits à 17857 Hz. Il n'y a pas de traitement des gaps interblocs, ce qui explique les tac-tac-tac-tac... Ne cherchez pas à analyser les fréquences de ce fichier, car je l'ai filtré pour enlever les sifflements introduits par dcmoto. Ces sifflements sont des battements à 4200 Hz, entre la fréquence de sortie son de dcmoto (22050 Hz) et la fréquence d'échantillonnage (17857 Hz). On ne les entend pas sur le vrai MO5.

Code : Tout sélectionner

/**************************************************\
*                   S D P W M                      * 
*           (c) 2015 - Daniel Coulom               *  
*           http://dcmoto.free.fr/                 *
*           http://forum.system-cfg.com/           *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune  garantie  et *
* sans  engager  la  responsabilité  de  l'auteur. *
* Vous  pouvez  l' utiliser,  le  modifier  et  le *
* diffuser librement, en conservant cette  licence *
* et les références de l'auteur dans   toutes  les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/

* Ce programme utilise l'interface SDMOTO ou SDMO
* associee au controleur CS91-280 pour jouer de la
* musique 1 bit en streaming sur le buzzer.
* L'adresse en parametre de la commande CMD18
* doit être initialisee en $9E03-$9E06

/**************************************************\
*                Version 2015.01.20                *
\**************************************************/
* Historique
* 2015.01.20 debut du developpement

*------------------------------------------------------
* DEBUT DU PROGRAMME
*------------------------------------------------------
  ORG   $9E00 
  BRA   INIT          initialisations 

*------------------------------------------------------
* FONCTIONS D'ACCES A LA CARTE SD
*------------------------------------------------------
CMD18
  FCB   $52           read multiple block
  FDB   $0000         adresse bloc (poids fort)
  FDB   $0000         adresse bloc (poids faible)
  FCB   $FF           checksum non testee 
  FCB   $00           code retour attendu  
CMD12
  FCB   $4C           stop transmission
  FDB   $0000         dummy parameter
  FDB   $0000         dummy parameter
  FCB   $FF           checksum non testee 
  FCB   $00           code retour attendu  

*------------------------------------------------------
* Initialisations et execution CMD18 = Read-Multiple-Block
*------------------------------------------------------
INIT
  PSHS  U,Y,X,DP,B,A,CC  sauvegarde des registres du Basic
  ORCC  #$50
  LDX   #$1F40        adresse pour test RAM ou ROM
  LDB   ,X            lecture adresse X
  COM   ,X            tente de modifier adresse X
  CMPB  ,X            test modification adresse X
  BEQ   INIT1         pas de difference -> TO
  COM   ,X            retablissement adresse X
  LDA   #$A7          valeur initialisation DP pour MO
  BRA   INIT2         suite des initialisations
INIT1
  LDA   #$E0          valeur adresse EXCMD (poids fort)
  STA   READ+1        pour execution CMD18
  STA   FIN+4         pour execution CMD12
  LDA   #$E7          valeur initialisation DP pour TO
INIT2
  TFR   A,DP          initialisation DP
* Initialisation PIA pour SDMOTO
  LDA   <$CE          lecture registre de controle A
  ANDA  #$FB          raz bit 2 
  STA   <$CE          selection DDRA
  LDB   #$60          set bits 5 et 6
  STB   <$CC          bits MOSI et CLOCK en sortie
  ORA   #$04          set b2
  STA   <$CE          selection PA
* Initialisation buzzer a zero
  LDA   <$C1          lecture port B 6821 systeme
  ANDA  #$FE          raz bit 0     
  STA   <$C1          raz buzzer

* Lancement de la commande CMD18
  LDU   #CMD18        adresse commande CMD18
READ
  JSR   $A028         EXCMD = execution commande
*                     modifie en $E028 pour TO  
  BRA   PLAY

*------------------------------------------------------
* ARRET DE LA LECTURE ET RETOUR AU BASIC
*------------------------------------------------------
FIN
  LDU   #CMD12        adresse commande CMD12
  JSR   $A028         EXCMD = execution commande CMD12
*                     FIN+4 modifie en $E028 pour TO  
  PULS  B             depile compteur octets supplementaires
  PULS  CC,A,B,DP,X,Y,U,PC

*------------------------------------------------------
* Lecture de la musique 17857Hz sur 2 bits
*------------------------------------------------------
PLAY
  LDD   #$367F
* lecture d'un bit dans carry et attente bit 0  
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  BCS   PLAY          attente bit 0
* lecture et sortie buzzer de 4096 bits
  LDX   #$0800        compteur pour 2048 boucles
PLAY1
* bit de poids fort 4+4+4+3+2+2=19 
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  BCS   PLAY3         carry set                 (3)
  NOP                 temporisation             (2)
  NOP                 temporisation             (2)
* bit de poids faible 4+4+4+3+2+6+6+5+3=37
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  BCS   PLAY2         carry set                 (3)
  NOP                 temporisation             (2)
  INC   <$C1          buzzer on                 (6) 
  DEC   <$C1          buzzer off                (6) 
  LEAX  -1,X          decrementation compteur   (5)
  BNE   PLAY1         nouvelle boucle           (3)
  BRA   PLAY5         lecture CRC               (3) 
PLAY2  
  INC   <$C1          buzzer on                 (6) 
  NOP                 temporisation             (2)
  DEC   <$C1          buzzer off                (6) 
  LEAX  -1,X          decrementation compteur   (5)
  BNE   PLAY1         nouvelle boucle           (3)
  BRA   PLAY5         lecture CRC               (3) 
PLAY3  
* bit de poids faible
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  BCS   PLAY4         carry set                 (3)
  NOP                 temporisation             (2)
  INC   <$C1          buzzer on                 (6) 
  NOP                 temporisation             (2)
  NOP                 temporisation             (2)
  DEC   <$C1          buzzer off                (6) 
  LEAX  -1,X          decrementation compteur   (5)
  BNE   PLAY1         nouvelle boucle           (3)
  BRA   PLAY5         lecture CRC               (3) 
PLAY4  
  INC   <$C1          buzzer on                 (6) 
  NOP                 temporisation             (2)
  NOP                 temporisation             (2)
  NOP                 temporisation             (2)
  DEC   <$C1          buzzer off                (6) 
  LEAX  -1,X          decrementation compteur   (5)
  BNE   PLAY1         nouvelle boucle           (3)
  BRA   PLAY5         lecture CRC               (3) 
* lecture de deux octets de CRC
PLAY5  
  LDX   #$0010        compteur pour 16 boucles
PLAY6
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  LEAX  -1,X          decrementation compteur
  BNE   PLAY6         nouvelle boucle
  BRA   PLAY          lecture bloc suivant

  END
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
Fabf
Messages : 54
Inscription : 11 déc. 2014 20:50
Localisation : Vienne(38)

Re: [Thomson] Son 1 bit PWM en streaming

Message par Fabf »

Pas si atroce que ça pour du 2 bits.
A part peut être si on est fan d'Elvis :lol:
Avatar de l’utilisateur
6502man
Messages : 12312
Inscription : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [Thomson] Son 1 bit PWM en streaming

Message par 6502man »

Ca me rappel mes essais de musique 1bit sur Alice :wink:
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

Oui c'est une expérience juste pour la beauté du geste car SDMOTO utilisant l'extension musique et jeux on a forcément de quoi jouer un son de meilleure qualité.

Un truc qui pourrait être tenté mieux que du PWM: faire du dithering audio sur 1 bit, ce qui revient à streamer directement les bits recus sur le buzzer. En quelque sorte le PWM serait pré-encodé dans les données lues, mais avec une résolution bien meilleure que 2 bits. A la louche si je me base sur des octets lus à 5586hz, les bits sont recus à au moins 44khz. Donc on pourrait probablement jouer de la musique dithered sur 1 bit à 44khz. Ca peut être intéressant.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Son 1 bit PWM en streaming

Message par Daniel »

J'ai eu aussi la même idée, mais je ne sais pas si ce sera mieux. J'ai remarqué que la qualité est très grossièrement fonction du nombre de bits multiplié par la fréquence. En divisant pas deux le nombre de bits on double la fréquence, peut-être un peu plus car il n'y a pas à générer la PWM, mais la qualité ne doit pas changer beaucoup. Je ferai l'essai pour confirmer.

J'ai testé le streaming en PWM avec le MO5 et SDMO sur le port magnétophone, sans extension musique et jeux. C'est la seule machine pour laquelle la sortie 1 bit à un intérêt, car sans doubleur de bus on ne peut pas mettre à la fois le contrôleur CS91-280 et l'extension SX90-018. L'idée m'est venue après avoir modifié SDPLAY pour l'adapter automatiquement à l'interface SDMO. Depuis ce matin SDPLAY fonctionne aussi bien sur TO avec SDMOTO, sur MO avec SDMOTO ou sur MO5 avec SDMO. Je publierai la nouvelle version dans les prochain jours.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

Il y a un challenge intéressant dans le streaming des bits reçus. Pour schématiser: on veut mettre le b7 de <$C0 dans le b0 de <$C1. J'imagine que le ROR <$C1 n'est pas bon car il modifie les autres bits de cette adresse.

L'algo que je vois est de détecter les transitions 1->0 et faire un "dec <$C1" ainsi que les transitions 0->1 et faire "inc <$C1".

Code : Tout sélectionner

  LDA  <$C1 
  ANDA #$FE
  STA <$C1 buzzer à bas
  LDD #$367F
ETAT0
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  BCC  ETAT0
  INC  <$C1
ETAT1
  STB  <$C2
  CMPB <$C0
  STA  <$C2
  BCS  ETAT1
  DEC <$C1
  BRA ETAT0
Pour les CRC, une série de 16 STB/STA fait l'affaire, et par la suite pour attendre le $FE on a pas besoin de lire les octets. On peut attendre sur ETAT1. Je n'ai pas calculé la fréquence atteinte avec ca, mais je présent qu'on dépasse le 44Khz.
Dernière modification par __sam__ le 20 janv. 2015 21:47, modifié 2 fois.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Son 1 bit PWM en streaming

Message par Daniel »

Oui pour les MO, et c'est le plus facile. Dans le code PWM (dans le premier post) je fais des INC et des DEC de <$C1.
Avec les TO le challenge se complique : c'est le bit 6 de $E7C1.

[Edit après le post de __sam__] Erratum : c'est le bit 3 de $E7C1.
Dernière modification par Daniel le 21 janv. 2015 10:40, modifié 1 fois.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

b6 ou b3 pour les TO ? cf la routine beep TO9

Code : Tout sélectionner

F280 0D73       TST    /$73                6
F282 2608       BNE    $F28C               3
F284 B6E7C1     LDA    $E7C1               5
F287 8808       EORA   #$08                2   b3 apparemment
F289 B7E7C1     STA    $E7C1               5
F28C 8E0080     LDX    #$0080              3
F28F 301F       LEAX   -$01,X              5
F291 26FC       BNE    $F28F               3
F293 5A         DECB                       2
F294 26EA       BNE    $F280               3
F296 39         RTS                        5
On peut ne produire la clock qu'avec B, ce qui fait perdre 4 cycles par bits, et faire un "EORA #8; STA <$C1" (4+2) au lieu du INC <$C1 (6). Ca reste jouable réorganisant le code car dans la génération de l'horloge: au lieu de faire STB en <$C2, on peut faire STD <$C1 et faire d'une pierre 2 coup: on met la clock à haut tout en positionnant le buzzer.

Code : Tout sélectionner

  LDA  <$C1 
  ANDA #255-8         (oui j'ai la flemme de compter en hexa)
ETAT0
  (prévoir leax -1,x et beq "lire fin de bloc")
  LDB   #$7F          (2)
  STD   <$C1          buzzer + clock high (5)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  LDB   #$36          (2)
  STB   <$C2          clock low                 (4) 
  BCC   ETAT0         (3)
  EORA  #8            (2)
ETAT1  
  (prévoir leax -1,x et beq "lire fin de bloc")
  LDB #$7F
  STD  <$C1
  CMPB <$C0
  LDB #$36
  STB  <$C2
  BCS  ETAT1
  EORA #8
  BRA ETAT0
Donc on perd 4 cycles avec les ldb #$74/$36, mais on en gagne 6-1 = 5 cycles en remplacant INC/DEC par le STD. Au final cette approche s'avère toujours plus rapide que le inc/dec je crois. Et en plus elle peut s'adapter au MO en remplacant 8 par 1.

(tout ca à la louche avec les mains sans être sur du calcul).

Autre trucs pas terrible, le LEAX -1,X et le BEQ correspondant. On perd 5+3=8 cycles par bits.. C'est beaucoup par rapport aux 22cycles pour lire 1 bit et écrire le buzzer dans le code ci-dessus. Mais bon avec 30 cycles par bit, ca nous ferait une fréquence de 33khz (vs 45khz avec 22cycles par bit).

33Khz... oui c'est à tenter.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

Hum... on doit pouvoir encore faire plus rapide dans la lecture des bits.

:idea: Idée: X contient le couple clock low/buzzer bas, et U contient le couple clock low/buzzer haut, B contient lui clock haut. A est libre ce qui permet de traiter 256 bits d'un coup. Il faudra appeler 16 fois la routine PLAY256 ci-après pour lire un bloc complet.

Code : Tout sélectionner

PLAY256             lit sur la SD et joue sur le buzzer 256 bits consécutifs
  LDB #$36
  LDA <$C1
  ORA #8            precalc buzzer à 1
  TFR D,X           X = clock low + buzzer 1
  EORA #8           precalc buzzer à 0
  TFR D,U           U = clock low + buzzer 0
  LDD #$007F        A = compeur bit, B=clock high
ETAT0
  DECA             (2)
  BEQ   FIN256     (3)
  STB  <$C2        clock high (4)
  CMPB <$C0        bit lu -> carry (4)
  STU  <$C1        clock low + buzzer 0 (5)
  BCC  ETAT0       (3)
  BRA  ETAT1       pour compenser le BRA ETAT0 final.
ETAT1
  DECA
  BEQ  FIB256
  STB  <$C2
  CMPB <$C0
  STX   <$C1
  BCS  ETAT1
  BRA  ETAT0
FIN256
  RTS
La lecture d'un bit et son envoi sur le buzzer se fait en 21cycles si je compte bien. Cela nous ferait un player à un peu plus que 47khz.
Miam :!:

A noter: le player met 3 cycles de plus lors des passages 0->1 et 1->0 que lors qu'il reste 1->1 ou 0->0. Ca peut introduire de légères distorsions, mais je pense que ce sera imperceptible. On peut corriger cela en introduisant un saut court juste après ETAT0 et ETAT1

Code : Tout sélectionner

ETAT0
  BRA   ETAT0bis   (3)
ETAT0bis
  DECA             (2)
  BEQ  FIN256      (3)
  STB  <$C2        clock high (4)
  CMPB <$C0        bit lu -> carry (4)
  STU  <$C1        clock low + buzzer 0 (5)
  BCC  ETAT0       (3)
ETAT1
  BRA ETAT1bis     
ETAT1bis
  DECA
  BEQ  FIB256
  STB  <$C2
  CMPB <$C0
  STX   <$C1
  BCS  ETAT1
  BRA  ETAT0bis
Ca nous met la lecture à 24cycles constant pour 0->0, 0->1, 1->1, et 1->0, soit 41.6khz. Ca reste acceptable. Tout dépend si la distorsion de 3 cycles s'entend ou pas.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

Hum en réorganisant le tout on fini par avoir un truc propre, court et rapide :D

Code : Tout sélectionner

PLAY256             lit sur la SD et joue sur le buzzer 256 bits consécutifs
  LDB  #$36
  LDA  <$C1
  ORA  #8           precalc buzzer à 1
  TFR  D,X          X = clock low + buzzer 1
  EORA #8           precalc buzzer à 0
  TFR  D,U          U = clock low + buzzer 0
  LDD  #$007F       A = compeur bit, B=clock high
LOOP
  STB  <$C2         clock high (4)
  CMPB <$C0         bit lu -> carry (4)
  BCS  BUZZ1         (3)
  STU  <$C1         clock low + buzzer 0 (5)
  DECA              (2)
  BNE  LOOP         (3)
  RTS
BUZZ1  
  STX  <$C1         clock low + buzzer 1 (5)
  DECA
  BNE  LOOP
  RTS
Ca nous met la lecture de bits à 21cycles à nouveau, soit un player à fréquence constante de 47khz.. COOL! 8) Le dithering 1 bit doit donner des résultats intéressants à cette fréquence.

A noter: le dithering 1 bit en dimension 1 est très simple à mettre en œuvre, et le convertisseur RAW->SD pourrait le faire facilement à partir des échantillons à 47khz.

Code : Tout sélectionner

erreur <- 0
BOUCLE
   echantillon <- LIRE (47khz) + erreur
   SI echantillon > niveau_max/2 ALORS
      SORTIR BIT à 1
      erreur <- echantillon - niveau_max
   SINON
      SORTIR BIT à 0
      erreur <- echantillon
   FIN SI
FIN BOUCLE
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Son 1 bit PWM en streaming

Message par Daniel »

J'ai essayé le dithering en dimension 1, ce n'est pas très bon. J'ai utilisé un autre algorithme de mon invention :

Code : Tout sélectionner

 //conversion du fichier .raw
 s = 0;
 n = 8;
 while(n == 8)
 {
  //lecture d'un buffer de 8 octets
  n = fread(buffer, 1, 8, fraw);
  //conversion en 1 bit
  e = 0;
  for(i = 0; i < 8; i++)
  {
   e <<= 1;
   s += buffer[i] & 0xff;
   if(s < 256) continue;
   s = s - 256;
   e += 1;
  }
  fputc(e, fbin);
 }
Pour le code 6809 il a suffi de copier/coller le code de __sam__ 8)
J'ai juste remplacé le ORA 8 et le EORA 8 par ORA 1 et EORA 1 car je teste sur MO5 (sans extension SX90-018).

Code : Tout sélectionner

/**************************************************\
*                S D D I T H E R                   * 
*           (c) 2015 - Daniel Coulom               *  
*           http://dcmoto.free.fr/                 *
*           http://forum.system-cfg.com/           *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune  garantie  et *
* sans  engager  la  responsabilité  de  l'auteur. *
* Vous  pouvez  l' utiliser,  le  modifier  et  le *
* diffuser librement, en conservant cette  licence *
* et les références de l'auteur dans   toutes  les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/

* Ce programme utilise l'interface SDMOTO ou SDMO
* associee au controleur CS91-280 pour jouer de la
* musique 1 bit en streaming sur le buzzer.
* L'adresse en parametre de la commande CMD18
* doit être initialisee en $9E03-$9E06

/**************************************************\
*                Version 2015.01.21                *
\**************************************************/
* Historique
* 2015.01.21 debut du developpement

*------------------------------------------------------
* DEBUT DU PROGRAMME
*------------------------------------------------------
  ORG   $9E00 
  BRA   INIT          initialisations 

*------------------------------------------------------
* FONCTIONS D'ACCES A LA CARTE SD
*------------------------------------------------------
CMD18
  FCB   $52           read multiple block
  FDB   $0000         adresse bloc (poids fort)
  FDB   $0000         adresse bloc (poids faible)
  FCB   $FF           checksum non testee 
  FCB   $00           code retour attendu  
CMD12
  FCB   $4C           stop transmission
  FDB   $0000         dummy parameter
  FDB   $0000         dummy parameter
  FCB   $FF           checksum non testee 
  FCB   $00           code retour attendu  

*------------------------------------------------------
* Initialisations et execution CMD18 = Read-Multiple-Block
*------------------------------------------------------
INIT
  PSHS  U,Y,X,DP,B,A,CC  sauvegarde des registres du Basic
  ORCC  #$50
  LDX   #$1F40        adresse pour test RAM ou ROM
  LDB   ,X            lecture adresse X
  COM   ,X            tente de modifier adresse X
  CMPB  ,X            test modification adresse X
  BEQ   INIT1         pas de difference -> TO
  COM   ,X            retablissement adresse X
  LDA   #$A7          valeur initialisation DP pour MO
  BRA   INIT2         suite des initialisations
INIT1
  LDA   #$E0          valeur adresse EXCMD (poids fort)
  STA   READ+1        pour execution CMD18
  STA   FIN+4         pour execution CMD12
  LDA   #$E7          valeur initialisation DP pour TO
INIT2
  TFR   A,DP          initialisation DP
* Initialisation PIA pour SDMOTO
  LDA   <$CE          lecture registre de controle A
  ANDA  #$FB          raz bit 2 
  STA   <$CE          selection DDRA
  LDB   #$60          set bits 5 et 6
  STB   <$CC          bits MOSI et CLOCK en sortie
  ORA   #$04          set b2
  STA   <$CE          selection PA
* Initialisation buzzer a zero
  LDA   <$C1          lecture port B 6821 systeme
  ANDA  #$FE          raz bit 0     
  STA   <$C1          raz buzzer

* Lancement de la commande CMD18
  LDU   #CMD18        adresse commande CMD18
READ
  JSR   $A028         EXCMD = execution commande
*                     modifie en $E028 pour TO  
  BRA   PLAY

*------------------------------------------------------
* ARRET DE LA LECTURE ET RETOUR AU BASIC
*------------------------------------------------------
FIN
  LDU   #CMD12        adresse commande CMD12
  JSR   $A028         EXCMD = execution commande CMD12
*                     FIN+4 modifie en $E028 pour TO  
  PULS  B             depile compteur octets supplementaires
  PULS  CC,A,B,DP,X,Y,U,PC

*------------------------------------------------------
* Lecture de la musique 44100 Hz sur 1 bit
*------------------------------------------------------
PLAY
  LDD   #$367F
* lecture d'un bit dans carry et attente bit 0  
  STB   <$C2          clock high                (4)
  CMPB  <$C0          PA b7 (bit lu) -> carry   (4)
  STA   <$C2          clock low                 (4) 
  BCS   PLAY          attente bit 0
* lecture et sortie buzzer de 4096 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BSR   PLAY256       lit et joue 256 bits
  BRA   PLAY          lecture bloc suivant


*------------------------------------------------------
* Lit 256 bits sur la SD et les joue sur le buzzer
*------------------------------------------------------
PLAY256             
  LDB  #$36
  LDA  <$C1
*  ORA  #8           precalc buzzer à 1 pour TO
  ORA  #1           precalc buzzer à 1 pour MO
  TFR  D,X          X = clock low + buzzer 1
*  EORA #8           precalc buzzer à 0 pour TO
  EORA #1           precalc buzzer à 0 pour MO
  TFR  D,U          U = clock low + buzzer 0
  LDD  #$007F       A = compeur bit, B=clock high
LOOP
  STB  <$C2         clock high (4)
  CMPB <$C0         bit lu -> carry (4)
  BCS  BUZZ1         (3)
  STU  <$C1         clock low + buzzer 0 (5)
  DECA              (2)
  BNE  LOOP         (3)
  RTS
BUZZ1 
  STX  <$C1         clock low + buzzer 1 (5)
  DECA
  BNE  LOOP
  RTS

  END
Et voici le résultat : http://dcmoto.free.fr/tmp/elvis_dither.mp3

Bien sûr, il reste les tac-tac-tac-tac-tac des changements de secteur, mais je trouve le résultat plutôt meilleur qu'en PWM.
Ma théorie sur la qualité (voir dans un de mes posts précédents) se vérifie : 47 * 1 est meilleur que 17 * 2.

[Edit] J'ai oublié la lecture des deux octets de CRC, ce qui a pour effet de produire des tac-tac-tac-tac-tac encore plus forts. Mais, même en corrigeant le programme, on ne peut pas espérer les supprimer.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

Pour le dither 1 bit, c'est étonnant que ca ne sonne pas terrible. Je présume qu'il siffle beaucoup à 47/2 = 23khz, et fait entendre une porteuse basse freq (1khz?) dans l'emul. Peut-être faut il répartir l'erreur sur plusieurs échantillons temporels (80% de l'erreur sur l'échantillon suivant, puis 20% sur l'échantillon d'après). Je n'ai pas encore eu le temps d'étudier ton dithering ([EDIT] en fait c'est du dithering sauf qu'au lieu de seuiller à valeur_max/2 on seuille à valeur_max. Quelque part on favorise les échantillons à 0, réduisant le sifflement je suppose), mais le résultat est vraiment bien pour un buzzer 1 bit. Le code mériterait d'être poussé jusqu'au bout pour voir si le tac-tac régulier à 91.7hz (i.e. tous les 4096 bits à 47khz) peut être bien réduit.

Je suis content que mon code ASM ait marché du premier coup. D'hab il faut s'y reprendre à plusieurs fois.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Son 1 bit PWM en streaming

Message par Daniel »

J'ai ajouté la lecture des deux octets de CRC, le code est plus propre ainsi, mais à l'oreille il n'y a pas de différence dans les tac-tac. Je ne vois pas de solution pour empêcher ces craquements entre secteurs. L'utilisation d'un buffer diminuerait beaucoup (trop) la fréquence.

Code : Tout sélectionner

* lecture des deux octets de CRC
  LDD   #$367F
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  STB   <$C2          clock high                (4)
  STA   <$C2          clock low                 (4) 
  BRA   PLAY          lecture bloc suivant
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7970
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Son 1 bit PWM en streaming

Message par __sam__ »

Hum.. pour le coup difficile de récupérer des bits en plus dans l'échantillon. Il faudrait les inventer.

Je me demande si on ne peut pas faire un truc abominable: le re-jeu.

:idea: Idée: dans play 256 on fait un ROR en mémoire pour stocker les 8 derniers bits lus. Ensuite dans la lecture du CRC et l'attente de $FE, on joue en boucle ces 8 derniers échantillons en faisant un ROR en mémoire et un BCS vers STX ou STU. Du coup pendant les périodes mortes on joue les 8 derniers échantillons, c'est à dire les dernières 170µs... hum... c'est pas beaucoup. J'aurais préféré un buffer de l'ordre de 1ms..

Hum.. mais oui, c'est possible :!: On remplace le dernier play256 par une version modifiée qui fait un ROR sur le A libre, et une fois le A plein le stocke en mémoire à des adresses consécutives (Y est dispo pour ca). C'est un peu plus lent, mais c'est pas grave. Du coup on bufferise les 256 derniers bits lus qu'on peut jouer en boucle durant les période mortes CRC et $FE. A 47khz ca nous fait un peu plus de 5ms de buffer à rejouer. Ca doit être suffisant pour les cartes SD même lentes, cf le buffer de 32 échantillons pour SDPlay.

Cette idée de re-jeu n'est que théorique. Difficile de dire si ce sera mieux que de ne rien jouer du tout pendant les périodes mortes. Il faudrait expérimenter.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17412
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Son 1 bit PWM en streaming

Message par Daniel »

Tous les moyens sont bons pour essayer de réduire les claquements. Je me demande s'il de suffirait pas de faire osciller le buzzer de telle façon que la moyenne soit égale à celle des deux ou huit derniers échantillons. Ou même de le faire osciller régulièrement pour avoir une moyenne à 0.5. Ou jouer des bits aléatoires. Ce serait mieux qu'une longue succession de bits identiques, comme actuellement.

Rejouer les 8 ou 256 derniers échantillons est peut-être moins perceptible à l'oreille. Il faudrait essayer toutes ces techniques et garder la meilleure, mais j'ai peur que le résultat soit décevant. L'oreille est trop sensible.
Daniel
L'obstacle augmente mon ardeur.
Répondre