commit
6df88ac948
|
@ -193,6 +193,10 @@ msgstr ""
|
|||
msgid "%q must be array of type 'H'"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/synthio/MidiTrack.c shared-bindings/synthio/__init__.c
|
||||
msgid "%q must be array of type 'h'"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c
|
||||
#: shared-bindings/canio/CAN.c shared-bindings/digitalio/Pull.c
|
||||
msgid "%q must be of type %q or %q, not %q"
|
||||
|
|
|
@ -44,6 +44,8 @@ CIRCUITPY_AUDIOIO = 1
|
|||
CIRCUITPY_AUDIOMIXER = 1
|
||||
CIRCUITPY_DISPLAYIO = 1
|
||||
CIRCUITPY_KEYPAD = 1
|
||||
CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS = 0
|
||||
CIRCUITPY_KEYPAD_KEYMATRIX = 0
|
||||
CIRCUITPY_MATH = 1
|
||||
CIRCUITPY_STAGE = 1
|
||||
CIRCUITPY_SYNTHIO = 1
|
||||
|
|
|
@ -38,7 +38,6 @@ INC += \
|
|||
-Iboards/$(BOARD) \
|
||||
-Iperipherals/ \
|
||||
-Iperipherals/mimxrt10xx/ \
|
||||
-Isdk/CMSIS/Include \
|
||||
-Isdk/devices/$(CHIP_FAMILY) \
|
||||
-Isdk/devices/$(CHIP_FAMILY)/drivers \
|
||||
-Isdk/drivers/common
|
||||
|
|
|
@ -18,6 +18,7 @@ CIRCUITPY_AUDIOIO = 0
|
|||
CIRCUITPY_AUDIOMIXER = 1
|
||||
CIRCUITPY_AUDIOMP3 = 1
|
||||
CIRCUITPY_AUDIOPWMIO = 1
|
||||
CIRCUITPY_SYNTHIO_MAX_CHANNELS = 12
|
||||
CIRCUITPY_BUSDEVICE = 1
|
||||
CIRCUITPY_COUNTIO = 0
|
||||
CIRCUITPY_FREQUENCYIO = 0
|
||||
|
|
|
@ -19,6 +19,7 @@ CIRCUITPY_PWMIO ?= 1
|
|||
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_DISPLAYIO)
|
||||
CIRCUITPY_ROTARYIO ?= 1
|
||||
CIRCUITPY_ROTARYIO_SOFTENCODER = 1
|
||||
CIRCUITPY_SYNTHIO_MAX_CHANNELS = 12
|
||||
|
||||
# Things that need to be implemented.
|
||||
# Use PWM internally
|
||||
|
|
|
@ -30,15 +30,30 @@ SRC_BITMAP := \
|
|||
displayio_min.c \
|
||||
shared-bindings/aesio/aes.c \
|
||||
shared-bindings/aesio/__init__.c \
|
||||
shared-bindings/audiocore/__init__.c \
|
||||
shared-bindings/audiocore/RawSample.c \
|
||||
shared-bindings/audiocore/WaveFile.c \
|
||||
shared-bindings/audiomixer/__init__.c \
|
||||
shared-bindings/audiomixer/Mixer.c \
|
||||
shared-bindings/audiomixer/MixerVoice.c \
|
||||
shared-bindings/bitmaptools/__init__.c \
|
||||
shared-bindings/displayio/Bitmap.c \
|
||||
shared-bindings/rainbowio/__init__.c \
|
||||
shared-bindings/struct/__init__.c \
|
||||
shared-bindings/synthio/__init__.c \
|
||||
shared-bindings/synthio/MidiTrack.c \
|
||||
shared-bindings/synthio/Synthesizer.c \
|
||||
shared-bindings/traceback/__init__.c \
|
||||
shared-bindings/util.c \
|
||||
shared-bindings/zlib/__init__.c \
|
||||
shared-module/aesio/aes.c \
|
||||
shared-module/aesio/__init__.c \
|
||||
shared-module/audiocore/__init__.c \
|
||||
shared-module/audiocore/RawSample.c \
|
||||
shared-module/audiocore/WaveFile.c \
|
||||
shared-module/audiomixer/__init__.c \
|
||||
shared-module/audiomixer/Mixer.c \
|
||||
shared-module/audiomixer/MixerVoice.c \
|
||||
shared-module/bitmaptools/__init__.c \
|
||||
shared-module/displayio/area.c \
|
||||
shared-module/displayio/Bitmap.c \
|
||||
|
@ -47,6 +62,9 @@ SRC_BITMAP := \
|
|||
shared-module/os/getenv.c \
|
||||
shared-module/rainbowio/__init__.c \
|
||||
shared-module/struct/__init__.c \
|
||||
shared-module/synthio/__init__.c \
|
||||
shared-module/synthio/MidiTrack.c \
|
||||
shared-module/synthio/Synthesizer.c \
|
||||
shared-module/traceback/__init__.c \
|
||||
shared-module/zlib/__init__.c \
|
||||
|
||||
|
@ -54,12 +72,17 @@ SRC_C += $(SRC_BITMAP)
|
|||
|
||||
CFLAGS += \
|
||||
-DCIRCUITPY_AESIO=1 \
|
||||
-DCIRCUITPY_AUDIOCORE=1 \
|
||||
-DCIRCUITPY_AUDIOMIXER=1 \
|
||||
-DCIRCUITPY_AUDIOCORE_DEBUG=1 \
|
||||
-DCIRCUITPY_BITMAPTOOLS=1 \
|
||||
-DCIRCUITPY_DISPLAYIO_UNIX=1 \
|
||||
-DCIRCUITPY_OS_GETENV=1 \
|
||||
-DCIRCUITPY_GIFIO=1 \
|
||||
-DCIRCUITPY_OS_GETENV=1 \
|
||||
-DCIRCUITPY_RAINBOWIO=1 \
|
||||
-DCIRCUITPY_STRUCT=1 \
|
||||
-DCIRCUITPY_SYNTHIO=1 \
|
||||
-DCIRCUITPY_SYNTHIO_MAX_CHANNELS=14 \
|
||||
-DCIRCUITPY_TRACEBACK=1 \
|
||||
-DCIRCUITPY_ZLIB=1
|
||||
|
||||
|
|
|
@ -648,6 +648,7 @@ SRC_SHARED_MODULE_ALL = \
|
|||
supervisor/__init__.c \
|
||||
supervisor/StatusBar.c \
|
||||
synthio/MidiTrack.c \
|
||||
synthio/Synthesizer.c \
|
||||
synthio/__init__.c \
|
||||
terminalio/Terminal.c \
|
||||
terminalio/__init__.c \
|
||||
|
|
|
@ -107,6 +107,11 @@ CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE)
|
|||
CIRCUITPY_AUDIOMIXER ?= $(CIRCUITPY_AUDIOIO)
|
||||
CFLAGS += -DCIRCUITPY_AUDIOMIXER=$(CIRCUITPY_AUDIOMIXER)
|
||||
|
||||
ifndef CIRCUITPY_AUDIOCORE_DEBUG
|
||||
CIRCUITPY_AUDIOCORE_DEBUG ?= 0
|
||||
endif
|
||||
CFLAGS += -DCIRCUITPY_AUDIOCORE_DEBUG=$(CIRCUITPY_AUDIOCORE_DEBUG)
|
||||
|
||||
ifndef CIRCUITPY_AUDIOMP3
|
||||
ifeq ($(CIRCUITPY_FULL_BUILD),1)
|
||||
CIRCUITPY_AUDIOMP3 = $(CIRCUITPY_AUDIOCORE)
|
||||
|
@ -286,6 +291,15 @@ CFLAGS += -DCIRCUITPY_JSON=$(CIRCUITPY_JSON)
|
|||
CIRCUITPY_KEYPAD ?= $(CIRCUITPY_FULL_BUILD)
|
||||
CFLAGS += -DCIRCUITPY_KEYPAD=$(CIRCUITPY_KEYPAD)
|
||||
|
||||
CIRCUITPY_KEYPAD_KEYS ?= $(CIRCUITPY_KEYPAD)
|
||||
CFLAGS += -DCIRCUITPY_KEYPAD_KEYS=$(CIRCUITPY_KEYPAD_KEYS)
|
||||
|
||||
CIRCUITPY_KEYPAD_KEYMATRIX ?= $(CIRCUITPY_KEYPAD)
|
||||
CFLAGS += -DCIRCUITPY_KEYPAD_KEYMATRIX=$(CIRCUITPY_KEYPAD_KEYMATRIX)
|
||||
|
||||
CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS ?= $(CIRCUITPY_KEYPAD)
|
||||
CFLAGS += -DCIRCUITPY_KEYPAD_SHIFTREGISTERKEYS=$(CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS)
|
||||
|
||||
CIRCUITPY_MATH ?= 1
|
||||
CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH)
|
||||
|
||||
|
@ -437,6 +451,10 @@ CFLAGS += -DCIRCUITPY_SUPERVISOR=$(CIRCUITPY_SUPERVISOR)
|
|||
CIRCUITPY_SYNTHIO ?= $(CIRCUITPY_AUDIOCORE)
|
||||
CFLAGS += -DCIRCUITPY_SYNTHIO=$(CIRCUITPY_SYNTHIO)
|
||||
|
||||
CIRCUITPY_SYNTHIO_MAX_CHANNELS ?= 2
|
||||
CFLAGS += -DCIRCUITPY_SYNTHIO_MAX_CHANNELS=$(CIRCUITPY_SYNTHIO_MAX_CHANNELS)
|
||||
|
||||
|
||||
CIRCUITPY_SYS ?= 1
|
||||
CFLAGS += -DCIRCUITPY_SYS=$(CIRCUITPY_SYS)
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
//| ...
|
||||
STATIC mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
#if !CIRCUITPY_AUDIOBUSIO_I2SOUT
|
||||
mp_raise_NotImplementedError(translate("I2SOut not available"));
|
||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_I2SOut);
|
||||
return NULL; // Not reachable.
|
||||
#else
|
||||
enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_left_justified };
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
//| ...
|
||||
STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
#if !CIRCUITPY_AUDIOBUSIO_PDMIN
|
||||
mp_raise_NotImplementedError(translate("PDMIn not available"));
|
||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_PDMIn);
|
||||
#else
|
||||
enum { ARG_clock_pin, ARG_data_pin, ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_oversample, ARG_startup_delay };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
//| def __init__(
|
||||
//| self, buffer: ReadableBuffer, *, channel_count: int = 1, sample_rate: int = 8000
|
||||
//| ) -> None:
|
||||
//| """Create a RawSample based on the given buffer of signed values. If channel_count is more than
|
||||
//| """Create a RawSample based on the given buffer of values. If channel_count is more than
|
||||
//| 1 then each channel's samples should alternate. In other words, for a two channel buffer, the
|
||||
//| first sample will be for channel 1, the second sample will be for channel two, the third for
|
||||
//| channel 1 and so on.
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "shared-bindings/audiocore/WaveFile.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
#include "extmod/vfs_posix.h"
|
||||
|
||||
//| class WaveFile:
|
||||
//| """Load a wave file for audio playback
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audiocore/__init__.h"
|
||||
#include "shared-bindings/audiocore/RawSample.h"
|
||||
#include "shared-bindings/audiocore/WaveFile.h"
|
||||
|
@ -37,10 +36,57 @@
|
|||
|
||||
//| """Support for audio samples"""
|
||||
|
||||
#if CIRCUITPY_AUDIOCORE_DEBUG
|
||||
// (no docstrings so that the debug functions are not shown on docs.circuitpython.org)
|
||||
STATIC mp_obj_t audiocore_get_buffer(mp_obj_t sample_in) {
|
||||
uint8_t *buffer = NULL;
|
||||
uint32_t buffer_length = 0;
|
||||
audioio_get_buffer_result_t gbr = audiosample_get_buffer(sample_in, false, 0, &buffer, &buffer_length);
|
||||
|
||||
mp_obj_t result[2] = {mp_obj_new_int_from_uint(gbr), mp_const_none};
|
||||
|
||||
if (gbr != GET_BUFFER_ERROR) {
|
||||
// copies the data because the gc semantics of get_buffer are unclear
|
||||
result[1] = mp_obj_new_bytes(buffer, buffer_length);
|
||||
}
|
||||
|
||||
return mp_obj_new_tuple(2, result);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiocore_get_buffer_obj, audiocore_get_buffer);
|
||||
|
||||
STATIC mp_obj_t audiocore_get_structure(mp_obj_t sample_in) {
|
||||
bool single_buffer, samples_signed;
|
||||
uint32_t max_buffer_length;
|
||||
uint8_t spacing;
|
||||
|
||||
audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
|
||||
mp_obj_t result[4] = {
|
||||
mp_obj_new_int_from_uint(single_buffer),
|
||||
mp_obj_new_int_from_uint(samples_signed),
|
||||
mp_obj_new_int_from_uint(max_buffer_length),
|
||||
mp_obj_new_int_from_uint(spacing),
|
||||
};
|
||||
return mp_obj_new_tuple(4, result);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiocore_get_structure_obj, audiocore_get_structure);
|
||||
|
||||
STATIC mp_obj_t audiocore_reset_buffer(mp_obj_t sample_in) {
|
||||
audiosample_reset_buffer(sample_in, false, 0);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiocore_reset_buffer_obj, audiocore_reset_buffer);
|
||||
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t audiocore_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiocore) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) },
|
||||
#if CIRCUITPY_AUDIOCORE_DEBUG
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_buffer), MP_ROM_PTR(&audiocore_get_buffer_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset_buffer), MP_ROM_PTR(&audiocore_reset_buffer_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_structure), MP_ROM_PTR(&audiocore_get_structure_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(audiocore_module_globals, audiocore_module_globals_table);
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
#include "py/binary.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audiocore/RawSample.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
|
|
|
@ -27,9 +27,7 @@
|
|||
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H
|
||||
#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H
|
||||
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "shared-module/audiomixer/Mixer.h"
|
||||
#include "shared-bindings/audiocore/RawSample.h"
|
||||
|
||||
extern const mp_obj_type_t audiomixer_mixer_type;
|
||||
extern const mp_obj_type_t audiomixer_mixervoice_type;
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
#include "py/binary.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audiocore/RawSample.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
|
@ -115,7 +113,7 @@ STATIC mp_obj_t audiomixer_mixervoice_obj_set_level(size_t n_args, const mp_obj_
|
|||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
float level = mp_obj_get_float(args[ARG_level].u_obj);
|
||||
mp_float_t level = mp_obj_get_float(args[ARG_level].u_obj);
|
||||
|
||||
if (level > 1 || level < 0) {
|
||||
mp_raise_ValueError(translate("level must be between 0 and 1"));
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
#ifndef SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_
|
||||
#define SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_
|
||||
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audiocore/RawSample.h"
|
||||
|
||||
#include "shared-module/audiomixer/MixerVoice.h"
|
||||
#include "shared-module/audiomixer/Mixer.h"
|
||||
|
||||
|
@ -39,8 +36,8 @@ void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *sel
|
|||
void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t *self, audiomixer_mixer_obj_t *parent);
|
||||
void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample, bool loop);
|
||||
void common_hal_audiomixer_mixervoice_stop(audiomixer_mixervoice_obj_t *self);
|
||||
float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self);
|
||||
void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *self, float gain);
|
||||
mp_float_t common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self);
|
||||
void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *self, mp_float_t gain);
|
||||
|
||||
bool common_hal_audiomixer_mixervoice_get_playing(audiomixer_mixervoice_obj_t *self);
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audiomixer/Mixer.h"
|
||||
|
||||
//| """Support for audio mixing"""
|
||||
|
|
|
@ -167,9 +167,9 @@ STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
|||
|
||||
STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "<Event: key_number %d %s>",
|
||||
mp_printf(print, "<Event: key_number %d %q>",
|
||||
common_hal_keypad_event_get_key_number(self),
|
||||
common_hal_keypad_event_get_pressed(self) ? "pressed" : "released");
|
||||
common_hal_keypad_event_get_pressed(self) ? MP_QSTR_pressed : MP_QSTR_released);
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = {
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
//| ...
|
||||
|
||||
STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
#if CIRCUITPY_KEYPAD_KEYMATRIX
|
||||
keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t);
|
||||
self->base.type = &keypad_keymatrix_type;
|
||||
enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events };
|
||||
|
@ -114,8 +115,13 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar
|
|||
|
||||
common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
#else
|
||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_KeyMatrix);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CIRCUITPY_KEYPAD_KEYMATRIX
|
||||
//| def deinit(self) -> None:
|
||||
//| """Stop scanning and release the pins."""
|
||||
//| ...
|
||||
|
@ -228,9 +234,13 @@ STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = {
|
|||
|
||||
STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table);
|
||||
|
||||
#endif
|
||||
|
||||
const mp_obj_type_t keypad_keymatrix_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_KeyMatrix,
|
||||
.make_new = keypad_keymatrix_make_new,
|
||||
#if CIRCUITPY_KEYPAD_KEYMATRIX
|
||||
.locals_dict = (mp_obj_t)&keypad_keymatrix_locals_dict,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
//| ...
|
||||
|
||||
STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
#if CIRCUITPY_KEYPAD_KEYS
|
||||
keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t);
|
||||
self->base.type = &keypad_keys_type;
|
||||
enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events };
|
||||
|
@ -106,8 +107,13 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, s
|
|||
common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
#else
|
||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_Keys);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CIRCUITPY_KEYPAD_KEYS
|
||||
//| def deinit(self) -> None:
|
||||
//| """Stop scanning and release the pins."""
|
||||
//| ...
|
||||
|
@ -162,10 +168,13 @@ STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = {
|
|||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table);
|
||||
#endif
|
||||
|
||||
const mp_obj_type_t keypad_keys_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Keys,
|
||||
.make_new = keypad_keys_make_new,
|
||||
#if CIRCUITPY_KEYPAD_KEYS
|
||||
.locals_dict = (mp_obj_t)&keypad_keys_locals_dict,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
//| ...
|
||||
|
||||
STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
#if CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS
|
||||
keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t);
|
||||
self->base.type = &keypad_shiftregisterkeys_type;
|
||||
enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events };
|
||||
|
@ -113,8 +114,12 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz
|
|||
self, clock, data, latch, value_to_latch, key_count, value_when_pressed, interval, max_events);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
#else
|
||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_ShiftRegisterKeys);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS
|
||||
//| def deinit(self) -> None:
|
||||
//| """Stop scanning and release the pins."""
|
||||
//| ...
|
||||
|
@ -169,10 +174,13 @@ STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = {
|
|||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table);
|
||||
#endif
|
||||
|
||||
const mp_obj_type_t keypad_shiftregisterkeys_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ShiftRegisterKeys,
|
||||
.make_new = keypad_shiftregisterkeys_make_new,
|
||||
#if CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS
|
||||
.locals_dict = (mp_obj_t)&keypad_shiftregisterkeys_locals_dict,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -32,13 +32,19 @@
|
|||
#include "py/runtime.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-bindings/synthio/MidiTrack.h"
|
||||
#include "shared-bindings/synthio/__init__.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
//| class MidiTrack:
|
||||
//| """Simple square-wave MIDI synth"""
|
||||
//| """Simple MIDI synth"""
|
||||
//|
|
||||
//| def __init__(
|
||||
//| self, buffer: ReadableBuffer, tempo: int, *, sample_rate: int = 11025
|
||||
//| self,
|
||||
//| buffer: ReadableBuffer,
|
||||
//| tempo: int,
|
||||
//| *,
|
||||
//| sample_rate: int = 11025,
|
||||
//| waveform: ReadableBuffer = None
|
||||
//| ) -> None:
|
||||
//| """Create a MidiTrack from the given stream of MIDI events. Only "Note On" and "Note Off" events
|
||||
//| are supported; channel numbers and key velocities are ignored. Up to two notes may be on at the
|
||||
|
@ -47,6 +53,7 @@
|
|||
//| :param ~circuitpython_typing.ReadableBuffer buffer: Stream of MIDI events, as stored in a MIDI file track chunk
|
||||
//| :param int tempo: Tempo of the streamed events, in MIDI ticks per second
|
||||
//| :param int sample_rate: The desired playback sample rate; higher sample rate requires more memory
|
||||
//| :param ReadableBuffer waveform: A single-cycle waveform. Default is a 50% duty cycle square wave. If specified, must be a ReadableBuffer of type 'h' (signed 16 bit)
|
||||
//|
|
||||
//| Simple melody::
|
||||
//|
|
||||
|
@ -65,11 +72,12 @@
|
|||
//| print("stopped")"""
|
||||
//| ...
|
||||
STATIC mp_obj_t synthio_miditrack_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_buffer, ARG_tempo, ARG_sample_rate };
|
||||
enum { ARG_buffer, ARG_tempo, ARG_sample_rate, ARG_waveform };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_tempo, MP_ARG_INT | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} },
|
||||
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
@ -77,13 +85,18 @@ STATIC mp_obj_t synthio_miditrack_make_new(const mp_obj_type_t *type, size_t n_a
|
|||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
mp_buffer_info_t bufinfo_waveform;
|
||||
synthio_synth_parse_waveform(&bufinfo_waveform, args[ARG_waveform].u_obj);
|
||||
|
||||
synthio_miditrack_obj_t *self = m_new_obj(synthio_miditrack_obj_t);
|
||||
self->base.type = &synthio_miditrack_type;
|
||||
|
||||
common_hal_synthio_miditrack_construct(self,
|
||||
(uint8_t *)bufinfo.buf, bufinfo.len,
|
||||
args[ARG_tempo].u_int,
|
||||
args[ARG_sample_rate].u_int);
|
||||
args[ARG_sample_rate].u_int,
|
||||
bufinfo_waveform.buf,
|
||||
bufinfo_waveform.len / 2);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
extern const mp_obj_type_t synthio_miditrack_type;
|
||||
|
||||
void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self,
|
||||
const uint8_t *buffer, uint32_t len, uint32_t tempo, uint32_t sample_rate);
|
||||
const uint8_t *buffer, uint32_t len, uint32_t tempo, uint32_t sample_rate, const int16_t *waveform, uint16_t waveform_len);
|
||||
|
||||
void common_hal_synthio_miditrack_deinit(synthio_miditrack_obj_t *self);
|
||||
bool common_hal_synthio_miditrack_deinited(synthio_miditrack_obj_t *self);
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Artyom Skrobov
|
||||
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "shared/runtime/context_manager_helpers.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-bindings/synthio/Synthesizer.h"
|
||||
#include "shared-bindings/synthio/__init__.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
//| class Synth:
|
||||
//| def __init__(self, *, sample_rate: int = 11025, waveform: ReadableBuffer = None) -> None:
|
||||
//| """Create a synthesizer object."""
|
||||
STATIC mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_sample_rate, ARG_waveform };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} },
|
||||
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_buffer_info_t bufinfo_waveform;
|
||||
synthio_synth_parse_waveform(&bufinfo_waveform, args[ARG_waveform].u_obj);
|
||||
|
||||
synthio_synthesizer_obj_t *self = m_new_obj(synthio_synthesizer_obj_t);
|
||||
self->base.type = &synthio_synthesizer_type;
|
||||
|
||||
common_hal_synthio_synthesizer_construct(self,
|
||||
args[ARG_sample_rate].u_int,
|
||||
bufinfo_waveform.buf,
|
||||
bufinfo_waveform.len / 2);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC void check_for_deinit(synthio_synthesizer_obj_t *self) {
|
||||
if (common_hal_synthio_synthesizer_deinited(self)) {
|
||||
raise_deinited_error();
|
||||
}
|
||||
}
|
||||
|
||||
//| def press(self, /, press: Sequence[int] = ()) -> None:
|
||||
//| """Turn some notes on. Notes use MIDI numbering, with 60 being middle C."""
|
||||
STATIC mp_obj_t synthio_synthesizer_press(mp_obj_t self_in, mp_obj_t press) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
common_hal_synthio_synthesizer_press(self, press);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(synthio_synthesizer_press_obj, synthio_synthesizer_press);
|
||||
//
|
||||
//| def release_then_press(
|
||||
//| self, release: Sequence[int] = (), press: Sequence[int] = ()
|
||||
//| ) -> None:
|
||||
//| """Turn some notes on and/or off. Notes use MIDI numbering, with 60 being middle C."""
|
||||
STATIC mp_obj_t synthio_synthesizer_release_then_press(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_release, ARG_press };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_release, MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple } },
|
||||
{ MP_QSTR_press, MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
check_for_deinit(self);
|
||||
common_hal_synthio_synthesizer_release(self, args[ARG_release].u_obj);
|
||||
common_hal_synthio_synthesizer_press(self, args[ARG_press].u_obj);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(synthio_synthesizer_release_then_press_obj, 1, synthio_synthesizer_release_then_press);
|
||||
|
||||
//
|
||||
//| def release_all_then_press(self, /, press: Sequence[int]) -> None:
|
||||
//| """Turn any currently-playing notes off, then turn on the given notes"""
|
||||
STATIC mp_obj_t synthio_synthesizer_release_all_then_press(mp_obj_t self_in, mp_obj_t press) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
common_hal_synthio_synthesizer_release_all(self);
|
||||
common_hal_synthio_synthesizer_press(self, press);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(synthio_synthesizer_release_all_then_press_obj, synthio_synthesizer_release_all_then_press);
|
||||
|
||||
//
|
||||
//| def release_all(self) -> None:
|
||||
//| """Turn any currently-playing notes off"""
|
||||
STATIC mp_obj_t synthio_synthesizer_release_all(mp_obj_t self_in) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
common_hal_synthio_synthesizer_release_all(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(synthio_synthesizer_release_all_obj, synthio_synthesizer_release_all);
|
||||
|
||||
//| def deinit(self) -> None:
|
||||
//| """Deinitialises the object and releases any memory resources for reuse."""
|
||||
//| ...
|
||||
STATIC mp_obj_t synthio_synthesizer_deinit(mp_obj_t self_in) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_synthio_synthesizer_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(synthio_synthesizer_deinit_obj, synthio_synthesizer_deinit);
|
||||
|
||||
//| def __enter__(self) -> MidiTrack:
|
||||
//| """No-op used by Context Managers."""
|
||||
//| ...
|
||||
// Provided by context manager helper.
|
||||
//|
|
||||
//| def __exit__(self) -> None:
|
||||
//| """Automatically deinitializes the hardware when exiting a context. See
|
||||
//| :ref:`lifetime-and-contextmanagers` for more info."""
|
||||
//| ...
|
||||
STATIC mp_obj_t synthio_synthesizer_obj___exit__(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
common_hal_synthio_synthesizer_deinit(args[0]);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(synthio_synthesizer___exit___obj, 4, 4, synthio_synthesizer_obj___exit__);
|
||||
//| sample_rate: int
|
||||
//| """32 bit value that tells how quickly samples are played in Hertz (cycles per second)."""
|
||||
STATIC mp_obj_t synthio_synthesizer_obj_get_sample_rate(mp_obj_t self_in) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_synthio_synthesizer_get_sample_rate(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_synthesizer_get_sample_rate_obj, synthio_synthesizer_obj_get_sample_rate);
|
||||
|
||||
MP_PROPERTY_GETTER(synthio_synthesizer_sample_rate_obj,
|
||||
(mp_obj_t)&synthio_synthesizer_get_sample_rate_obj);
|
||||
|
||||
//| pressed: Tuple[int]
|
||||
//| """A sequence of the currently pressed notes (read-only property)"""
|
||||
//|
|
||||
STATIC mp_obj_t synthio_synthesizer_obj_get_pressed(mp_obj_t self_in) {
|
||||
synthio_synthesizer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
check_for_deinit(self);
|
||||
return common_hal_synthio_synthesizer_get_pressed_notes(self);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_synthesizer_get_pressed_obj, synthio_synthesizer_obj_get_pressed);
|
||||
|
||||
MP_PROPERTY_GETTER(synthio_synthesizer_pressed_obj,
|
||||
(mp_obj_t)&synthio_synthesizer_get_pressed_obj);
|
||||
|
||||
STATIC const mp_rom_map_elem_t synthio_synthesizer_locals_dict_table[] = {
|
||||
// Methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_press), MP_ROM_PTR(&synthio_synthesizer_press_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_all), MP_ROM_PTR(&synthio_synthesizer_release_all_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_then_press), MP_ROM_PTR(&synthio_synthesizer_release_then_press_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_release_all_then_press), MP_ROM_PTR(&synthio_synthesizer_release_all_then_press_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&synthio_synthesizer_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&synthio_synthesizer___exit___obj) },
|
||||
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&synthio_synthesizer_sample_rate_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&synthio_synthesizer_pressed_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(synthio_synthesizer_locals_dict, synthio_synthesizer_locals_dict_table);
|
||||
|
||||
STATIC const audiosample_p_t synthio_synthesizer_proto = {
|
||||
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
|
||||
.sample_rate = (audiosample_sample_rate_fun)common_hal_synthio_synthesizer_get_sample_rate,
|
||||
.bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_synthio_synthesizer_get_bits_per_sample,
|
||||
.channel_count = (audiosample_channel_count_fun)common_hal_synthio_synthesizer_get_channel_count,
|
||||
.reset_buffer = (audiosample_reset_buffer_fun)synthio_synthesizer_reset_buffer,
|
||||
.get_buffer = (audiosample_get_buffer_fun)synthio_synthesizer_get_buffer,
|
||||
.get_buffer_structure = (audiosample_get_buffer_structure_fun)synthio_synthesizer_get_buffer_structure,
|
||||
};
|
||||
|
||||
const mp_obj_type_t synthio_synthesizer_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Synthesizer,
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.make_new = synthio_synthesizer_make_new,
|
||||
.locals_dict = (mp_obj_dict_t *)&synthio_synthesizer_locals_dict,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
.protocol = &synthio_synthesizer_proto,
|
||||
),
|
||||
};
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Artyom Skrobov
|
||||
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared-module/synthio/Synthesizer.h"
|
||||
|
||||
extern const mp_obj_type_t synthio_synthesizer_type;
|
||||
|
||||
void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self,
|
||||
uint32_t sample_rate, const int16_t *waveform, uint16_t waveform_len);
|
||||
|
||||
void common_hal_synthio_synthesizer_deinit(synthio_synthesizer_obj_t *self);
|
||||
bool common_hal_synthio_synthesizer_deinited(synthio_synthesizer_obj_t *self);
|
||||
uint32_t common_hal_synthio_synthesizer_get_sample_rate(synthio_synthesizer_obj_t *self);
|
||||
uint8_t common_hal_synthio_synthesizer_get_bits_per_sample(synthio_synthesizer_obj_t *self);
|
||||
uint8_t common_hal_synthio_synthesizer_get_channel_count(synthio_synthesizer_obj_t *self);
|
||||
void common_hal_synthio_synthesizer_release(synthio_synthesizer_obj_t *self, mp_obj_t to_release);
|
||||
void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_obj_t to_press);
|
||||
void common_hal_synthio_synthesizer_release_all(synthio_synthesizer_obj_t *self);
|
||||
mp_obj_t common_hal_synthio_synthesizer_get_pressed_notes(synthio_synthesizer_obj_t *self);
|
|
@ -30,9 +30,11 @@
|
|||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "extmod/vfs_posix.h"
|
||||
|
||||
#include "shared-bindings/synthio/__init__.h"
|
||||
#include "shared-bindings/synthio/MidiTrack.h"
|
||||
#include "shared-bindings/synthio/Synthesizer.h"
|
||||
|
||||
//| """Support for MIDI synthesis"""
|
||||
//|
|
||||
|
@ -42,6 +44,7 @@
|
|||
//|
|
||||
//| :param typing.BinaryIO file: Already opened MIDI file
|
||||
//| :param int sample_rate: The desired playback sample rate; higher sample rate requires more memory
|
||||
//| :param ReadableBuffer waveform: A single-cycle waveform. Default is a 50% duty cycle square wave. If specified, must be a ReadableBuffer of type 'h' (signed 16 bit)
|
||||
//|
|
||||
//|
|
||||
//| Playing a MIDI file from flash::
|
||||
|
@ -62,10 +65,11 @@
|
|||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_file, ARG_sample_rate };
|
||||
enum { ARG_file, ARG_sample_rate, ARG_waveform };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} },
|
||||
{ MP_QSTR_waveform, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
@ -74,6 +78,10 @@ STATIC mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
|||
}
|
||||
pyb_file_obj_t *file = MP_OBJ_TO_PTR(args[ARG_file].u_obj);
|
||||
|
||||
|
||||
mp_buffer_info_t bufinfo_waveform;
|
||||
synthio_synth_parse_waveform(&bufinfo_waveform, args[ARG_waveform].u_obj);
|
||||
|
||||
uint8_t chunk_header[14];
|
||||
f_rewind(&file->fp);
|
||||
UINT bytes_read;
|
||||
|
@ -113,9 +121,13 @@ STATIC mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
|||
result->base.type = &synthio_miditrack_type;
|
||||
|
||||
common_hal_synthio_miditrack_construct(result, buffer, track_size,
|
||||
tempo, args[ARG_sample_rate].u_int);
|
||||
tempo, args[ARG_sample_rate].u_int, bufinfo_waveform.buf, bufinfo_waveform.len / 2);
|
||||
|
||||
#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
|
||||
m_free(buffer, track_size);
|
||||
#else
|
||||
m_free(buffer);
|
||||
#endif
|
||||
|
||||
return MP_OBJ_FROM_PTR(result);
|
||||
}
|
||||
|
@ -125,6 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(synthio_from_file_obj, 1, synthio_from_file);
|
|||
STATIC const mp_rom_map_elem_t synthio_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_synthio) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MidiTrack), MP_ROM_PTR(&synthio_miditrack_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Synthesizer), MP_ROM_PTR(&synthio_synthesizer_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_from_file), MP_ROM_PTR(&synthio_from_file_obj) },
|
||||
};
|
||||
|
||||
|
|
|
@ -24,11 +24,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO___INIT___H
|
||||
#define MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO___INIT___H
|
||||
#pragma once
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
// Nothing now.
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO___INIT___H
|
||||
extern int16_t shared_bindings_synthio_square_wave[];
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
|
||||
#include "py/runtime.h"
|
||||
#include "shared-module/audiocore/__init__.h"
|
||||
#include "shared-module/audiocore/RawSample.h"
|
||||
|
||||
#if defined(__arm__) && __arm__
|
||||
#include "cmsis_compiler.h"
|
||||
#endif
|
||||
|
||||
void common_hal_audiomixer_mixer_construct(audiomixer_mixer_obj_t *self,
|
||||
uint8_t voice_count,
|
||||
|
@ -140,7 +143,7 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
|
|||
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));
|
||||
int32_t intermediate = ai * mod_mul;
|
||||
int32_t intermediate = (int32_t)(ai * mod_mul);
|
||||
if (intermediate > SHRT_MAX) {
|
||||
intermediate = SHRT_MAX;
|
||||
} else if (intermediate < SHRT_MIN) {
|
||||
|
|
|
@ -42,12 +42,12 @@ void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t *se
|
|||
self->parent = parent;
|
||||
}
|
||||
|
||||
float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self) {
|
||||
return (float)self->level / (1 << 15);
|
||||
mp_float_t common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self) {
|
||||
return (mp_float_t)self->level / (1 << 15);
|
||||
}
|
||||
|
||||
void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *self, float level) {
|
||||
self->level = level * (1 << 15);
|
||||
void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *self, mp_float_t level) {
|
||||
self->level = (uint16_t)(level * (1 << 15));
|
||||
}
|
||||
|
||||
void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample, bool loop) {
|
||||
|
|
|
@ -27,10 +27,6 @@
|
|||
#include "py/runtime.h"
|
||||
#include "shared-bindings/synthio/MidiTrack.h"
|
||||
|
||||
#define LOUDNESS 0x4000 // 0.5
|
||||
#define BITS_PER_SAMPLE 16
|
||||
#define BYTES_PER_SAMPLE (BITS_PER_SAMPLE / 8)
|
||||
#define SILENCE 0x80
|
||||
|
||||
STATIC NORETURN void raise_midi_stream_error(uint32_t pos) {
|
||||
mp_raise_ValueError_varg(translate("Error in MIDI stream at position %d"), pos);
|
||||
|
@ -47,36 +43,42 @@ STATIC uint8_t parse_note(const uint8_t *buffer, uint32_t len, uint32_t *pos) {
|
|||
return note;
|
||||
}
|
||||
|
||||
STATIC void terminate_span(synthio_miditrack_obj_t *self, uint16_t *dur, uint16_t *max_dur) {
|
||||
STATIC void terminate_span(synthio_miditrack_obj_t *self, uint16_t *dur) {
|
||||
if (*dur) {
|
||||
self->track[self->total_spans - 1].dur = *dur;
|
||||
if (*dur > *max_dur) {
|
||||
*max_dur = *dur;
|
||||
}
|
||||
*dur = 0;
|
||||
} else {
|
||||
self->total_spans--;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void add_span(synthio_miditrack_obj_t *self, uint8_t note1, uint8_t note2) {
|
||||
synthio_midi_span_t span = { 0, {note1, note2} };
|
||||
self->track = m_realloc(self->track,
|
||||
(self->total_spans + 1) * sizeof(synthio_midi_span_t));
|
||||
self->track[self->total_spans++] = span;
|
||||
STATIC void add_span(synthio_miditrack_obj_t *self, const synthio_midi_span_t *span) {
|
||||
self->track = m_renew(synthio_midi_span_t, self->track, self->total_spans, self->total_spans + 1);
|
||||
self->track[self->total_spans++] = *span;
|
||||
}
|
||||
|
||||
STATIC void change_span_note(synthio_miditrack_obj_t *self, uint8_t old_note, uint8_t new_note, uint16_t *dur) {
|
||||
synthio_midi_span_t span = self->track[self->total_spans - 1];
|
||||
if (synthio_span_change_note(&span, old_note, new_note)) {
|
||||
terminate_span(self, dur);
|
||||
add_span(self, &span);
|
||||
*dur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self,
|
||||
const uint8_t *buffer, uint32_t len, uint32_t tempo, uint32_t sample_rate) {
|
||||
const uint8_t *buffer, uint32_t len, uint32_t tempo, uint32_t sample_rate,
|
||||
const int16_t *waveform, uint16_t waveform_length) {
|
||||
|
||||
synthio_midi_span_t initial = { 0, {SILENCE, SILENCE} };
|
||||
self->sample_rate = sample_rate;
|
||||
self->synth.sample_rate = sample_rate;
|
||||
self->track = m_malloc(sizeof(synthio_midi_span_t), false);
|
||||
synthio_span_init(self->track);
|
||||
self->next_span = 0;
|
||||
self->total_spans = 1;
|
||||
*self->track = initial;
|
||||
self->synth.waveform = waveform;
|
||||
self->synth.waveform_length = waveform_length;
|
||||
|
||||
uint16_t dur = 0, max_dur = 0;
|
||||
uint16_t dur = 0;
|
||||
uint32_t pos = 0;
|
||||
while (pos < len) {
|
||||
uint8_t c;
|
||||
|
@ -91,37 +93,19 @@ void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self,
|
|||
raise_midi_stream_error(pos);
|
||||
}
|
||||
|
||||
// dur is carried over here so that if a note on/off message doesn't actually produce a change, the
|
||||
// underlying "span" is extended. Otherwise, it is zeroed out in the call to `terminate_span`.
|
||||
dur += delta * sample_rate / tempo;
|
||||
|
||||
switch (buffer[pos++] >> 4) {
|
||||
case 8: { // Note Off
|
||||
uint8_t note = parse_note(buffer, len, &pos);
|
||||
|
||||
// Ignore if not a note which is playing
|
||||
synthio_midi_span_t last_span = self->track[self->total_spans - 1];
|
||||
if (last_span.note[0] == note || last_span.note[1] == note) {
|
||||
terminate_span(self, &dur, &max_dur);
|
||||
if (last_span.note[0] == note) {
|
||||
add_span(self, last_span.note[1], SILENCE);
|
||||
} else {
|
||||
add_span(self, last_span.note[0], SILENCE);
|
||||
}
|
||||
}
|
||||
change_span_note(self, note, SYNTHIO_SILENCE, &dur);
|
||||
break;
|
||||
}
|
||||
case 9: { // Note On
|
||||
uint8_t note = parse_note(buffer, len, &pos);
|
||||
|
||||
// Ignore if two notes are already playing
|
||||
synthio_midi_span_t last_span = self->track[self->total_spans - 1];
|
||||
if (last_span.note[1] == SILENCE) {
|
||||
terminate_span(self, &dur, &max_dur);
|
||||
if (last_span.note[0] == SILENCE) {
|
||||
add_span(self, note, SILENCE);
|
||||
} else {
|
||||
add_span(self, last_span.note[0], note);
|
||||
}
|
||||
}
|
||||
change_span_note(self, SYNTHIO_SILENCE, note, &dur);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
|
@ -142,27 +126,29 @@ void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self,
|
|||
raise_midi_stream_error(pos);
|
||||
}
|
||||
}
|
||||
terminate_span(self, &dur, &max_dur);
|
||||
terminate_span(self, &dur);
|
||||
|
||||
self->buffer_length = max_dur * BYTES_PER_SAMPLE;
|
||||
self->buffer = m_malloc(self->buffer_length, false);
|
||||
uint16_t max_dur = 0;
|
||||
for (int i = 0; i < self->total_spans; i++) {
|
||||
max_dur = MAX(self->track[i].dur, max_dur);
|
||||
}
|
||||
synthio_synth_init(&self->synth, max_dur);
|
||||
}
|
||||
|
||||
void common_hal_synthio_miditrack_deinit(synthio_miditrack_obj_t *self) {
|
||||
m_free(self->buffer);
|
||||
self->buffer = NULL;
|
||||
m_free(self->track);
|
||||
synthio_synth_deinit(&self->synth);
|
||||
m_del(synthio_midi_span_t, self->track, self->total_spans + 1);
|
||||
self->track = NULL;
|
||||
}
|
||||
bool common_hal_synthio_miditrack_deinited(synthio_miditrack_obj_t *self) {
|
||||
return self->buffer == NULL;
|
||||
return synthio_synth_deinited(&self->synth);
|
||||
}
|
||||
|
||||
uint32_t common_hal_synthio_miditrack_get_sample_rate(synthio_miditrack_obj_t *self) {
|
||||
return self->sample_rate;
|
||||
return self->synth.sample_rate;
|
||||
}
|
||||
uint8_t common_hal_synthio_miditrack_get_bits_per_sample(synthio_miditrack_obj_t *self) {
|
||||
return BITS_PER_SAMPLE;
|
||||
return SYNTHIO_BITS_PER_SAMPLE;
|
||||
}
|
||||
uint8_t common_hal_synthio_miditrack_get_channel_count(synthio_miditrack_obj_t *self) {
|
||||
return 1;
|
||||
|
@ -170,47 +156,29 @@ uint8_t common_hal_synthio_miditrack_get_channel_count(synthio_miditrack_obj_t *
|
|||
|
||||
void synthio_miditrack_reset_buffer(synthio_miditrack_obj_t *self,
|
||||
bool single_channel_output, uint8_t channel) {
|
||||
|
||||
synthio_synth_reset_buffer(&self->synth, single_channel_output, channel);
|
||||
self->synth.span.dur = 0;
|
||||
self->next_span = 0;
|
||||
}
|
||||
|
||||
STATIC const uint16_t notes[] = {8372, 8870, 9397, 9956, 10548, 11175, 11840,
|
||||
12544, 13290, 14080, 14917, 15804}; // 9th octave
|
||||
|
||||
audioio_get_buffer_result_t synthio_miditrack_get_buffer(synthio_miditrack_obj_t *self,
|
||||
bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) {
|
||||
|
||||
if (self->next_span >= self->total_spans) {
|
||||
*buffer_length = 0;
|
||||
return GET_BUFFER_DONE;
|
||||
if (self->synth.span.dur == 0) {
|
||||
if (self->next_span >= self->total_spans) {
|
||||
*buffer_length = 0;
|
||||
return GET_BUFFER_DONE;
|
||||
}
|
||||
self->synth.span = self->track[self->next_span++];
|
||||
}
|
||||
|
||||
synthio_midi_span_t span = self->track[self->next_span++];
|
||||
*buffer_length = span.dur * BYTES_PER_SAMPLE;
|
||||
uint8_t octave1 = span.note[0] / 12; // 0..10
|
||||
uint8_t octave2 = span.note[1] / 12; // 0..10
|
||||
int32_t base_freq1 = notes[span.note[0] % 12];
|
||||
int32_t base_freq2 = notes[span.note[1] % 12];
|
||||
int32_t sample_rate = self->sample_rate;
|
||||
synthio_synth_synthesize(&self->synth, buffer, buffer_length, single_channel_output ? 0 : channel);
|
||||
|
||||
for (uint16_t i = 0; i < span.dur; i++) {
|
||||
int16_t semiperiod1 = span.note[0] == SILENCE ? 0 :
|
||||
((base_freq1 * i * 2) / sample_rate) >> (10 - octave1);
|
||||
int16_t semiperiod2 = span.note[1] == SILENCE ? semiperiod1 :
|
||||
((base_freq2 * i * 2) / sample_rate) >> (10 - octave2);
|
||||
self->buffer[i] = ((semiperiod1 % 2 + semiperiod2 % 2) - 1) * LOUDNESS;
|
||||
}
|
||||
*buffer = (uint8_t *)self->buffer;
|
||||
|
||||
return self->next_span >= self->total_spans ?
|
||||
return (self->synth.span.dur == 0 && self->next_span >= self->total_spans) ?
|
||||
GET_BUFFER_DONE : GET_BUFFER_MORE_DATA;
|
||||
}
|
||||
|
||||
void synthio_miditrack_get_buffer_structure(synthio_miditrack_obj_t *self, bool single_channel_output,
|
||||
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) {
|
||||
|
||||
*single_buffer = true;
|
||||
*samples_signed = true;
|
||||
*max_buffer_length = self->buffer_length;
|
||||
*spacing = 1;
|
||||
return synthio_synth_get_buffer_structure(&self->synth, single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing);
|
||||
}
|
||||
|
|
|
@ -31,19 +31,12 @@
|
|||
|
||||
#include "shared-module/synthio/__init__.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t dur;
|
||||
uint8_t note[2];
|
||||
} synthio_midi_span_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
uint32_t sample_rate;
|
||||
uint16_t *buffer;
|
||||
uint16_t buffer_length;
|
||||
synthio_midi_span_t *track;
|
||||
synthio_synth_t synth;
|
||||
uint16_t next_span;
|
||||
uint16_t total_spans;
|
||||
synthio_midi_span_t *track;
|
||||
} synthio_miditrack_obj_t;
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Artyom Skrobov
|
||||
*
|
||||
* 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 "py/runtime.h"
|
||||
#include "shared-bindings/synthio/Synthesizer.h"
|
||||
|
||||
|
||||
|
||||
void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self,
|
||||
uint32_t sample_rate, const int16_t *waveform, uint16_t waveform_length) {
|
||||
|
||||
self->synth.sample_rate = sample_rate;
|
||||
self->synth.waveform = waveform;
|
||||
self->synth.waveform_length = waveform_length;
|
||||
synthio_synth_init(&self->synth, SYNTHIO_MAX_DUR);
|
||||
common_hal_synthio_synthesizer_release_all(self);
|
||||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_deinit(synthio_synthesizer_obj_t *self) {
|
||||
synthio_synth_deinit(&self->synth);
|
||||
}
|
||||
bool common_hal_synthio_synthesizer_deinited(synthio_synthesizer_obj_t *self) {
|
||||
return synthio_synth_deinited(&self->synth);
|
||||
}
|
||||
|
||||
uint32_t common_hal_synthio_synthesizer_get_sample_rate(synthio_synthesizer_obj_t *self) {
|
||||
return self->synth.sample_rate;
|
||||
}
|
||||
uint8_t common_hal_synthio_synthesizer_get_bits_per_sample(synthio_synthesizer_obj_t *self) {
|
||||
return SYNTHIO_BITS_PER_SAMPLE;
|
||||
}
|
||||
uint8_t common_hal_synthio_synthesizer_get_channel_count(synthio_synthesizer_obj_t *self) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void synthio_synthesizer_reset_buffer(synthio_synthesizer_obj_t *self,
|
||||
bool single_channel_output, uint8_t channel) {
|
||||
synthio_synth_reset_buffer(&self->synth, single_channel_output, channel);
|
||||
}
|
||||
|
||||
audioio_get_buffer_result_t synthio_synthesizer_get_buffer(synthio_synthesizer_obj_t *self,
|
||||
bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) {
|
||||
self->synth.span.dur = SYNTHIO_MAX_DUR;
|
||||
synthio_synth_synthesize(&self->synth, buffer, buffer_length, single_channel_output ? channel : 0);
|
||||
return GET_BUFFER_MORE_DATA;
|
||||
}
|
||||
|
||||
void synthio_synthesizer_get_buffer_structure(synthio_synthesizer_obj_t *self, bool single_channel_output,
|
||||
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) {
|
||||
return synthio_synth_get_buffer_structure(&self->synth, single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing);
|
||||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_release_all(synthio_synthesizer_obj_t *self) {
|
||||
synthio_span_init(&self->synth.span);
|
||||
}
|
||||
void common_hal_synthio_synthesizer_release(synthio_synthesizer_obj_t *self, mp_obj_t to_release) {
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(to_release, &iter_buf);
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
synthio_span_change_note(&self->synth.span, mp_arg_validate_int_range(mp_obj_get_int(item), 0, 127, MP_QSTR_note), SYNTHIO_SILENCE);
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_obj_t to_press) {
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(to_press, &iter_buf);
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
synthio_span_change_note(&self->synth.span, SYNTHIO_SILENCE, mp_arg_validate_int_range(mp_obj_get_int(item), 0, 127, MP_QSTR_note));
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_synthio_synthesizer_get_pressed_notes(synthio_synthesizer_obj_t *self) {
|
||||
mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(synthio_span_count_active_channels(&self->synth.span), NULL));
|
||||
for (size_t i = 0, j = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) {
|
||||
if (self->synth.span.note[i] != SYNTHIO_SILENCE) {
|
||||
result->items[j++] = MP_OBJ_NEW_SMALL_INT(self->synth.span.note[i]);
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(result);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Artyom Skrobov
|
||||
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#include "shared-module/synthio/__init__.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
synthio_synth_t synth;
|
||||
} synthio_synthesizer_obj_t;
|
||||
|
||||
|
||||
// These are not available from Python because it may be called in an interrupt.
|
||||
void synthio_synthesizer_reset_buffer(synthio_synthesizer_obj_t *self,
|
||||
bool single_channel_output,
|
||||
uint8_t channel);
|
||||
|
||||
audioio_get_buffer_result_t synthio_synthesizer_get_buffer(synthio_synthesizer_obj_t *self,
|
||||
bool single_channel_output,
|
||||
uint8_t channel,
|
||||
uint8_t **buffer,
|
||||
uint32_t *buffer_length); // length in bytes
|
||||
|
||||
void synthio_synthesizer_get_buffer_structure(synthio_synthesizer_obj_t *self, bool single_channel_output,
|
||||
bool *single_buffer, bool *samples_signed,
|
||||
uint32_t *max_buffer_length, uint8_t *spacing);
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Artyom Skrobov
|
||||
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shared-module/synthio/__init__.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
STATIC const int16_t square_wave[] = {-32768, 32767};
|
||||
|
||||
STATIC const uint16_t notes[] = {8372, 8870, 9397, 9956, 10548, 11175, 11840,
|
||||
12544, 13290, 14080, 14917, 15804}; // 9th octave
|
||||
|
||||
int synthio_span_count_active_channels(synthio_midi_span_t *span) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) {
|
||||
if (span->note[i] != SYNTHIO_SILENCE) {
|
||||
result += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) {
|
||||
|
||||
if (channel == synth->other_channel) {
|
||||
*buffer_length = synth->last_buffer_length;
|
||||
*bufptr = (uint8_t *)(synth->buffers[synth->other_buffer_index] + channel);
|
||||
return;
|
||||
}
|
||||
|
||||
synth->buffer_index = !synth->buffer_index;
|
||||
synth->other_channel = 1 - channel;
|
||||
synth->other_buffer_index = synth->buffer_index;
|
||||
int16_t *out_buffer = (int16_t *)(void *)synth->buffers[synth->buffer_index];
|
||||
|
||||
uint16_t dur = MIN(SYNTHIO_MAX_DUR, synth->span.dur);
|
||||
synth->span.dur -= dur;
|
||||
memset(out_buffer, 0, synth->buffer_length);
|
||||
|
||||
int32_t sample_rate = synth->sample_rate;
|
||||
int active_channels = synthio_span_count_active_channels(&synth->span);
|
||||
const int16_t *waveform = synth->waveform;
|
||||
uint32_t waveform_length = synth->waveform_length;
|
||||
if (active_channels) {
|
||||
int16_t loudness = 0x3fff / (1 + active_channels);
|
||||
for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) {
|
||||
if (synth->span.note[chan] == SYNTHIO_SILENCE) {
|
||||
synth->accum[chan] = 0;
|
||||
continue;
|
||||
}
|
||||
uint8_t octave = synth->span.note[chan] / 12;
|
||||
uint16_t base_freq = notes[synth->span.note[chan] % 12];
|
||||
uint32_t accum = synth->accum[chan];
|
||||
#define SHIFT (16)
|
||||
// rate = base_freq * waveform_length
|
||||
// den = sample_rate * 2 ^ (10 - octave)
|
||||
// den = sample_rate * 2 ^ 10 / 2^octave
|
||||
// dds_rate = 2^SHIFT * rate / den
|
||||
// dds_rate = 2^(SHIFT-10+octave) * base_freq * waveform_length / sample_rate
|
||||
uint32_t dds_rate = (sample_rate / 2 + ((uint64_t)(base_freq * waveform_length) << (SHIFT - 10 + octave))) / sample_rate;
|
||||
|
||||
for (uint16_t i = 0; i < dur; i++) {
|
||||
accum += dds_rate;
|
||||
if (accum > waveform_length << SHIFT) {
|
||||
accum -= waveform_length << SHIFT;
|
||||
}
|
||||
int16_t idx = accum >> SHIFT;
|
||||
out_buffer[i] += (waveform[idx] * loudness) / 65536;
|
||||
}
|
||||
synth->accum[chan] = accum;
|
||||
}
|
||||
}
|
||||
|
||||
*buffer_length = synth->last_buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE;
|
||||
*bufptr = (uint8_t *)out_buffer;
|
||||
}
|
||||
|
||||
void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel) {
|
||||
if (single_channel_output && channel == 1) {
|
||||
return;
|
||||
}
|
||||
synth->other_channel = -1;
|
||||
}
|
||||
|
||||
bool synthio_synth_deinited(synthio_synth_t *synth) {
|
||||
return synth->buffers[0] == NULL;
|
||||
}
|
||||
|
||||
void synthio_synth_deinit(synthio_synth_t *synth) {
|
||||
m_del(uint8_t, synth->buffers[0], synth->buffer_length);
|
||||
m_del(uint8_t, synth->buffers[1], synth->buffer_length);
|
||||
synth->buffers[0] = NULL;
|
||||
synth->buffers[1] = NULL;
|
||||
}
|
||||
|
||||
void synthio_synth_init(synthio_synth_t *synth, uint16_t max_dur) {
|
||||
synth->buffer_length = MIN(SYNTHIO_MAX_DUR, max_dur) * SYNTHIO_BYTES_PER_SAMPLE;
|
||||
synth->buffers[0] = m_malloc(synth->buffer_length, false);
|
||||
synth->buffers[1] = m_malloc(synth->buffer_length, false);
|
||||
synth->other_channel = -1;
|
||||
}
|
||||
|
||||
void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_channel_output,
|
||||
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) {
|
||||
*single_buffer = false;
|
||||
*samples_signed = true;
|
||||
*max_buffer_length = synth->buffer_length;
|
||||
*spacing = 1;
|
||||
}
|
||||
|
||||
void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t waveform_obj) {
|
||||
*bufinfo_waveform = ((mp_buffer_info_t) { .buf = (void *)square_wave, .len = 4 });
|
||||
|
||||
if (waveform_obj != mp_const_none) {
|
||||
mp_get_buffer_raise(waveform_obj, bufinfo_waveform, MP_BUFFER_READ);
|
||||
if (bufinfo_waveform->typecode != 'h') {
|
||||
mp_raise_ValueError_varg(translate("%q must be array of type 'h'"), MP_QSTR_waveform);
|
||||
}
|
||||
}
|
||||
mp_arg_validate_length_range(bufinfo_waveform->len / 2, 2, 1024, MP_QSTR_waveform);
|
||||
}
|
||||
|
||||
void synthio_span_init(synthio_midi_span_t *span) {
|
||||
span->dur = 0;
|
||||
for (size_t i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) { span->note[i] = SYNTHIO_SILENCE;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int find_channel_with_note(const synthio_midi_span_t *span, uint8_t note) {
|
||||
for (int i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) {
|
||||
if (span->note[i] == note) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool synthio_span_change_note(synthio_midi_span_t *span, uint8_t old_note, uint8_t new_note) {
|
||||
int channel = find_channel_with_note(span, old_note);
|
||||
if (channel != -1) {
|
||||
span->note[channel] = new_note;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -24,9 +24,41 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_SHARED_MODULE_SYNTHIO__INIT__H
|
||||
#define MICROPY_INCLUDED_SHARED_MODULE_SYNTHIO__INIT__H
|
||||
#pragma once
|
||||
|
||||
#define SYNTHIO_BITS_PER_SAMPLE (16)
|
||||
#define SYNTHIO_BYTES_PER_SAMPLE (SYNTHIO_BITS_PER_SAMPLE / 8)
|
||||
#define SYNTHIO_MAX_DUR (256)
|
||||
#define SYNTHIO_SILENCE (0x80)
|
||||
|
||||
#include "shared-module/audiocore/__init__.h"
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_MODULE_SYNTHIO__INIT__H
|
||||
typedef struct {
|
||||
uint16_t dur;
|
||||
uint8_t note[CIRCUITPY_SYNTHIO_MAX_CHANNELS];
|
||||
} synthio_midi_span_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sample_rate;
|
||||
int16_t *buffers[2];
|
||||
const int16_t *waveform;
|
||||
uint16_t buffer_length;
|
||||
uint16_t last_buffer_length;
|
||||
uint8_t other_channel, buffer_index, other_buffer_index;
|
||||
uint16_t waveform_length;
|
||||
synthio_midi_span_t span;
|
||||
uint32_t accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS];
|
||||
} synthio_synth_t;
|
||||
|
||||
void synthio_span_init(synthio_midi_span_t *span);
|
||||
void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t *buffer_length, uint8_t channel);
|
||||
void synthio_synth_deinit(synthio_synth_t *synth);
|
||||
bool synthio_synth_deinited(synthio_synth_t *synth);
|
||||
void synthio_synth_init(synthio_synth_t *synth, uint16_t max_dur);
|
||||
void synthio_synth_get_buffer_structure(synthio_synth_t *synth, bool single_channel_output,
|
||||
bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing);
|
||||
void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_output, uint8_t channel);
|
||||
void synthio_synth_parse_waveform(mp_buffer_info_t *bufinfo_waveform, mp_obj_t waveform_obj);
|
||||
|
||||
bool synthio_span_change_note(synthio_midi_span_t *span, uint8_t old_note, uint8_t new_note);
|
||||
int synthio_span_count_active_channels(synthio_midi_span_t *span);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import array
|
||||
|
||||
try:
|
||||
from synthio import MidiTrack
|
||||
from audiocore import get_buffer, get_structure
|
||||
except ImportError:
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
SCORE = b"\0\x90@\0\x20\x90b\0\x20\x80@\0\0\x80\b\0"
|
||||
|
||||
with MidiTrack(SCORE, sample_rate=8000, tempo=640) as m:
|
||||
print(get_structure(m))
|
||||
print(get_buffer(m))
|
||||
|
||||
with MidiTrack(
|
||||
SCORE, sample_rate=8000, tempo=640, waveform=array.array("h", [0, 32767, 0, -32768])
|
||||
) as m:
|
||||
print(get_structure(m))
|
||||
print(get_buffer(m))
|
|
@ -0,0 +1,4 @@
|
|||
(0, 1, 512, 1)
|
||||
(1, b'\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\xff\x0f\xff\x0f')
|
||||
(0, 1, 512, 1)
|
||||
(1, b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x01\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x00\x00\x00')
|
|
@ -0,0 +1,24 @@
|
|||
import struct
|
||||
import synthio
|
||||
import audiocore
|
||||
|
||||
|
||||
def dump_samples():
|
||||
print(struct.unpack("12h", audiocore.get_buffer(s)[1][:24]))
|
||||
|
||||
|
||||
s = synthio.Synthesizer(sample_rate=8000)
|
||||
print(s.pressed)
|
||||
dump_samples()
|
||||
|
||||
s.press((80,))
|
||||
print(s.pressed)
|
||||
dump_samples()
|
||||
|
||||
s.press((91,))
|
||||
print(s.pressed)
|
||||
dump_samples()
|
||||
|
||||
s.release_then_press((80,))
|
||||
print(s.pressed)
|
||||
dump_samples()
|
|
@ -0,0 +1,8 @@
|
|||
()
|
||||
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
(80,)
|
||||
(-4095, -4095, -4095, -4095, 4095, 4095, 4095, 4095, 4095, -4095, -4095, -4095)
|
||||
(80, 91)
|
||||
(0, 0, 5460, 5460, 0, -5460, -5460, 0, 5460, 5460, 0, 0)
|
||||
(91,)
|
||||
(-4095, 4095, 4095, 4095, -4095, -4095, 4095, 4095, 4095, -4095, -4095, 4095)
|
|
@ -30,20 +30,21 @@ ame__
|
|||
mport
|
||||
|
||||
builtins micropython _asyncio _thread
|
||||
_uasyncio aesio array binascii
|
||||
bitmaptools btree cexample cmath
|
||||
collections cppexample displayio errno
|
||||
ffi framebuf gc hashlib
|
||||
json math qrio rainbowio
|
||||
re struct sys termios
|
||||
traceback ubinascii uctypes uerrno
|
||||
uheapq uio ujson ulab
|
||||
ulab.numpy ulab.numpy.fft ulab.numpy.linalg
|
||||
ulab.scipy ulab.scipy.linalg
|
||||
ulab.scipy.optimize ulab.scipy.signal
|
||||
ulab.scipy.special ulab.utils uos
|
||||
urandom ure uselect utime
|
||||
utimeq uzlib zlib
|
||||
_uasyncio aesio array audiocore
|
||||
audiomixer binascii bitmaptools btree
|
||||
cexample cmath collections cppexample
|
||||
displayio errno ffi framebuf
|
||||
gc hashlib json math
|
||||
qrio rainbowio re struct
|
||||
synthio sys termios traceback
|
||||
ubinascii uctypes uerrno uheapq
|
||||
uio ujson ulab ulab.numpy
|
||||
ulab.numpy.fft ulab.numpy.linalg ulab.scipy
|
||||
ulab.scipy.linalg ulab.scipy.optimize
|
||||
ulab.scipy.signal ulab.scipy.special
|
||||
ulab.utils uos urandom ure
|
||||
uselect utime utimeq uzlib
|
||||
zlib
|
||||
ime
|
||||
|
||||
utime utimeq
|
||||
|
|
Loading…
Reference in New Issue