diff options
| author | Dan Halbert <halbert@halwitz.org> | 2018-10-09 19:26:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-09 19:26:50 -0400 |
| commit | 3206d9a5da5e5018ecf3a5878924a202885e0864 (patch) | |
| tree | 79e6a9ad0c7cb721482ba786162ae621f64a7a0f | |
| parent | e9aefccdb5a280a7b510cf2a85837d0ea9ebd5df (diff) | |
| parent | 570ac05145cecc2e1c61cc0ba710e6db9b2af5d2 (diff) | |
Merge pull request #1242 from tannewt/mixer
Introduce audioio.Mixer to allow for multiple sample playback
| -rw-r--r-- | locale/circuitpython.pot | 56 | ||||
| -rw-r--r-- | locale/de_DE.po | 57 | ||||
| -rw-r--r-- | locale/en_US.po | 54 | ||||
| -rw-r--r-- | locale/es.po | 58 | ||||
| -rw-r--r-- | locale/fil.po | 58 | ||||
| -rw-r--r-- | locale/fr.po | 68 | ||||
| -rw-r--r-- | locale/it_IT.po | 60 | ||||
| -rw-r--r-- | locale/pt_BR.po | 57 | ||||
| -rw-r--r-- | ports/atmel-samd/Makefile | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/audio_dma.c | 76 | ||||
| -rw-r--r-- | ports/atmel-samd/mpconfigport.h | 2 | ||||
| -rw-r--r-- | shared-bindings/audioio/Mixer.c | 249 | ||||
| -rw-r--r-- | shared-bindings/audioio/Mixer.h | 52 | ||||
| -rw-r--r-- | shared-bindings/audioio/__init__.c | 4 | ||||
| -rw-r--r-- | shared-module/audioio/Mixer.c | 341 | ||||
| -rw-r--r-- | shared-module/audioio/Mixer.h | 75 | ||||
| -rw-r--r-- | shared-module/audioio/WaveFile.c | 18 | ||||
| -rw-r--r-- | shared-module/audioio/__init__.c | 125 | ||||
| -rw-r--r-- | shared-module/audioio/__init__.h | 17 | ||||
| -rw-r--r-- | shared-module/displayio/Sprite.c | 2 | ||||
| -rwxr-xr-x | tools/preprocess_frozen_modules.py | 2 |
21 files changed, 1274 insertions, 159 deletions
diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index dca0801c8..04f16be3b 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 13:56-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -218,7 +218,7 @@ msgstr "" msgid "soft reboot\n" msgstr "" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "" @@ -2026,6 +2026,22 @@ msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +#: shared-bindings/audioio/Mixer.c:94 +msgid "Invalid voice count" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:99 +msgid "Invalid channel count" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:103 +msgid "Sample rate must be positive" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:107 +msgid "bits_per_sample must be 8 or 16" +msgstr "" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2316,6 +2332,34 @@ msgid "" "Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "" @@ -2336,14 +2380,6 @@ msgstr "" msgid "Invalid file" msgstr "" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index 58cc33331..51c3c4504 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -227,7 +227,7 @@ msgstr "" msgid "soft reboot\n" msgstr "weicher reboot\n" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "Alle sync event Kanäle werden benutzt" @@ -2040,6 +2040,25 @@ msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +#: shared-bindings/audioio/Mixer.c:94 +#, fuzzy +msgid "Invalid voice count" +msgstr "Ungültiger clock pin" + +#: shared-bindings/audioio/Mixer.c:99 +#, fuzzy +msgid "Invalid channel count" +msgstr "Ungültiger clock pin" + +#: shared-bindings/audioio/Mixer.c:103 +msgid "Sample rate must be positive" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:107 +#, fuzzy +msgid "bits_per_sample must be 8 or 16" +msgstr "bits müssen 8 sein" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2331,6 +2350,34 @@ msgid "" "Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "" @@ -2351,14 +2398,6 @@ msgstr "" msgid "Invalid file" msgstr "" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "" diff --git a/locale/en_US.po b/locale/en_US.po index 6491f2f27..4b4ee2415 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -218,7 +218,7 @@ msgstr "" msgid "soft reboot\n" msgstr "" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "" @@ -2026,6 +2026,22 @@ msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +#: shared-bindings/audioio/Mixer.c:94 +msgid "Invalid voice count" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:99 +msgid "Invalid channel count" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:103 +msgid "Sample rate must be positive" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:107 +msgid "bits_per_sample must be 8 or 16" +msgstr "" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2316,6 +2332,34 @@ msgid "" "Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "" @@ -2336,14 +2380,6 @@ msgstr "" msgid "Invalid file" msgstr "" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "" diff --git a/locale/es.po b/locale/es.po index 28d68a013..bc70f1d81 100644 --- a/locale/es.po +++ b/locale/es.po @@ -233,7 +233,7 @@ msgstr "" msgid "soft reboot\n" msgstr "reinicio suave\n" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "Todos los sync event channels están siendo utilizados" @@ -2067,6 +2067,26 @@ msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +#: shared-bindings/audioio/Mixer.c:94 +#, fuzzy +msgid "Invalid voice count" +msgstr "Dirección inválida." + +#: shared-bindings/audioio/Mixer.c:99 +#, fuzzy +msgid "Invalid channel count" +msgstr "argumentos inválidos" + +#: shared-bindings/audioio/Mixer.c:103 +#, fuzzy +msgid "Sample rate must be positive" +msgstr "STA debe estar activo" + +#: shared-bindings/audioio/Mixer.c:107 +#, fuzzy +msgid "bits_per_sample must be 8 or 16" +msgstr "bits debe ser 8" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2359,6 +2379,34 @@ msgid "" "Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "" @@ -2379,14 +2427,6 @@ msgstr "" msgid "Invalid file" msgstr "" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "" diff --git a/locale/fil.po b/locale/fil.po index d34e1b9f0..192ec58a5 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -230,7 +230,7 @@ msgstr "" msgid "soft reboot\n" msgstr "malambot na reboot\n" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "Lahat ng sync event channels ay ginagamit" @@ -2069,6 +2069,26 @@ msgstr "" "ang destination buffer ay dapat na isang bytearray o array ng uri na 'B' " "para sa bit_depth = 8" +#: shared-bindings/audioio/Mixer.c:94 +#, fuzzy +msgid "Invalid voice count" +msgstr "Mali ang tipo ng serbisyo" + +#: shared-bindings/audioio/Mixer.c:99 +#, fuzzy +msgid "Invalid channel count" +msgstr "Maling argumento" + +#: shared-bindings/audioio/Mixer.c:103 +#, fuzzy +msgid "Sample rate must be positive" +msgstr "Dapat aktibo ang STA" + +#: shared-bindings/audioio/Mixer.c:107 +#, fuzzy +msgid "bits_per_sample must be 8 or 16" +msgstr "bits ay dapat 7, 8 o 9" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2378,6 +2398,34 @@ msgstr "" "Object ay deinitialized at hindi na magagamit. Lumikha ng isang bagong " "Object." +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "Hindi ma-iallocate ang first buffer" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "Hindi ma-iallocate ang second buffer" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "May hindi tama sa wave file" @@ -2398,14 +2446,6 @@ msgstr "Dapat sunurin ng Data chunk ang fmt chunk" msgid "Invalid file" msgstr "Mali ang file" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "Hindi ma-iallocate ang first buffer" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "Hindi ma-iallocate ang second buffer" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "Masyadong mahaba ang Clock stretch" diff --git a/locale/fr.po b/locale/fr.po index 4d5e126ad..1a5af3fef 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 13:56-0700\n" "PO-Revision-Date: 2018-08-14 11:01+0200\n" "Last-Translator: Pierrick Couturier <arofarn@arofarn.info>\n" "Language-Team: fr\n" @@ -225,7 +225,7 @@ msgstr "Appuyez sur une touche pour entrer sur REPL ou CTRL-D pour recharger." msgid "soft reboot\n" msgstr "redémarrage logiciel\n" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "Tous les canaux d'événements de synchro sont utilisés" @@ -2060,6 +2060,26 @@ msgid "" msgstr "" "le tampon de destination doit être un tableau de type 'B' pour bit_depth = 8" +#: shared-bindings/audioio/Mixer.c:94 +#, fuzzy +msgid "Invalid voice count" +msgstr "Type de service invalide" + +#: shared-bindings/audioio/Mixer.c:99 +#, fuzzy +msgid "Invalid channel count" +msgstr "Argument invalide" + +#: shared-bindings/audioio/Mixer.c:103 +#, fuzzy +msgid "Sample rate must be positive" +msgstr "'STA' doit être actif" + +#: shared-bindings/audioio/Mixer.c:107 +#, fuzzy +msgid "bits_per_sample must be 8 or 16" +msgstr "bits doivent être 7, 8 ou 9" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2374,6 +2394,34 @@ msgstr "" "L'objet a été désinitialisé et ne peut plus être utilisé. Créez un nouvel " "objet." +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "Impossible d'allouer le 1er tampon" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "Impossible d'allouer le 2e tampon" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "Fichier WAVE invalide" @@ -2394,14 +2442,6 @@ msgstr "Un bloc de données doit suivre un bloc de format" msgid "Invalid file" msgstr "Fichier invalide" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "Impossible d'allouer le 1er tampon" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "Impossible d'allouer le 2e tampon" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "Période de l'horloge trop longue" @@ -2471,9 +2511,9 @@ msgid "too many arguments provided with the given format" msgstr "trop d'arguments fournis avec ce format" #, fuzzy -#~ msgid "palette must be displayio.Palette" -#~ msgstr "la palette doit être longue de 32 octets" - -#, fuzzy #~ msgid "value_size must be power of two" #~ msgstr "'len' doit être un multiple de 4" + +#, fuzzy +#~ msgid "palette must be displayio.Palette" +#~ msgstr "la palette doit être longue de 32 octets" diff --git a/locale/it_IT.po b/locale/it_IT.po index dd8b41f76..9318952c2 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 10:54+0200\n" +"POT-Creation-Date: 2018-10-09 13:56-0700\n" "PO-Revision-Date: 2018-10-02 16:27+0200\n" "Last-Translator: Enrico Paganin <enrico.paganin@mail.com>\n" "Language-Team: \n" @@ -231,7 +231,7 @@ msgstr "" msgid "soft reboot\n" msgstr "soft reboot\n" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "Tutti i canali di eventi sincronizzati in uso" @@ -2064,6 +2064,26 @@ msgstr "" "il buffer di destinazione deve essere un bytearray o un array di tipo 'B' " "con bit_depth = 8" +#: shared-bindings/audioio/Mixer.c:94 +#, fuzzy +msgid "Invalid voice count" +msgstr "Tipo di servizio non valido" + +#: shared-bindings/audioio/Mixer.c:99 +#, fuzzy +msgid "Invalid channel count" +msgstr "Argomento non valido" + +#: shared-bindings/audioio/Mixer.c:103 +#, fuzzy +msgid "Sample rate must be positive" +msgstr "STA deve essere attiva" + +#: shared-bindings/audioio/Mixer.c:107 +#, fuzzy +msgid "bits_per_sample must be 8 or 16" +msgstr "i bit devono essere 7, 8 o 9" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2364,6 +2384,34 @@ msgstr "" "L'oggetto è stato deinizializzato e non può essere più usato. Crea un nuovo " "oggetto." +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "Impossibile allocare il primo buffer" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "Impossibile allocare il secondo buffer" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "File wave non valido" @@ -2384,14 +2432,6 @@ msgstr "" msgid "Invalid file" msgstr "File non valido" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "Impossibile allocare il primo buffer" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "Impossibile allocare il secondo buffer" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 190c2a93d..9b92333fc 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -218,7 +218,7 @@ msgstr "" msgid "soft reboot\n" msgstr "" -#: ports/atmel-samd/audio_dma.c:285 +#: ports/atmel-samd/audio_dma.c:209 #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c:361 msgid "All sync event channels in use" msgstr "" @@ -2029,6 +2029,25 @@ msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +#: shared-bindings/audioio/Mixer.c:94 +#, fuzzy +msgid "Invalid voice count" +msgstr "certificado inválido" + +#: shared-bindings/audioio/Mixer.c:99 +#, fuzzy +msgid "Invalid channel count" +msgstr "certificado inválido" + +#: shared-bindings/audioio/Mixer.c:103 +msgid "Sample rate must be positive" +msgstr "" + +#: shared-bindings/audioio/Mixer.c:107 +#, fuzzy +msgid "bits_per_sample must be 8 or 16" +msgstr "bits devem ser 8" + #: shared-bindings/audioio/RawSample.c:98 msgid "" "sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or " @@ -2320,6 +2339,34 @@ msgid "" msgstr "" "Objeto foi desinicializado e não pode ser mais usaado. Crie um novo objeto." +#: shared-module/audioio/Mixer.c:47 shared-module/audioio/WaveFile.c:117 +msgid "Couldn't allocate first buffer" +msgstr "Não pôde alocar primeiro buffer" + +#: shared-module/audioio/Mixer.c:53 shared-module/audioio/WaveFile.c:123 +msgid "Couldn't allocate second buffer" +msgstr "Não pôde alocar segundo buffer" + +#: shared-module/audioio/Mixer.c:82 +msgid "Voice index too high" +msgstr "" + +#: shared-module/audioio/Mixer.c:85 +msgid "The sample's sample rate does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:88 +msgid "The sample's channel count does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:91 +msgid "The sample's bits_per_sample does not match the mixer's" +msgstr "" + +#: shared-module/audioio/Mixer.c:100 +msgid "The sample's signedness does not match the mixer's" +msgstr "" + #: shared-module/audioio/WaveFile.c:61 msgid "Invalid wave file" msgstr "Aqruivo de ondas inválido" @@ -2340,14 +2387,6 @@ msgstr "Pedaço de dados deve seguir o pedaço de cortes" msgid "Invalid file" msgstr "Arquivo inválido" -#: shared-module/audioio/WaveFile.c:117 -msgid "Couldn't allocate first buffer" -msgstr "Não pôde alocar primeiro buffer" - -#: shared-module/audioio/WaveFile.c:123 -msgid "Couldn't allocate second buffer" -msgstr "Não pôde alocar segundo buffer" - #: shared-module/bitbangio/I2C.c:58 msgid "Clock stretch too long" msgstr "Clock se estendeu por tempo demais" diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index f8e5051c2..c8ade987d 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -407,6 +407,8 @@ ifneq ($(CHIP_VARIANT),SAMR21G18A) audioio/__init__.c \ audioio/AudioOut.c SRC_SHARED_MODULE += \ + audioio/__init__.c \ + audioio/Mixer.c \ audioio/RawSample.c \ audioio/WaveFile.c endif diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index 45d698c17..68d6f182d 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -40,82 +40,6 @@ static audio_dma_t* audio_dma_state[AUDIO_DMA_CHANNEL_COUNT]; // This cannot be in audio_dma_state because it's volatile. static volatile bool audio_dma_pending[AUDIO_DMA_CHANNEL_COUNT]; -uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return sample->sample_rate; - } - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return file->sample_rate; - } - return 16000; -} - -uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return sample->bits_per_sample; - } - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return file->bits_per_sample; - } - return 8; -} - -uint8_t audiosample_channel_count(mp_obj_t sample_obj) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return sample->channel_count; - } - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return file->channel_count; - } - return 1; -} - -static void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - audioio_rawsample_reset_buffer(sample, single_channel, audio_channel); - } - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_wavefile_reset_buffer(file, single_channel, audio_channel); - } -} - -static audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, - bool single_channel, - uint8_t channel, - uint8_t** buffer, uint32_t* buffer_length) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return audioio_rawsample_get_buffer(sample, single_channel, channel, buffer, buffer_length); - } - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length); - } - return GET_BUFFER_DONE; -} - -static void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - audioio_rawsample_get_buffer_structure(sample, single_channel, single_buffer, - samples_signed, max_buffer_length, spacing); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed, - max_buffer_length, spacing); - } -} - uint8_t find_free_audio_dma_channel(void) { uint8_t channel; for (channel = 0; channel < AUDIO_DMA_CHANNEL_COUNT; channel++) { diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index 14f72ccfb..69a146c1f 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -207,7 +207,7 @@ extern const struct _mp_obj_module_t usb_hid_module; #define MICROPY_PY_URE (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #ifndef MICROPY_PY_FRAMEBUF - #define MICROPY_PY_FRAMEBUF (1) + #define MICROPY_PY_FRAMEBUF (0) #endif #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audioio/Mixer.c new file mode 100644 index 000000000..dc7a12ebc --- /dev/null +++ b/shared-bindings/audioio/Mixer.c @@ -0,0 +1,249 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "shared-bindings/audioio/Mixer.h" + +#include <stdint.h> + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audioio +//| +//| :class:`Mixer` -- Mixes one or more audio samples together +//| =========================================================== +//| +//| Mixer mixes multiple samples into one sample. +//| +//| .. class:: Mixer(channel_count=2, buffer_size=1024) +//| +//| Create a Mixer object that can mix multiple channels with the same sample rate. +//| +//| :param int channel_count: The maximum number of samples to mix at once +//| :param int buffer_size: The total size in bytes of the buffers to mix into +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audioio +//| import digitalio +//| +//| # Required for CircuitPlayground Express +//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) +//| speaker_enable.switch_to_output(value=True) +//| +//| music = audioio.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) +//| drum = audioio.WaveFile(open("drum.wav", "rb")) +//| mixer = audioio.Mixer(voice_count=2, sample_rate=16000, channel_count=1, bits_per_sample=16, samples_signed=True) +//| a = audioio.AudioOut(board.A0) +//| +//| print("playing") +//| a.play(mixer) +//| mixer.play(music, voice=0) +//| while mixer.playing: +//| mixer.play(drum, voice=1) +//| time.sleep(1) +//| print("stopped") +//| +STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, 2, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t voice_count = args[ARG_voice_count].u_int; + if (voice_count < 1 || voice_count > 255) { + mp_raise_ValueError(translate("Invalid voice count")); + } + + mp_int_t channel_count = args[ARG_channel_count].u_int; + if (channel_count < 1 || channel_count > 2) { + mp_raise_ValueError(translate("Invalid channel count")); + } + mp_int_t sample_rate = args[ARG_sample_rate].u_int; + if (sample_rate < 1) { + mp_raise_ValueError(translate("Sample rate must be positive")); + } + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); + } + audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_t, voice_count); + self->base.type = &audioio_mixer_type; + common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the Mixer and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audioio_mixer_deinit(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioio_mixer_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_deinit_obj, audioio_mixer_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audioio_mixer_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); + + +//| .. method:: play(sample, *, voice=0, loop=False) +//| +//| Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +STATIC mp_obj_t audioio_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_voice, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audioio_mixer_play(self, sample, args[ARG_voice].u_int, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_play_obj, 1, audioio_mixer_obj_play); + +//| .. method:: stop_voice(voice=0) +//| +//| Stops playback of the sample on the given voice. +//| +STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); + +//| .. attribute:: playing +//| +//| True when any voice is being output. (read-only) +//| +STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); + +const mp_obj_property_t audioio_mixer_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixer_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: sample_rate +//| +//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). +//| +STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); + + +const mp_obj_property_t audioio_mixer_sample_rate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixer_get_sample_rate_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_voice), MP_ROM_PTR(&audioio_mixer_stop_voice_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_mixer_sample_rate_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_mixer_locals_dict, audioio_mixer_locals_dict_table); + +const mp_obj_type_t audioio_mixer_type = { + { &mp_type_type }, + .name = MP_QSTR_Mixer, + .make_new = audioio_mixer_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_mixer_locals_dict, +}; diff --git a/shared-bindings/audioio/Mixer.h b/shared-bindings/audioio/Mixer.h new file mode 100644 index 000000000..832072b8f --- /dev/null +++ b/shared-bindings/audioio/Mixer.h @@ -0,0 +1,52 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audioio/Mixer.h" +#include "shared-bindings/audioio/RawSample.h" + +extern const mp_obj_type_t audioio_mixer_type; + +void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, + uint8_t voice_count, + uint32_t buffer_size, + uint8_t bits_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate); + +void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self); +bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self); +void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t voice, bool loop); +void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice); + +bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); +uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H diff --git a/shared-bindings/audioio/__init__.c b/shared-bindings/audioio/__init__.c index 8a00b43d8..4786b6425 100644 --- a/shared-bindings/audioio/__init__.c +++ b/shared-bindings/audioio/__init__.c @@ -32,6 +32,8 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audioio/__init__.h" #include "shared-bindings/audioio/AudioOut.h" +#include "shared-bindings/audioio/Mixer.h" +#include "shared-bindings/audioio/RawSample.h" #include "shared-bindings/audioio/WaveFile.h" //| :mod:`audioio` --- Support for audio input and output @@ -49,6 +51,7 @@ //| :maxdepth: 3 //| //| AudioOut +//| Mixer //| RawSample //| WaveFile //| @@ -61,6 +64,7 @@ STATIC const mp_rom_map_elem_t audioio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioio) }, { MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audioio_audioout_type) }, + { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, }; diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c new file mode 100644 index 000000000..8020a621e --- /dev/null +++ b/shared-module/audioio/Mixer.c @@ -0,0 +1,341 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/audioio/Mixer.h" + +#include <stdint.h> + +#include "py/runtime.h" +#include "shared-module/audioio/__init__.h" +#include "shared-module/audioio/RawSample.h" + +void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, + uint8_t voice_count, + uint32_t buffer_size, + uint8_t bits_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate) { + self->len = buffer_size / 2 / sizeof(uint32_t) * sizeof(uint32_t); + + self->first_buffer = m_malloc(self->len, false); + if (self->first_buffer == NULL) { + common_hal_audioio_mixer_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); + } + + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audioio_mixer_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + } + + self->bits_per_sample = bits_per_sample; + self->samples_signed = samples_signed; + self->channel_count = channel_count; + self->sample_rate = sample_rate; + self->voice_count = voice_count; + + for (uint8_t i = 0; i < self->voice_count; i++) { + self->voice[i].sample = NULL; + } +} + +void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self) { + self->first_buffer = NULL; + self->second_buffer = NULL; +} + +bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self) { + return self->first_buffer == NULL; +} + +uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self) { + return self->sample_rate; +} + +void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t v, bool loop) { + if (v >= self->voice_count) { + mp_raise_ValueError(translate("Voice index too high")); + } + if (audiosample_sample_rate(sample) != self->sample_rate) { + mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); + } + if (audiosample_channel_count(sample) != self->channel_count) { + mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); + } + if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { + mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); + } + bool single_buffer; + bool samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + if (samples_signed != self->samples_signed) { + mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); + } + audioio_mixer_voice_t* voice = &self->voice[v]; + voice->sample = sample; + voice->loop = loop; + + audiosample_reset_buffer(sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); + // Track length in terms of words. + voice->buffer_length /= sizeof(uint32_t); + voice->more_data = result == GET_BUFFER_MORE_DATA; +} + +void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice) { + self->voice[voice].sample = NULL; +} + +bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self) { + for (int32_t v = 0; v < self->voice_count; v++) { + if (self->voice[v].sample != NULL) { + return true; + } + } + return false; +} + +void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel) { + for (int32_t i = 0; i < self->voice_count; i++) { + self->voice[i].sample = NULL; + } +} + +uint32_t add8signed(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __QADD8(a, b); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = a >> (sizeof(int8_t) * 8 * i); + int8_t bi = b >> (sizeof(int8_t) * 8 * i); + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > CHAR_MAX) { + intermediate = CHAR_MAX; + } else if (intermediate < CHAR_MIN) { + //intermediate = CHAR_MIN; + } + result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add8unsigned(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // Subtract out the DC offset, add and then shift back. + a = __USUB8(a, 0x80808080); + b = __USUB8(b, 0x80808080); + uint32_t sum = __QADD8(a, b); + return __UADD8(sum, 0x80808080); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = (a >> (sizeof(uint8_t) * 8 * i)) - 128; + int8_t bi = (b >> (sizeof(uint8_t) * 8 * i)) - 128; + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > UCHAR_MAX) { + intermediate = UCHAR_MAX; + } + result |= ((uint8_t) intermediate + 128) << (sizeof(uint8_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add16signed(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __QADD16(a, b); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = a >> (sizeof(int16_t) * 8 * i); + int16_t bi = b >> (sizeof(int16_t) * 8 * i); + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add16unsigned(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // Subtract out the DC offset, add and then shift back. + a = __USUB16(a, 0x80008000); + b = __USUB16(b, 0x80008000); + uint32_t sum = __QADD16(a, b); + return __UADD16(sum, 0x80008000); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > USHRT_MAX) { + intermediate = USHRT_MAX; + } + result |= ((uint16_t) intermediate + 0x8000) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + +audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length) { + if (!single_channel) { + channel = 0; + } + + uint32_t channel_read_count = self->left_read_count; + if (channel == 1) { + channel_read_count = self->right_read_count; + } + *buffer_length = self->len; + + bool need_more_data = self->read_count == channel_read_count; + if (need_more_data) { + uint32_t* word_buffer; + if (self->use_first_buffer) { + *buffer = (uint8_t*) self->first_buffer; + word_buffer = self->first_buffer; + } else { + *buffer = (uint8_t*) self->second_buffer; + word_buffer = self->second_buffer; + } + self->use_first_buffer = !self->use_first_buffer; + bool voices_active = false; + for (int32_t v = 0; v < self->voice_count; v++) { + audioio_mixer_voice_t* voice = &self->voice[v]; + + uint32_t j = 0; + bool voice_done = voice->sample == NULL; + for (uint32_t i = 0; i < self->len / sizeof(uint32_t); i++) { + if (!voice_done && j >= voice->buffer_length) { + if (!voice->more_data) { + if (voice->loop) { + audiosample_reset_buffer(voice->sample, false, 0); + } else { + voice->sample = NULL; + voice_done = true; + } + } + if (!voice_done) { + // Load another buffer + audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); + // Track length in terms of words. + voice->buffer_length /= sizeof(uint32_t); + voice->more_data = result == GET_BUFFER_MORE_DATA; + j = 0; + } + } + // First active voice gets copied over verbatim. + uint32_t sample_value; + if (voice_done) { + // Exit early if another voice already set all samples once. + if (voices_active) { + continue; + } + sample_value = 0; + if (!self->samples_signed) { + if (self->bits_per_sample == 8) { + sample_value = 0x7f7f7f7f; + } else { + sample_value = 0x7fff7fff; + } + } + } else { + sample_value = voice->remaining_buffer[j]; + } + + if (!voices_active) { + word_buffer[i] = sample_value; + } else { + if (self->bits_per_sample == 8) { + if (self->samples_signed) { + word_buffer[i] = add8signed(word_buffer[i], sample_value); + } else { + word_buffer[i] = add8unsigned(word_buffer[i], sample_value); + } + } else { + if (self->samples_signed) { + word_buffer[i] = add16signed(word_buffer[i], sample_value); + } else { + word_buffer[i] = add16unsigned(word_buffer[i], sample_value); + } + } + } + j++; + } + voice->buffer_length -= j; + voice->remaining_buffer += j; + + voices_active = true; + } + + self->read_count += 1; + } else if (!self->use_first_buffer) { + *buffer = (uint8_t*) self->first_buffer; + } else { + *buffer = (uint8_t*) self->second_buffer; + } + + + if (channel == 0) { + self->left_read_count += 1; + } else if (channel == 1) { + self->right_read_count += 1; + *buffer = *buffer + self->bits_per_sample / 8; + } + return GET_BUFFER_MORE_DATA; +} + +void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + *single_buffer = false; + *samples_signed = self->samples_signed; + *max_buffer_length = self->len; + if (single_channel) { + *spacing = self->channel_count; + } else { + *spacing = 1; + } +} diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h new file mode 100644 index 000000000..6a88fe0bd --- /dev/null +++ b/shared-module/audioio/Mixer.h @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H + +#include "py/obj.h" + +#include "shared-module/audioio/__init__.h" + +typedef struct { + mp_obj_t sample; + bool loop; + bool more_data; + uint32_t* remaining_buffer; + uint32_t buffer_length; +} audioio_mixer_voice_t; + +typedef struct { + mp_obj_base_t base; + uint32_t* first_buffer; + uint32_t* second_buffer; + uint32_t len; // in words + uint8_t bits_per_sample; + bool use_first_buffer; + bool samples_signed; + uint8_t channel_count; + uint32_t sample_rate; + + uint32_t read_count; + uint32_t left_read_count; + uint32_t right_read_count; + + uint8_t voice_count; + audioio_mixer_voice_t voice[]; +} audioio_mixer_obj_t; + + +// These are not available from Python because it may be called in an interrupt. +void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel); +audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length); // length in bytes +void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H diff --git a/shared-module/audioio/WaveFile.c b/shared-module/audioio/WaveFile.c index 7efad05e0..e5a7b1a3b 100644 --- a/shared-module/audioio/WaveFile.c +++ b/shared-module/audioio/WaveFile.c @@ -200,13 +200,29 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK) { return GET_BUFFER_ERROR; } + self->bytes_remaining -= length_read; + // Pad the last buffer to word align it. + if (self->bytes_remaining == 0 && length_read % sizeof(uint32_t) != 0) { + uint32_t pad = length_read % sizeof(uint32_t); + length_read += pad; + if (self->bits_per_sample == 8) { + for (uint32_t i = 0; i < pad; i++) { + ((uint8_t*) (*buffer))[length_read / sizeof(uint8_t) - i - 1] = 0x80; + } + } else if (self->bits_per_sample == 16) { + // We know the buffer is aligned because we allocated it onto the heap ourselves. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + ((int16_t*) (*buffer))[length_read / sizeof(int16_t) - 1] = 0; + #pragma GCC diagnostic pop + } + } *buffer_length = length_read; if (self->buffer_index % 2 == 1) { self->second_buffer_length = length_read; } else { self->buffer_length = length_read; } - self->bytes_remaining -= length_read; self->buffer_index += 1; self->read_count += 1; } diff --git a/shared-module/audioio/__init__.c b/shared-module/audioio/__init__.c new file mode 100644 index 000000000..b87b06a83 --- /dev/null +++ b/shared-module/audioio/__init__.c @@ -0,0 +1,125 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/audioio/__init__.h" + +#include "py/obj.h" +#include "shared-bindings/audioio/Mixer.h" +#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audioio/WaveFile.h" +#include "shared-module/audioio/Mixer.h" +#include "shared-module/audioio/RawSample.h" +#include "shared-module/audioio/WaveFile.h" + +uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return sample->sample_rate; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return file->sample_rate; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + return mixer->sample_rate; + } + return 16000; +} + +uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return sample->bits_per_sample; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return file->bits_per_sample; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + return mixer->bits_per_sample; + } + return 8; +} + +uint8_t audiosample_channel_count(mp_obj_t sample_obj) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return sample->channel_count; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return file->channel_count; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + return mixer->channel_count; + } + return 1; +} + +void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + audioio_rawsample_reset_buffer(sample, single_channel, audio_channel); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_wavefile_reset_buffer(file, single_channel, audio_channel); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_mixer_reset_buffer(file, single_channel, audio_channel); + } +} + +audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, + bool single_channel, + uint8_t channel, + uint8_t** buffer, uint32_t* buffer_length) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return audioio_rawsample_get_buffer(sample, single_channel, channel, buffer, buffer_length); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return audioio_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length); + } + return GET_BUFFER_DONE; +} + +void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + audioio_rawsample_get_buffer_structure(sample, single_channel, single_buffer, + samples_signed, max_buffer_length, spacing); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed, + max_buffer_length, spacing); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed, + max_buffer_length, spacing); + } +} diff --git a/shared-module/audioio/__init__.h b/shared-module/audioio/__init__.h index 2491beb12..c805f3116 100644 --- a/shared-module/audioio/__init__.h +++ b/shared-module/audioio/__init__.h @@ -27,10 +27,27 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO__INIT__H #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO__INIT__H +#include <stdbool.h> +#include <stdint.h> + +#include "py/obj.h" + typedef enum { GET_BUFFER_DONE, // No more data to read GET_BUFFER_MORE_DATA, // More data to read. GET_BUFFER_ERROR, // Error while reading data. } audioio_get_buffer_result_t; +uint32_t audiosample_sample_rate(mp_obj_t sample_obj); +uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj); +uint8_t audiosample_channel_count(mp_obj_t sample_obj); +void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel); +audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, + bool single_channel, + uint8_t channel, + uint8_t** buffer, uint32_t* buffer_length); +void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + #endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO__INIT__H diff --git a/shared-module/displayio/Sprite.c b/shared-module/displayio/Sprite.c index 4fe8d1ff6..87600f721 100644 --- a/shared-module/displayio/Sprite.c +++ b/shared-module/displayio/Sprite.c @@ -68,7 +68,7 @@ bool displayio_sprite_get_pixel(displayio_sprite_t *self, int16_t x, int16_t y, if (y < 0 || y >= self->height || x >= self->width || x < 0) { return false; } - uint32_t value; + uint32_t value = 0; if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { value = common_hal_displayio_bitmap_get_pixel(self->bitmap, x, y); } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { diff --git a/tools/preprocess_frozen_modules.py b/tools/preprocess_frozen_modules.py index d157deeee..bb6959f0d 100755 --- a/tools/preprocess_frozen_modules.py +++ b/tools/preprocess_frozen_modules.py @@ -33,7 +33,7 @@ def copy_and_process(in_dir, out_dir): for root, subdirs, files in os.walk(in_dir): # Skip library examples directories. - if Path(root).name in ['examples', 'docs']: + if Path(root).name in ['examples', 'docs', 'tests']: continue for file in files: |
