De la musique one-bit - meowbit

Le précédent article consacré à la carte d'entraînement Meowbit et aux implémentations Python se terminait par une mention de l'incapacité de CircuitPython à jouer de la musique simultanément avec le jeu: CircuitPython ne permet pas aux gestionnaires d'interruptions d'être écrits en Python, et sans cela, un délai pour le redessiner de l'écran (environ 0,15 s) "accroche" le son ... Néanmoins, le son de fond est souvent nécessaire, et pour la plupart des cartes prises en charge (100 sur 189), CircuitPython comprend un module audioio



ou audiopwmio



qui implémente le son de fond de manière native à la carte. Malheureusement, pour Meowbit (et en général pour les cartes basées sur STM32) ni l'un ni l'autre module n'est implémenté; mais dans un projet open source, cela peut être corrigé. Trouvez l'œuf de Pâques sur la photo Tout d'abord: pourquoi y a-t-il deux modules différents pour jouer du son avec des API complètement identiques, et l'un ou l'autre est pris en charge sur des cartes différentes?













Voici à quoi ressemble ⅒ secondes d'un fichier

WAV normal (16 bits) dans un éditeur audio (comme Audacity) :





La valeur change en douceur dans la plage d'environ -0,2 à +0,2 "unités conventionnelles". Si la tension fournie au haut-parleur électrodynamique est modifiée de la même manière , la membrane oscillera tout aussi doucement - d'environ 0,2 de son écart maximal possible dans une direction à 0,2 écart dans l'autre direction. Le module audioio



met en œuvre une telle lecture audio - via le DAC, il modifie en douceur la tension à la sortie connectée au haut-parleur.



Mais chez Meowbit, au lieu d'un haut-parleur, il y a un tweeter piézo pas cher, incapable de dévier la membrane vers des positions intermédiaires: il passe très rapidement d'une position extrême à une autre extrême, et y reste jusqu'à la transition suivante. Considérez-le comme un son avec une résolution d'un bit par échantillon:





De cette façon, il est impossible de transmettre le changement de volume sonore, mais il est théoriquement possible de transmettre toutes les harmoniques présentes - si, parallèlement à la réduction de résolution de 32768 fois, la fréquence d'échantillonnage est augmentée de la même montant (c'est-à-dire jusqu'à des centaines de mégahertz). Il est peu probable qu'une membrane de tweeter piézoélectrique puisse vibrer à cette fréquence; mais cela peut être utilisé à votre avantage - si vous apprenez à commuter la tension sur le buzzer, lorsque la membrane est à mi-chemin, vous pouvez faire des sons de volume intermédiaire! Une recherche de brevet confirme que les gens explorent effectivement les possibilités d'utiliser le tweeter piézo de cette manière. Nous n'entrerons pas profondément dans cette jungle, et laisserons le taux d'échantillonnage WAV habituel de plusieurs dizaines de kilohertz. Pour la musique où les harmoniques fondamentales sont dans la région du kilohertz, cela suffit; la parole, cependant, se transforme en un bruit à peine intelligible.Vous pouvez comparer la façon dont l'échantillon sonore de huit secondes que j'ai utilisé, joué sur un sondeur piézo un bit, est perçu: d'abord l'original, puis la version un bit, puis l'enregistrement Meowbit avec un microphone.





Le module audiopwmio



implémente la lecture du son via une sortie numérique en utilisant PWM : un enregistrement audio à un bit se transforme en une séquence de retards entre la commutation de la

sortie à la valeur opposée.



Ainsi, le plan général de mise en œuvre audiopwmio



de Meowbit est le suivant:



  1. Nous traduisons l'enregistrement audio transmis par l'utilisateur au format PWM (une liste de retards entre les commutateurs);
  2. . pulseio



    , , – – Python .


Il n'était pas immédiatement évident qu'il y avait un autre aspect de l'implémentation à prendre en charge: la mise en mémoire tampon audio. Mon échantillon de test de 8 secondes est de 8 * 22050 * 2 ≈ 340 Ko - trois fois la taille de toute la RAM Meowbit; par conséquent, il devra être chargé en mémoire morceau par morceau. L'implémentation standard audiocore.WaveFile



charge le fichier WAV par blocs de 256 octets, ce qui correspond à 128 échantillons ou 5,8 ms de temps de lecture. Cela signifie qu'en moyenne, toutes les 5,8 ms audiopwmio



devra demander le remplissage du tampon; il n'y a pas d'issue, sauf de placer cet appel dans le même gestionnaire d'interruption de minuterie - sinon, le redessiner de l'écran peut retarder le remplissage du tampon d'une bonne centaine de millisecondes. Cependant, cela ne résout pas complètement le problème: que se passe-t-il si une interruption du minuteur se produit pendant le rafraîchissement de l'écran? L'écran Meowbit est connecté via le bus SPI , le lecteur flash est connecté via lui, ce qui signifie qu'il est toujours impossible d'accéder au flash en redessinant l'écran!



Le résultat est une implémentation audiopwmio



capable de lire des enregistrements audio à partir de la mémoire (ou générés de manière procédurale) dans la meilleure qualité possible sur Meowbit; mais les enregistrements audio à partir de fichiers ne sont lus qu'en l'absence d'appels simultanés à l'écran et au flash. Cela suffit amplement pour la bande originale de jeux simples. PR avec mon implémentation attend un examen depuis plus d'une semaine, et on audiopwmio



ne sait pas quand Meowbit apparaîtra dans la version officielle de CircuitPython; mais cela n'empêche personne de vouloir compiler CircuitPython pour lui-même avec mon add-on.










All Articles