summaryrefslogtreecommitdiff
path: root/shared-module
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2020-02-20 22:27:16 -0500
committerDan Halbert <halbert@halwitz.org>2020-02-20 22:27:16 -0500
commit23d6a3dc1fe2ece41642f602343650fce5be83c7 (patch)
tree801979949b826c0a2c439563f0efe692831a25d1 /shared-module
parent1caf6bd8d3924b2f7861cd8b0af0d16a608bb736 (diff)
parent675930083de102ab73af6f6a586614793e467f5f (diff)
merge from upstream
Diffstat (limited to 'shared-module')
-rw-r--r--shared-module/_eve/__init__.c317
-rw-r--r--shared-module/_eve/__init__.h37
-rw-r--r--shared-module/_pixelbuf/PixelBuf.c306
-rw-r--r--shared-module/_pixelbuf/PixelBuf.h37
-rw-r--r--shared-module/_stage/__init__.c6
-rw-r--r--shared-module/_stage/__init__.h3
-rw-r--r--shared-module/audiomixer/Mixer.c377
-rw-r--r--shared-module/audiomixer/MixerVoice.c6
-rw-r--r--shared-module/audiomixer/MixerVoice.h2
-rw-r--r--shared-module/audiomp3/MP3Decoder.c (renamed from shared-module/audiomp3/MP3File.c)76
-rw-r--r--shared-module/audiomp3/MP3Decoder.h (renamed from shared-module/audiomp3/MP3File.h)2
-rw-r--r--shared-module/board/__init__.c22
-rw-r--r--shared-module/displayio/__init__.c8
-rw-r--r--shared-module/storage/__init__.c4
14 files changed, 844 insertions, 359 deletions
diff --git a/shared-module/_eve/__init__.c b/shared-module/_eve/__init__.c
new file mode 100644
index 000000000..2c93eb69f
--- /dev/null
+++ b/shared-module/_eve/__init__.c
@@ -0,0 +1,317 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 James Bowman for Excamera Labs
+ *
+ * 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 <stddef.h>
+#include <stdint.h>
+#include "py/runtime.h"
+#include "shared-module/_eve/__init__.h"
+
+STATIC void write(common_hal__eve_t *eve, size_t len, void *buf) {
+ eve->dest[2] = mp_obj_new_bytearray_by_ref(len, buf);
+ mp_call_method_n_kw(1, 0, eve->dest);
+}
+
+void common_hal__eve_flush(common_hal__eve_t *eve) {
+ if (eve->n != 0) {
+ write(eve, eve->n, eve->buf);
+ eve->n = 0;
+ }
+}
+
+static void *append(common_hal__eve_t *eve, size_t m) {
+ if ((eve->n + m) > sizeof(eve->buf))
+ common_hal__eve_flush(eve);
+ uint8_t *r = eve->buf + eve->n;
+ eve->n += m;
+ return (void*)r;
+}
+
+void common_hal__eve_add(common_hal__eve_t *eve, size_t len, void *buf) {
+ if (len <= sizeof(eve->buf)) {
+ uint8_t *p = (uint8_t*)append(eve, len);
+ // memcpy(p, buffer_info.buf, buffer_info.len);
+ uint8_t *s = buf; for (size_t i = 0; i < len; i++) *p++ = *s++;
+ } else {
+ common_hal__eve_flush(eve);
+ write(eve, len, buf);
+ }
+}
+
+#define C4(eve, u) (*(uint32_t*)append((eve), sizeof(uint32_t)) = (u))
+
+void common_hal__eve_Vertex2f(common_hal__eve_t *eve, mp_float_t x, mp_float_t y) {
+ int16_t ix = (int)(eve->vscale * x);
+ int16_t iy = (int)(eve->vscale * y);
+ C4(eve, (1 << 30) | ((ix & 32767) << 15) | (iy & 32767));
+}
+
+void common_hal__eve_VertexFormat(common_hal__eve_t *eve, uint32_t frac)
+{
+ C4(eve, ((27 << 24) | ((frac & 7))));
+ eve->vscale = 1 << eve->vscale;
+}
+
+
+
+void common_hal__eve_AlphaFunc(common_hal__eve_t *eve, uint32_t func, uint32_t ref) {
+ C4(eve, ((9 << 24) | ((func & 7) << 8) | ((ref & 255))));
+}
+
+
+void common_hal__eve_Begin(common_hal__eve_t *eve, uint32_t prim) {
+ C4(eve, ((31 << 24) | ((prim & 15))));
+}
+
+
+void common_hal__eve_BitmapExtFormat(common_hal__eve_t *eve, uint32_t fmt) {
+ C4(eve, ((46 << 24) | (fmt & 65535)));
+}
+
+
+void common_hal__eve_BitmapHandle(common_hal__eve_t *eve, uint32_t handle) {
+ C4(eve, ((5 << 24) | ((handle & 31))));
+}
+
+
+void common_hal__eve_BitmapLayoutH(common_hal__eve_t *eve, uint32_t linestride, uint32_t height) {
+ C4(eve, ((40 << 24) | (((linestride) & 3) << 2) | (((height) & 3))));
+}
+
+
+void common_hal__eve_BitmapLayout(common_hal__eve_t *eve, uint32_t format, uint32_t linestride, uint32_t height) {
+ C4(eve, ((7 << 24) | ((format & 31) << 19) | ((linestride & 1023) << 9) | ((height & 511))));
+}
+
+
+void common_hal__eve_BitmapSizeH(common_hal__eve_t *eve, uint32_t width, uint32_t height) {
+ C4(eve, ((41 << 24) | (((width) & 3) << 2) | (((height) & 3))));
+}
+
+
+void common_hal__eve_BitmapSize(common_hal__eve_t *eve, uint32_t filter, uint32_t wrapx, uint32_t wrapy, uint32_t width, uint32_t height) {
+ C4(eve, ((8 << 24) | ((filter & 1) << 20) | ((wrapx & 1) << 19) | ((wrapy & 1) << 18) | ((width & 511) << 9) | ((height & 511))));
+}
+
+
+void common_hal__eve_BitmapSource(common_hal__eve_t *eve, uint32_t addr) {
+ C4(eve, ((1 << 24) | ((addr & 0xffffff))));
+}
+
+
+void common_hal__eve_BitmapSwizzle(common_hal__eve_t *eve, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ C4(eve, ((47 << 24) | ((r & 7) << 9) | ((g & 7) << 6) | ((b & 7) << 3) | ((a & 7))));
+}
+
+
+void common_hal__eve_BitmapTransformA(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((21 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformB(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((22 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformC(common_hal__eve_t *eve, uint32_t v) {
+ C4(eve, ((23 << 24) | ((v & 16777215))));
+}
+
+
+void common_hal__eve_BitmapTransformD(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((24 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformE(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((25 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformF(common_hal__eve_t *eve, uint32_t v) {
+ C4(eve, ((26 << 24) | ((v & 16777215))));
+}
+
+
+void common_hal__eve_BlendFunc(common_hal__eve_t *eve, uint32_t src, uint32_t dst) {
+ C4(eve, ((11 << 24) | ((src & 7) << 3) | ((dst & 7))));
+}
+
+
+void common_hal__eve_Call(common_hal__eve_t *eve, uint32_t dest) {
+ C4(eve, ((29 << 24) | ((dest & 65535))));
+}
+
+
+void common_hal__eve_Cell(common_hal__eve_t *eve, uint32_t cell) {
+ C4(eve, ((6 << 24) | ((cell & 127))));
+}
+
+
+void common_hal__eve_ClearColorA(common_hal__eve_t *eve, uint32_t alpha) {
+ C4(eve, ((15 << 24) | ((alpha & 255))));
+}
+
+
+void common_hal__eve_ClearColorRGB(common_hal__eve_t *eve, uint32_t red, uint32_t green, uint32_t blue) {
+ C4(eve, ((2 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | ((blue & 255))));
+}
+
+
+void common_hal__eve_Clear(common_hal__eve_t *eve, uint32_t c, uint32_t s, uint32_t t) {
+ C4(eve, ((38 << 24) | ((c & 1) << 2) | ((s & 1) << 1) | ((t & 1))));
+}
+
+
+void common_hal__eve_ClearStencil(common_hal__eve_t *eve, uint32_t s) {
+ C4(eve, ((17 << 24) | ((s & 255))));
+}
+
+
+void common_hal__eve_ClearTag(common_hal__eve_t *eve, uint32_t s) {
+ C4(eve, ((18 << 24) | ((s & 255))));
+}
+
+
+void common_hal__eve_ColorA(common_hal__eve_t *eve, uint32_t alpha) {
+ C4(eve, ((16 << 24) | ((alpha & 255))));
+}
+
+
+void common_hal__eve_ColorMask(common_hal__eve_t *eve, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ C4(eve, ((32 << 24) | ((r & 1) << 3) | ((g & 1) << 2) | ((b & 1) << 1) | ((a & 1))));
+}
+
+
+void common_hal__eve_ColorRGB(common_hal__eve_t *eve, uint32_t red, uint32_t green, uint32_t blue) {
+ C4(eve, ((4 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | ((blue & 255))));
+}
+
+
+void common_hal__eve_Display(common_hal__eve_t *eve) {
+ C4(eve, ((0 << 24)));
+}
+
+
+void common_hal__eve_End(common_hal__eve_t *eve) {
+ C4(eve, ((33 << 24)));
+}
+
+
+void common_hal__eve_Jump(common_hal__eve_t *eve, uint32_t dest) {
+ C4(eve, ((30 << 24) | ((dest & 65535))));
+}
+
+
+void common_hal__eve_LineWidth(common_hal__eve_t *eve, uint32_t width) {
+ C4(eve, ((14 << 24) | ((width & 4095))));
+}
+
+
+void common_hal__eve_Macro(common_hal__eve_t *eve, uint32_t m) {
+ C4(eve, ((37 << 24) | ((m & 1))));
+}
+
+
+void common_hal__eve_Nop(common_hal__eve_t *eve) {
+ C4(eve, ((45 << 24)));
+}
+
+
+void common_hal__eve_PaletteSource(common_hal__eve_t *eve, uint32_t addr) {
+ C4(eve, ((42 << 24) | (((addr) & 4194303))));
+}
+
+
+void common_hal__eve_PointSize(common_hal__eve_t *eve, uint32_t size) {
+ C4(eve, ((13 << 24) | ((size & 8191))));
+}
+
+
+void common_hal__eve_RestoreContext(common_hal__eve_t *eve) {
+ C4(eve, ((35 << 24)));
+}
+
+
+void common_hal__eve_Return(common_hal__eve_t *eve) {
+ C4(eve, ((36 << 24)));
+}
+
+
+void common_hal__eve_SaveContext(common_hal__eve_t *eve) {
+ C4(eve, ((34 << 24)));
+}
+
+
+void common_hal__eve_ScissorSize(common_hal__eve_t *eve, uint32_t width, uint32_t height) {
+ C4(eve, ((28 << 24) | ((width & 4095) << 12) | ((height & 4095))));
+}
+
+
+void common_hal__eve_ScissorXY(common_hal__eve_t *eve, uint32_t x, uint32_t y) {
+ C4(eve, ((27 << 24) | ((x & 2047) << 11) | ((y & 2047))));
+}
+
+
+void common_hal__eve_StencilFunc(common_hal__eve_t *eve, uint32_t func, uint32_t ref, uint32_t mask) {
+ C4(eve, ((10 << 24) | ((func & 7) << 16) | ((ref & 255) << 8) | ((mask & 255))));
+}
+
+
+void common_hal__eve_StencilMask(common_hal__eve_t *eve, uint32_t mask) {
+ C4(eve, ((19 << 24) | ((mask & 255))));
+}
+
+
+void common_hal__eve_StencilOp(common_hal__eve_t *eve, uint32_t sfail, uint32_t spass) {
+ C4(eve, ((12 << 24) | ((sfail & 7) << 3) | ((spass & 7))));
+}
+
+
+void common_hal__eve_TagMask(common_hal__eve_t *eve, uint32_t mask) {
+ C4(eve, ((20 << 24) | ((mask & 1))));
+}
+
+
+void common_hal__eve_Tag(common_hal__eve_t *eve, uint32_t s) {
+ C4(eve, ((3 << 24) | ((s & 255))));
+}
+
+
+void common_hal__eve_VertexTranslateX(common_hal__eve_t *eve, uint32_t x) {
+ C4(eve, ((43 << 24) | (((x) & 131071))));
+}
+
+
+void common_hal__eve_VertexTranslateY(common_hal__eve_t *eve, uint32_t y) {
+ C4(eve, ((44 << 24) | (((y) & 131071))));
+}
+
+
+void common_hal__eve_Vertex2ii(common_hal__eve_t *eve, uint32_t x, uint32_t y, uint32_t handle, uint32_t cell) {
+ C4(eve, ((2 << 30) | (((x) & 511) << 21) | (((y) & 511) << 12) | (((handle) & 31) << 7) | (((cell) & 127) << 0)));
+}
+
diff --git a/shared-module/_eve/__init__.h b/shared-module/_eve/__init__.h
new file mode 100644
index 000000000..5217d860a
--- /dev/null
+++ b/shared-module/_eve/__init__.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 James Bowman for Excamera Labs
+ *
+ * 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__EVE___INIT___H
+#define MICROPY_INCLUDED_SHARED_MODULE__EVE___INIT___H
+
+typedef struct _common_hal__eve_t {
+ mp_obj_t dest[3]; // Own 'write' method, plus argument
+ int vscale; // fixed-point scaling used for Vertex2f
+ size_t n; // Current size of command buffer
+ uint8_t buf[512]; // Command buffer
+} common_hal__eve_t;
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE__EVE___INIT___H
diff --git a/shared-module/_pixelbuf/PixelBuf.c b/shared-module/_pixelbuf/PixelBuf.c
index 020151bc3..bad8539ea 100644
--- a/shared-module/_pixelbuf/PixelBuf.c
+++ b/shared-module/_pixelbuf/PixelBuf.c
@@ -26,95 +26,263 @@
#include "py/obj.h"
-#include "py/objarray.h"
+#include "py/objstr.h"
+#include "py/objtype.h"
#include "py/runtime.h"
-#include "PixelBuf.h"
+#include "shared-bindings/_pixelbuf/PixelBuf.h"
#include <string.h>
-void pixelbuf_set_pixel_int(uint8_t *buf, mp_int_t value, pixelbuf_byteorder_details_t *byteorder) {
- buf[byteorder->byteorder.r] = value >> 16 & 0xff;
- buf[byteorder->byteorder.g] = (value >> 8) & 0xff;
- buf[byteorder->byteorder.b] = value & 0xff;
- if (byteorder->bpp == 4 && byteorder->has_white &&
- (buf[byteorder->byteorder.r] == buf[byteorder->byteorder.g] &&
- buf[byteorder->byteorder.r] == buf[byteorder->byteorder.b])) {
- buf[byteorder->byteorder.w] = buf[byteorder->byteorder.r];
- buf[byteorder->byteorder.r] = buf[byteorder->byteorder.g] = buf[byteorder->byteorder.b] = 0;
- }
-}
-
-void pixelbuf_set_pixel(uint8_t *buf, uint8_t *rawbuf, float brightness, mp_obj_t *item, pixelbuf_byteorder_details_t *byteorder, bool dotstar) {
- if (MP_OBJ_IS_INT(item)) {
- uint8_t *target = rawbuf ? rawbuf : buf;
- pixelbuf_set_pixel_int(target, mp_obj_get_int_truncated(item), byteorder);
- if (dotstar) {
- buf[0] = DOTSTAR_LED_START_FULL_BRIGHT;
- if (rawbuf)
- rawbuf[0] = DOTSTAR_LED_START_FULL_BRIGHT;
+// Helper to ensure we have the native super class instead of a subclass.
+static pixelbuf_pixelbuf_obj_t* native_pixelbuf(mp_obj_t pixelbuf_obj) {
+ mp_obj_t native_pixelbuf = mp_instance_cast_to_native_base(pixelbuf_obj, &pixelbuf_pixelbuf_type);
+ mp_obj_assert_native_inited(native_pixelbuf);
+ return MP_OBJ_TO_PTR(native_pixelbuf);
+}
+
+void common_hal__pixelbuf_pixelbuf_construct(pixelbuf_pixelbuf_obj_t *self, size_t n,
+ pixelbuf_byteorder_details_t* byteorder, mp_float_t brightness, bool auto_write,
+ uint8_t* header, size_t header_len, uint8_t* trailer, size_t trailer_len) {
+
+ self->pixel_count = n;
+ self->byteorder = *byteorder; // Copied because we modify for dotstar
+ self->bytes_per_pixel = byteorder->is_dotstar ? 4 : byteorder->bpp;
+ self->auto_write = false;
+
+ size_t pixel_len = self->pixel_count * self->bytes_per_pixel;
+ self->transmit_buffer_obj = mp_obj_new_bytes_of_zeros(header_len + pixel_len + trailer_len);
+ mp_obj_str_t *o = MP_OBJ_TO_PTR(self->transmit_buffer_obj);
+
+ // Abuse the bytes object a bit by mutating it's data by dropping the const. If the user's
+ // Python code holds onto it, they'll find out that it changes. At least this way it isn't
+ // mutable by the code itself.
+ uint8_t* transmit_buffer = (uint8_t*) o->data;
+ memcpy(transmit_buffer, header, header_len);
+ memcpy(transmit_buffer + header_len + pixel_len, trailer, trailer_len);
+ self->post_brightness_buffer = transmit_buffer + header_len;
+
+ if (self->byteorder.is_dotstar) {
+ // Initialize the buffer with the dotstar start bytes.
+ // Note: Header and end must be setup by caller
+ for (uint i = 0; i < self->pixel_count * 4; i += 4) {
+ self->post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT;
}
- if (rawbuf) {
- buf[byteorder->byteorder.r] = rawbuf[byteorder->byteorder.r] * brightness;
- buf[byteorder->byteorder.g] = rawbuf[byteorder->byteorder.g] * brightness;
- buf[byteorder->byteorder.b] = rawbuf[byteorder->byteorder.b] * brightness;
- } else {
- buf[byteorder->byteorder.r] *= brightness;
- buf[byteorder->byteorder.g] *= brightness;
- buf[byteorder->byteorder.b] *= brightness;
+ }
+ // Call set_brightness so that it can allocate a second buffer if needed.
+ self->brightness = 1.0;
+ common_hal__pixelbuf_pixelbuf_set_brightness(MP_OBJ_FROM_PTR(self), brightness);
+
+ // Turn on auto_write. We don't want to do it with the above brightness call.
+ self->auto_write = auto_write;
+}
+
+size_t common_hal__pixelbuf_pixelbuf_get_len(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->pixel_count;
+}
+
+uint8_t common_hal__pixelbuf_pixelbuf_get_bpp(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->byteorder.bpp;
+}
+
+mp_obj_t common_hal__pixelbuf_pixelbuf_get_byteorder_string(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->byteorder.order_string;
+}
+
+bool common_hal__pixelbuf_pixelbuf_get_auto_write(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->auto_write;
+}
+
+void common_hal__pixelbuf_pixelbuf_set_auto_write(mp_obj_t self_in, bool auto_write) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ self->auto_write = auto_write;
+}
+
+mp_float_t common_hal__pixelbuf_pixelbuf_get_brightness(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->brightness;
+}
+
+void common_hal__pixelbuf_pixelbuf_set_brightness(mp_obj_t self_in, mp_float_t brightness) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ // Skip out if the brightness is already set. The default of self->brightness is 1.0. So, this
+ // also prevents the pre_brightness_buffer allocation when brightness is set to 1.0 again.
+ mp_float_t change = brightness - self->brightness;
+ if (-0.001 < change && change < 0.001) {
+ return;
+ }
+ self->brightness = brightness;
+ size_t pixel_len = self->pixel_count * self->bytes_per_pixel;
+ if (self->pre_brightness_buffer == NULL) {
+ self->pre_brightness_buffer = m_malloc(pixel_len, false);
+ memcpy(self->pre_brightness_buffer, self->post_brightness_buffer, pixel_len);
+ }
+ for (size_t i = 0; i < pixel_len; i++) {
+ // Don't adjust per-pixel luminance bytes in dotstar mode
+ if (self->byteorder.is_dotstar && i % 4 == 0) {
+ continue;
+ }
+ self->post_brightness_buffer[i] = self->pre_brightness_buffer[i] * self->brightness;
+ }
+
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
+ }
+}
+
+void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t* self, mp_obj_t color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* w) {
+ pixelbuf_byteorder_details_t *byteorder = &self->byteorder;
+ // w is shared between white in NeoPixels and brightness in dotstars (so that DotStars can have
+ // per-pixel brightness). Set the defaults here in case it isn't set below.
+ if (byteorder->is_dotstar) {
+ *w = 255;
+ } else {
+ *w = 0;
+ }
+
+ if (MP_OBJ_IS_INT(color)) {
+ mp_int_t value = mp_obj_get_int_truncated(color);
+ *r = value >> 16 & 0xff;
+ *g = (value >> 8) & 0xff;
+ *b = value & 0xff;
+ // Int colors can't set white directly so convert to white when all components are equal.
+ if (!byteorder->is_dotstar && byteorder->bpp == 4 && byteorder->has_white && *r == *g && *r == *b) {
+ *w = *r;
+ *r = 0;
+ *g = 0;
+ *b = 0;
}
} else {
mp_obj_t *items;
size_t len;
- mp_obj_get_array(item, &len, &items);
- if (len != byteorder->bpp && !dotstar)
+ mp_obj_get_array(color, &len, &items);
+ if (len != byteorder->bpp && !byteorder->is_dotstar) {
mp_raise_ValueError_varg(translate("Expected tuple of length %d, got %d"), byteorder->bpp, len);
-
- buf[byteorder->byteorder.r] = mp_obj_get_int_truncated(items[PIXEL_R]) * brightness;
- buf[byteorder->byteorder.g] = mp_obj_get_int_truncated(items[PIXEL_G]) * brightness;
- buf[byteorder->byteorder.b] = mp_obj_get_int_truncated(items[PIXEL_B]) * brightness;
- if (rawbuf) {
- rawbuf[byteorder->byteorder.r] = mp_obj_get_int_truncated(items[PIXEL_R]);
- rawbuf[byteorder->byteorder.g] = mp_obj_get_int_truncated(items[PIXEL_G]);
- rawbuf[byteorder->byteorder.b] = mp_obj_get_int_truncated(items[PIXEL_B]);
}
+
+ *r = mp_obj_get_int_truncated(items[PIXEL_R]);
+ *g = mp_obj_get_int_truncated(items[PIXEL_G]);
+ *b = mp_obj_get_int_truncated(items[PIXEL_B]);
if (len > 3) {
- if (dotstar) {
- buf[byteorder->byteorder.w] = DOTSTAR_LED_START | DOTSTAR_BRIGHTNESS(mp_obj_get_float(items[PIXEL_W]));
- if (rawbuf)
- rawbuf[byteorder->byteorder.w] = buf[byteorder->byteorder.w];
+ if (mp_obj_is_float(items[PIXEL_W])) {
+ *w = 255 * mp_obj_get_float(items[PIXEL_W]);
} else {
- buf[byteorder->byteorder.w] = mp_obj_get_int_truncated(items[PIXEL_W]) * brightness;
- if (rawbuf)
- rawbuf[byteorder->byteorder.w] = mp_obj_get_int_truncated(items[PIXEL_W]);
+ *w = mp_obj_get_int_truncated(items[PIXEL_W]);
}
- } else if (dotstar) {
- buf[byteorder->byteorder.w] = DOTSTAR_LED_START_FULL_BRIGHT;
- if (rawbuf)
- rawbuf[byteorder->byteorder.w] = DOTSTAR_LED_START_FULL_BRIGHT;
}
}
}
-mp_obj_t *pixelbuf_get_pixel_array(uint8_t *buf, uint len, pixelbuf_byteorder_details_t *byteorder, uint8_t step, mp_int_t slice_step, bool dotstar) {
- mp_obj_t elems[len];
- for (uint i = 0; i < len; i++) {
- elems[i] = pixelbuf_get_pixel(buf + ((i * slice_step) * step), byteorder, dotstar);
+void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t* self, size_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
+ // DotStars don't have white, instead they have 5 bit brightness so pack it into w. Shift right
+ // by three to leave the top five bits.
+ if (self->bytes_per_pixel == 4 && self->byteorder.is_dotstar) {
+ w = DOTSTAR_LED_START | w >> 3;
+ }
+ pixelbuf_rgbw_t *rgbw_order = &self->byteorder.byteorder;
+ size_t offset = index * self->bytes_per_pixel;
+ if (self->pre_brightness_buffer != NULL) {
+ uint8_t* pre_brightness_buffer = self->pre_brightness_buffer + offset;
+ if (self->bytes_per_pixel == 4) {
+ pre_brightness_buffer[rgbw_order->w] = w;
+ }
+
+ pre_brightness_buffer[rgbw_order->r] = r;
+ pre_brightness_buffer[rgbw_order->g] = g;
+ pre_brightness_buffer[rgbw_order->b] = b;
+ }
+
+ uint8_t* post_brightness_buffer = self->post_brightness_buffer + offset;
+ if (self->bytes_per_pixel == 4) {
+ // Only apply brightness if w is actually white (aka not DotStar.)
+ if (!self->byteorder.is_dotstar) {
+ w *= self->brightness;
+ }
+ post_brightness_buffer[rgbw_order->w] = w;
+ }
+ post_brightness_buffer[rgbw_order->r] = r * self->brightness;
+ post_brightness_buffer[rgbw_order->g] = g * self->brightness;
+ post_brightness_buffer[rgbw_order->b] = b * self->brightness;
+}
+
+void _pixelbuf_set_pixel(pixelbuf_pixelbuf_obj_t* self, size_t index, mp_obj_t value) {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t w;
+ _pixelbuf_parse_color(self, value, &r, &g, &b, &w);
+ _pixelbuf_set_pixel_color(self, index, r, g, b, w);
+}
+
+void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, size_t stop, size_t step, mp_obj_t* values) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ size_t source_i = 0;
+ for (size_t target_i = start; target_i < stop; target_i += step) {
+ _pixelbuf_set_pixel(self, target_i, values[source_i]);
+ source_i++;
+ }
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
+ }
+}
+
+void common_hal__pixelbuf_pixelbuf_set_pixel(mp_obj_t self_in, size_t index, mp_obj_t value) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ _pixelbuf_set_pixel(self, index, value);
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
}
- return mp_obj_new_tuple(len, elems);
}
-mp_obj_t *pixelbuf_get_pixel(uint8_t *buf, pixelbuf_byteorder_details_t *byteorder, bool dotstar) {
- mp_obj_t elems[byteorder->bpp];
-
- elems[0] = mp_obj_new_int(buf[byteorder->byteorder.r]);
- elems[1] = mp_obj_new_int(buf[byteorder->byteorder.g]);
- elems[2] = mp_obj_new_int(buf[byteorder->byteorder.b]);
- if (byteorder->bpp > 3)
- {
- if (dotstar)
- elems[3] = mp_obj_new_float(DOTSTAR_GET_BRIGHTNESS(buf[byteorder->byteorder.w]));
- else
- elems[3] = mp_obj_new_int(buf[byteorder->byteorder.w]);
+mp_obj_t common_hal__pixelbuf_pixelbuf_get_pixel(mp_obj_t self_in, size_t index) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ mp_obj_t elems[self->byteorder.bpp];
+ uint8_t* pixel_buffer = self->post_brightness_buffer;
+ if (self->pre_brightness_buffer != NULL) {
+ pixel_buffer = self->pre_brightness_buffer;
+ }
+
+ pixelbuf_rgbw_t *rgbw_order = &self->byteorder.byteorder;
+ elems[0] = MP_OBJ_NEW_SMALL_INT(pixel_buffer[rgbw_order->r]);
+ elems[1] = MP_OBJ_NEW_SMALL_INT(pixel_buffer[rgbw_order->g]);
+ elems[2] = MP_OBJ_NEW_SMALL_INT(pixel_buffer[rgbw_order->b]);
+ if (self->byteorder.bpp > 3) {
+ uint8_t w = pixel_buffer[rgbw_order->w];
+ if (self->byteorder.is_dotstar) {
+ elems[3] = mp_obj_new_float((w & 0b00011111) / 31.0);
+ } else {
+ elems[3] = MP_OBJ_NEW_SMALL_INT(w);
+ }
}
- return mp_obj_new_tuple(byteorder->bpp, elems);
+ return mp_obj_new_tuple(self->byteorder.bpp, elems);
+}
+
+void common_hal__pixelbuf_pixelbuf_show(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ mp_obj_t dest[2 + 1];
+ mp_load_method(self_in, MP_QSTR__transmit, dest);
+
+ dest[2] = self->transmit_buffer_obj;
+
+ mp_call_method_n_kw(1, 0, dest);
+}
+
+void common_hal__pixelbuf_pixelbuf_fill(mp_obj_t self_in, mp_obj_t fill_color) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t w;
+ _pixelbuf_parse_color(self, fill_color, &r, &g, &b, &w);
+
+ for (size_t i = 0; i < self->pixel_count; i++) {
+ _pixelbuf_set_pixel_color(self, i, r, g, b, w);
+ }
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
+ }
}
diff --git a/shared-module/_pixelbuf/PixelBuf.h b/shared-module/_pixelbuf/PixelBuf.h
index 173ce61a8..a9fbed366 100644
--- a/shared-module/_pixelbuf/PixelBuf.h
+++ b/shared-module/_pixelbuf/PixelBuf.h
@@ -27,24 +27,45 @@
#include "py/obj.h"
#include "py/objarray.h"
-#include "../../shared-bindings/_pixelbuf/types.h"
#ifndef PIXELBUF_SHARED_MODULE_H
#define PIXELBUF_SHARED_MODULE_H
+typedef struct {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t w;
+} pixelbuf_rgbw_t;
+
+typedef struct {
+ uint8_t bpp;
+ pixelbuf_rgbw_t byteorder;
+ bool has_white;
+ bool is_dotstar;
+ mp_obj_t order_string;
+} pixelbuf_byteorder_details_t;
+
+typedef struct {
+ mp_obj_base_t base;
+ size_t pixel_count;
+ size_t bytes_per_pixel;
+ pixelbuf_byteorder_details_t byteorder;
+ mp_float_t brightness;
+ mp_obj_t transmit_buffer_obj;
+ // The post_brightness_buffer is offset into the buffer allocated in transmit_buffer_obj to
+ // account for any header.
+ uint8_t *post_brightness_buffer;
+ uint8_t *pre_brightness_buffer;
+ bool auto_write;
+} pixelbuf_pixelbuf_obj_t;
+
#define PIXEL_R 0
#define PIXEL_G 1
#define PIXEL_B 2
#define PIXEL_W 3
#define DOTSTAR_LED_START 0b11100000
-#define DOTSTAR_BRIGHTNESS(brightness) ((32 - (uint8_t)(32 - brightness * 31)) & 0b00011111)
-#define DOTSTAR_GET_BRIGHTNESS(value) ((value & 0b00011111) / 31.0)
#define DOTSTAR_LED_START_FULL_BRIGHT 0xFF
-void pixelbuf_set_pixel(uint8_t *buf, uint8_t *rawbuf, float brightness, mp_obj_t *item, pixelbuf_byteorder_details_t *byteorder, bool dotstar);
-mp_obj_t *pixelbuf_get_pixel(uint8_t *buf, pixelbuf_byteorder_details_t *byteorder, bool dotstar);
-mp_obj_t *pixelbuf_get_pixel_array(uint8_t *buf, uint len, pixelbuf_byteorder_details_t *byteorder, uint8_t step, mp_int_t slice_step, bool dotstar);
-void pixelbuf_set_pixel_int(uint8_t *buf, mp_int_t value, pixelbuf_byteorder_details_t *byteorder);
-
#endif
diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c
index d5da74272..0323c32cb 100644
--- a/shared-module/_stage/__init__.c
+++ b/shared-module/_stage/__init__.c
@@ -34,7 +34,8 @@
void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
mp_obj_t *layers, size_t layers_size,
uint16_t *buffer, size_t buffer_size,
- displayio_display_obj_t *display, uint8_t scale) {
+ displayio_display_obj_t *display,
+ uint8_t scale, uint16_t background) {
displayio_area_t area;
@@ -68,6 +69,9 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
break;
}
}
+ if (c == TRANSPARENT) {
+ c = background;
+ }
for (uint8_t xscale = 0; xscale < scale; ++xscale) {
buffer[index] = c;
index += 1;
diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h
index 5af2124ae..7a1826200 100644
--- a/shared-module/_stage/__init__.h
+++ b/shared-module/_stage/__init__.h
@@ -37,6 +37,7 @@
void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
mp_obj_t *layers, size_t layers_size,
uint16_t *buffer, size_t buffer_size,
- displayio_display_obj_t *display, uint8_t scale);
+ displayio_display_obj_t *display,
+ uint8_t scale, uint16_t background);
#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE
diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c
index afa3a0632..4a72dab28 100644
--- a/shared-module/audiomixer/Mixer.c
+++ b/shared-module/audiomixer/Mixer.c
@@ -101,198 +101,141 @@ void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self,
}
}
-uint32_t add8signed(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __SHADD8(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 / 2;
- 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
+__attribute__((always_inline))
+static inline uint32_t add16signed(uint32_t a, uint32_t b) {
+ return __QADD16(a, b);
}
-uint32_t add8unsigned(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __UHADD8(a, b);
- #else
- uint32_t result = 0;
- for (int8_t i = 0; i < 4; i++) {
- uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i));
- uint8_t bi = (b >> (sizeof(uint8_t) * 8 * i));
- int32_t intermediate = (int32_t) (ai + bi) / 2;
- if (intermediate > UCHAR_MAX) {
- intermediate = UCHAR_MAX;
- }
- result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i);
- }
- return result;
- #endif
+__attribute__((always_inline))
+static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
+ mul <<= 16;
+ int32_t hi, lo;
+ enum { bits = 16 }; // saturate to 16 bits
+ enum { shift = 15 }; // shift is done automatically
+ asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val));
+ asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val));
+ asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift));
+ asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift));
+ asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack
+ return val;
}
-uint32_t add16signed(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __SHADD16(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 / 2;
- 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
+static inline uint32_t tounsigned8(uint32_t val) {
+ return __UADD8(val, 0x80808080);
}
-uint32_t add16unsigned(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __UHADD16(a, b);
- #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 / 2;
- if (intermediate > USHRT_MAX) {
- intermediate = USHRT_MAX;
- }
- result |= ((uint32_t) intermediate & 0xffff) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- #endif
+static inline uint32_t tounsigned16(uint32_t val) {
+ return __UADD16(val, 0x80008000);
}
-static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
- }
- /* TODO: workout ARMv7 instructions
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return val;
- #else*/
- uint32_t result = 0;
- float mod_mul = (float) mul / (float) ((1<<15)-1);
- for (int8_t i = 0; i < 4; i++) {
- uint8_t ai = val >> (sizeof(uint8_t) * 8 * i);
- int32_t intermediate = ai * mod_mul;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- }
- result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i);
- }
+static inline uint32_t tosigned16(uint32_t val) {
+ return __UADD16(val, 0x80008000);
+}
- return result;
- //#endif
+static inline uint32_t unpack8(uint16_t val) {
+ return ((val & 0xff00) << 16) | ((val & 0x00ff) << 8);
}
-static inline uint32_t mult8signed(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
- }
- /* TODO: workout ARMv7 instructions
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return val;
- #else
- */
- uint32_t result = 0;
- float mod_mul = (float)mul / (float)((1<<15)-1);
- for (int8_t i = 0; i < 4; i++) {
- int16_t ai = val >> (sizeof(int8_t) * 8 * i);
- int32_t intermediate = ai * mod_mul;
- if (intermediate > CHAR_MAX) {
- intermediate = CHAR_MAX;
- } else if (intermediate < CHAR_MIN) {
- intermediate = CHAR_MIN;
- }
- result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- //#endif
+static inline uint32_t pack8(uint32_t val) {
+ return ((val & 0xff000000) >> 16) | ((val & 0xff00) >> 8);
}
-//TODO:
-static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
- }
- /* TODO: the below ARMv7m instructions "work", but the amplitude is much higher/louder
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- // there is no unsigned equivalent to the 'SMULWx' ARMv7 Thumb function,
- // so we have to do it by hand.
- uint32_t lo = val & 0xffff;
- uint32_t hi = val >> 16;
- //mp_printf(&mp_plat_print, "pre-asm: (mul: %d)\n\tval: %x\tlo: %x\thi: %x\n", mul, val, lo, hi);
- uint32_t val_lo;
- asm volatile("mul %0, %1, %2" : "=r" (val_lo) : "r" (mul), "r" (lo));
- asm volatile("mla %0, %1, %2, %3" : "=r" (val) : "r" (mul), "r" (hi), "r" (val_lo));
- //mp_printf(&mp_plat_print, "post-asm:\n\tval: %x\tlo: %x\n\n", val, val_lo);
- return val;
- #else
- */
- uint32_t result = 0;
- float mod_mul = (float)mul / (float)((1<<15)-1);
- for (int8_t i = 0; i < 2; i++) {
- int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000;
- int32_t intermediate = ai * mod_mul;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- } else if (intermediate < SHRT_MIN) {
- intermediate = SHRT_MIN;
+static void mix_down_one_voice(audiomixer_mixer_obj_t* self,
+ audiomixer_mixervoice_obj_t* voice, bool voices_active,
+ uint32_t* word_buffer, uint32_t length) {
+ bool voice_done = voice->sample == NULL;
+ while (!voice_done && length != 0) {
+ if (voice->buffer_length == 0) {
+ if (!voice->more_data) {
+ if (voice->loop) {
+ audiosample_reset_buffer(voice->sample, false, 0);
+ } else {
+ voice->sample = NULL;
+ voice_done = true;
+ break;
+ }
+ }
+ 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;
+ }
}
- result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- //#endif
-}
-static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
+ uint32_t n = MIN(voice->buffer_length, length);
+ uint32_t *src = voice->remaining_buffer;
+ uint16_t level = voice->level;
+
+ // First active voice gets copied over verbatim.
+ if (!voices_active) {
+ if (MP_LIKELY(self->bits_per_sample == 16)) {
+ if (MP_LIKELY(self->samples_signed)) {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t v = src[i];
+ word_buffer[i] = mult16signed(v, level);
+ }
+ } else {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t v = src[i];
+ v = tosigned16(v);
+ word_buffer[i] = mult16signed(v, level);
+ }
+ }
+ } else {
+ uint16_t *hword_buffer = (uint16_t*)word_buffer;
+ uint16_t *hsrc = (uint16_t*)src;
+ for (uint32_t i = 0; i<n*2; i++) {
+ uint32_t word = unpack8(hsrc[i]);
+ if (MP_LIKELY(!self->samples_signed)) {
+ word = tosigned16(word);
+ }
+ word = mult16signed(word, level);
+ hword_buffer[i] = pack8(word);
+ }
+ }
+ } else {
+ if (MP_LIKELY(self->bits_per_sample == 16)) {
+ if (MP_LIKELY(self->samples_signed)) {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t word = src[i];
+ word_buffer[i] = add16signed(mult16signed(word, level), word_buffer[i]);
+ }
+ } else {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t word = src[i];
+ word = tosigned16(word);
+ word_buffer[i] = add16signed(mult16signed(word, level), word_buffer[i]);
+ }
+ }
+ } else {
+ uint16_t *hword_buffer = (uint16_t*)word_buffer;
+ uint16_t *hsrc = (uint16_t*)src;
+ for (uint32_t i = 0; i<n*2; i++) {
+ uint32_t word = unpack8(hsrc[i]);
+ if (MP_LIKELY(!self->samples_signed)) {
+ word = tosigned16(word);
+ }
+ word = mult16signed(word, level);
+ word = add16signed(word, unpack8(hword_buffer[i]));
+ hword_buffer[i] = pack8(word);
+ }
+ }
+ }
+ length -= n;
+ word_buffer += n;
+ voice->remaining_buffer += n;
+ voice->buffer_length -= n;
}
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- int32_t hi, lo;
- enum { bits = 16 }; // saturate to 16 bits
- enum { shift = 0 }; // shift is done automatically
- asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val));
- asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val));
- asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift));
- asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift));
- asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack
- return val;
- #else
- uint32_t result = 0;
- float mod_mul = (float)mul / (float)((1<<15)-1);
- for (int8_t i = 0; i < 2; i++) {
- int16_t ai = val >> (sizeof(int16_t) * 8 * i);
- int32_t intermediate = ai * mod_mul;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- } else if (intermediate < SHRT_MIN) {
- intermediate = SHRT_MIN;
+
+ if (length && !voices_active) {
+ uint32_t sample_value = self->bits_per_sample == 8
+ ? 0x80808080 : 0x80008000;
+ for (uint32_t i = 0; i<length; i++) {
+ word_buffer[i] = sample_value;
}
- result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i);
}
- return result;
- #endif
}
audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t* self,
@@ -322,87 +265,25 @@ audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t*
}
self->use_first_buffer = !self->use_first_buffer;
bool voices_active = false;
+ uint32_t length = self->len / sizeof(uint32_t);
+
for (int32_t v = 0; v < self->voice_count; v++) {
audiomixer_mixervoice_obj_t* voice = MP_OBJ_TO_PTR(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];
- }
+ mix_down_one_voice(self, voice, voices_active, word_buffer, length);
+ voices_active = true;
+ }
- // apply the mixer level
- if (!self->samples_signed) {
- if (self->bits_per_sample == 8) {
- sample_value = mult8unsigned(sample_value, voice->level);
- } else {
- sample_value = mult16unsigned(sample_value, voice->level);
- }
- } else {
- if (self->bits_per_sample == 8) {
- sample_value = mult8signed(sample_value, voice->level);
- } else {
- sample_value = mult16signed(sample_value, voice->level);
- }
+ if (!self->samples_signed) {
+ if (self->bits_per_sample == 16) {
+ for (uint32_t i = 0; i < length; i++) {
+ word_buffer[i] = tounsigned16(word_buffer[i]);
}
-
- 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);
- }
- }
+ } else {
+ for (uint32_t i = 0; i < length; i++) {
+ word_buffer[i] = tounsigned8(word_buffer[i]);
}
- j++;
}
- voice->buffer_length -= j;
- voice->remaining_buffer += j;
-
- voices_active = true;
}
self->read_count += 1;
diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c
index ff05dc93e..9be104afc 100644
--- a/shared-module/audiomixer/MixerVoice.c
+++ b/shared-module/audiomixer/MixerVoice.c
@@ -34,7 +34,7 @@
void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self) {
self->sample = NULL;
- self->level = ((1 << 15) - 1);
+ self->level = 1 << 15;
}
void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t* self, audiomixer_mixer_obj_t *parent) {
@@ -42,11 +42,11 @@ void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t* se
}
float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t* self) {
- return ((float) self->level / ((1 << 15) - 1));
+ return ((float) self->level / (1 << 15));
}
void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t* self, float level) {
- self->level = level * ((1 << 15)-1);
+ self->level = level * (1 << 15);
}
void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t* self, mp_obj_t sample, bool loop) {
diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h
index efac19156..a85316e3d 100644
--- a/shared-module/audiomixer/MixerVoice.h
+++ b/shared-module/audiomixer/MixerVoice.h
@@ -39,7 +39,7 @@ typedef struct {
bool more_data;
uint32_t* remaining_buffer;
uint32_t buffer_length;
- int16_t level;
+ uint16_t level;
} audiomixer_mixervoice_obj_t;
diff --git a/shared-module/audiomp3/MP3File.c b/shared-module/audiomp3/MP3Decoder.c
index 0aa4f24a6..30357c616 100644
--- a/shared-module/audiomp3/MP3File.c
+++ b/shared-module/audiomp3/MP3Decoder.c
@@ -25,18 +25,21 @@
* THE SOFTWARE.
*/
-#include "shared-bindings/audiomp3/MP3File.h"
+#include "shared-bindings/audiomp3/MP3Decoder.h"
#include <stdint.h>
#include <string.h>
+#include <math.h>
#include "py/mperrno.h"
#include "py/runtime.h"
-#include "shared-module/audiomp3/MP3File.h"
+#include "shared-module/audiomp3/MP3Decoder.h"
#include "supervisor/shared/translate.h"
#include "lib/mp3/src/mp3common.h"
+#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
+
/** Fill the input buffer if it is less than half full.
*
* Returns true if the input buffer contains any useful data,
@@ -143,7 +146,7 @@ STATIC bool mp3file_get_next_frame_info(audiomp3_mp3file_obj_t* self, MP3FrameIn
do {
err = MP3GetNextFrameInfo(self->decoder, fi, READ_PTR(self));
if (err == ERR_MP3_NONE) {
- break;
+ break;
}
CONSUME(self, 1);
mp3file_find_sync_word(self);
@@ -165,7 +168,6 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
// than the two 4kB output buffers, except that the alignment allows to
// never allocate that extra frame buffer.
- self->file = file;
self->inbuf_length = 2048;
self->inbuf_offset = self->inbuf_length;
self->inbuf = m_malloc(self->inbuf_length, false);
@@ -181,40 +183,56 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
translate("Couldn't allocate decoder"));
}
- mp3file_find_sync_word(self);
- MP3FrameInfo fi;
- if(!mp3file_get_next_frame_info(self, &fi)) {
- mp_raise_msg(&mp_type_RuntimeError,
- translate("Failed to parse MP3 file"));
- }
-
- self->sample_rate = fi.samprate;
- self->channel_count = fi.nChans;
- self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
-
if ((intptr_t)buffer & 1) {
buffer += 1; buffer_size -= 1;
}
- if (buffer_size >= 2 * self->frame_buffer_size) {
- self->len = buffer_size / 2 / self->frame_buffer_size * self->frame_buffer_size;
+ if (buffer_size >= 2 * MAX_BUFFER_LEN) {
self->buffers[0] = (int16_t*)(void*)buffer;
- self->buffers[1] = (int16_t*)(void*)buffer + self->len;
+ self->buffers[1] = (int16_t*)(void*)(buffer + MAX_BUFFER_LEN);
} else {
- self->len = 2 * self->frame_buffer_size;
- self->buffers[0] = m_malloc(self->len, false);
+ self->buffers[0] = m_malloc(MAX_BUFFER_LEN, false);
if (self->buffers[0] == NULL) {
common_hal_audiomp3_mp3file_deinit(self);
mp_raise_msg(&mp_type_MemoryError,
translate("Couldn't allocate first buffer"));
}
- self->buffers[1] = m_malloc(self->len, false);
+ self->buffers[1] = m_malloc(MAX_BUFFER_LEN, false);
if (self->buffers[1] == NULL) {
common_hal_audiomp3_mp3file_deinit(self);
mp_raise_msg(&mp_type_MemoryError,
translate("Couldn't allocate second buffer"));
}
}
+
+ common_hal_audiomp3_mp3file_set_file(self, file);
+}
+
+void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
+ self->file = file;
+ f_lseek(&self->file->fp, 0);
+ self->inbuf_offset = self->inbuf_length;
+ self->eof = 0;
+ self->other_channel = -1;
+ mp3file_update_inbuf(self);
+ mp3file_find_sync_word(self);
+ // It **SHOULD** not be necessary to do this; the buffer should be filled
+ // with fresh content before it is returned by get_buffer(). The fact that
+ // this is necessary to avoid a glitch at the start of playback of a second
+ // track using the same decoder object means there's still a bug in
+ // get_buffer() that I didn't understand.
+ memset(self->buffers[0], 0, MAX_BUFFER_LEN);
+ memset(self->buffers[1], 0, MAX_BUFFER_LEN);
+ MP3FrameInfo fi;
+ if(!mp3file_get_next_frame_info(self, &fi)) {
+ mp_raise_msg(&mp_type_RuntimeError,
+ translate("Failed to parse MP3 file"));
+ }
+
+ self->sample_rate = fi.samprate;
+ self->channel_count = fi.nChans;
+ self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
+ self->len = 2 * self->frame_buffer_size;
}
void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self) {
@@ -280,7 +298,6 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
channel = 0;
}
- *bufptr = (uint8_t*)(self->buffers[self->buffer_index] + channel);
*buffer_length = self->frame_buffer_size;
if (channel == self->other_channel) {
@@ -289,11 +306,12 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
return GET_BUFFER_MORE_DATA;
}
- self->other_channel = 1-channel;
- self->other_buffer_index = self->buffer_index;
self->buffer_index = !self->buffer_index;
+ self->other_channel = 1-channel;
+ self->other_buffer_index = self->buffer_index;
int16_t *buffer = (int16_t *)(void *)self->buffers[self->buffer_index];
+ *bufptr = (uint8_t*)buffer;
mp3file_skip_id3v2(self);
if (!mp3file_find_sync_word(self)) {
@@ -322,3 +340,13 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t* self, bool si
*spacing = 1;
}
}
+
+float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self) {
+ float sumsq = 0.f;
+ // Assumes no DC component to the audio. Is that a safe assumption?
+ int16_t *buffer = (int16_t *)(void *)self->buffers[self->buffer_index];
+ for(size_t i=0; i<self->frame_buffer_size / sizeof(int16_t); i++) {
+ sumsq += (float)buffer[i] * buffer[i];
+ }
+ return sqrtf(sumsq) / (self->frame_buffer_size / sizeof(int16_t));
+}
diff --git a/shared-module/audiomp3/MP3File.h b/shared-module/audiomp3/MP3Decoder.h
index 9d99e8d1f..9ee1d0949 100644
--- a/shared-module/audiomp3/MP3File.h
+++ b/shared-module/audiomp3/MP3Decoder.h
@@ -67,4 +67,6 @@ void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t* self, bool si
bool* single_buffer, bool* samples_signed,
uint32_t* max_buffer_length, uint8_t* spacing);
+float audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self);
+
#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c
index 914bc4313..952e1fc10 100644
--- a/shared-module/board/__init__.c
+++ b/shared-module/board/__init__.c
@@ -100,8 +100,28 @@ mp_obj_t common_hal_board_create_uart(void) {
const mcu_pin_obj_t* rx = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RX);
const mcu_pin_obj_t* tx = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_TX);
+#ifdef DEFAULT_UART_BUS_RTS
+ const mcu_pin_obj_t* rts = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RTS);
+#else
+ const mcu_pin_obj_t* rts = mp_const_none;
+#endif
+#ifdef DEFAULT_UART_BUS_CTS
+ const mcu_pin_obj_t* cts = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_CTS);
+#else
+ const mcu_pin_obj_t* cts = mp_const_none;
+#endif
+#ifdef DEFAULT_UART_IS_RS485
+ const mcu_pin_obj_t* rs485_dir = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RS485DIR);
+#ifdef DEFAULT_UART_RS485_INVERT
+ const bool rs485_invert = true;
+#endif
+#else
+ const mcu_pin_obj_t* rs485_dir = mp_const_none;
+ const bool rs485_invert = true;
+#endif
- common_hal_busio_uart_construct(self, tx, rx, 9600, 8, PARITY_NONE, 1, 1.0f, 64);
+ common_hal_busio_uart_construct(self, tx, rx, rts, cts, rs485_dir, rs485_invert,
+ 9600, 8, PARITY_NONE, 1, 1.0f, 64);
MP_STATE_VM(shared_uart_bus) = MP_OBJ_FROM_PTR(self);
return MP_STATE_VM(shared_uart_bus);
}
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index af22cb0df..efa61265e 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -16,6 +16,9 @@
#include "supervisor/shared/display.h"
#include "supervisor/memory.h"
+#include "supervisor/spi_flash_api.h"
+#include "py/mpconfig.h"
+
primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
// Check for recursive calls to displayio_background.
@@ -100,6 +103,11 @@ void reset_displays(void) {
continue;
}
#endif
+ #ifdef BOARD_USE_INTERNAL_SPI
+ if (original_spi == (mp_obj_t)(&supervisor_flash_spi_bus)) {
+ continue;
+ }
+ #endif
memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t));
fourwire->bus = &fourwire->inline_bus;
// Check for other displays that use the same spi bus and swap them too.
diff --git a/shared-module/storage/__init__.c b/shared-module/storage/__init__.c
index 215e1356a..c3d4b50c8 100644
--- a/shared-module/storage/__init__.c
+++ b/shared-module/storage/__init__.c
@@ -149,9 +149,7 @@ void common_hal_storage_remount(const char *mount_path, bool readonly, bool disa
}
#ifdef USB_AVAILABLE
- // TODO(dhalbert): is this is a good enough check? It checks for
- // CDC enabled. There is no "MSC enabled" check.
- if (usb_enabled()) {
+ if (!usb_msc_ejected()) {
mp_raise_RuntimeError(translate("Cannot remount '/' when USB is active."));
}
#endif