.. and add a very basic audioeffects test, showing that it plausibly
is working
I had to address several build errors that occurred in the Unix build,
mostly related to conversion from FP types to integral types (replaced
by explicit casts) and by
accidental mixing of regular & f-suffixed floating constants (replaced
with the MICROPY_FLOAT_CONST macro)
Particularly this change could use consideration:
```diff
- self->max_echo_buffer_len = self->sample_rate / 1000.0f * max_delay_ms * (self->channel_count * sizeof(uint16_t)); // bytes
+ self->max_echo_buffer_len = (uint32_t)(self->sample_rate / 1000.0f * max_delay_ms) * (self->channel_count * sizeof(uint16_t)); // bytes
```
The buffer length is being calculated in floating point based on the
millisecond delay & the sample rate. The result could then be a fractional
number such as 529.2 for a 12ms delay at 44.1kHz. Multiplying a floating
number by the size required for each echo buffer item
(`(self->channel_count * sizeof(uint16_t))`) could yield a number of bytes
that doesn't correspond to an integral number of buffer items. I grouped
the float->int conversion so that it converts the number of echo buffer
items to an integer and then multiplies by the size of the item.
BlockBiquad takes kind, f0 (center frequency) & Q (sharpness)
block type arguments and calculates the actual filter coefficients
every frame.
This allows the filter characteristics f0 and Q to be changed dynamically
from LFOs & arithmetic blocks.
A new manual test demonstrates this on a host computer, playing a simple
tone that is dynamically filtered.
This commit makes sure that functions in usb.core.Device return as
soon as they raise a MicroPython exception rather than continuing
on with whatever code would normally run. This will hopefully help
to avoid things like dereferencing null pointers.
shared-module/usb/core/Device.c had several spots where it would
raise a MicroPython exception with a NULL argument. That made it
very difficult for CircuitPython code to attempt to recover from
fault conditions caused by quirky USB device behavior. This adds
short error strings to distinguish the different types of faults.
- Starts with @tannewt's changes.
- Make sure proper component is being compiled.
- Added `I2C.probe()` as a visible new method. This was a hidden common-hal method, but the C version of adafruit_bus_device could not use it because it needs to call probe via a Python method call. So make it visible. It's useful, and `I2C.scan()` could be phased out, since now `.scan()` can be implemented in Python with `.probe()`.
- set clock-stretching timeout on espressif to a minimum of 1 second. In all impls of busio.I2C()`, the timeout is ignored and is set to a fixed 1 second. @tannewt's new code was using the passed-in value, which was often too short.
To do:
- switch esp-camera to new-driver version. We have to use the same I2C driver everywhere.
- Check about I2CTarget.
Make busio.I2C use finalizers for reset instead of bulk reset. This
makes it easier to track and free the memory that the IDF allocates
internally for its "handle".
Extend the bitfields of these instructions: BitmapHandle, ClearTag, Tag, BitmapSource, PaletteSource
Add instructions: BitmapSourceH PaletteSourceH
All the new bits and opcodes are ignored by earlier hardware, so this change is backwards-compatible.
Passes tests on all EVE hardware.
The setmodel() method controls the behavior
So existing code will continue to work unchanged
Subsequent releases of the ``eve`` library will call setmodel() to enable the new behavior
Confirmed all code paths on EVE hardware
Now, try_lock (SPI & I2C) & begin_transaction (display bus core) will check
that the related objects are still valid first; if they are not,
the lock/begin transaction will fail by returning false, rather than
"other things" such as raising a Python exception where it is not
permitted, accessing invalid memory, etc.
Closes#8278 and Closes#9426
This adds support for the next RP2 microcontroller, the RP2350.
Thanks to Raspberry Pi folks for early access and to @arturo182,
@oberchoo and @SalamCytron for helping with CircuitPython.
The traditional layout of pixels in bitmaps of depth less than eight
is with the order of values in a byte reversed, but with bytes in
the same order as the pixels on the line.
Before now, displayio.Bitmap did reverse the values, but did it on a
word (four bytes) basis, not byte, which resulted in groups of four
bytes being in the order opposite to the screen order.
This patch fixes this, by making processing of pixels in bitmaps of
depth less than 8 bits based on bytes, not words. Since the internal
details are changing, any code that accessed bitmaps through the
memoryview buffer, or that created bitmaps directly from raw data,
and that used depth of less than 8 bits will be affected.
Therefore, the gen_display_resources.py script also had to be modified
to account for the changes.
These protocol operations should not raise exceptions, but sometimes
they do. Catch the exception and extract the errno value if available.
At the same time, harmonize the argument types for the underlying C
routines
* Don't consume in the case of "indata overflow".
Doing so leaves us at a bad boundary within the MP3 data
and can continue decoding from an inappropriate spot
i.e., one that looks likede mp3 data but is NOT.
because there are many crashing bugs in the helix mp3 library on
invalid input data, we must do our best to avoid them, and this
is one way to do that.
* clear the output buffer in the case there's not a sync word in the
buffer. this can also happen when too little data is available.
this changes more "stuttering" conditions into "silent" conditions.
With these changes, I can get through 3+ plays of "idea.mp3" from a local
http server with long pauses (but not stuttering glitches or safe mode
crashes).
I was also able to play through 10+ minutes of http://ice2.somafm.com/dronezone-128-mp3
without crashing or "end of stream", though again there are pauses
due to packet loss.
I think this is good now, except for the problems that arise when
the socket layer doesn't deliver a fresh packet for a long time.
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.
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)
```
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
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.
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.
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
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.
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.
In principle this allows core SSL code to be used with e.g., wiznet
or airlift sockets. It might actually be useful with wiznet ethernet devices
(it's probably not with airlift)
Incorrect error handling in send/recv would raise an OSError with
an incorrect (negative) code.
It's likely that this bug was always happening in the Pico W
implementation, which became the basis of the current shared
implementation.
Push handling of WANT_{READ,WRITE} down into mbedtls_raise_error
and use it in recv_into and send.
Tested by connecting to google.com:443, sending nothing, and trying
to read a byte:
```py
import socketpool, ssl, time, wifi
socket = socketpool.SocketPool(wifi.radio)
ctx = ssl.SSLContext()
with ctx.wrap_socket(socket.socket()) as ss:
ss.connect(("google.com", 443))
ss.settimeout(1)
b = bytearray(1)
try:
t0 = time.monotonic()
ss.recv_into(b)
except Exception as ee:
t1 = time.monotonic()
exc = ee
print(t1-t0)
raise exc
```
As desired, an exception `OSError: [Errno 116] ETIMEDOUT` occurred
and the time delta value was 1.0 seconds.
(tested on pycamera)
Closes: #8988
the mbedtls version is a bit different so there are some new #ifdefs
needed.
Tested with the ssl test from https://github.com/adafruit/circuitpython/issues/8910
on Adafruit MatrixPortal S3 (no pico w testing done)
This can perform arbitrary channel mixing between two images.
Alpha blend & maximum functions are demonstrated in the test.
However, it should make most of the usual photo editing blends
possible. (for dissolve, fill a mask bitmap with random values,
which may be expensive to do from circuitpython code; we can
specifically accelerate it if we need to)
Otherwise it will be freed during a collect and potentially
overwritten. This is a bug in 8.x but isn't seen as early as in
9.x because 9.x will collect before expanding the split heap
further.
Fixes#8793
This replaces the earlier, Bitmap-based way of interacting with the
UVC framebuffer.
Typical usage:
```py
displayio.release_displays()
display = frambufferio.FramebufferDisplay(uvc.UVCFramebuffer())
```
This works on a MacroPad with a 128x128 framebuffer, but does not work
on a QT Py esp32s3.
On esp32s3, having the UVC-configuring line alone causes a hard-fault
at startup. However, disabling some other USB devices allows it to boot
and run code.py:
```py
import uvc
import usb_hid
import usb_midi
usb_hid.disable()
usb_midi.disable()
uvc.enable_framebuffer(64, 64)
```
however, as far as I can tell within qv4l2, the device never actually
transmits a frame of data (received frame count never increases).
I have not yet analyzed this failure in further detail.
Otherwise it will be freed during a collect and potentially
overwritten. This is a bug in 8.x but isn't seen as early as in
9.x because 9.x will collect before expanding the split heap
further.
Fixes#8793
This changes storage.mount() to require that a mount point exist
on the parent file system.
A bug in background tasks is also fixed where the function
parameter is cleared on pending callbacks during "reset".
Disk usage is shown on the directory listing and changes based on
the mounted file system. Writable is also loaded per-directory.
Fixes#8108. Fixes#8690. Fixes#8107.
This reduces the time from about 133ms to about 122ms on my test
image on the memento pycamera
a similar change to morph did not produce a performance improvement,
so I didn't include it.
morph9 is a form of morph which performs 9 different convolutions,
like a version of mix where each coefficient is a (2n+1)x(2n+1) matrix.
Most use cases are covered by morph-then-mix, but some advanced operations
may be more efficient to implement via morph9.
This allows operations between channels in an image. It can be used for
the following use cases:
* Conversion to B&W or sepia
* Adding color casts
* Mixing or swapping arbitrary channels
* Inverting or scaling arbitrary channels
bitmapfilter.morph is taken from openmv's imlib.
It is substantially faster than blur/sharpen implemented in ulab,
by up to 10x. It also avoids making many allocations.
due to mbedtls version skew, some macros need to be provided.
The espressif common-hal implementation is no longer needed.
The copyright of hashlib/__init__.h comes from micropython
extmod/modhashlib.c where I found the macro definitions.
Previously, negative amplitudes were clamped to zero.
Now, they are allowed to range from -ALMOST_ONE to +ALMOST_ONE.
This is useful in certain circumstances, such as using synthio
to create CV-like outputs that can be positive or negative, by
using the amplitude property of the note.
This simplifies allocating outside of the VM because the VM doesn't
take up all remaining memory by default.
On ESP we delegate to the IDF for allocations. For all other ports,
we use TLSF to manage an outer "port" heap. The IDF uses TLSF
internally and we use their fork for the other ports.
This also removes the dynamic C stack sizing. It wasn't often used
and is not possible with a fixed outer heap.
Fixes#8512. Fixes#7334.
micropython puts the pointer-ness into the typedef; we can put the
const-ness there too.
this reduces the delta to micropython; for instance, emitinlinextensa
and emitinlinethumb now match upstream.
These are moved:
* Display -> busdisplay.BusDisplay
* FourWire -> fourwire.FourWire
* EPaperDisplay -> epaperdisplay.EPaperDisplay
* I2CDisplay -> i2cdisplaybus.I2CDisplayBus
`paralleldisplay` is now `paralleldisplaybus` (and registered as
`paralleldisplay` too).
Bus related helpers are split out of display_core into bus_core.
It is in still displayio since it is a dependency of both
busdisplay and epaperdisplay.
Fixes#7667