Commit graph

1599 commits

Author SHA1 Message Date
cb295c57d7 MP3Decoder: Make it possible to start in the middle of an MP3
You can now, e.g.,
```
with open("/whatever.mp3") as mp3_file:
    mp3_file.seek(16000*30)
    decoder.file = mp3_file
    i2s.play(decoder)
```
to start about 30 seconds into a 128kbit/s CBR track.

If a track is looped, the loop will start at the beginning.

This also changes the behavior if the track is started & stopped: it will
continue from where it left off, except if it had prevously run to
completion. To get other behavior, you can seek the file and then re-assign
the file property.
2024-06-05 10:33:40 -05:00
6f6b680c18 MP3Decoder: improve some comments 2024-06-04 12:24:34 -05:00
f81a3aed68 MP3Decoder: avoid all blocking reads in background
This gets MP3 playback of a soma.fm stream working for up to a minute
at a time, though it's still vulnerable to network glitches.

 * the buffer can empty, in which case a single block of audio
   plays repeatedly in max headroom stutter fashion
 * the server eventually (after 1 to 5 5 minutes) stops getting packets
   at all. At this point stream playback stops, with the internal error
   indicating a problem MP3 decoding (which doesn't quite make sense):
   -9, ERR_MP3_INVALID_HUFFCODES.
 * other combinations of audiomixer buffer & mp3 buffer might give
   different results
```py
import time

import adafruit_connection_manager
import adafruit_requests
import audiobusio
import audiomixer
import audiomp3
import board
import wifi

pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)

# todo: parse PLS files like https://somafm.com/nossl/dronezone.pls
# todo: figure out why https URLs don't work at all (missing select?)
# STREAMING_URL = "http://ice2.somafm.com/dronezone-128-mp3"
STREAMING_URL = "http://ice4.somafm.com/tikitime-128-mp3"


def get_mp3_stream():
    if STREAMING_URL.startswith("http:") or STREAMING_URL.startswith("https:"):
        return requests.get(STREAMING_URL, headers={"connection": "close"}).socket
    return open(STREAMING_URL, "rb")


mixer_buffer_size = 1152 * 2
mp3_buffer = bytearray(32768)

with audiobusio.I2SOut(
    bit_clock=board.D12, word_select=board.D13, data=board.D11
) as i2s, get_mp3_stream() as stream, audiomp3.MP3Decoder(
    stream, mp3_buffer
) as sample, audiomixer.Mixer(
    channel_count=2, sample_rate=44100, buffer_size=mixer_buffer_size
) as m:

    v = m.voice[0]
    print(sample)

    i2s.play(m)

    v.play(sample, loop=False)
    while v.playing:
        time.sleep(0.1)
```
2024-06-03 15:49:14 -05:00
a5c4a86349 MP3Decoder: ssize_t type is not portable, don't use it 2024-05-30 16:45:35 -05:00
dffc55ee17 MP3Decoder: STATIC -> static 2024-05-30 14:32:48 -05:00
9bc89f5fba MP3Decoder: better handle INDATA_UNDERFLOW & MAINDATA_UNDERFLOW
This allows playback of some 128k http streams from somafm, though
glitches occur with some regularity.

```py
import time

import adafruit_connection_manager
import adafruit_requests
import audiobusio
import audiomixer
import audiomp3
import board
import wifi

pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)

# todo: parse PLS files like https://somafm.com/nossl/dronezone.pls
# todo: figure out why https URLs don't work at all (missing select?)
# STREAMING_URL = "http://ice2.somafm.com/dronezone-128-mp3"
STREAMING_URL = "http://ice4.somafm.com/tikitime-128-mp3"


def get_mp3_stream():
    if STREAMING_URL.startswith("http:") or STREAMING_URL.startswith("https:"):
        return requests.get(STREAMING_URL, headers={"connection": "close"}).socket
    return open(STREAMING_URL, "rb")


mixer_buffer_size = 1152 * 16
mp3_buffer = bytearray(16384)

with audiobusio.I2SOut(
    bit_clock=board.D12, word_select=board.D13, data=board.D11
) as i2s, get_mp3_stream() as stream, audiomp3.MP3Decoder(
    stream, mp3_buffer
) as sample, audiomixer.Mixer(
    channel_count=2, sample_rate=44100, buffer_size=mixer_buffer_size
) as m:

    v = m.voice[0]
    print(sample)

    i2s.play(m)

    v.play(sample, loop=False)
    while v.playing:
        time.sleep(0.1)
```
2024-05-30 14:22:51 -05:00
974b21a079 MP3Decoder: do better at keeping stream buffer full 2024-05-30 14:22:51 -05:00
a80311d4c0 MP3Decoder: make testable in coverage build
An mp3 decoder (note that this needs `audiocore.get_buffer`, not
enabled on devices):
```py
import sys
import audiomp3
import audiocore

GET_BUFFER_DONE, GET_BUFFER_MORE_DATA, GET_BUFFER_ERROR = range(3)

with audiomp3.MP3Decoder(sys.argv[1]) as decoder, open(sys.argv[2], "wb") as target:

    while True:
        res, samples = audiocore.get_buffer(decoder)
        if res != GET_BUFFER_ERROR:
            target.write(samples)
        if res != GET_BUFFER_MORE_DATA:
            break
```

this doesn't actually add any tests though
2024-05-30 14:22:39 -05:00
d6ddd55462 MP3Decoder: Allow passing any stream-like object
This can sort-of play MP3s from a http request, but the buffering is
not good enough to play glitch-free. A new kind of buffer that can
read ahead further without blocking is needed.
2024-05-30 14:21:34 -05:00
Dan Halbert
3f4d9310ff CircuitPython files: replace STATIC with static 2024-05-20 11:02:17 -04:00
Dan Halbert
950b5d09d2 guard2once -s ... 2024-05-19 20:40:44 -04:00
Dan Halbert
dbef48d5e2 add #pragma once to all CircuitPython header files without any include guards 2024-05-19 20:38:07 -04:00
Dan Halbert
747b7619ea update headers of most CircuitPython-only files 2024-05-17 14:56:28 -04:00
Dan Halbert
daa11cb1c2 updates before header conversion 2024-05-17 14:56:28 -04:00
Scott Shawcroft
9ab8831d38
Merge pull request #9218 from jepler/mp3-esp
Enable mp3 output on esp32s3
2024-05-02 14:30:07 -07:00
7af2a13245 MP3Decoder: Allow port to override the allocator
.. espressif will be able to put the mp3 data in faster RAM this way.
2024-05-01 14:20:39 -05:00
08a440d19b espressif: Don't hold interrupts disabled a long time
.. just to prevent background tasks from running
2024-05-01 10:07:13 -05:00
Scott Shawcroft
6d802fe616
Fix ESP builds 2024-04-29 14:11:38 -07:00
Scott Shawcroft
28b7421124
Merge remote-tracking branch 'adafruit/main' into renode 2024-04-29 11:27:19 -07:00
Scott Shawcroft
0cbd8b2e0c
Add CIRCUITPY_USB_DEVICE config
This replaces CIRCUITPY_USB and makes room for CIRCUITPY_TINYUSB
when it may only be included for host support.
2024-04-26 11:58:49 -07:00
Scott Shawcroft
b63d422768
Fix more boards and docs 2024-04-23 16:04:42 -07:00
Scott Shawcroft
442def3e68
Add minimal Renode port
This runs in the Renode simulator and enables easier tracing and
debugging of the CircuitPython core. This port can also serve as
a starting point for new ports because it implements the minimal
necessary for the CP core to run.
2024-04-23 13:31:31 -07:00
93490c301f Don't close an SSL socket twice 2024-04-17 15:17:37 -05:00
2f53c6edbb ssl: Swallow errors during socket.close()
.. for reasons given in the comment
2024-04-17 15:17:04 -05:00
2f04028d10 Merge remote-tracking branch 'origin/main' into ssl-anything 2024-04-17 13:45:43 -05:00
Scott Shawcroft
aca3191a58
Add Max3421E support for usb host
It is enabled on:
* SAMD51 boards with 1MB flash (SKU ending in 20A)
* Feather RP2040 DVI. Others have PIO usb host.
* All ESP32 boards.
* All nRF boards

Fixes #8676
2024-04-10 10:57:28 -07:00
Dan Halbert
817a7fa4af
Merge branch 'main' into main 2024-04-06 16:21:01 -04:00
Dan Halbert
0f66ecb32f
Merge pull request #9146 from brushmate/customizable_midi_interface_names
Make USB MIDI interface names customizable
2024-04-06 13:05:44 -04:00
Dan Halbert
e97ac185d2 factor out name-setting in usb_midi_set_names() 2024-04-06 11:33:00 -04:00
Steffen Kreutz
814ebc6246 Make USB MIDI interface names customizable 2024-04-06 12:09:19 +02:00
Joshua
e956f2994b Updated to use ringbuf and an event callback. 2024-04-06 12:53:08 +10:30
Dan Halbert
e847999a42 Runtime.serial_bytes_available: return count isntead of bool 2024-04-06 09:26:58 +10:30
Fabien Chouteau
8f55dfeb3d shared-module/fourwire/FourWire.c: make the chip_select pin optional
If there's only one device on the bus, the chip_select pin of the
peripheral can be fixed in hardware, therefore lowering the number of
pins required on the microcontroller side.

This patch allows this by making the chip_select pin optional.
2024-04-06 09:23:10 +10:30
Scott Shawcroft
fbd9a6e410
Merge pull request #9141 from dhalbert/serial_bytes_available
Runtime.serial_bytes_available: return count instead of bool
2024-04-05 10:20:02 -07:00
Dan Halbert
8027efe245
Merge pull request #9106 from wee-noise-makers/fourwire_optional_cs
shared-module/fourwire/FourWire.c: make the chip_select pin optional
2024-04-04 22:38:06 -04:00
Joshua
4d8310e374 Fixed precommit spacing problems. 2024-04-05 12:55:14 +10:30
Joshua
090f330ad5 Added support for Cardputer keyboard input. 2024-04-05 10:39:04 +10:30
Dan Halbert
bb9968215c Runtime.serial_bytes_available: return count isntead of bool 2024-04-04 12:26:06 -04:00
9efb034cba Add pio-based flux capturing for rp2040 2024-04-02 15:42:28 -05:00
1be36bd7cb Add floppyio to unix port, test mfm decoding 2024-04-02 15:42:28 -05:00
7d2e46aa19 Update adafruit_floppy 2024-04-02 14:57:20 -05:00
Fabien Chouteau
659c38562b shared-module/fourwire/FourWire.c: make the chip_select pin optional
If there's only one device on the bus, the chip_select pin of the
peripheral can be fixed in hardware, therefore lowering the number of
pins required on the microcontroller side.

This patch allows this by making the chip_select pin optional.
2024-03-30 11:04:18 +01:00
Dan Halbert
ec16f6d8ba
Merge pull request #8855 from xs5871/feature-better-keypad-debouncing
Add state integration based debouncing to the `keypad` module
2024-03-26 15:41:35 -04:00
e5f0579d6c SSLSocket: implement setsockopt (untested) 2024-03-25 09:24:57 -05:00
xs5871
3e184e994c
Add state integration based debouncing to the keypad module 2024-03-22 19:17:23 +00:00
KB Sriram
bed6483823 Set SPI clock line idle polarity for CPOL=1
Fixes https://github.com/adafruit/circuitpython/issues/9074
2024-03-21 22:50:01 -07:00
14a19726f0 Fix return value of accept()
The subscripting to get the `peer` object was wrong.
2024-03-21 14:06:37 -05:00
8c5d9d28d8 ssl: make bind & listen into void functions (they throw exceptions) 2024-03-21 14:06:32 -05:00
f960c5b7c1 SSLSocket: propagate any exception from socket.settimeout directly 2024-03-21 13:54:40 -05:00
b330989704 sslsocket: Simplify handling the timeout value
We're just going to pass it down to the underlying socket, so don't
parse it, multiply it, etc.
2024-03-21 13:54:40 -05:00