├── .gitattributes ├── LICENSE ├── README.md ├── examples ├── play-mono-wav-from-sdcard-uasyncio.py ├── play-mono-wav-from-sdcard.py ├── play-stereo-wav-from-internal-flash.py ├── record-mono-mic-to-internal-flash.py └── record-mono-mic-to-sdcard.py ├── firmware ├── esp32-idf4-0-2-i2s-2021-02-27-v1-14.bin └── esp32spiram-idf4-0-2-i2s-2021-02-27-v1-14.bin ├── images ├── ALL_LEFT.PNG ├── ALL_RIGHT.PNG ├── ONLY_LEFT.PNG ├── RIGHT_LEFT.PNG ├── test-fixture-sdcard.JPG └── test-fixture.JPG └── wav_files ├── pattern-16k-32bits.wav ├── side-to-side-8k-16bits-stereo.wav ├── taunt-16k-16bits-mono-12db.wav └── taunt-16k-16bits-mono.wav /.gitattributes: -------------------------------------------------------------------------------- 1 | # Per default everything gets normalized and gets LF line endings on checkout. 2 | * text eol=lf 3 | 4 | # These will always have CRLF line endings on checkout. 5 | *.vcxproj text eol=crlf 6 | *.props text eol=crlf 7 | *.bat text eol=crlf 8 | 9 | # These are binary so should never be modified by git. 10 | *.png binary 11 | *.jpg binary 12 | *.dxf binary 13 | *.wav binary 14 | *.bin binary -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mike Teachman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # MicroPython I2S Guide and Examples for ESP32 4 | 5 | **Deprecation Notice: These examples are associated with a MicroPython PR that is now obsolete. I2S is now supported in official MicroPython builds, since July 5, 2021. Binaries can be downloaded at [MicroPython downloads](https://micropython.org/download/). A [new set of examples](https://github.com/miketeachman/micropython-i2s-examples) is available that works with Pyboards and the ESP32.** 6 | 7 | This guide outlines the capabilities of a new MicroPython [I2S](https://en.wikipedia.org/wiki/I%C2%B2S) class that has been developed for the MicroPython project. The I2S class works on ESP32 processors and is implemented using Espressif's [ESP-IDF API](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html). To use I2S with MicroPython you will need to make a custom MicroPython build and integrate a [pull request](https://github.com/micropython/micropython/pull/4471) into the build. Or, download and program your ESP32 board using one of the pre-built [firmware binaries](firmware). 8 | *** 9 | **Example usage - Read audio samples from an I2S microphone module** 10 | 11 | ``` 12 | from machine import I2S 13 | from machine import Pin 14 | 15 | bck_pin = Pin(14) # Bit clock output 16 | ws_pin = Pin(13) # Word clock output 17 | sdin_pin = Pin(12) # Serial data input 18 | 19 | audio_in = I2S(I2S.NUM0, # create I2S peripheral to read audio 20 | bck=bck_pin, ws=ws_pin, sdin=sdin_pin, # sample data from an INMP441 21 | standard=I2S.PHILIPS, mode=I2S.MASTER_RX, # microphone module 22 | dataformat=I2S.B32, 23 | channelformat=I2S.RIGHT_LEFT, 24 | samplerate=16000, 25 | dmacount=16,dmalen=256) 26 | 27 | samples = bytearray(2048) # bytearray to receive audio samples 28 | 29 | num_bytes_read = audio_in.readinto(samples) # read audio samples from microphone 30 | # note: blocks until sample array is full 31 | # - see optional timeout argument 32 | # to configure maximum blocking duration 33 | ``` 34 | *** 35 | **Example usage - Play audio samples through a speaker using an I2S amplifier module** 36 | 37 | ``` 38 | from machine import I2S 39 | from machine import Pin 40 | 41 | bck_pin = Pin(14) # Bit clock output 42 | ws_pin = Pin(13) # Word clock output 43 | sdout_pin = Pin(12) # Serial data output 44 | 45 | audio_out = I2S(I2S.NUM1, # create I2S peripheral to write audio 46 | bck=bck_pin, ws=ws_pin, sdout=sdout_pin, # sample data to an Adafruit I2S Amplifier 47 | standard=I2S.PHILIPS, mode=I2S.MASTER_TX, # breakout board, 48 | dataformat=I2S.B16, # based on MAX98357A device 49 | channelformat=I2S.ONLY_RIGHT, 50 | samplerate=16000, 51 | dmacount=16,dmalen=512) 52 | 53 | samples = bytearray(1024) # bytearray containing audio samples to transmit 54 | 55 | num_bytes_written = audio_out.write(samples) # write audio samples to amplifier 56 | # note: blocks until sample array is emptied 57 | # - see optional timeout argument 58 | # to configure maximum blocking duration 59 | ``` 60 | # class I2S 61 | ## Constructor 62 | ``` 63 | class machine.I2S(id, 64 | bck, ws, [sdin], [sdout], 65 | [standard=I2S.PHILIPS], mode, 66 | dataformat, channelformat, 67 | samplerate, 68 | [dmacount=16], [dmalen=64], 69 | [apllrate=0]) 70 | ``` 71 | Construct and return a new I2S object with the given arguments: 72 | * **id** specifies I2S peripheral instance 73 | * **bck** pin object for the bit clock output 74 | * **ws** pin object for the word select output 75 | * **sdin** pin object for the serial data input (optional) 76 | * **sdout** pin object for the serial data output (optional) 77 | * **standard** protocol used by the I2S peripheral (optional) 78 | * **mode** specifies receive or transmit 79 | * **dataformat** number of bits in each sample 80 | * **channelformat** specifies audio format, e.g. stereo, mono 81 | * **samplerate** audio sampling rate (samples/s) 82 | * **dmacount** number of linked DMA buffers (optional) 83 | * **dmalen** length of each DMA buffer (in samples) (optional) 84 | * **apllrate** audio PLL sampling rate (samples/s) (optional) 85 | 86 | Notes: 87 | * **sdin** must be specified for mode = I2S.MASTER_RX 88 | * **sdout** must be specified for mode = I2S.MASTER_TX 89 | * only **one** of **sdin** or **sdout** can be specified 90 | * **apllrate** allows precise specification of the sampling clock rate. **Not needed** for most audio applications. See ESP-IDF docs for usage 91 | 92 | ## Methods 93 | ``` 94 | I2S.init(bck, ...) 95 | ``` 96 | Initialize the I2S peripheral with the given arguments: 97 | * see Constructor for argument descriptions 98 | 99 | *** 100 | ``` 101 | I2S.deinit() 102 | ``` 103 | 104 | Deinitialize the I2S peripheral 105 | 106 | *** 107 | ``` 108 | I2S.readinto(buf, [timeout = -1]) 109 | ``` 110 | 111 | Read audio samples from an I2S peripheral with the given arguments: 112 | 113 | * **buf** receive buffer. Must support buffer protocol, such as bytearray or array 114 | * **timeout** maximum time to wait for a DMA buffer (in ms). 115 | If no DMA buffer is available in **timeout** ms the method will return. Default = wait forever to fill buf. When timeout=0 the method will return ***immediately*** if there is no data in DMA memory to copy into the supplied buffer. Timeout=0 can be used to create a non-blocking I2S application with uasyncio. This is shown in the [example code](examples). See discussion below on *Understanding the timeout argument* 116 | 117 | Notes: 118 | * method blocks until buf is *completely* filled from DMA memory, unless timeout is specified 119 | * The DMA engine works in the background, filling DMA buffers with audio samples read from the I2S peripheral. The MicroPython runtime is not impacted by this DMA operation. 120 | 121 | **Returns** number of bytes read 122 | 123 | *** 124 | ``` 125 | I2S.write(buf, [timeout = -1]) 126 | ``` 127 | Write audio samples to an I2S peripheral with the given arguments: 128 | 129 | * **buf** transmit buffer. Must support buffer protocol, such as bytearray or array 130 | * **timeout** maximum time to wait for a DMA buffer (in ms). If no DMA buffer is available in **timeout** ms the function will return. Default = wait forever to write buf. When timeout=0 the method will return ***immediately*** if there is no free DMA memory to copy the transmit buffer. Timeout=0 can be used to create a non-blocking I2S application with uasyncio. This is shown in the [example code](examples). See discussion below on *Understanding the timeout argument* 131 | 132 | Notes: 133 | * method blocks until buf is *completely* copied to DMA memory, unless timeout is specified 134 | * The DMA engine works in the background, transfering audio samples from DMA buffers to the I2S peripheral. The MicroPython runtime is not impacted by this DMA operation. 135 | 136 | **Returns** number of bytes written 137 | *** 138 | 139 | ## Constants 140 | 141 | **id** of I2S peripheral 142 | 143 | ``` 144 | I2S.NUM0, I2S.NUM1 145 | ``` 146 | *** 147 | 148 | **standard** of I2S peripheral 149 | 150 | ``` 151 | I2S.PHILIPS, I2S.LSB 152 | ``` 153 | *** 154 | 155 | **mode** of I2S peripheral 156 | 157 | ``` 158 | I2S.MASTER_RX, I2S.MASTER_TX 159 | ``` 160 | *** 161 | 162 | **dataformat** of I2S peripheral 163 | 164 | ``` 165 | I2S.B16, I2S.B24, I2S.B32 166 | ``` 167 | *** 168 | 169 | **channelformat** of I2S peripheral 170 | 171 | ``` 172 | I2S.RIGHT_LEFT, I2S.ALL_RIGHT, I2S.ALL_LEFT, I2S.ONLY_RIGHT, I2S.ONLY_LEFT, 173 | ``` 174 | See section below "Understanding Channel Format" 175 | *** 176 | 177 | ### ESP32 Development Boards Tested 178 | * Adafruit Huzzah Feather ESP32 with external SD card 179 | * Lolin D32 Pro 180 | * Lolin D32 with external SD card 181 | 182 | ### I2S Microphone Boards Tested 183 | * INMP441 microphone module available on ebay, aliexpress, amazon 184 | * MSM261S4030H0 microphone module available on ebay, aliexpress, amazon 185 | * Adafruit I2S MEMS Microphone Breakout - SPH0645LM4H. **This board is NOT recommended**. The SPH0645LM4H chip implements non-standard Philips I2S timing. When used with the ESP32, all audio samples coming from the I2S microphone are shifted to the left by one bit. This increases the sound level by 6dB. More details on this problem are outlined a [StreetSense project log](https://hackaday.io/project/162059-street-sense/log/160705-new-i2s-microphone). It is unfortunate that the chip manufacturer failed to follow the de-facto [Philips I2S bus specification](https://web.archive.org/web/20070102004400/http://www.nxp.com/acrobat_download/various/I2SBUS.pdf). 186 | 187 | ### I2S DAC and Amplifier Boards Tested 188 | * Adafruit I2S 3W Class D Amplifier Breakout - MAX98357A 189 | * I2S PCM5102 Stereo DAC Decoder available on ebay, aliexpress, amazon 190 | * Wondom 2 x 30W Class D Audio Amplifier Board & DAC, based on TI TAS5756 device 191 | 192 | ### Pre-built Firmware Binaries 193 | Pre-built firmware binaries that support I2S are available in the [firmware folder](firmware). Binaries are provided for the regular ESP32 module and the enhanced ESP32 module with external PSRAM. 194 | 195 | ### DMA considerations 196 | The ESP32 uses [DMA](https://en.wikipedia.org/wiki/Direct_memory_access) to transfer data between a MicroPython application and an I2S hardware peripheral. DMA memory is implemented as a linked-list of DMA buffers and is specified by the two constructor arguments `dmacount` and `dmalen`. 197 | 198 | DMA runs continuously in the background and allows user applications to perform other operations while sample data is transfered between DMA memory and the I2S hardware. In general, more DMA memory = more time that user applications can operate before DMA "undderruns" or "overruns" happen. 199 | 200 | **DMA memory allocation** 201 | 202 | DMA memory is allocated by the ESP32 when either the I2S constructor or the init() method is called. The following formula provides a close approximation to the total amount of DMA memory allocated (in bytes) 203 | 204 | * DMA memory allocation = `dmacount * dmalen * # bytes/sample * # channels` bytes 205 | 206 | **Understanding DMA buffer size** 207 | 208 | size of each DMA buffer = `dmalen * # bytes/sample * # channels` bytes 209 | 210 | where `# channels` refers to mono versus stereo operation: 211 | * mono = 1 channel, (channelformat=ONLY_RIGHT, ONLY_LEFT) 212 | * stereo = 2 channels, (channelformat=RIGHT_LEFT, ALL_RIGHT, or ALL_LEFT) 213 | 214 | example: dmalen=128, dataformat=I2S.B32, channelformat=RIGHT_LEFT (e.g. stereo) 215 | * DMA buffer size= 128 \* 4 \* 2 = 1024 bytes 216 | 217 | **Sizing 'buf' for readinto() method**: For efficient use of DMA memory, the sizeof `buf` should be an *integer multiple* of the DMA buffer size. For example, with a DMA buffer size = 2000, a good size for buf could be 4000 bytes. Larger `buf` sizes can be advantageous when writing samples to internal flash memory or external SD cards. A larger `buf` will permit a continuous bulk write to memory, which is more efficient than multiple small block writes. 218 | 219 | **Sizing 'buf' for write() method**: Similar to the read method, the sizeof `buf` should ideally be an integer multiple of the DMA buffer size. For a *simple* design using the `timeout` argument, the sizeof `buf` can be equal to the sizeof the DMA buffer. Why? The entire contents of `buf` can be written to a DMA memory buffer with one call to the write method - this approach avoids possible design complications of dealing with residual samples remaining in `buf`. 220 | 221 | ### Understanding the timeout argument 222 | The optional `timeout` argument in the readinto and write methods specifies the maximum amount of time (in ms) that these method calls wait for a DMA buffer to become available. If `timeout = 0` is specified, then the readinto and write methods will return "immediately" (measured ~125us) when: 223 | * no DMA buffer is available with data to read (readinto method) 224 | * no DMA buffer is available to be filled (write method) 225 | 226 | The `timeout=0` setting allows application code to effectively poll DMA memory and then perform other operations when all DMA buffers are empty (readinto method) or full (write method). 227 | 228 | ### Understanding the Channel Format argument 229 | The `channelformat` constructor argument determines how sample data is mapped to the sdin, sdout, and bck I2S signals. The relationships can be understood through example, showing oscilloscope captures of the relevant I2S signals. 230 | 231 | The following oscilloscope captures use data contained in the following WAV file: 232 | 233 | ../wav_files/pattern-16k-32bits.wav 234 | 235 | The first sample starts at byte 44 (00 00 00 FF). WAV data is little endian format. In the images below, the sample values are indicated below the SDOUT signal (e.g, "0xFF 00 00 00", etc). 236 | 237 | **channelformat = RIGHT_LEFT** 238 | 239 | Example: output stereo audio data to an I2S DAC device that supports 2 channels (stereo) 240 | 241 | ![RIGHT_LEFT](images/RIGHT_LEFT.PNG) 242 | 243 | **channelformat = ALL_LEFT** 244 | 245 | Example: output Left channel stereo audio data to an I2S DAC device that supports 1 channel 246 | 247 | ![ALL_LEFT](images/ALL_LEFT.PNG) 248 | 249 | **channelformat = ALL_RIGHT** 250 | 251 | Example: output Right channel stereo audio data to an I2S DAC device that supports 1 channel 252 | 253 | ![ALL_RIGHT](images/ALL_RIGHT.PNG) 254 | 255 | **channelformat = ONLY_LEFT or ONLY_RIGHT** 256 | 257 | Example: output audio data to an I2S DAC device that supports 1 channel 258 | 259 | ![ONLY_LEFT](images/ONLY_LEFT.PNG) 260 | 261 | ### MicroPython examples 262 | MicroPython example code is contained in the [examples](examples) folder. WAV files used in the examples are contained in the [wav_files](wav_files) folder. These examples have been tested with all [pre-built firmware binary files](firmware). 263 | #### Example 1. Play stereo WAV file stored internal flash 264 | MicroPython code: 265 | * play-stereo-wav-from-internal-flash.py 266 | 267 | WAV file used in the example (copy to file system using rshell, ampy, etc): 268 | * side-to-side-8k-16bits-stereo.wav 269 | 270 | 271 | #### Example 2. Play mono WAV file stored in SD card 272 | MicroPython code: 273 | * play-mono-wav-from-sdcard.py 274 | 275 | WAV files used in the example code (copy to the SD card) 276 | * taunt-16k-16bits-mono.wav 277 | * taunt-16k-16bits-mono-12db.wav (-12db version) 278 | 279 | #### Example 3. Record 16 bit audio to SD card WAV file 280 | MicroPython code: 281 | * record-mono-mic-to-sdcard.py 282 | 283 | Note: I2S microphones often have 24 bits of resolution. In practice, using only 16 bits of audio data (throwing out the lower 8 bits) is adequate resolution for audio applications. [https://www.mojo-audio.com/blog/the-24bit-delusion/](https://www.mojo-audio.com/blog/the-24bit-delusion/) 284 | 285 | #### Example 4. Uasyncio example: Play mono WAV file stored in SD card 286 | MicroPython code: 287 | * play-mono-wav-from-sdcard-uasyncio.py 288 | 289 | WAV files used in the example code (copy to the SD card) 290 | * taunt-16k-16bits-mono.wav 291 | * taunt-16k-16bits-mono-12db.wav (-12db version) 292 | 293 | Notes: 294 | * uasyncio V3 is used 295 | * all co-routines are not shutdown when a ctrl-C is performed. A board reset will be needed. 296 | 297 | #### Example 5. Record 16 bit audio to internal flash WAV file 298 | MicroPython code: 299 | * record-mono-mic-to-internal-flash.py 300 | 301 | Note: I2S microphones often have 24 bits of resolution. In practice, using only 16 bits of audio data (throwing out the lower 8 bits) is adequate resolution for audio applications. [https://www.mojo-audio.com/blog/the-24bit-delusion/](https://www.mojo-audio.com/blog/the-24bit-delusion/) 302 | 303 | ### Hardware Test Setup 304 | [Pre-built firmware binaries](firmware) and [example MicroPython code](examples) were tested on the hardware fixtures shown in the photos below. The ESP32 pin mappings used in the hardware board are shown in the following table. The SD card is mapped to 4 pins (CS: pin4, SCK: pin18, MISO: pin19, MOSI: pin23). The first photo shows the Lolin D32 Pro board which has an integrated SD card. The second photo shows a Lolin D32 board with an external SD card module added using jumpers. 305 | 306 | |GPIO pin|I2S device|I2S pin name| 307 | |--|--|--| 308 | |0||| 309 | |2||| 310 | |4||| 311 | |5||| 312 | |12||| 313 | |13|INMP441 microphone|BCK| 314 | |14|INMP441 microphone|WS| 315 | |15|MSM261S4030H0 microphone|BCK| 316 | |18||| 317 | |19||| 318 | |21|MAX98357A 3W amplifier|BCK| 319 | |22|MAX98357A 3W amplifier|WS| 320 | |23||| 321 | |25|PCM5102 stereo DAC|WS| 322 | |26|MSM261S4030H0 microphone|WS| 323 | |27|MAX98357A 3W amplifier|Dout| 324 | |32|PCM5102 stereo DAC|Dout| 325 | |33|PCM5102 stereo DAC|BCK| 326 | |34|INMP441 microphone|Din| 327 | |36/VP|MSM261S4030H0 microphone|Din| 328 | |39/VN||| 329 | 330 | Test board using Lolin D32 Pro development board 331 | ![I2S Test Fixture - Lolin D32 Pro (SPIRAM version)](images/test-fixture.JPG) 332 | 333 | Test board using Lolin D32 development board with external SD card module 334 | ![I2S Test Fixture - Lolin D32 with external SD card](images/test-fixture-sdcard.JPG) 335 | 336 | ### Troubleshooting 337 | #### Problem: Microphone recording has no sound 338 | Possible cause: `channelformat` is reversed. This problem might be due to an I2S bug fix that Espressif made in July 2019. Espressif swapped the I2S left-right channel orientation in ESP-IDF v3.3.1 in July 2019. The MicroPython mainline switched to ESP-IDF v3.3.1 on Jan 14, 2020. All I2S examples in the repository are based on having the bug fix in place. If your MicroPython firmware was created before Jan 14, 2020 and you are using the most recent examples, then the `channelformat` argument in the constructor will be reversed. Most I2S mono microphone boards are configured to output samples on the Left channel. For firmware created before Jan 14, 2020 `channelformat=I2S.ONLY_RIGHT`. For firmware created after Jan 14, 2020 `channelformat=I2S.ONLY_LEFT`. 339 | 340 | [Espressif Issue #3399](https://github.com/espressif/esp-idf/commit/ff325e84b65e88547ed5508ae1de82232f2d8f43) 341 | 342 | MicroPython pulled in this ESP-IDF v3.3.1 release on Jan 14, 2020. 343 | [commit: 3032ae1155db4bd89786f715f5227967d2cb71cf](https://github.com/micropython/micropython/commit/3032ae1155db4bd89786f715f5227967d2cb71cf) 344 | 345 | 346 | 347 | ### Future development of I2S on MicroPython 348 | The initial I2S class offers basic capabilities to implement many audio I2S applications. Here is a wishlist for future development: 349 | * integrate the I2S implementation into mainstream MicroPython 350 | * Pyboard (stm32) implementation (**in progress as of May 2020**) 351 | * full duplex 352 | * slave mode 353 | * non-blocking read and write with callback on completion 354 | * uasyncio implementation 355 | * stream protocol implementation 356 | * exposing I2S events to detect gaps in the sample stream. e.g. underrun (Master Tx) and overrun (Master Rx) in DMA buffering 357 | -------------------------------------------------------------------------------- /examples/play-mono-wav-from-sdcard-uasyncio.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2020 Mike Teachman 3 | # https://opensource.org/licenses/MIT 4 | 5 | # Purpose: 6 | # - read 16-bit audio samples from a mono formatted WAV file on SD card 7 | # - write audio samples to an I2S amplifier or DAC module 8 | # 9 | # Uasyncio: 10 | # - two co-routines are demonstrated 11 | # - play the WAV file 12 | # - write text to the REPL 13 | # - Uasyncio version >= 3 is needed for this example 14 | # 15 | # Sample WAV files in wav_files folder: 16 | # "taunt-16k-16bits-mono.wav" 17 | # "taunt-16k-16bits-mono-12db.wav" (lower volume version) 18 | # 19 | # Hardware tested: 20 | # - MAX98357A amplifier module (Adafruit I2S 3W Class D Amplifier Breakout) 21 | # - PCM5102 stereo DAC module 22 | # 23 | # The WAV file will play continuously until a keyboard interrupt is detected or 24 | # the ESP32 is reset 25 | 26 | from machine import I2S 27 | from machine import SDCard 28 | from machine import Pin 29 | import uasyncio as asyncio 30 | 31 | if (asyncio.__version__)[0] < 3: 32 | raise ImportError ('example requires uasyncio verion >= 3') 33 | 34 | #======= USER CONFIGURATION ======= 35 | WAV_FILE = 'taunt-16k-16bits-mono-12db.wav' 36 | SAMPLE_RATE_IN_HZ = 16000 37 | #======= USER CONFIGURATION ======= 38 | 39 | async def play_wav(): 40 | bck_pin = Pin(21) 41 | ws_pin = Pin(22) 42 | sdout_pin = Pin(27) 43 | 44 | # channelformat settings: 45 | # mono WAV: channelformat=I2S.ONLY_LEFT 46 | audio_out = I2S( 47 | I2S.NUM0, 48 | bck=bck_pin, ws=ws_pin, sdout=sdout_pin, 49 | standard=I2S.PHILIPS, 50 | mode=I2S.MASTER_TX, 51 | dataformat=I2S.B16, 52 | channelformat=I2S.ONLY_LEFT, 53 | samplerate=SAMPLE_RATE_IN_HZ, 54 | dmacount=10, dmalen=512) 55 | 56 | # configure SD card: 57 | # See [docs](https://docs.micropython.org/en/latest/library/machine.SDCard.html#esp32) for 58 | # recommended pins depending on the chosen slot. 59 | # slot=2 configures SD card to use the SPI3 controller (VSPI), DMA channel = 2 60 | # slot=3 configures SD card to use the SPI2 controller (HSPI), DMA channel = 1 61 | sd = SDCard(slot=2, sck=Pin(18), mosi=Pin(23), miso=Pin(19), cs=Pin(5)) 62 | uos.mount(sd, "/sd") 63 | wav_file = '/sd/{}'.format(WAV_FILE) 64 | wav = open(wav_file,'rb') 65 | 66 | # advance to first byte of Data section in WAV file 67 | pos = wav.seek(44) 68 | 69 | # allocate sample arrays 70 | # memoryview used to reduce heap allocation in while loop 71 | wav_samples = bytearray(1024) 72 | wav_samples_mv = memoryview(wav_samples) 73 | 74 | print('Starting ... ') 75 | # continuously read audio samples from the WAV file 76 | # and write them to an I2S DAC 77 | 78 | try: 79 | while True: 80 | num_read = wav.readinto(wav_samples_mv) 81 | num_written = 0 82 | # end of WAV file? 83 | if num_read == 0: 84 | # advance to first byte of Data section 85 | pos = wav.seek(44) 86 | else: 87 | # loop until all samples are written to the I2S peripheral 88 | while num_written < num_read: 89 | num_written += audio_out.write(wav_samples_mv[num_written:num_read], timeout=0) 90 | await asyncio.sleep_ms(10) 91 | except (KeyboardInterrupt, Exception) as e: 92 | print('caught exception {} {}'.format(type(e).__name__, e)) 93 | raise 94 | finally: 95 | wav.close() 96 | uos.umount("/sd") 97 | sd.deinit() 98 | audio_out.deinit() 99 | print('Done') 100 | 101 | async def another_coro(): 102 | i = 0 103 | while True: 104 | print(i) 105 | i+=1 106 | await asyncio.sleep(1) 107 | 108 | async def main(): 109 | play_wav_task = asyncio.create_task(play_wav()) 110 | another_task = asyncio.create_task(another_coro()) 111 | while True: 112 | await asyncio.sleep(1) 113 | 114 | asyncio.run(main()) 115 | -------------------------------------------------------------------------------- /examples/play-mono-wav-from-sdcard.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2020 Mike Teachman 3 | # https://opensource.org/licenses/MIT 4 | 5 | # Purpose: 6 | # - read 16-bit audio samples from a mono formatted WAV file on SD card 7 | # - write audio samples to an I2S amplifier or DAC module 8 | # 9 | # Sample WAV files in wav_files folder: 10 | # "taunt-16k-16bits-mono.wav" 11 | # "taunt-16k-16bits-mono-12db.wav" (lower volume version) 12 | # 13 | # Hardware tested: 14 | # - MAX98357A amplifier module (Adafruit I2S 3W Class D Amplifier Breakout) 15 | # - PCM5102 stereo DAC module 16 | # 17 | # The WAV file will play continuously until a keyboard interrupt is detected or 18 | # the ESP32 is reset 19 | 20 | from machine import I2S 21 | from machine import SDCard 22 | from machine import Pin 23 | 24 | #======= USER CONFIGURATION ======= 25 | WAV_FILE = 'taunt-16k-16bits-mono-12db.wav' 26 | SAMPLE_RATE_IN_HZ = 16000 27 | #======= USER CONFIGURATION ======= 28 | 29 | bck_pin = Pin(21) 30 | ws_pin = Pin(22) 31 | sdout_pin = Pin(27) 32 | 33 | # channelformat settings: 34 | # mono WAV: channelformat=I2S.ONLY_LEFT 35 | audio_out = I2S( 36 | I2S.NUM0, 37 | bck=bck_pin, ws=ws_pin, sdout=sdout_pin, 38 | standard=I2S.PHILIPS, 39 | mode=I2S.MASTER_TX, 40 | dataformat=I2S.B16, 41 | channelformat=I2S.ONLY_LEFT, 42 | samplerate=SAMPLE_RATE_IN_HZ, 43 | dmacount=10, dmalen=512) 44 | 45 | # configure SD card: 46 | # See [docs](https://docs.micropython.org/en/latest/library/machine.SDCard.html#esp32) for 47 | # recommended pins depending on the chosen slot. 48 | # slot=2 configures SD card to use the SPI3 controller (VSPI), DMA channel = 2 49 | # slot=3 configures SD card to use the SPI2 controller (HSPI), DMA channel = 1 50 | sd = SDCard(slot=2, sck=Pin(18), mosi=Pin(23), miso=Pin(19), cs=Pin(5)) 51 | uos.mount(sd, "/sd") 52 | wav_file = '/sd/{}'.format(WAV_FILE) 53 | wav = open(wav_file,'rb') 54 | 55 | # advance to first byte of Data section in WAV file 56 | pos = wav.seek(44) 57 | 58 | # allocate sample arrays 59 | # memoryview used to reduce heap allocation in while loop 60 | wav_samples = bytearray(1024) 61 | wav_samples_mv = memoryview(wav_samples) 62 | 63 | print('Starting') 64 | # continuously read audio samples from the WAV file 65 | # and write them to an I2S DAC 66 | while True: 67 | try: 68 | num_read = wav.readinto(wav_samples_mv) 69 | num_written = 0 70 | # end of WAV file? 71 | if num_read == 0: 72 | # advance to first byte of Data section 73 | pos = wav.seek(44) 74 | else: 75 | # loop until all samples are written to the I2S peripheral 76 | while num_written < num_read: 77 | num_written += audio_out.write(wav_samples_mv[num_written:num_read], timeout=0) 78 | except (KeyboardInterrupt, Exception) as e: 79 | print('caught exception {} {}'.format(type(e).__name__, e)) 80 | break 81 | 82 | wav.close() 83 | uos.umount("/sd") 84 | sd.deinit() 85 | audio_out.deinit() 86 | print('Done') -------------------------------------------------------------------------------- /examples/play-stereo-wav-from-internal-flash.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2020 Mike Teachman 3 | # https://opensource.org/licenses/MIT 4 | 5 | # Purpose: 6 | # - read 16-bit audio samples from a stereo formatted WAV file 7 | # stored in the internal MicroPython filesystem 8 | # - write audio samples to an I2S amplifier or DAC module 9 | # 10 | # Sample WAV file in wav_files folder: 11 | # "side-to-side-8k-16bits-stereo.wav" 12 | # 13 | # Hardware tested: 14 | # - PCM5102 stereo DAC module 15 | # 16 | # The WAV file will play continuously until a keyboard interrupt is detected or 17 | # the ESP32 is reset 18 | 19 | from machine import I2S 20 | from machine import Pin 21 | 22 | #======= USER CONFIGURATION ======= 23 | WAV_FILE = 'side-to-side-8k-16bits-stereo.wav' 24 | SAMPLE_RATE_IN_HZ = 8000 25 | #======= USER CONFIGURATION ======= 26 | 27 | bck_pin = Pin(33) 28 | ws_pin = Pin(25) 29 | sdout_pin = Pin(32) 30 | 31 | # channelformat setting: 32 | # stereo WAV: channelformat=I2S.RIGHT_LEFT 33 | audio_out = I2S( 34 | I2S.NUM1, 35 | bck=bck_pin, ws=ws_pin, sdout=sdout_pin, 36 | standard=I2S.PHILIPS, 37 | mode=I2S.MASTER_TX, 38 | dataformat=I2S.B16, 39 | channelformat=I2S.RIGHT_LEFT, 40 | samplerate=SAMPLE_RATE_IN_HZ, 41 | dmacount=10, dmalen=512) 42 | 43 | wav = open(WAV_FILE,'rb') 44 | 45 | # advance to first byte of Data section in WAV file 46 | pos = wav.seek(44) 47 | 48 | # allocate sample arrays 49 | # memoryview used to reduce heap allocation in while loop 50 | wav_samples = bytearray(2048) 51 | wav_samples_mv = memoryview(wav_samples) 52 | 53 | print('Starting') 54 | # continuously read audio samples from the WAV file 55 | # and write them to an I2S DAC 56 | while True: 57 | try: 58 | num_read = wav.readinto(wav_samples_mv) 59 | num_written = 0 60 | # end of WAV file? 61 | if num_read == 0: 62 | # advance to first byte of Data section 63 | pos = wav.seek(44) 64 | else: 65 | # loop until all samples are written to the I2S peripheral 66 | while num_written < num_read: 67 | num_written += audio_out.write(wav_samples_mv[num_written:num_read], timeout=0) 68 | except (KeyboardInterrupt, Exception) as e: 69 | print('caught exception {} {}'.format(type(e).__name__, e)) 70 | break 71 | 72 | wav.close() 73 | audio_out.deinit() 74 | print('Done') -------------------------------------------------------------------------------- /examples/record-mono-mic-to-internal-flash.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2019 Michael Shi 3 | # Copyright (c) 2020 Mike Teachman 4 | # https://opensource.org/licenses/MIT 5 | 6 | # Purpose: 7 | # - read 32-bit audio samples from the left channel of an I2S microphone 8 | # - snip upper 16-bits from each 32-bit microphone sample 9 | # - write 16-bit samples to an internal flash file using WAV format 10 | # 11 | # Recorded WAV file is named: 12 | # "mic_left_channel_16bits.wav" 13 | # 14 | # Hardware tested: 15 | # - INMP441 microphone module 16 | # - MSM261S4030H0 microphone module 17 | # 18 | # Notes: 19 | # - writing audio sample data to internal flash is slow. Gapless recordings require low sample rates (e.g. 8000 samples/second) 20 | # - reading WAV files from internal flash to a PC: 21 | # - for short WAV files the AMPY tool can be used (e.g. 2 seconds @ 8000/samples). Ampy throws an exception for long files 22 | # - for longer WAV files use the "Get a file" feature of the WebREPL. 23 | 24 | from machine import Pin 25 | from machine import I2S 26 | 27 | #======= USER CONFIGURATION ======= 28 | RECORD_TIME_IN_SECONDS = 5 29 | SAMPLE_RATE_IN_HZ = 8000 30 | #======= USER CONFIGURATION ======= 31 | 32 | WAV_SAMPLE_SIZE_IN_BITS = 16 33 | WAV_SAMPLE_SIZE_IN_BYTES = WAV_SAMPLE_SIZE_IN_BITS // 8 34 | MIC_SAMPLE_BUFFER_SIZE_IN_BYTES = 4096 35 | SDCARD_SAMPLE_BUFFER_SIZE_IN_BYTES = MIC_SAMPLE_BUFFER_SIZE_IN_BYTES // 2 # why divide by 2? only using 16-bits of 32-bit samples 36 | NUM_SAMPLE_BYTES_TO_WRITE = RECORD_TIME_IN_SECONDS * SAMPLE_RATE_IN_HZ * WAV_SAMPLE_SIZE_IN_BYTES 37 | NUM_SAMPLES_IN_DMA_BUFFER = 256 38 | NUM_CHANNELS = 1 39 | 40 | # snip_16_mono(): snip 16-bit samples from a 32-bit mono sample stream 41 | # assumption: I2S configuration for mono microphone. e.g. I2S channelformat = ONLY_LEFT or ONLY_RIGHT 42 | # example snip: 43 | # samples_in[] = [0x44, 0x55, 0xAB, 0x77, 0x99, 0xBB, 0x11, 0x22] 44 | # samples_out[] = [0xAB, 0x77, 0x11, 0x22] 45 | # notes: 46 | # samples_in[] arranged in little endian format: 47 | # 0x77 is the most significant byte of the 32-bit sample 48 | # 0x44 is the least significant byte of the 32-bit sample 49 | # 50 | # returns: number of bytes snipped 51 | def snip_16_mono(samples_in, samples_out): 52 | num_samples = len(samples_in) // 4 53 | for i in range(num_samples): 54 | samples_out[2*i] = samples_in[4*i + 2] 55 | samples_out[2*i + 1] = samples_in[4*i + 3] 56 | 57 | return num_samples * 2 58 | 59 | def create_wav_header(sampleRate, bitsPerSample, num_channels, num_samples): 60 | datasize = num_samples * num_channels * bitsPerSample // 8 61 | o = bytes("RIFF",'ascii') # (4byte) Marks file as RIFF 62 | o += (datasize + 36).to_bytes(4,'little') # (4byte) File size in bytes excluding this and RIFF marker 63 | o += bytes("WAVE",'ascii') # (4byte) File type 64 | o += bytes("fmt ",'ascii') # (4byte) Format Chunk Marker 65 | o += (16).to_bytes(4,'little') # (4byte) Length of above format data 66 | o += (1).to_bytes(2,'little') # (2byte) Format type (1 - PCM) 67 | o += (num_channels).to_bytes(2,'little') # (2byte) 68 | o += (sampleRate).to_bytes(4,'little') # (4byte) 69 | o += (sampleRate * num_channels * bitsPerSample // 8).to_bytes(4,'little') # (4byte) 70 | o += (num_channels * bitsPerSample // 8).to_bytes(2,'little') # (2byte) 71 | o += (bitsPerSample).to_bytes(2,'little') # (2byte) 72 | o += bytes("data",'ascii') # (4byte) Data Chunk Marker 73 | o += (datasize).to_bytes(4,'little') # (4byte) Data size in bytes 74 | return o 75 | 76 | bck_pin = Pin(33) 77 | ws_pin = Pin(32) 78 | sdin_pin = Pin(14) 79 | 80 | audio_in = I2S( 81 | I2S.NUM0, 82 | bck=bck_pin, ws=ws_pin, sdin=sdin_pin, 83 | standard=I2S.PHILIPS, 84 | mode=I2S.MASTER_RX, 85 | dataformat=I2S.B32, 86 | channelformat=I2S.ONLY_LEFT, 87 | samplerate=SAMPLE_RATE_IN_HZ, 88 | dmacount=50, 89 | dmalen=NUM_SAMPLES_IN_DMA_BUFFER 90 | ) 91 | 92 | wav = open('mic_left_channel_16bits.wav','wb') 93 | 94 | # create header for WAV file and write to SD card 95 | wav_header = create_wav_header( 96 | SAMPLE_RATE_IN_HZ, 97 | WAV_SAMPLE_SIZE_IN_BITS, 98 | NUM_CHANNELS, 99 | SAMPLE_RATE_IN_HZ * RECORD_TIME_IN_SECONDS 100 | ) 101 | num_bytes_written = wav.write(wav_header) 102 | 103 | # allocate sample arrays 104 | # memoryview used to reduce heap allocation in while loop 105 | mic_samples = bytearray(MIC_SAMPLE_BUFFER_SIZE_IN_BYTES) 106 | mic_samples_mv = memoryview(mic_samples) 107 | wav_samples = bytearray(SDCARD_SAMPLE_BUFFER_SIZE_IN_BYTES) 108 | wav_samples_mv = memoryview(wav_samples) 109 | 110 | num_sample_bytes_written_to_wav = 0 111 | 112 | print('Starting') 113 | # read 32-bit samples from I2S microphone, snip upper 16-bits, write snipped samples to WAV file 114 | while num_sample_bytes_written_to_wav < NUM_SAMPLE_BYTES_TO_WRITE: 115 | try: 116 | # try to read a block of samples from the I2S microphone 117 | # readinto() method returns 0 if no DMA buffer is full 118 | num_bytes_read_from_mic = audio_in.readinto(mic_samples_mv, timeout=0) 119 | if num_bytes_read_from_mic > 0: 120 | # snip upper 16-bits from each 32-bit microphone sample 121 | num_bytes_snipped = snip_16_mono(mic_samples_mv[:num_bytes_read_from_mic], wav_samples_mv) 122 | num_bytes_to_write = min(num_bytes_snipped, NUM_SAMPLE_BYTES_TO_WRITE - num_sample_bytes_written_to_wav) 123 | # write samples to WAV file 124 | num_bytes_written = wav.write(wav_samples_mv[:num_bytes_to_write]) 125 | num_sample_bytes_written_to_wav += num_bytes_written 126 | except (KeyboardInterrupt, Exception) as e: 127 | print('caught exception {} {}'.format(type(e).__name__, e)) 128 | break 129 | 130 | wav.close() 131 | audio_in.deinit() 132 | print('Done') 133 | print('%d sample bytes written to WAV file' % num_sample_bytes_written_to_wav) -------------------------------------------------------------------------------- /examples/record-mono-mic-to-sdcard.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2019 Michael Shi 3 | # Copyright (c) 2020 Mike Teachman 4 | # https://opensource.org/licenses/MIT 5 | 6 | # Purpose: 7 | # - read 32-bit audio samples from the left channel of an I2S microphone 8 | # - snip upper 16-bits from each 32-bit microphone sample 9 | # - write 16-bit samples to a SD card file using WAV format 10 | # 11 | # Recorded WAV file is named: 12 | # "mic_left_channel_16bits.wav" 13 | # 14 | # Hardware tested: 15 | # - INMP441 microphone module 16 | # - MSM261S4030H0 microphone module 17 | 18 | import uos 19 | from machine import Pin 20 | from machine import SDCard 21 | from machine import I2S 22 | 23 | #======= USER CONFIGURATION ======= 24 | RECORD_TIME_IN_SECONDS = 5 25 | SAMPLE_RATE_IN_HZ = 22050 26 | #======= USER CONFIGURATION ======= 27 | 28 | WAV_SAMPLE_SIZE_IN_BITS = 16 29 | WAV_SAMPLE_SIZE_IN_BYTES = WAV_SAMPLE_SIZE_IN_BITS // 8 30 | MIC_SAMPLE_BUFFER_SIZE_IN_BYTES = 4096 31 | SDCARD_SAMPLE_BUFFER_SIZE_IN_BYTES = MIC_SAMPLE_BUFFER_SIZE_IN_BYTES // 2 # why divide by 2? only using 16-bits of 32-bit samples 32 | NUM_SAMPLE_BYTES_TO_WRITE = RECORD_TIME_IN_SECONDS * SAMPLE_RATE_IN_HZ * WAV_SAMPLE_SIZE_IN_BYTES 33 | NUM_SAMPLES_IN_DMA_BUFFER = 256 34 | NUM_CHANNELS = 1 35 | 36 | # snip_16_mono(): snip 16-bit samples from a 32-bit mono sample stream 37 | # assumption: I2S configuration for mono microphone. e.g. I2S channelformat = ONLY_LEFT or ONLY_RIGHT 38 | # example snip: 39 | # samples_in[] = [0x44, 0x55, 0xAB, 0x77, 0x99, 0xBB, 0x11, 0x22] 40 | # samples_out[] = [0xAB, 0x77, 0x11, 0x22] 41 | # notes: 42 | # samples_in[] arranged in little endian format: 43 | # 0x77 is the most significant byte of the 32-bit sample 44 | # 0x44 is the least significant byte of the 32-bit sample 45 | # 46 | # returns: number of bytes snipped 47 | def snip_16_mono(samples_in, samples_out): 48 | num_samples = len(samples_in) // 4 49 | for i in range(num_samples): 50 | samples_out[2*i] = samples_in[4*i + 2] 51 | samples_out[2*i + 1] = samples_in[4*i + 3] 52 | 53 | return num_samples * 2 54 | 55 | def create_wav_header(sampleRate, bitsPerSample, num_channels, num_samples): 56 | datasize = num_samples * num_channels * bitsPerSample // 8 57 | o = bytes("RIFF",'ascii') # (4byte) Marks file as RIFF 58 | o += (datasize + 36).to_bytes(4,'little') # (4byte) File size in bytes excluding this and RIFF marker 59 | o += bytes("WAVE",'ascii') # (4byte) File type 60 | o += bytes("fmt ",'ascii') # (4byte) Format Chunk Marker 61 | o += (16).to_bytes(4,'little') # (4byte) Length of above format data 62 | o += (1).to_bytes(2,'little') # (2byte) Format type (1 - PCM) 63 | o += (num_channels).to_bytes(2,'little') # (2byte) 64 | o += (sampleRate).to_bytes(4,'little') # (4byte) 65 | o += (sampleRate * num_channels * bitsPerSample // 8).to_bytes(4,'little') # (4byte) 66 | o += (num_channels * bitsPerSample // 8).to_bytes(2,'little') # (2byte) 67 | o += (bitsPerSample).to_bytes(2,'little') # (2byte) 68 | o += bytes("data",'ascii') # (4byte) Data Chunk Marker 69 | o += (datasize).to_bytes(4,'little') # (4byte) Data size in bytes 70 | return o 71 | 72 | bck_pin = Pin(13) 73 | ws_pin = Pin(14) 74 | sdin_pin = Pin(34) 75 | 76 | audio_in = I2S( 77 | I2S.NUM0, 78 | bck=bck_pin, ws=ws_pin, sdin=sdin_pin, 79 | standard=I2S.PHILIPS, 80 | mode=I2S.MASTER_RX, 81 | dataformat=I2S.B32, 82 | channelformat=I2S.ONLY_LEFT, 83 | samplerate=SAMPLE_RATE_IN_HZ, 84 | dmacount=50, 85 | dmalen=NUM_SAMPLES_IN_DMA_BUFFER 86 | ) 87 | 88 | # configure SD card: 89 | # See [docs](https://docs.micropython.org/en/latest/library/machine.SDCard.html#esp32) for 90 | # recommended pins depending on the chosen slot. 91 | # slot=2 configures SD card to use the SPI3 controller (VSPI), DMA channel = 2 92 | # slot=3 configures SD card to use the SPI2 controller (HSPI), DMA channel = 1 93 | sd = SDCard(slot=2, sck=Pin(18), mosi=Pin(23), miso=Pin(19), cs=Pin(5)) 94 | uos.mount(sd, "/sd") 95 | wav = open('/sd/mic_left_channel_16bits.wav','wb') 96 | 97 | # create header for WAV file and write to SD card 98 | wav_header = create_wav_header( 99 | SAMPLE_RATE_IN_HZ, 100 | WAV_SAMPLE_SIZE_IN_BITS, 101 | NUM_CHANNELS, 102 | SAMPLE_RATE_IN_HZ * RECORD_TIME_IN_SECONDS 103 | ) 104 | num_bytes_written = wav.write(wav_header) 105 | 106 | # allocate sample arrays 107 | # memoryview used to reduce heap allocation in while loop 108 | mic_samples = bytearray(MIC_SAMPLE_BUFFER_SIZE_IN_BYTES) 109 | mic_samples_mv = memoryview(mic_samples) 110 | wav_samples = bytearray(SDCARD_SAMPLE_BUFFER_SIZE_IN_BYTES) 111 | wav_samples_mv = memoryview(wav_samples) 112 | 113 | num_sample_bytes_written_to_wav = 0 114 | 115 | print('Starting') 116 | # read 32-bit samples from I2S microphone, snip upper 16-bits, write snipped samples to WAV file 117 | while num_sample_bytes_written_to_wav < NUM_SAMPLE_BYTES_TO_WRITE: 118 | try: 119 | # try to read a block of samples from the I2S microphone 120 | # readinto() method returns 0 if no DMA buffer is full 121 | num_bytes_read_from_mic = audio_in.readinto(mic_samples_mv, timeout=0) 122 | if num_bytes_read_from_mic > 0: 123 | # snip upper 16-bits from each 32-bit microphone sample 124 | num_bytes_snipped = snip_16_mono(mic_samples_mv[:num_bytes_read_from_mic], wav_samples_mv) 125 | num_bytes_to_write = min(num_bytes_snipped, NUM_SAMPLE_BYTES_TO_WRITE - num_sample_bytes_written_to_wav) 126 | # write samples to WAV file 127 | num_bytes_written = wav.write(wav_samples_mv[:num_bytes_to_write]) 128 | num_sample_bytes_written_to_wav += num_bytes_written 129 | except (KeyboardInterrupt, Exception) as e: 130 | print('caught exception {} {}'.format(type(e).__name__, e)) 131 | break 132 | 133 | wav.close() 134 | uos.umount("/sd") 135 | sd.deinit() 136 | audio_in.deinit() 137 | print('Done') 138 | print('%d sample bytes written to WAV file' % num_sample_bytes_written_to_wav) -------------------------------------------------------------------------------- /firmware/esp32-idf4-0-2-i2s-2021-02-27-v1-14.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/firmware/esp32-idf4-0-2-i2s-2021-02-27-v1-14.bin -------------------------------------------------------------------------------- /firmware/esp32spiram-idf4-0-2-i2s-2021-02-27-v1-14.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/firmware/esp32spiram-idf4-0-2-i2s-2021-02-27-v1-14.bin -------------------------------------------------------------------------------- /images/ALL_LEFT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/images/ALL_LEFT.PNG -------------------------------------------------------------------------------- /images/ALL_RIGHT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/images/ALL_RIGHT.PNG -------------------------------------------------------------------------------- /images/ONLY_LEFT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/images/ONLY_LEFT.PNG -------------------------------------------------------------------------------- /images/RIGHT_LEFT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/images/RIGHT_LEFT.PNG -------------------------------------------------------------------------------- /images/test-fixture-sdcard.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/images/test-fixture-sdcard.JPG -------------------------------------------------------------------------------- /images/test-fixture.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/images/test-fixture.JPG -------------------------------------------------------------------------------- /wav_files/pattern-16k-32bits.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/wav_files/pattern-16k-32bits.wav -------------------------------------------------------------------------------- /wav_files/side-to-side-8k-16bits-stereo.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/wav_files/side-to-side-8k-16bits-stereo.wav -------------------------------------------------------------------------------- /wav_files/taunt-16k-16bits-mono-12db.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/wav_files/taunt-16k-16bits-mono-12db.wav -------------------------------------------------------------------------------- /wav_files/taunt-16k-16bits-mono.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketeachman/micropython-esp32-i2s-examples/14782d5cb6f1bfd20cfbc0e22d8c071c79d1226a/wav_files/taunt-16k-16bits-mono.wav --------------------------------------------------------------------------------