diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index 39c9dde648e13..fbf12674c87e9 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -251,7 +251,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, } - if (audiosample_bits_per_sample(sample) == 16) { + if (audiosample_get_bits_per_sample(sample) == 16) { dma->beat_size = 2; dma->bytes_per_sample = 2; } else { @@ -262,7 +262,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, } } // Transfer both channels at once. - if (!single_channel_output && audiosample_channel_count(sample) == 2) { + if (!single_channel_output && audiosample_get_channel_count(sample) == 2) { dma->beat_size *= 2; } diff --git a/ports/atmel-samd/audio_dma.h b/ports/atmel-samd/audio_dma.h index 284e2cbfd4f2b..3b294492b0f11 100644 --- a/ports/atmel-samd/audio_dma.h +++ b/ports/atmel-samd/audio_dma.h @@ -10,6 +10,7 @@ #include "py/obj.h" #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" +#include "shared-module/audiocore/__init__.h" #include "supervisor/background_callback.h" typedef struct { @@ -40,10 +41,6 @@ typedef enum { AUDIO_DMA_MEMORY_ERROR, } audio_dma_result; -uint32_t audiosample_sample_rate(mp_obj_t sample_obj); -uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj); -uint8_t audiosample_channel_count(mp_obj_t sample_obj); - void audio_dma_init(audio_dma_t *dma); void audio_dma_reset(void); diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index b8c8e93e88d8e..178db2f07d040 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -216,10 +216,10 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, mp_raise_RuntimeError(MP_ERROR_TEXT("Clock unit in use")); } #endif - uint8_t bits_per_sample = audiosample_bits_per_sample(sample); + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); // We always output stereo so output twice as many bits. uint16_t bits_per_sample_output = bits_per_sample * 2; - uint16_t divisor = 48000000 / (bits_per_sample_output * audiosample_sample_rate(sample)); + uint16_t divisor = 48000000 / (bits_per_sample_output * audiosample_get_sample_rate(sample)); // Find a free GCLK to generate the MCLK signal. uint8_t gclk = find_free_gclk(divisor); if (gclk > GCLK_GEN_NUM) { @@ -235,7 +235,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, } else { clkctrl |= I2S_CLKCTRL_FSOUTINV | I2S_CLKCTRL_BITDELAY_I2S; } - uint8_t channel_count = audiosample_channel_count(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); if (channel_count > 2) { mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample")); } @@ -245,7 +245,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, #ifdef SAM_D5X_E5X uint32_t serctrl = (self->clock_unit << I2S_RXCTRL_CLKSEL_Pos) | I2S_TXCTRL_TXSAME_SAME; #endif - if (audiosample_channel_count(sample) == 1) { + if (audiosample_get_channel_count(sample) == 1) { serctrl |= SERCTRL(MONO_MONO); } else { serctrl |= SERCTRL(MONO_STEREO); diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index e6c90243fa566..d9078a7470902 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -333,7 +333,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, common_hal_audioio_audioout_stop(self); } audio_dma_result result = AUDIO_DMA_OK; - uint32_t sample_rate = audiosample_sample_rate(sample); + uint32_t sample_rate = audiosample_get_sample_rate(sample); #ifdef SAMD21 const uint32_t max_sample_rate = 350000; #endif @@ -364,12 +364,12 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, right_channel_reg = (uint32_t)&DAC->DATABUF[0].reg; } - size_t num_channels = audiosample_channel_count(sample); + size_t num_channels = audiosample_get_channel_count(sample); if (num_channels == 2 && // Are DAC channels sequential? left_channel_reg + 2 == right_channel_reg && - audiosample_bits_per_sample(sample) == 16) { + audiosample_get_bits_per_sample(sample) == 16) { result = audio_dma_setup_playback(&self->left_dma, sample, loop, false, 0, false /* output unsigned */, left_channel_reg, @@ -403,7 +403,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, } } Tc *timer = tc_insts[self->tc_index]; - set_timer_frequency(timer, audiosample_sample_rate(sample)); + set_timer_frequency(timer, audiosample_get_sample_rate(sample)); timer->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER; while (timer->COUNT16.STATUS.bit.STOP == 1) { } diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index 0841ab1d2eada..226e371c5b0b0 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -149,8 +149,8 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { port_i2s_pause(self); self->sample = sample; self->loop = loop; - self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8; - self->channel_count = audiosample_channel_count(sample); + self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; + self->channel_count = audiosample_get_channel_count(sample); bool single_buffer; bool samples_signed; uint32_t max_buffer_length; @@ -164,7 +164,7 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { audiosample_reset_buffer(self->sample, false, 0); - uint32_t sample_rate = audiosample_sample_rate(sample); + uint32_t sample_rate = audiosample_get_sample_rate(sample); i2s_std_clk_config_t clk_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate); CHECK_ESP_RESULT(i2s_channel_reconfig_std_clock(self->handle, &clk_config)); diff --git a/ports/espressif/common-hal/audioio/AudioOut.c b/ports/espressif/common-hal/audioio/AudioOut.c index 7f32dbc58c9f6..8322bc3799850 100644 --- a/ports/espressif/common-hal/audioio/AudioOut.c +++ b/ports/espressif/common-hal/audioio/AudioOut.c @@ -595,7 +595,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, self->sample = sample; self->looping = loop; - freq_hz = audiosample_sample_rate(self->sample); + freq_hz = audiosample_get_sample_rate(self->sample); if (freq_hz != self->freq_hz) { common_hal_audioio_audioout_deinit(self); @@ -603,8 +603,8 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, audioout_init(self); } - samples_size = audiosample_bits_per_sample(self->sample); - channel_count = audiosample_channel_count(self->sample); + samples_size = audiosample_get_bits_per_sample(self->sample); + channel_count = audiosample_get_channel_count(self->sample); audiosample_get_buffer_structure(self->sample, false, &_single_buffer, &samples_signed, &_max_buffer_length, &_spacing); diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 339e899b80612..502e7bf90fdce 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -337,6 +337,3 @@ USB_NUM_IN_ENDPOINTS = 5 # Usually lots of flash space available CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 - -CIRCUITPY_AUDIOMP3 ?= 1 -CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR ?= 1 diff --git a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c index fcedf34ef72ea..2430b6bdaa637 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c @@ -374,11 +374,11 @@ static void set_sai_clocking_for_sample_rate(uint32_t sample_rate) { void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { self->sample = sample; self->loop = loop; - self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8; - self->channel_count = audiosample_channel_count(sample); + self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; + self->channel_count = audiosample_get_channel_count(sample); int instance = SAI_GetInstance(self->peripheral); i2s_playing |= (1 << instance); - uint32_t sample_rate = audiosample_sample_rate(sample); + uint32_t sample_rate = audiosample_get_sample_rate(sample); if (sample_rate != self->sample_rate) { if (__builtin_popcount(i2s_playing) <= 1) { // as this is the first/only i2s instance playing audio, we can diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index 6e8fc2088134c..01758ee9b21e1 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -240,8 +240,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, self->sample = sample; self->loop = loop; - uint32_t sample_rate = audiosample_sample_rate(sample); - self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8; + uint32_t sample_rate = audiosample_get_sample_rate(sample); + self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; uint32_t max_buffer_length; bool single_buffer, samples_signed; diff --git a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c index 89c83bc0669f4..760da1b633a42 100644 --- a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c @@ -223,15 +223,15 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, self->sample = sample; self->loop = loop; - uint32_t sample_rate = audiosample_sample_rate(sample); - self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8; + uint32_t sample_rate = audiosample_get_sample_rate(sample); + self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; uint32_t max_buffer_length; uint8_t spacing; audiosample_get_buffer_structure(sample, /* single channel */ false, &self->single_buffer, &self->signed_to_unsigned, &max_buffer_length, &spacing); - self->sample_channel_count = audiosample_channel_count(sample); + self->sample_channel_count = audiosample_get_channel_count(sample); mp_arg_validate_length_max(max_buffer_length, UINT16_MAX, MP_QSTR_buffer); diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index de7214af27093..cd7330a416e59 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -203,7 +203,7 @@ audio_dma_result audio_dma_setup_playback( dma->output_signed = output_signed; dma->sample_spacing = 1; dma->output_resolution = output_resolution; - dma->sample_resolution = audiosample_bits_per_sample(sample); + dma->sample_resolution = audiosample_get_bits_per_sample(sample); dma->output_register_address = output_register_address; dma->swap_channel = swap_channel; @@ -250,7 +250,7 @@ audio_dma_result audio_dma_setup_playback( dma->output_size = 1; } // Transfer both channels at once. - if (!single_channel_output && audiosample_channel_count(sample) == 2) { + if (!single_channel_output && audiosample_get_channel_count(sample) == 2) { dma->output_size *= 2; } enum dma_channel_transfer_size dma_size = DMA_SIZE_8; diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index 559c023836fc5..591d71632c962 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -232,7 +232,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, common_hal_audiobusio_i2sout_stop(self); } - uint8_t bits_per_sample = audiosample_bits_per_sample(sample); + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); // Make sure we transmit a minimum of 16 bits. // TODO: Maybe we need an intermediate object to upsample instead. This is // only needed for some I2S devices that expect at least 8. @@ -242,8 +242,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, // We always output stereo so output twice as many bits. uint16_t bits_per_sample_output = bits_per_sample * 2; size_t clocks_per_bit = 6; - uint32_t frequency = bits_per_sample_output * audiosample_sample_rate(sample); - uint8_t channel_count = audiosample_channel_count(sample); + uint32_t frequency = bits_per_sample_output * audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); if (channel_count > 2) { mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample.")); } diff --git a/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c b/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c index eee9060d13249..0494e937f4b42 100644 --- a/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c @@ -187,7 +187,7 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, // to trigger the DMA. Each has a 16 bit fractional divisor system clock * X / Y where X and Y // are 16-bit. - uint32_t sample_rate = audiosample_sample_rate(sample); + uint32_t sample_rate = audiosample_get_sample_rate(sample); uint32_t system_clock = common_hal_mcu_processor_get_frequency(); uint32_t best_denominator; diff --git a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c index 9a82398aeb6f9..d6f6faef7e143 100644 --- a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c @@ -240,8 +240,8 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, self->sample = sample; self->loop = loop; - uint32_t sample_rate = audiosample_sample_rate(sample); - self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8; + uint32_t sample_rate = audiosample_get_sample_rate(sample); + self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; uint32_t max_buffer_length; uint8_t spacing; @@ -249,7 +249,7 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, bool samples_signed; audiosample_get_buffer_structure(sample, /* single channel */ false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); - self->sample_channel_count = audiosample_channel_count(sample); + self->sample_channel_count = audiosample_get_channel_count(sample); self->sample_offset = (samples_signed ? 0x8000 : 0) - self->quiescent_value; free_buffers(self); diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index 246156f3564a2..96dfcd68bcc3e 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -144,7 +144,6 @@ CFLAGS += \ -DCIRCUITPY_AUDIOFILTERS=1 \ -DCIRCUITPY_AUDIOMIXER=1 \ -DCIRCUITPY_AUDIOMP3=1 \ - -DCIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR=0 \ -DCIRCUITPY_AUDIOCORE_DEBUG=1 \ -DCIRCUITPY_BITMAPTOOLS=1 \ -DCIRCUITPY_CODEOP=1 \ diff --git a/shared-bindings/audiocore/RawSample.c b/shared-bindings/audiocore/RawSample.c index 137460700bb90..7036ca9a40f6a 100644 --- a/shared-bindings/audiocore/RawSample.c +++ b/shared-bindings/audiocore/RawSample.c @@ -12,6 +12,7 @@ #include "py/runtime.h" #include "shared-bindings/util.h" #include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/__init__.h" //| class RawSample: //| """A raw audio sample buffer in memory""" @@ -120,12 +121,6 @@ static mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit); -static void check_for_deinit(audioio_rawsample_obj_t *self) { - if (common_hal_audioio_rawsample_deinited(self)) { - raise_deinited_error(); - } -} - //| def __enter__(self) -> RawSample: //| """No-op used by Context Managers.""" //| ... @@ -151,24 +146,6 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4, //| change it.""" //| //| -static mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) { - audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate); - -static mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { - audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(audioio_rawsample_set_sample_rate_obj, audioio_rawsample_obj_set_sample_rate); - -MP_PROPERTY_GETSET(audioio_rawsample_sample_rate_obj, - (mp_obj_t)&audioio_rawsample_get_sample_rate_obj, - (mp_obj_t)&audioio_rawsample_set_sample_rate_obj); static const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = { // Methods @@ -177,18 +154,14 @@ static const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_rawsample___exit___obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_rawsample_sample_rate_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audioio_rawsample_locals_dict, audioio_rawsample_locals_dict_table); static const audiosample_p_t audioio_rawsample_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_rawsample_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_rawsample_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audioio_rawsample_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audioio_rawsample_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audioio_rawsample_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_rawsample_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index b8c42a791dbbf..c88f8b7622eb6 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -10,6 +10,7 @@ #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/audiocore/WaveFile.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/util.h" #include "extmod/vfs_posix.h" @@ -88,12 +89,6 @@ static mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit); -static void check_for_deinit(audioio_wavefile_obj_t *self) { - if (common_hal_audioio_wavefile_deinited(self)) { - raise_deinited_error(); - } -} - //| def __enter__(self) -> WaveFile: //| """No-op used by Context Managers.""" //| ... @@ -116,50 +111,14 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4, //| """32 bit value that dictates how quickly samples are loaded into the DAC //| in Hertz (cycles per second). When the sample is looped, this can change //| the pitch output without changing the underlying sample.""" -static mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate); - -static mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(audioio_wavefile_set_sample_rate_obj, audioio_wavefile_obj_set_sample_rate); - -MP_PROPERTY_GETSET(audioio_wavefile_sample_rate_obj, - (mp_obj_t)&audioio_wavefile_get_sample_rate_obj, - (mp_obj_t)&audioio_wavefile_set_sample_rate_obj); //| bits_per_sample: int //| """Bits per sample. (read only)""" -static mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample); - -MP_PROPERTY_GETTER(audioio_wavefile_bits_per_sample_obj, - (mp_obj_t)&audioio_wavefile_get_bits_per_sample_obj); +// //| channel_count: int //| """Number of audio channels. (read only)""" //| //| -static mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count); - -MP_PROPERTY_GETTER(audioio_wavefile_channel_count_obj, - (mp_obj_t)&audioio_wavefile_get_channel_count_obj); - static const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = { // Methods @@ -168,20 +127,14 @@ static const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_wavefile___exit___obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_wavefile_sample_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audioio_wavefile_bits_per_sample_obj) }, - { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audioio_wavefile_channel_count_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audioio_wavefile_locals_dict, audioio_wavefile_locals_dict_table); static const audiosample_p_t audioio_wavefile_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_wavefile_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_wavefile_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audioio_wavefile_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audioio_wavefile_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audioio_wavefile_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_wavefile_get_buffer_structure, }; diff --git a/shared-bindings/audiocore/__init__.c b/shared-bindings/audiocore/__init__.c index 4eff83bcfdbfc..5cd1fd83f2297 100644 --- a/shared-bindings/audiocore/__init__.c +++ b/shared-bindings/audiocore/__init__.c @@ -7,12 +7,14 @@ #include #include "py/obj.h" +#include "py/objproperty.h" #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" +#include "shared-bindings/util.h" // #include "shared-bindings/audiomixer/Mixer.h" //| """Support for audio samples""" @@ -24,6 +26,9 @@ static mp_obj_t audiocore_get_buffer(mp_obj_t sample_in) { uint32_t buffer_length = 0; audioio_get_buffer_result_t gbr = audiosample_get_buffer(sample_in, false, 0, &buffer, &buffer_length); + // audiosample_get_buffer checked that we're a sample so this is a safe cast + audiosample_base_t *sample = MP_OBJ_TO_PTR(sample_in); + mp_obj_t result[2] = {mp_obj_new_int_from_uint(gbr), mp_const_none}; if (gbr != GET_BUFFER_ERROR) { @@ -31,8 +36,8 @@ static mp_obj_t audiocore_get_buffer(mp_obj_t sample_in) { uint32_t max_buffer_length; uint8_t spacing; - uint8_t bits_per_sample = audiosample_bits_per_sample(sample_in); - audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); // copies the data because the gc semantics of get_buffer are unclear void *result_buf = m_malloc(buffer_length); memcpy(result_buf, buffer, buffer_length); @@ -55,7 +60,7 @@ static mp_obj_t audiocore_get_structure(mp_obj_t sample_in) { uint32_t max_buffer_length; uint8_t spacing; - audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); + audiosample_get_buffer_structure_checked(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), @@ -92,4 +97,61 @@ const mp_obj_module_t audiocore_module = { .globals = (mp_obj_dict_t *)&audiocore_module_globals, }; +bool audiosample_deinited(const audiosample_base_t *self) { + return self->channel_count == 0; +} + +void audiosample_check_for_deinit(const audiosample_base_t *self) { + if (audiosample_deinited(self)) { + raise_deinited_error(); + } +} + +void audiosample_mark_deinit(audiosample_base_t *self) { + self->channel_count = 0; +} + +// common implementation of channel_count property for audio samples +static mp_obj_t audiosample_obj_get_channel_count(mp_obj_t self_in) { + audiosample_base_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(audiosample_get_channel_count(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_channel_count_obj, audiosample_obj_get_channel_count); + +MP_PROPERTY_GETTER(audiosample_channel_count_obj, + (mp_obj_t)&audiosample_get_channel_count_obj); + + +// common implementation of bits_per_sample property for audio samples +static mp_obj_t audiosample_obj_get_bits_per_sample(mp_obj_t self_in) { + audiosample_base_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(audiosample_get_bits_per_sample(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_bits_per_sample_obj, audiosample_obj_get_bits_per_sample); + +MP_PROPERTY_GETTER(audiosample_bits_per_sample_obj, + (mp_obj_t)&audiosample_get_bits_per_sample_obj); + +// common implementation of sample_rate property for audio samples +static mp_obj_t audiosample_obj_get_sample_rate(mp_obj_t self_in) { + audiosample_base_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(audiosample_get_sample_rate(audiosample_check(self_in))); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_sample_rate_obj, audiosample_obj_get_sample_rate); + +static mp_obj_t audiosample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { + audiosample_base_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(self); + audiosample_set_sample_rate(audiosample_check(self_in), mp_obj_get_int(sample_rate)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiosample_set_sample_rate_obj, audiosample_obj_set_sample_rate); + +MP_PROPERTY_GETSET(audiosample_sample_rate_obj, + (mp_obj_t)&audiosample_get_sample_rate_obj, + (mp_obj_t)&audiosample_set_sample_rate_obj); + MP_REGISTER_MODULE(MP_QSTR_audiocore, audiocore_module); diff --git a/shared-bindings/audiocore/__init__.h b/shared-bindings/audiocore/__init__.h index 2c669f638b6b5..defa3d6c8dcb8 100644 --- a/shared-bindings/audiocore/__init__.h +++ b/shared-bindings/audiocore/__init__.h @@ -5,3 +5,18 @@ // SPDX-License-Identifier: MIT #pragma once + +#include "py/objproperty.h" + +#define AUDIOSAMPLE_FIELDS \ + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiosample_sample_rate_obj) }, \ + { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audiosample_bits_per_sample_obj) }, \ + { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audiosample_channel_count_obj) } + +typedef struct audiosample_base audiosample_base_t; +extern const mp_obj_property_getset_t audiosample_sample_rate_obj; +extern const mp_obj_property_getter_t audiosample_bits_per_sample_obj; +extern const mp_obj_property_getter_t audiosample_channel_count_obj; +void audiosample_check_for_deinit(const audiosample_base_t *self); +bool audiosample_deinited(const audiosample_base_t *self); +void audiosample_mark_deinit(audiosample_base_t *self); diff --git a/shared-bindings/audiodelays/Echo.c b/shared-bindings/audiodelays/Echo.c index 8b660cb1c74e3..f867bd361c080 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -7,6 +7,7 @@ #include #include "shared-bindings/audiodelays/Echo.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-module/audiodelays/Echo.h" #include "shared/runtime/context_manager_helpers.h" @@ -122,9 +123,7 @@ static mp_obj_t audiodelays_echo_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_echo_deinit_obj, audiodelays_echo_deinit); static void check_for_deinit(audiodelays_echo_obj_t *self) { - if (common_hal_audiodelays_echo_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->base); } //| def __enter__(self) -> Echo: @@ -292,17 +291,14 @@ static const mp_rom_map_elem_t audiodelays_echo_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_decay), MP_ROM_PTR(&audiodelays_echo_decay_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_echo_mix_obj) }, { MP_ROM_QSTR(MP_QSTR_freq_shift), MP_ROM_PTR(&audiodelays_echo_freq_shift_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiodelays_echo_locals_dict, audiodelays_echo_locals_dict_table); static const audiosample_p_t audiodelays_echo_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audiodelays_echo_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiodelays_echo_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audiodelays_echo_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audiodelays_echo_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audiodelays_echo_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiodelays_echo_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index 7e61570358a12..d89a7e72a4453 100644 --- a/shared-bindings/audiofilters/Distortion.c +++ b/shared-bindings/audiofilters/Distortion.c @@ -7,6 +7,7 @@ #include #include "shared-bindings/audiofilters/Distortion.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared/runtime/context_manager_helpers.h" #include "py/binary.h" @@ -161,9 +162,7 @@ static mp_obj_t audiofilters_distortion_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_distortion_deinit_obj, audiofilters_distortion_deinit); static void check_for_deinit(audiofilters_distortion_obj_t *self) { - if (common_hal_audiofilters_distortion_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->base); } //| def __enter__(self) -> Distortion: @@ -370,17 +369,14 @@ static const mp_rom_map_elem_t audiofilters_distortion_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&audiofilters_distortion_mode_obj) }, { MP_ROM_QSTR(MP_QSTR_soft_clip), MP_ROM_PTR(&audiofilters_distortion_soft_clip_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiofilters_distortion_mix_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiofilters_distortion_locals_dict, audiofilters_distortion_locals_dict_table); static const audiosample_p_t audiofilters_distortion_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audiofilters_distortion_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiofilters_distortion_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audiofilters_distortion_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audiofilters_distortion_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audiofilters_distortion_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiofilters_distortion_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index e12f2cc3e6373..8a5f51fd1d560 100644 --- a/shared-bindings/audiofilters/Filter.c +++ b/shared-bindings/audiofilters/Filter.c @@ -7,6 +7,7 @@ #include #include "shared-bindings/audiofilters/Filter.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-module/audiofilters/Filter.h" #include "shared/runtime/context_manager_helpers.h" @@ -109,9 +110,7 @@ static mp_obj_t audiofilters_filter_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_filter_deinit_obj, audiofilters_filter_deinit); static void check_for_deinit(audiofilters_filter_obj_t *self) { - if (common_hal_audiofilters_filter_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->base); } //| def __enter__(self) -> Filter: @@ -238,17 +237,14 @@ static const mp_rom_map_elem_t audiofilters_filter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiofilters_filter_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&audiofilters_filter_filter_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiofilters_filter_mix_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiofilters_filter_locals_dict, audiofilters_filter_locals_dict_table); static const audiosample_p_t audiofilters_filter_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audiofilters_filter_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiofilters_filter_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audiofilters_filter_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audiofilters_filter_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audiofilters_filter_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiofilters_filter_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/audiomixer/Mixer.c b/shared-bindings/audiomixer/Mixer.c index f5068bb775e03..633d362b3f4e3 100644 --- a/shared-bindings/audiomixer/Mixer.c +++ b/shared-bindings/audiomixer/Mixer.c @@ -5,6 +5,7 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiomixer/Mixer.h" #include "shared-bindings/audiomixer/MixerVoice.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-module/audiomixer/MixerVoice.h" #include @@ -108,9 +109,7 @@ static mp_obj_t audiomixer_mixer_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_deinit_obj, audiomixer_mixer_deinit); static void check_for_deinit(audiomixer_mixer_obj_t *self) { - if (common_hal_audiomixer_mixer_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->base); } //| def __enter__(self) -> Mixer: @@ -145,15 +144,6 @@ MP_PROPERTY_GETTER(audiomixer_mixer_playing_obj, //| sample_rate: int //| """32 bit value that dictates how quickly samples are played in Hertz (cycles per second).""" -static mp_obj_t audiomixer_mixer_obj_get_sample_rate(mp_obj_t self_in) { - audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audiomixer_mixer_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_sample_rate_obj, audiomixer_mixer_obj_get_sample_rate); - -MP_PROPERTY_GETTER(audiomixer_mixer_sample_rate_obj, - (mp_obj_t)&audiomixer_mixer_get_sample_rate_obj); //| voice: Tuple[MixerVoice, ...] //| """A tuple of the mixer's `audiomixer.MixerVoice` object(s). @@ -244,19 +234,15 @@ static const mp_rom_map_elem_t audiomixer_mixer_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiomixer_mixer_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomixer_mixer_sample_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_voice), MP_ROM_PTR(&audiomixer_mixer_voice_obj) } + { MP_ROM_QSTR(MP_QSTR_voice), MP_ROM_PTR(&audiomixer_mixer_voice_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiomixer_mixer_locals_dict, audiomixer_mixer_locals_dict_table); static const audiosample_p_t audiomixer_mixer_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audiomixer_mixer_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiomixer_mixer_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audiomixer_mixer_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audiomixer_mixer_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audiomixer_mixer_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiomixer_mixer_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/audiomp3/MP3Decoder.c b/shared-bindings/audiomp3/MP3Decoder.c index dab1f4dd45d2f..9ea5fa62e4c52 100644 --- a/shared-bindings/audiomp3/MP3Decoder.c +++ b/shared-bindings/audiomp3/MP3Decoder.c @@ -8,6 +8,7 @@ #include #include "shared/runtime/context_manager_helpers.h" +#include "shared-bindings/audiocore/__init__.h" #include "py/objproperty.h" #include "py/runtime.h" #include "py/stream.h" @@ -122,9 +123,7 @@ static mp_obj_t audiomp3_mp3file_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_deinit_obj, audiomp3_mp3file_deinit); static void check_for_deinit(audiomp3_mp3file_obj_t *self) { - if (common_hal_audiomp3_mp3file_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->base); } //| def __enter__(self) -> MP3Decoder: @@ -193,48 +192,12 @@ MP_PROPERTY_GETSET(audiomp3_mp3file_file_obj, //| """32 bit value that dictates how quickly samples are loaded into the DAC //| in Hertz (cycles per second). When the sample is looped, this can change //| the pitch output without changing the underlying sample.""" -static mp_obj_t audiomp3_mp3file_obj_get_sample_rate(mp_obj_t self_in) { - audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_sample_rate_obj, audiomp3_mp3file_obj_get_sample_rate); - -static mp_obj_t audiomp3_mp3file_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { - audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_audiomp3_mp3file_set_sample_rate(self, mp_obj_get_int(sample_rate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(audiomp3_mp3file_set_sample_rate_obj, audiomp3_mp3file_obj_set_sample_rate); - -MP_PROPERTY_GETSET(audiomp3_mp3file_sample_rate_obj, - (mp_obj_t)&audiomp3_mp3file_get_sample_rate_obj, - (mp_obj_t)&audiomp3_mp3file_set_sample_rate_obj); //| bits_per_sample: int //| """Bits per sample. (read only)""" -static mp_obj_t audiomp3_mp3file_obj_get_bits_per_sample(mp_obj_t self_in) { - audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_bits_per_sample(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_bits_per_sample_obj, audiomp3_mp3file_obj_get_bits_per_sample); - -MP_PROPERTY_GETTER(audiomp3_mp3file_bits_per_sample_obj, - (mp_obj_t)&audiomp3_mp3file_get_bits_per_sample_obj); //| channel_count: int //| """Number of audio channels. (read only)""" -static mp_obj_t audiomp3_mp3file_obj_get_channel_count(mp_obj_t self_in) { - audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_channel_count(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_channel_count_obj, audiomp3_mp3file_obj_get_channel_count); - -MP_PROPERTY_GETTER(audiomp3_mp3file_channel_count_obj, - (mp_obj_t)&audiomp3_mp3file_get_channel_count_obj); //| rms_level: float //| """The RMS audio level of a recently played moment of audio. (read only)""" @@ -272,22 +235,16 @@ static const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_file), MP_ROM_PTR(&audiomp3_mp3file_file_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomp3_mp3file_sample_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audiomp3_mp3file_bits_per_sample_obj) }, - { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audiomp3_mp3file_channel_count_obj) }, { MP_ROM_QSTR(MP_QSTR_rms_level), MP_ROM_PTR(&audiomp3_mp3file_rms_level_obj) }, { MP_ROM_QSTR(MP_QSTR_samples_decoded), MP_ROM_PTR(&audiomp3_mp3file_samples_decoded_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiomp3_mp3file_locals_dict, audiomp3_mp3file_locals_dict_table); static const audiosample_p_t audiomp3_mp3file_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_audiomp3_mp3file_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiomp3_mp3file_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_audiomp3_mp3file_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)audiomp3_mp3file_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)audiomp3_mp3file_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiomp3_mp3file_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/audiomp3/MP3Decoder.h b/shared-bindings/audiomp3/MP3Decoder.h index 4381430c228a1..2b6103f7b0e7b 100644 --- a/shared-bindings/audiomp3/MP3Decoder.h +++ b/shared-bindings/audiomp3/MP3Decoder.h @@ -19,7 +19,6 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t *self, void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t stream); void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self); -bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t *self); uint32_t common_hal_audiomp3_mp3file_get_sample_rate(audiomp3_mp3file_obj_t *self); void common_hal_audiomp3_mp3file_set_sample_rate(audiomp3_mp3file_obj_t *self, uint32_t sample_rate); uint8_t common_hal_audiomp3_mp3file_get_bits_per_sample(audiomp3_mp3file_obj_t *self); diff --git a/shared-bindings/synthio/MidiTrack.c b/shared-bindings/synthio/MidiTrack.c index 2178d758d44ae..665e7e853c29c 100644 --- a/shared-bindings/synthio/MidiTrack.c +++ b/shared-bindings/synthio/MidiTrack.c @@ -13,6 +13,7 @@ #include "shared-bindings/util.h" #include "shared-bindings/synthio/MidiTrack.h" #include "shared-bindings/synthio/__init__.h" +#include "shared-bindings/audiocore/__init__.h" //| class MidiTrack: //| """Simple MIDI synth""" @@ -94,9 +95,7 @@ static mp_obj_t synthio_miditrack_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(synthio_miditrack_deinit_obj, synthio_miditrack_deinit); static void check_for_deinit(synthio_miditrack_obj_t *self) { - if (common_hal_synthio_miditrack_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->synth.base); } //| def __enter__(self) -> MidiTrack: @@ -120,15 +119,6 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(synthio_miditrack___exit___obj, 4, 4, //| sample_rate: int //| """32 bit value that tells how quickly samples are played in Hertz (cycles per second).""" //| -static mp_obj_t synthio_miditrack_obj_get_sample_rate(mp_obj_t self_in) { - synthio_miditrack_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_synthio_miditrack_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(synthio_miditrack_get_sample_rate_obj, synthio_miditrack_obj_get_sample_rate); - -MP_PROPERTY_GETTER(synthio_miditrack_sample_rate_obj, - (mp_obj_t)&synthio_miditrack_get_sample_rate_obj); //| error_location: Optional[int] //| """Offset, in bytes within the midi data, of a decoding error""" @@ -155,19 +145,15 @@ static const mp_rom_map_elem_t synthio_miditrack_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&synthio_miditrack___exit___obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&synthio_miditrack_sample_rate_obj) }, { MP_ROM_QSTR(MP_QSTR_error_location), MP_ROM_PTR(&synthio_miditrack_error_location_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(synthio_miditrack_locals_dict, synthio_miditrack_locals_dict_table); static const audiosample_p_t synthio_miditrack_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .sample_rate = (audiosample_sample_rate_fun)common_hal_synthio_miditrack_get_sample_rate, - .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_synthio_miditrack_get_bits_per_sample, - .channel_count = (audiosample_channel_count_fun)common_hal_synthio_miditrack_get_channel_count, .reset_buffer = (audiosample_reset_buffer_fun)synthio_miditrack_reset_buffer, .get_buffer = (audiosample_get_buffer_fun)synthio_miditrack_get_buffer, - .get_buffer_structure = (audiosample_get_buffer_structure_fun)synthio_miditrack_get_buffer_structure, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/synthio/MidiTrack.h b/shared-bindings/synthio/MidiTrack.h index 50a6c921cb659..215521dd8a364 100644 --- a/shared-bindings/synthio/MidiTrack.h +++ b/shared-bindings/synthio/MidiTrack.h @@ -14,7 +14,6 @@ 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, mp_obj_t waveform_obj, mp_obj_t filter_obj, mp_obj_t envelope_obj); void common_hal_synthio_miditrack_deinit(synthio_miditrack_obj_t *self); -bool common_hal_synthio_miditrack_deinited(synthio_miditrack_obj_t *self); uint32_t common_hal_synthio_miditrack_get_sample_rate(synthio_miditrack_obj_t *self); uint8_t common_hal_synthio_miditrack_get_bits_per_sample(synthio_miditrack_obj_t *self); uint8_t common_hal_synthio_miditrack_get_channel_count(synthio_miditrack_obj_t *self); diff --git a/shared-bindings/synthio/Synthesizer.c b/shared-bindings/synthio/Synthesizer.c index a354dcc8746d5..219f83954184e 100644 --- a/shared-bindings/synthio/Synthesizer.c +++ b/shared-bindings/synthio/Synthesizer.c @@ -17,6 +17,7 @@ #include "shared-bindings/synthio/Synthesizer.h" #include "shared-bindings/synthio/LFO.h" #include "shared-bindings/synthio/__init__.h" +#include "shared-bindings/audiocore/__init__.h" //| NoteSequence = Sequence[Union[int, Note]] //| """A sequence of notes, which can each be integer MIDI note numbers or `Note` objects""" @@ -72,9 +73,7 @@ static mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n } static void check_for_deinit(synthio_synthesizer_obj_t *self) { - if (common_hal_synthio_synthesizer_deinited(self)) { - raise_deinited_error(); - } + audiosample_check_for_deinit(&self->synth.base); } //| def press(self, /, press: NoteOrNoteSequence = ()) -> None: @@ -234,15 +233,6 @@ MP_PROPERTY_GETSET(synthio_synthesizer_envelope_obj, //| 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: NoteSequence //| """A sequence of the currently pressed notes (read-only property). @@ -332,7 +322,7 @@ static mp_obj_t synthio_synthesizer_lpf(size_t n_pos, const mp_obj_t *pos_args, args[ARG_Q].u_obj == MP_OBJ_NULL ? MICROPY_FLOAT_CONST(0.7071067811865475) : mp_arg_validate_type_float(args[ARG_Q].u_obj, MP_QSTR_Q); - mp_float_t w0 = f0 / self->synth.sample_rate * 2 * MP_PI; + mp_float_t w0 = f0 / self->synth.base.sample_rate * 2 * MP_PI; return common_hal_synthio_new_lpf(w0, Q); @@ -363,7 +353,7 @@ static mp_obj_t synthio_synthesizer_hpf(size_t n_pos, const mp_obj_t *pos_args, args[ARG_Q].u_obj == MP_OBJ_NULL ? MICROPY_FLOAT_CONST(0.7071067811865475) : mp_arg_validate_type_float(args[ARG_Q].u_obj, MP_QSTR_Q); - mp_float_t w0 = f0 / self->synth.sample_rate * 2 * MP_PI; + mp_float_t w0 = f0 / self->synth.base.sample_rate * 2 * MP_PI; return common_hal_synthio_new_hpf(w0, Q); @@ -397,7 +387,7 @@ static mp_obj_t synthio_synthesizer_bpf(size_t n_pos, const mp_obj_t *pos_args, args[ARG_Q].u_obj == MP_OBJ_NULL ? MICROPY_FLOAT_CONST(0.7071067811865475) : mp_arg_validate_type_float(args[ARG_Q].u_obj, MP_QSTR_Q); - mp_float_t w0 = f0 / self->synth.sample_rate * 2 * MP_PI; + mp_float_t w0 = f0 / self->synth.base.sample_rate * 2 * MP_PI; return common_hal_synthio_new_bpf(w0, Q); @@ -422,22 +412,18 @@ static const mp_rom_map_elem_t synthio_synthesizer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_band_pass_filter), MP_ROM_PTR(&synthio_synthesizer_bpf_fun_obj) }, // Properties { MP_ROM_QSTR(MP_QSTR_envelope), MP_ROM_PTR(&synthio_synthesizer_envelope_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&synthio_synthesizer_sample_rate_obj) }, { MP_ROM_QSTR(MP_QSTR_max_polyphony), MP_ROM_INT(CIRCUITPY_SYNTHIO_MAX_CHANNELS) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&synthio_synthesizer_pressed_obj) }, { MP_ROM_QSTR(MP_QSTR_note_info), MP_ROM_PTR(&synthio_synthesizer_note_info_obj) }, { MP_ROM_QSTR(MP_QSTR_blocks), MP_ROM_PTR(&synthio_synthesizer_blocks_obj) }, + AUDIOSAMPLE_FIELDS, }; 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, }; MP_DEFINE_CONST_OBJ_TYPE( diff --git a/shared-bindings/synthio/Synthesizer.h b/shared-bindings/synthio/Synthesizer.h index 65e15ae88ad5b..24d2f4559343b 100644 --- a/shared-bindings/synthio/Synthesizer.h +++ b/shared-bindings/synthio/Synthesizer.h @@ -15,7 +15,6 @@ void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *self, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t envelope_obj); 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); diff --git a/shared-module/audiocore/RawSample.c b/shared-module/audiocore/RawSample.c index 9944597d08f1c..900b42c3c3e7d 100644 --- a/shared-module/audiocore/RawSample.c +++ b/shared-module/audiocore/RawSample.c @@ -7,6 +7,7 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/__init__.h" #include @@ -22,34 +23,18 @@ void common_hal_audioio_rawsample_construct(audioio_rawsample_obj_t *self, bool single_buffer) { self->buffer = buffer; - self->bits_per_sample = bytes_per_sample * 8; - self->samples_signed = samples_signed; - self->len = len; - self->channel_count = channel_count; - self->sample_rate = sample_rate; - self->single_buffer = single_buffer; + self->base.bits_per_sample = bytes_per_sample * 8; + self->base.samples_signed = samples_signed; + self->base.max_buffer_length = len; + self->base.channel_count = channel_count; + self->base.sample_rate = sample_rate; + self->base.single_buffer = single_buffer; self->buffer_index = 0; } void common_hal_audioio_rawsample_deinit(audioio_rawsample_obj_t *self) { self->buffer = NULL; -} -bool common_hal_audioio_rawsample_deinited(audioio_rawsample_obj_t *self) { - return self->buffer == NULL; -} - -uint32_t common_hal_audioio_rawsample_get_sample_rate(audioio_rawsample_obj_t *self) { - return self->sample_rate; -} -void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t *self, - uint32_t sample_rate) { - self->sample_rate = sample_rate; -} -uint8_t common_hal_audioio_rawsample_get_bits_per_sample(audioio_rawsample_obj_t *self) { - return self->bits_per_sample; -} -uint8_t common_hal_audioio_rawsample_get_channel_count(audioio_rawsample_obj_t *self) { - return self->channel_count; + audiosample_mark_deinit(&self->base); } void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t *self, @@ -63,37 +48,23 @@ audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t uint8_t **buffer, uint32_t *buffer_length) { - if (self->single_buffer) { - *buffer_length = self->len; + if (self->base.single_buffer) { + *buffer_length = self->base.max_buffer_length; if (single_channel_output) { - *buffer = self->buffer + (channel % self->channel_count) * (self->bits_per_sample / 8); + *buffer = self->buffer + (channel % self->base.channel_count) * (self->base.bits_per_sample / 8); } else { *buffer = self->buffer; } return GET_BUFFER_DONE; } else { - *buffer_length = self->len / 2; + *buffer_length = self->base.max_buffer_length / 2; if (single_channel_output) { - *buffer = self->buffer + (channel % self->channel_count) * (self->bits_per_sample / 8) + \ - self->len / 2 * self->buffer_index; + *buffer = self->buffer + (channel % self->base.channel_count) * (self->base.bits_per_sample / 8) + \ + self->base.max_buffer_length / 2 * self->buffer_index; } else { - *buffer = self->buffer + self->len / 2 * self->buffer_index; + *buffer = self->buffer + self->base.max_buffer_length / 2 * self->buffer_index; } self->buffer_index = 1 - self->buffer_index; return GET_BUFFER_DONE; } } - -void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing) { - - *single_buffer = self->single_buffer; - *samples_signed = self->samples_signed; - *max_buffer_length = self->len; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiocore/RawSample.h b/shared-module/audiocore/RawSample.h index 3fa94404f1c4a..1489bc3f504d0 100644 --- a/shared-module/audiocore/RawSample.h +++ b/shared-module/audiocore/RawSample.h @@ -11,14 +11,8 @@ #include "shared-module/audiocore/__init__.h" typedef struct { - mp_obj_base_t base; + audiosample_base_t base; uint8_t *buffer; - uint32_t len; - uint8_t bits_per_sample; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - bool single_buffer; uint8_t buffer_index; } audioio_rawsample_obj_t; @@ -32,6 +26,3 @@ audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes -void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); diff --git a/shared-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c index ffb9e8cf60e4f..624541cb1441d 100644 --- a/shared-module/audiocore/WaveFile.c +++ b/shared-module/audiocore/WaveFile.c @@ -13,6 +13,7 @@ #include "py/runtime.h" #include "shared-module/audiocore/WaveFile.h" +#include "shared-bindings/audiocore/__init__.h" struct wave_format_chunk { uint16_t audio_format; @@ -71,9 +72,12 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("Unsupported format")); } // Get the sample_rate - self->sample_rate = format.sample_rate; - self->channel_count = format.num_channels; - self->bits_per_sample = format.bits_per_sample; + self->base.sample_rate = format.sample_rate; + self->base.channel_count = format.num_channels; + self->base.bits_per_sample = format.bits_per_sample; + self->base.samples_signed = format.bits_per_sample > 8; + self->base.max_buffer_length = 512; + self->base.single_buffer = false; uint8_t chunk_tag[4]; uint32_t chunk_length; @@ -132,27 +136,7 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t *self, void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t *self) { self->buffer = NULL; self->second_buffer = NULL; -} - -bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t *self) { - return self->buffer == NULL; -} - -uint32_t common_hal_audioio_wavefile_get_sample_rate(audioio_wavefile_obj_t *self) { - return self->sample_rate; -} - -void common_hal_audioio_wavefile_set_sample_rate(audioio_wavefile_obj_t *self, - uint32_t sample_rate) { - self->sample_rate = sample_rate; -} - -uint8_t common_hal_audioio_wavefile_get_bits_per_sample(audioio_wavefile_obj_t *self) { - return self->bits_per_sample; -} - -uint8_t common_hal_audioio_wavefile_get_channel_count(audioio_wavefile_obj_t *self) { - return self->channel_count; + audiosample_mark_deinit(&self->base); } void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t *self, @@ -211,11 +195,11 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t * if (self->bytes_remaining == 0 && length_read % sizeof(uint32_t) != 0) { uint32_t pad = length_read % sizeof(uint32_t); length_read += pad; - if (self->bits_per_sample == 8) { + if (self->base.bits_per_sample == 8) { for (uint32_t i = 0; i < pad; i++) { ((uint8_t *)(*buffer))[length_read / sizeof(uint8_t) - i - 1] = 0x80; } - } else if (self->bits_per_sample == 16) { + } else if (self->base.bits_per_sample == 16) { // We know the buffer is aligned because we allocated it onto the heap ourselves. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" @@ -246,22 +230,8 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t * self->left_read_count += 1; } else if (channel == 1) { self->right_read_count += 1; - *buffer = *buffer + self->bits_per_sample / 8; + *buffer = *buffer + self->base.bits_per_sample / 8; } return self->bytes_remaining == 0 ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; } - -void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing) { - *single_buffer = false; - // In WAV files, 8-bit samples are always unsigned, and larger samples are always signed. - *samples_signed = self->bits_per_sample > 8; - *max_buffer_length = 512; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiocore/WaveFile.h b/shared-module/audiocore/WaveFile.h index a86c1409abc9a..74e25ffebfec0 100644 --- a/shared-module/audiocore/WaveFile.h +++ b/shared-module/audiocore/WaveFile.h @@ -12,20 +12,16 @@ #include "shared-module/audiocore/__init__.h" typedef struct { - mp_obj_base_t base; + audiosample_base_t base; uint8_t *buffer; uint32_t buffer_length; uint8_t *second_buffer; uint32_t second_buffer_length; uint32_t file_length; // In bytes uint16_t data_start; // Where the data values start - uint8_t bits_per_sample; uint16_t buffer_index; uint32_t bytes_remaining; - uint8_t channel_count; - uint32_t sample_rate; - uint32_t len; pyb_file_obj_t *file; @@ -43,6 +39,3 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t * uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes -void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 8be5be5425c3a..bf80403137996 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -7,6 +7,7 @@ #include "shared-module/audioio/__init__.h" #include "py/obj.h" +#include "py/runtime.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" #include "shared-module/audiocore/RawSample.h" @@ -15,21 +16,6 @@ #include "shared-bindings/audiomixer/Mixer.h" #include "shared-module/audiomixer/Mixer.h" -uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { - const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); - return proto->sample_rate(MP_OBJ_TO_PTR(sample_obj)); -} - -uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { - const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); - return proto->bits_per_sample(MP_OBJ_TO_PTR(sample_obj)); -} - -uint8_t audiosample_channel_count(mp_obj_t sample_obj) { - const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); - return proto->channel_count(MP_OBJ_TO_PTR(sample_obj)); -} - void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel_output, uint8_t audio_channel) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); proto->reset_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, audio_channel); @@ -43,14 +29,6 @@ audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, return proto->get_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, channel, buffer, buffer_length); } -void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing) { - const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); - proto->get_buffer_structure(MP_OBJ_TO_PTR(sample_obj), single_channel_output, single_buffer, - samples_signed, max_buffer_length, spacing); -} - void audiosample_convert_u8m_s16s(int16_t *buffer_out, const uint8_t *buffer_in, size_t nframes) { for (; nframes--;) { int16_t sample = (*buffer_in++ - 0x80) << 8; @@ -217,3 +195,19 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, *buffer_out++ = sample; } } + +void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in) { + const audiosample_base_t *other = audiosample_check(other_in); + if (other->sample_rate != self->sample_rate) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); + } + if (other->channel_count != self->channel_count) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); + } + if (other->bits_per_sample != self->bits_per_sample) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); + } + if (other->samples_signed != self->samples_signed) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); + } +} diff --git a/shared-module/audiocore/__init__.h b/shared-module/audiocore/__init__.h index 2502045594d1e..875ac90ecc5c1 100644 --- a/shared-module/audiocore/__init__.h +++ b/shared-module/audiocore/__init__.h @@ -18,40 +18,78 @@ typedef enum { GET_BUFFER_ERROR, // Error while reading data. } audioio_get_buffer_result_t; -typedef uint32_t (*audiosample_sample_rate_fun)(mp_obj_t); -typedef uint8_t (*audiosample_bits_per_sample_fun)(mp_obj_t); -typedef uint8_t (*audiosample_channel_count_fun)(mp_obj_t); +typedef struct audiosample_base { + mp_obj_base_t self; + uint32_t sample_rate; + uint32_t max_buffer_length; + uint8_t bits_per_sample; + uint8_t channel_count; + uint8_t samples_signed; + bool single_buffer; +} audiosample_base_t; + typedef void (*audiosample_reset_buffer_fun)(mp_obj_t, bool single_channel_output, uint8_t audio_channel); typedef audioio_get_buffer_result_t (*audiosample_get_buffer_fun)(mp_obj_t, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); -typedef void (*audiosample_get_buffer_structure_fun)(mp_obj_t, - bool single_channel_output, bool *single_buffer, - bool *samples_signed, uint32_t *max_buffer_length, - uint8_t *spacing); typedef struct _audiosample_p_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_audiosample - audiosample_sample_rate_fun sample_rate; - audiosample_bits_per_sample_fun bits_per_sample; - audiosample_channel_count_fun channel_count; audiosample_reset_buffer_fun reset_buffer; audiosample_get_buffer_fun get_buffer; - audiosample_get_buffer_structure_fun get_buffer_structure; } audiosample_p_t; -uint32_t audiosample_sample_rate(mp_obj_t sample_obj); -uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj); -uint8_t audiosample_channel_count(mp_obj_t sample_obj); +static inline uint32_t audiosample_get_bits_per_sample(audiosample_base_t *self) { + return self->bits_per_sample; +} + +static inline uint32_t audiosample_get_sample_rate(audiosample_base_t *self) { + return self->sample_rate; +} + +static inline void audiosample_set_sample_rate(audiosample_base_t *self, uint32_t sample_rate) { + self->sample_rate = sample_rate; +} + +static inline uint8_t audiosample_get_channel_count(audiosample_base_t *self) { + return self->channel_count; +} + void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel_output, uint8_t audio_channel); audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); -void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel_output, + +static inline void audiosample_get_buffer_structure(audiosample_base_t *self, bool single_channel_output, bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); + uint32_t *max_buffer_length, uint8_t *spacing) { + + *single_buffer = self->single_buffer; + *samples_signed = self->samples_signed; + *max_buffer_length = self->max_buffer_length; + + if (single_channel_output) { + *spacing = self->channel_count; + } else { + *spacing = 1; + } +} + +static inline audiosample_base_t *audiosample_check(mp_obj_t self_in) { + // called for side effect + (void)mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, self_in); + return MP_OBJ_TO_PTR(self_in); +} + +static inline void audiosample_get_buffer_structure_checked(mp_obj_t self_in, bool single_channel_output, + bool *single_buffer, bool *samples_signed, + uint32_t *max_buffer_length, uint8_t *spacing) { + audiosample_get_buffer_structure(audiosample_check(self_in), single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing); +} + +void audiosample_must_match(audiosample_base_t *self, mp_obj_t other); void audiosample_convert_u8m_s16s(int16_t *buffer_out, const uint8_t *buffer_in, size_t nframes); void audiosample_convert_u8s_s16s(int16_t *buffer_out, const uint8_t *buffer_in, size_t nframes); diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index b4ff82e3024c1..6cb0d659d629f 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -19,10 +19,12 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ // Basic settings every effect and audio sample has // These are the effects values, not the source sample(s) - self->bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places - self->samples_signed = samples_signed; // Are the samples we provide signed (common is true) - self->channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo - self->sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer // A double buffer is set up here so the audio output can use DMA on buffer 1 while we @@ -78,7 +80,7 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ // Allocate the echo buffer for the max possible delay, echo is always 16-bit self->max_delay_ms = max_delay_ms; - self->max_echo_buffer_len = (uint32_t)(self->sample_rate / MICROPY_FLOAT_CONST(1000.0) * max_delay_ms) * (self->channel_count * sizeof(uint16_t)); // bytes + self->max_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * max_delay_ms) * (self->base.channel_count * sizeof(uint16_t)); // bytes self->echo_buffer = m_malloc(self->max_echo_buffer_len); if (self->echo_buffer == NULL) { common_hal_audiodelays_echo_deinit(self); @@ -87,7 +89,7 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ memset(self->echo_buffer, 0, self->max_echo_buffer_len); // calculate the length of a single sample in milliseconds - self->sample_ms = MICROPY_FLOAT_CONST(1000.0) / self->sample_rate; + self->sample_ms = MICROPY_FLOAT_CONST(1000.0) / self->base.sample_rate; // calculate everything needed for the current delay mp_float_t f_delay_ms = synthio_block_slot_get(&self->delay_ms); @@ -140,7 +142,7 @@ void recalculate_delay(audiodelays_echo_obj_t *self, mp_float_t f_delay_ms) { self->echo_buffer_len = self->max_echo_buffer_len; } else { // Calculate the current echo buffer length in bytes - uint32_t new_echo_buffer_len = (uint32_t)(self->sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * (self->channel_count * sizeof(uint16_t)); + uint32_t new_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * (self->base.channel_count * sizeof(uint16_t)); // Check if our new echo is too long for our maximum buffer if (new_echo_buffer_len > self->max_echo_buffer_len) { @@ -189,18 +191,6 @@ void common_hal_audiodelays_echo_set_freq_shift(audiodelays_echo_obj_t *self, bo recalculate_delay(self, delay_ms); } -uint32_t common_hal_audiodelays_echo_get_sample_rate(audiodelays_echo_obj_t *self) { - return self->sample_rate; -} - -uint8_t common_hal_audiodelays_echo_get_channel_count(audiodelays_echo_obj_t *self) { - return self->channel_count; -} - -uint8_t common_hal_audiodelays_echo_get_bits_per_sample(audiodelays_echo_obj_t *self) { - return self->bits_per_sample; -} - void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self, bool single_channel_output, uint8_t channel) { @@ -215,27 +205,7 @@ bool common_hal_audiodelays_echo_get_playing(audiodelays_echo_obj_t *self) { } void common_hal_audiodelays_echo_play(audiodelays_echo_obj_t *self, mp_obj_t sample, bool loop) { - // When a sample is to be played we must ensure the samples values matches what we expect - // Then we reset the sample and get the first buffer to play - // The get_buffer function will actually process that data - - if (audiosample_sample_rate(sample) != self->sample_rate) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); - } - if (audiosample_channel_count(sample) != self->channel_count) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); - } - if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); - if (samples_signed != self->samples_signed) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); - } + audiosample_must_match(&self->base, sample); self->sample = sample; self->loop = loop; @@ -244,7 +214,7 @@ void common_hal_audiodelays_echo_play(audiodelays_echo_obj_t *self, mp_obj_t sam audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); // Track remaining sample length in terms of bytes per sample - self->sample_buffer_length /= (self->bits_per_sample / 8); + self->sample_buffer_length /= (self->base.bits_per_sample / 8); // Store if we have more data in the sample to retrieve self->more_data = result == GET_BUFFER_MORE_DATA; @@ -271,7 +241,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; int8_t *hword_buffer = self->buffer[self->last_buf_idx]; - uint32_t length = self->buffer_len / (self->bits_per_sample / 8); + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); // The echo buffer is always stored as a 16-bit value internally int16_t *echo_buffer = (int16_t *)self->echo_buffer; @@ -291,7 +261,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); // Track length in terms of words. - self->sample_buffer_length /= (self->bits_per_sample / 8); + self->sample_buffer_length /= (self->base.bits_per_sample / 8); self->more_data = result == GET_BUFFER_MORE_DATA; } } @@ -299,13 +269,13 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining uint32_t n; if (self->sample == NULL) { - n = MIN(length, SYNTHIO_MAX_DUR * self->channel_count); + n = MIN(length, SYNTHIO_MAX_DUR * self->base.channel_count); } else { - n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->channel_count); + n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); } // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required - shared_bindings_synthio_lfo_tick(self->sample_rate, n / self->channel_count); + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); mp_float_t decay = synthio_block_slot_get_limited(&self->decay, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); @@ -328,17 +298,17 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * // If we have no sample keep the echo echoing if (self->sample == NULL) { if (mix <= MICROPY_FLOAT_CONST(0.01)) { // Mix of 0 is pure sample sound. We have no sample so no sound - if (self->samples_signed) { - memset(word_buffer, 0, length * (self->bits_per_sample / 8)); + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); } else { // For unsigned samples set to the middle which is "quiet" - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { uint16_t *uword_buffer = (uint16_t *)word_buffer; while (length--) { *uword_buffer++ = 32768; } } else { - memset(hword_buffer, 128, length * (self->bits_per_sample / 8)); + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); } } } else { @@ -363,14 +333,14 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = (int16_t)(echo * mix); - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = word; - if (!self->samples_signed) { + if (!self->base.samples_signed) { word_buffer[i] ^= 0x8000; } } else { hword_buffer[i] = (int8_t)word; - if (!self->samples_signed) { + if (!self->base.samples_signed) { hword_buffer[i] ^= 0x80; } } @@ -396,7 +366,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * if (mix <= MICROPY_FLOAT_CONST(0.01)) { // if mix is zero pure sample only for (uint32_t i = 0; i < n; i++) { - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = sample_src[i]; } else { hword_buffer[i] = sample_hsrc[i]; @@ -405,10 +375,10 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * } else { for (uint32_t i = 0; i < n; i++) { int32_t sample_word = 0; - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { sample_word = sample_src[i]; } else { - if (self->samples_signed) { + if (self->base.samples_signed) { sample_word = sample_hsrc[i]; } else { // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed @@ -426,7 +396,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = (int32_t)(echo * decay + sample_word); } - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { if (self->freq_shift) { for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int32_t)(echo_buffer[j % echo_buf_len] * decay + sample_word); @@ -455,14 +425,14 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = echo + sample_word; word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = (int16_t)((sample_word * (MICROPY_FLOAT_CONST(1.0) - mix)) + (word * mix)); - if (!self->samples_signed) { + if (!self->base.samples_signed) { word_buffer[i] ^= 0x8000; } } else { int8_t mixed = (int16_t)((sample_word * (MICROPY_FLOAT_CONST(1.0) - mix)) + (word * mix)); - if (self->samples_signed) { + if (self->base.samples_signed) { hword_buffer[i] = mixed; } else { hword_buffer[i] = (uint8_t)mixed ^ 0x80; @@ -486,7 +456,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * length -= n; word_buffer += n; hword_buffer += n; - self->sample_remaining_buffer += (n * (self->bits_per_sample / 8)); + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); self->sample_buffer_length -= n; } @@ -506,18 +476,3 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * // Echo always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h) return GET_BUFFER_MORE_DATA; } - -void audiodelays_echo_get_buffer_structure(audiodelays_echo_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) { - - // Return information about the effect's buffer (not the sample's) - // These are used by calling audio objects to determine how to handle the effect's buffer - *single_buffer = false; - *samples_signed = self->samples_signed; - *max_buffer_length = self->buffer_len; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiodelays/Echo.h b/shared-module/audiodelays/Echo.h index dd05318186240..7f5dbb69f090a 100644 --- a/shared-module/audiodelays/Echo.h +++ b/shared-module/audiodelays/Echo.h @@ -14,7 +14,7 @@ extern const mp_obj_type_t audiodelays_echo_type; typedef struct { - mp_obj_base_t base; + audiosample_base_t base; uint32_t max_delay_ms; synthio_block_slot_t delay_ms; mp_float_t current_delay_ms; @@ -22,11 +22,6 @@ typedef struct { synthio_block_slot_t decay; synthio_block_slot_t mix; - uint8_t bits_per_sample; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes @@ -63,7 +58,3 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes - -void audiodelays_echo_get_buffer_structure(audiodelays_echo_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); diff --git a/shared-module/audiofilters/Distortion.c b/shared-module/audiofilters/Distortion.c index 04ce082b9576f..1e44f08e83346 100644 --- a/shared-module/audiofilters/Distortion.c +++ b/shared-module/audiofilters/Distortion.c @@ -25,10 +25,12 @@ void common_hal_audiofilters_distortion_construct(audiofilters_distortion_obj_t // Basic settings every effect and audio sample has // These are the effects values, not the source sample(s) - self->bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places - self->samples_signed = samples_signed; // Are the samples we provide signed (common is true) - self->channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo - self->sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer // A double buffer is set up here so the audio output can use DMA on buffer 1 while we @@ -131,18 +133,6 @@ void common_hal_audiofilters_distortion_set_mix(audiofilters_distortion_obj_t *s synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); } -uint32_t common_hal_audiofilters_distortion_get_sample_rate(audiofilters_distortion_obj_t *self) { - return self->sample_rate; -} - -uint8_t common_hal_audiofilters_distortion_get_channel_count(audiofilters_distortion_obj_t *self) { - return self->channel_count; -} - -uint8_t common_hal_audiofilters_distortion_get_bits_per_sample(audiofilters_distortion_obj_t *self) { - return self->bits_per_sample; -} - void audiofilters_distortion_reset_buffer(audiofilters_distortion_obj_t *self, bool single_channel_output, uint8_t channel) { @@ -156,27 +146,7 @@ bool common_hal_audiofilters_distortion_get_playing(audiofilters_distortion_obj_ } void common_hal_audiofilters_distortion_play(audiofilters_distortion_obj_t *self, mp_obj_t sample, bool loop) { - // When a sample is to be played we must ensure the samples values matches what we expect - // Then we reset the sample and get the first buffer to play - // The get_buffer function will actually process that data - - if (audiosample_sample_rate(sample) != self->sample_rate) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); - } - if (audiosample_channel_count(sample) != self->channel_count) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); - } - if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); - if (samples_signed != self->samples_signed) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); - } + audiosample_must_match(&self->base, sample); self->sample = sample; self->loop = loop; @@ -185,7 +155,7 @@ void common_hal_audiofilters_distortion_play(audiofilters_distortion_obj_t *self audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); // Track remaining sample length in terms of bytes per sample - self->sample_buffer_length /= (self->bits_per_sample / 8); + self->sample_buffer_length /= (self->base.bits_per_sample / 8); // Store if we have more data in the sample to retrieve self->more_data = result == GET_BUFFER_MORE_DATA; @@ -211,7 +181,7 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; int8_t *hword_buffer = self->buffer[self->last_buf_idx]; - uint32_t length = self->buffer_len / (self->bits_per_sample / 8); + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample while (length != 0) { @@ -228,25 +198,25 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); // Track length in terms of words. - self->sample_buffer_length /= (self->bits_per_sample / 8); + self->sample_buffer_length /= (self->base.bits_per_sample / 8); self->more_data = result == GET_BUFFER_MORE_DATA; } } if (self->sample == NULL) { - if (self->samples_signed) { - memset(word_buffer, 0, length * (self->bits_per_sample / 8)); + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); } else { // For unsigned samples set to the middle which is "quiet" - if (MP_LIKELY(self->bits_per_sample == 16)) { - memset(word_buffer, 32768, length * (self->bits_per_sample / 8)); + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + memset(word_buffer, 32768, length * (self->base.bits_per_sample / 8)); } else { - memset(hword_buffer, 128, length * (self->bits_per_sample / 8)); + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); } } // tick all block inputs - shared_bindings_synthio_lfo_tick(self->sample_rate, length / self->channel_count); + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / self->base.channel_count); (void)synthio_block_slot_get(&self->drive); (void)synthio_block_slot_get(&self->pre_gain); (void)synthio_block_slot_get(&self->post_gain); @@ -256,13 +226,13 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist } else { // we have a sample to play and apply effect // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining - uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->channel_count); + uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required - shared_bindings_synthio_lfo_tick(self->sample_rate, n / self->channel_count); + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t drive = synthio_block_slot_get_limited(&self->drive, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); mp_float_t pre_gain = db_to_linear(synthio_block_slot_get_limited(&self->pre_gain, MICROPY_FLOAT_CONST(-60.0), MICROPY_FLOAT_CONST(60.0))); mp_float_t post_gain = db_to_linear(synthio_block_slot_get_limited(&self->post_gain, MICROPY_FLOAT_CONST(-80.0), MICROPY_FLOAT_CONST(24.0))); @@ -280,7 +250,7 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist if (mix <= MICROPY_FLOAT_CONST(0.01)) { // if mix is zero pure sample only for (uint32_t i = 0; i < n; i++) { - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = sample_src[i]; } else { hword_buffer[i] = sample_hsrc[i]; @@ -289,10 +259,10 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist } else { for (uint32_t i = 0; i < n; i++) { int32_t sample_word = 0; - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { sample_word = sample_src[i]; } else { - if (self->samples_signed) { + if (self->base.samples_signed) { sample_word = sample_hsrc[i]; } else { // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed @@ -357,14 +327,14 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist word = MIN(MAX(word, -32767), 32768); } - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = (int16_t)((sample_word * (MICROPY_FLOAT_CONST(1.0) - mix)) + (word * mix)); - if (!self->samples_signed) { + if (!self->base.samples_signed) { word_buffer[i] ^= 0x8000; } } else { int8_t mixed = (int8_t)((sample_word * (MICROPY_FLOAT_CONST(1.0) - mix)) + (word * mix)); - if (self->samples_signed) { + if (self->base.samples_signed) { hword_buffer[i] = mixed; } else { hword_buffer[i] = (uint8_t)mixed ^ 0x80; @@ -377,7 +347,7 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist length -= n; word_buffer += n; hword_buffer += n; - self->sample_remaining_buffer += (n * (self->bits_per_sample / 8)); + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); self->sample_buffer_length -= n; } } @@ -389,18 +359,3 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist // Distortion always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h) return GET_BUFFER_MORE_DATA; } - -void audiofilters_distortion_get_buffer_structure(audiofilters_distortion_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) { - - // Return information about the effect's buffer (not the sample's) - // These are used by calling audio objects to determine how to handle the effect's buffer - *single_buffer = false; - *samples_signed = self->samples_signed; - *max_buffer_length = self->buffer_len; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiofilters/Distortion.h b/shared-module/audiofilters/Distortion.h index 86f5c71cf42a1..ddfa1231e645e 100644 --- a/shared-module/audiofilters/Distortion.h +++ b/shared-module/audiofilters/Distortion.h @@ -21,7 +21,7 @@ typedef enum { extern const mp_obj_type_t audiofilters_distortion_type; typedef struct { - mp_obj_base_t base; + audiosample_base_t base; synthio_block_slot_t drive; synthio_block_slot_t pre_gain; synthio_block_slot_t post_gain; @@ -29,11 +29,6 @@ typedef struct { bool soft_clip; synthio_block_slot_t mix; - uint8_t bits_per_sample; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes @@ -54,7 +49,3 @@ void audiofilters_distortion_reset_buffer(audiofilters_distortion_obj_t *self, audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_distortion_obj_t *self, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); - -void audiofilters_distortion_get_buffer_structure(audiofilters_distortion_obj_t *self, - bool single_channel_output, bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 8e90605519547..3a9448d38b34a 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -15,10 +15,12 @@ void common_hal_audiofilters_filter_construct(audiofilters_filter_obj_t *self, // Basic settings every effect and audio sample has // These are the effects values, not the source sample(s) - self->bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places - self->samples_signed = samples_signed; // Are the samples we provide signed (common is true) - self->channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo - self->sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer // A double buffer is set up here so the audio output can use DMA on buffer 1 while we @@ -138,18 +140,6 @@ void common_hal_audiofilters_filter_set_mix(audiofilters_filter_obj_t *self, mp_ synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); } -uint32_t common_hal_audiofilters_filter_get_sample_rate(audiofilters_filter_obj_t *self) { - return self->sample_rate; -} - -uint8_t common_hal_audiofilters_filter_get_channel_count(audiofilters_filter_obj_t *self) { - return self->channel_count; -} - -uint8_t common_hal_audiofilters_filter_get_bits_per_sample(audiofilters_filter_obj_t *self) { - return self->bits_per_sample; -} - void audiofilters_filter_reset_buffer(audiofilters_filter_obj_t *self, bool single_channel_output, uint8_t channel) { @@ -170,27 +160,7 @@ bool common_hal_audiofilters_filter_get_playing(audiofilters_filter_obj_t *self) } void common_hal_audiofilters_filter_play(audiofilters_filter_obj_t *self, mp_obj_t sample, bool loop) { - // When a sample is to be played we must ensure the samples values matches what we expect - // Then we reset the sample and get the first buffer to play - // The get_buffer function will actually process that data - - if (audiosample_sample_rate(sample) != self->sample_rate) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); - } - if (audiosample_channel_count(sample) != self->channel_count) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); - } - if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing); - if (samples_signed != self->samples_signed) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); - } + audiosample_must_match(&self->base, sample); self->sample = sample; self->loop = loop; @@ -199,7 +169,7 @@ void common_hal_audiofilters_filter_play(audiofilters_filter_obj_t *self, mp_obj audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); // Track remaining sample length in terms of bytes per sample - self->sample_buffer_length /= (self->bits_per_sample / 8); + self->sample_buffer_length /= (self->base.bits_per_sample / 8); // Store if we have more data in the sample to retrieve self->more_data = result == GET_BUFFER_MORE_DATA; @@ -226,7 +196,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; int8_t *hword_buffer = self->buffer[self->last_buf_idx]; - uint32_t length = self->buffer_len / (self->bits_per_sample / 8); + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample while (length != 0) { @@ -243,27 +213,27 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); // Track length in terms of words. - self->sample_buffer_length /= (self->bits_per_sample / 8); + self->sample_buffer_length /= (self->base.bits_per_sample / 8); self->more_data = result == GET_BUFFER_MORE_DATA; } } if (self->sample == NULL) { // tick all block inputs - shared_bindings_synthio_lfo_tick(self->sample_rate, length / self->channel_count); + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / self->base.channel_count); (void)synthio_block_slot_get(&self->mix); - if (self->samples_signed) { - memset(word_buffer, 0, length * (self->bits_per_sample / 8)); + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); } else { // For unsigned samples set to the middle which is "quiet" - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { uint16_t *uword_buffer = (uint16_t *)word_buffer; while (length--) { *uword_buffer++ = 32768; } } else { - memset(hword_buffer, 128, length * (self->bits_per_sample / 8)); + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); } } @@ -271,18 +241,18 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o } else { // we have a sample to play and filter // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining - uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->channel_count); + uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required - shared_bindings_synthio_lfo_tick(self->sample_rate, n / self->channel_count); + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); if (mix <= MICROPY_FLOAT_CONST(0.01) || !self->filter_states) { // if mix is zero pure sample only or no biquad filter objects are provided for (uint32_t i = 0; i < n; i++) { - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = sample_src[i]; } else { hword_buffer[i] = sample_hsrc[i]; @@ -295,10 +265,10 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // Fill filter buffer with samples for (uint32_t j = 0; j < n_samples; j++) { - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { self->filter_buffer[j] = sample_src[i + j]; } else { - if (self->samples_signed) { + if (self->base.samples_signed) { self->filter_buffer[j] = sample_hsrc[i + j]; } else { // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed @@ -314,13 +284,13 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // Mix processed signal with original sample and transfer to output buffer for (uint32_t j = 0; j < n_samples; j++) { - if (MP_LIKELY(self->bits_per_sample == 16)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i + j] = synthio_mix_down_sample((int32_t)((sample_src[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)), SYNTHIO_MIX_DOWN_SCALE(2)); - if (!self->samples_signed) { + if (!self->base.samples_signed) { word_buffer[i + j] ^= 0x8000; } } else { - if (self->samples_signed) { + if (self->base.samples_signed) { hword_buffer[i + j] = (int8_t)((sample_hsrc[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)); } else { hword_buffer[i + j] = (uint8_t)(((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)) ^ 0x80; @@ -336,7 +306,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o length -= n; word_buffer += n; hword_buffer += n; - self->sample_remaining_buffer += (n * (self->bits_per_sample / 8)); + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); self->sample_buffer_length -= n; } } @@ -348,18 +318,3 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // Filter always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h) return GET_BUFFER_MORE_DATA; } - -void audiofilters_filter_get_buffer_structure(audiofilters_filter_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, uint32_t *max_buffer_length, uint8_t *spacing) { - - // Return information about the effect's buffer (not the sample's) - // These are used by calling audio objects to determine how to handle the effect's buffer - *single_buffer = false; - *samples_signed = self->samples_signed; - *max_buffer_length = self->buffer_len; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiofilters/Filter.h b/shared-module/audiofilters/Filter.h index 3110f52b46740..a895b5e5991fd 100644 --- a/shared-module/audiofilters/Filter.h +++ b/shared-module/audiofilters/Filter.h @@ -16,18 +16,13 @@ extern const mp_obj_type_t audiofilters_filter_type; typedef struct { - mp_obj_base_t base; + audiosample_base_t base; mp_obj_t *filter; synthio_block_slot_t mix; size_t filter_states_len; biquad_filter_state *filter_states; - uint8_t bits_per_sample; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes @@ -54,7 +49,3 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes - -void audiofilters_filter_get_buffer_structure(audiofilters_filter_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index fdb00ecd363f3..60939f1a30aae 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -37,11 +37,13 @@ void common_hal_audiomixer_mixer_construct(audiomixer_mixer_obj_t *self, m_malloc_fail(self->len); } - self->bits_per_sample = bits_per_sample; - self->samples_signed = samples_signed; - self->channel_count = channel_count; - self->sample_rate = sample_rate; + self->base.bits_per_sample = bits_per_sample; + self->base.samples_signed = samples_signed; + self->base.channel_count = channel_count; + self->base.sample_rate = sample_rate; + self->base.single_buffer = false; self->voice_count = voice_count; + self->base.max_buffer_length = buffer_size; } void common_hal_audiomixer_mixer_deinit(audiomixer_mixer_obj_t *self) { @@ -53,18 +55,6 @@ bool common_hal_audiomixer_mixer_deinited(audiomixer_mixer_obj_t *self) { return self->first_buffer == NULL; } -uint32_t common_hal_audiomixer_mixer_get_sample_rate(audiomixer_mixer_obj_t *self) { - return self->sample_rate; -} - -uint8_t common_hal_audiomixer_mixer_get_channel_count(audiomixer_mixer_obj_t *self) { - return self->channel_count; -} - -uint8_t common_hal_audiomixer_mixer_get_bits_per_sample(audiomixer_mixer_obj_t *self) { - return self->bits_per_sample; -} - bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t *self) { for (uint8_t v = 0; v < self->voice_count; v++) { if (common_hal_audiomixer_mixervoice_get_playing(MP_OBJ_TO_PTR(self->voice[v]))) { @@ -191,10 +181,10 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, uint32_t *src = voice->remaining_buffer; #if CIRCUITPY_SYNTHIO - uint32_t n = MIN(MIN(voice->buffer_length, length), SYNTHIO_MAX_DUR * self->channel_count); + uint32_t n = MIN(MIN(voice->buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); // Get the current level from the BlockInput. These may change at run time so you need to do bounds checking if required. - shared_bindings_synthio_lfo_tick(self->sample_rate, n / self->channel_count); + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); uint16_t level = (uint16_t)(synthio_block_slot_get_limited(&voice->level, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * (1 << 15)); #else uint32_t n = MIN(voice->buffer_length, length); @@ -203,8 +193,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, // First active voice gets copied over verbatim. if (!voices_active) { - if (MP_LIKELY(self->bits_per_sample == 16)) { - if (MP_LIKELY(self->samples_signed)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + if (MP_LIKELY(self->base.samples_signed)) { for (uint32_t i = 0; i < n; i++) { uint32_t v = src[i]; word_buffer[i] = mult16signed(v, level); @@ -221,7 +211,7 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, 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)) { + if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } word = mult16signed(word, level); @@ -229,8 +219,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, } } } else { - if (MP_LIKELY(self->bits_per_sample == 16)) { - if (MP_LIKELY(self->samples_signed)) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + if (MP_LIKELY(self->base.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]); @@ -247,7 +237,7 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, 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)) { + if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } word = mult16signed(word, level); @@ -312,8 +302,8 @@ audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t * } } - if (!self->samples_signed) { - if (self->bits_per_sample == 16) { + if (!self->base.samples_signed) { + if (self->base.bits_per_sample == 16) { for (uint32_t i = 0; i < length; i++) { word_buffer[i] = tounsigned16(word_buffer[i]); } @@ -336,20 +326,7 @@ audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t * self->left_read_count += 1; } else if (channel == 1) { self->right_read_count += 1; - *buffer = *buffer + self->bits_per_sample / 8; + *buffer = *buffer + self->base.bits_per_sample / 8; } return GET_BUFFER_MORE_DATA; } - -void audiomixer_mixer_get_buffer_structure(audiomixer_mixer_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing) { - *single_buffer = false; - *samples_signed = self->samples_signed; - *max_buffer_length = self->len; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiomixer/Mixer.h b/shared-module/audiomixer/Mixer.h index 771b3969719c9..b793fa12a2d49 100644 --- a/shared-module/audiomixer/Mixer.h +++ b/shared-module/audiomixer/Mixer.h @@ -12,15 +12,11 @@ #include "shared-module/audiocore/__init__.h" typedef struct { - mp_obj_base_t base; + audiosample_base_t base; uint32_t *first_buffer; uint32_t *second_buffer; uint32_t len; // in words - uint8_t bits_per_sample; bool use_first_buffer; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; uint32_t read_count; uint32_t left_read_count; @@ -41,6 +37,3 @@ audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t * uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes -void audiomixer_mixer_get_buffer_structure(audiomixer_mixer_obj_t *self, bool single_channel_output, - bool *single_buffer, bool *samples_signed, - uint32_t *max_buffer_length, uint8_t *spacing); diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c index 49a88639d395b..a63229cf5af03 100644 --- a/shared-module/audiomixer/MixerVoice.c +++ b/shared-module/audiomixer/MixerVoice.c @@ -46,25 +46,10 @@ void common_hal_audiomixer_mixervoice_set_loop(audiomixer_mixervoice_obj_t *self self->loop = loop; } -void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample, bool loop) { - if (audiosample_sample_rate(sample) != self->parent->sample_rate) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); - } - if (audiosample_channel_count(sample) != self->parent->channel_count) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); - } - if (audiosample_bits_per_sample(sample) != self->parent->bits_per_sample) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, - &max_buffer_length, &spacing); - if (samples_signed != self->parent->samples_signed) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); - } +void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample_in, bool loop) { + audiosample_must_match(&self->parent->base, sample_in); + // cast is safe, checked by must_match + audiosample_base_t *sample = MP_OBJ_TO_PTR(sample_in); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index 3d20ce43a846c..49bd4835e8855 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -6,6 +6,7 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiomp3/MP3Decoder.h" +#include "shared-bindings/audiocore/__init__.h" #include #include @@ -168,7 +169,7 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block */ static void mp3file_update_inbuf_cb(void *self_in) { audiomp3_mp3file_obj_t *self = self_in; - if (common_hal_audiomp3_mp3file_deinited(self_in)) { + if (audiosample_deinited(&self->base)) { return; } if (!self->eof && stream_readable(self->stream)) { @@ -380,14 +381,18 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t MP_ERROR_TEXT("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; + self->base.sample_rate = fi.samprate; + self->base.channel_count = fi.nChans; + self->base.single_buffer = false; + self->base.bits_per_sample = 16; + self->base.samples_signed = false; + self->base.max_buffer_length = fi.outputSamps * sizeof(int16_t); + self->len = 2 * self->base.max_buffer_length; self->samples_decoded = 0; } void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) { + audiosample_mark_deinit(&self->base); if (self->decoder) { MP3FreeDecoder(self->decoder); } @@ -400,27 +405,6 @@ void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) { self->samples_decoded = 0; } -bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t *self) { - return self->pcm_buffer[0] == NULL; -} - -uint32_t common_hal_audiomp3_mp3file_get_sample_rate(audiomp3_mp3file_obj_t *self) { - return self->sample_rate; -} - -void common_hal_audiomp3_mp3file_set_sample_rate(audiomp3_mp3file_obj_t *self, - uint32_t sample_rate) { - self->sample_rate = sample_rate; -} - -uint8_t common_hal_audiomp3_mp3file_get_bits_per_sample(audiomp3_mp3file_obj_t *self) { - return 16; -} - -uint8_t common_hal_audiomp3_mp3file_get_channel_count(audiomp3_mp3file_obj_t *self) { - return self->channel_count; -} - void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self, bool single_channel_output, uint8_t channel) { @@ -457,7 +441,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * channel = 0; } - size_t frame_buffer_size_bytes = self->frame_buffer_size; + size_t frame_buffer_size_bytes = self->base.max_buffer_length; *buffer_length = frame_buffer_size_bytes; if (channel == self->other_channel) { @@ -479,7 +463,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * mp3file_skip_id3v2(self, false); if (!mp3file_find_sync_word(self, false)) { - memset(buffer, 0, self->frame_buffer_size); + memset(buffer, 0, self->base.max_buffer_length); *buffer_length = 0; return self->eof ? GET_BUFFER_DONE : GET_BUFFER_ERROR; } @@ -495,7 +479,7 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * mp_printf(&mp_plat_print, "%s:%d err=%d\n", __FILE__, __LINE__, err); } if (self->eof || (err != ERR_MP3_INDATA_UNDERFLOW && err != ERR_MP3_MAINDATA_UNDERFLOW)) { - memset(buffer, 0, self->frame_buffer_size); + memset(buffer, 0, self->base.max_buffer_length); *buffer_length = 0; self->eof = true; return GET_BUFFER_ERROR; @@ -523,27 +507,14 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * return result; } -void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t *self, 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 = self->frame_buffer_size; - if (single_channel_output) { - *spacing = self->channel_count; - } else { - *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->pcm_buffer[self->buffer_index]; - for (size_t i = 0; i < self->frame_buffer_size / sizeof(int16_t); i++) { + for (size_t i = 0; i < self->base.max_buffer_length / sizeof(int16_t); i++) { sumsq += (float)buffer[i] * buffer[i]; } - return sqrtf(sumsq) / (self->frame_buffer_size / sizeof(int16_t)); + return sqrtf(sumsq) / (self->base.max_buffer_length / sizeof(int16_t)); } uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self) { diff --git a/shared-module/audiomp3/MP3Decoder.h b/shared-module/audiomp3/MP3Decoder.h index 9f1b97a5a516d..9af3300047b26 100644 --- a/shared-module/audiomp3/MP3Decoder.h +++ b/shared-module/audiomp3/MP3Decoder.h @@ -21,19 +21,16 @@ typedef struct { } mp3_input_buffer_t; typedef struct { - mp_obj_base_t base; + audiosample_base_t base; struct _MP3DecInfo *decoder; background_callback_t inbuf_fill_cb; mp3_input_buffer_t inbuf; int16_t *pcm_buffer[2]; uint32_t len; - uint32_t frame_buffer_size; - uint32_t sample_rate; mp_obj_t stream; uint8_t buffer_index; - uint8_t channel_count; bool eof; bool block_ok; mp_obj_t settimeout_args[3]; @@ -53,9 +50,6 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t * uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes -void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t *self, bool single_channel_output, - 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); diff --git a/shared-module/synthio/MidiTrack.c b/shared-module/synthio/MidiTrack.c index 2391a8bb7c7cd..94430289bda10 100644 --- a/shared-module/synthio/MidiTrack.c +++ b/shared-module/synthio/MidiTrack.c @@ -6,6 +6,7 @@ #include "py/runtime.h" #include "shared-bindings/synthio/MidiTrack.h" +#include "shared-bindings/audiocore/__init__.h" static void record_midi_stream_error(synthio_miditrack_obj_t *self) { @@ -42,7 +43,7 @@ static int decode_duration(synthio_miditrack_obj_t *self) { self->pos = self->track.len; record_midi_stream_error(self); } - return delta * self->synth.sample_rate / self->tempo; + return delta * self->synth.base.sample_rate / self->tempo; } // invariant: pointing at a MIDI message @@ -111,24 +112,10 @@ void common_hal_synthio_miditrack_deinit(synthio_miditrack_obj_t *self) { synthio_synth_deinit(&self->synth); } -bool common_hal_synthio_miditrack_deinited(synthio_miditrack_obj_t *self) { - return synthio_synth_deinited(&self->synth); -} - mp_int_t common_hal_synthio_miditrack_get_error_location(synthio_miditrack_obj_t *self) { return self->error_location; } -uint32_t common_hal_synthio_miditrack_get_sample_rate(synthio_miditrack_obj_t *self) { - return self->synth.sample_rate; -} -uint8_t common_hal_synthio_miditrack_get_bits_per_sample(synthio_miditrack_obj_t *self) { - return SYNTHIO_BITS_PER_SAMPLE; -} -uint8_t common_hal_synthio_miditrack_get_channel_count(synthio_miditrack_obj_t *self) { - return 1; -} - 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); @@ -137,7 +124,7 @@ void synthio_miditrack_reset_buffer(synthio_miditrack_obj_t *self, 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 (common_hal_synthio_miditrack_deinited(self)) { + if (audiosample_deinited(&self->synth.base)) { *buffer_length = 0; return GET_BUFFER_ERROR; } @@ -152,8 +139,3 @@ audioio_get_buffer_result_t synthio_miditrack_get_buffer(synthio_miditrack_obj_t } return 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) { - return synthio_synth_get_buffer_structure(&self->synth, single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing); -} diff --git a/shared-module/synthio/MidiTrack.h b/shared-module/synthio/MidiTrack.h index 816c0be695886..1e4d5cba2daf8 100644 --- a/shared-module/synthio/MidiTrack.h +++ b/shared-module/synthio/MidiTrack.h @@ -11,7 +11,6 @@ #include "shared-module/synthio/__init__.h" typedef struct { - mp_obj_base_t base; synthio_synth_t synth; mp_buffer_info_t track; // invariant: after initial startup, pos always points just after an encoded duration, i.e., at a midi message (or at EOF) @@ -31,7 +30,3 @@ audioio_get_buffer_result_t synthio_miditrack_get_buffer(synthio_miditrack_obj_t uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); // length in bytes - -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); diff --git a/shared-module/synthio/Synthesizer.c b/shared-module/synthio/Synthesizer.c index e4b343f6ba215..39eb4a02e6a36 100644 --- a/shared-module/synthio/Synthesizer.c +++ b/shared-module/synthio/Synthesizer.c @@ -7,6 +7,7 @@ #include "py/runtime.h" #include "shared-bindings/synthio/LFO.h" #include "shared-bindings/synthio/Note.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/synthio/Synthesizer.h" #include "shared-module/synthio/Note.h" @@ -23,19 +24,6 @@ void common_hal_synthio_synthesizer_construct(synthio_synthesizer_obj_t *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 self->synth.channel_count; -} void synthio_synthesizer_reset_buffer(synthio_synthesizer_obj_t *self, bool single_channel_output, uint8_t channel) { @@ -44,7 +32,7 @@ void synthio_synthesizer_reset_buffer(synthio_synthesizer_obj_t *self, 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) { - if (common_hal_synthio_synthesizer_deinited(self)) { + if (audiosample_deinited(&self->synth.base)) { *buffer_length = 0; return GET_BUFFER_ERROR; } @@ -67,11 +55,6 @@ audioio_get_buffer_result_t synthio_synthesizer_get_buffer(synthio_synthesizer_o 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) { for (size_t i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) { if (self->synth.span.note_obj[i] != SYNTHIO_SILENCE) { @@ -114,7 +97,7 @@ void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_ob if (is_note(to_press)) { if (!mp_obj_is_small_int(to_press)) { synthio_note_obj_t *note = MP_OBJ_TO_PTR(to_press); - synthio_note_start(note, self->synth.sample_rate); + synthio_note_start(note, self->synth.base.sample_rate); } synthio_span_change_note(&self->synth, SYNTHIO_SILENCE, validate_note(to_press)); return; @@ -127,7 +110,7 @@ void common_hal_synthio_synthesizer_press(synthio_synthesizer_obj_t *self, mp_ob note_obj = validate_note(note_obj); if (!mp_obj_is_small_int(note_obj)) { synthio_note_obj_t *note = MP_OBJ_TO_PTR(note_obj); - synthio_note_start(note, self->synth.sample_rate); + synthio_note_start(note, self->synth.base.sample_rate); } synthio_span_change_note(&self->synth, SYNTHIO_SILENCE, note_obj); } diff --git a/shared-module/synthio/Synthesizer.h b/shared-module/synthio/Synthesizer.h index 4fd5012cdcd94..a4dac7c25c6da 100644 --- a/shared-module/synthio/Synthesizer.h +++ b/shared-module/synthio/Synthesizer.h @@ -12,7 +12,6 @@ #include "shared-module/synthio/__init__.h" typedef struct { - mp_obj_base_t base; synthio_synth_t synth; mp_obj_t blocks; } synthio_synthesizer_obj_t; @@ -28,7 +27,3 @@ audioio_get_buffer_result_t synthio_synthesizer_get_buffer(synthio_synthesizer_o 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); diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index d3d5b068f57d0..bb39daf083973 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -6,6 +6,7 @@ // SPDX-License-Identifier: MIT #include "shared-module/synthio/__init__.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/synthio/__init__.h" #include "shared-module/synthio/Biquad.h" #include "shared-module/synthio/BlockBiquad.h" @@ -154,7 +155,7 @@ int16_t synthio_mix_down_sample(int32_t sample, int32_t scale) { static bool synth_note_into_buffer(synthio_synth_t *synth, int chan, int32_t *out_buffer32, int16_t dur, int16_t loudness[2]) { mp_obj_t note_obj = synth->span.note_obj[chan]; - int32_t sample_rate = synth->sample_rate; + int32_t sample_rate = synth->base.sample_rate; uint32_t dds_rate; @@ -290,7 +291,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t return; } - shared_bindings_synthio_lfo_tick(synth->sample_rate, SYNTHIO_MAX_DUR); + shared_bindings_synthio_lfo_tick(synth->base.sample_rate, SYNTHIO_MAX_DUR); synth->buffer_index = !synth->buffer_index; synth->other_channel = 1 - channel; @@ -299,9 +300,9 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t uint16_t dur = MIN(SYNTHIO_MAX_DUR, synth->span.dur); synth->span.dur -= dur; - int32_t out_buffer32[SYNTHIO_MAX_DUR * synth->channel_count]; + int32_t out_buffer32[SYNTHIO_MAX_DUR * synth->base.channel_count]; int32_t tmp_buffer32[SYNTHIO_MAX_DUR]; - memset(out_buffer32, 0, synth->channel_count * dur * sizeof(int32_t)); + memset(out_buffer32, 0, synth->base.channel_count * dur * sizeof(int32_t)); for (int chan = 0; chan < CIRCUITPY_SYNTHIO_MAX_CHANNELS; chan++) { mp_obj_t note_obj = synth->span.note_obj[chan]; @@ -333,13 +334,13 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t } // adjust loudness by envelope - sum_with_loudness(out_buffer32, tmp_buffer32, loudness, dur, synth->channel_count); + sum_with_loudness(out_buffer32, tmp_buffer32, loudness, dur, synth->base.channel_count); } int16_t *out_buffer16 = (int16_t *)(void *)synth->buffers[synth->buffer_index]; // mix down audio - for (size_t i = 0; i < dur * synth->channel_count; i++) { + for (size_t i = 0; i < dur * synth->base.channel_count; i++) { int32_t sample = out_buffer32[i]; out_buffer16[i] = synthio_mix_down_sample(sample, SYNTHIO_MIX_DOWN_SCALE(CIRCUITPY_SYNTHIO_MAX_CHANNELS)); } @@ -353,7 +354,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t synthio_envelope_state_step(&synth->envelope_state[chan], synthio_synth_get_note_envelope(synth, note_obj), dur); } - *buffer_length = synth->last_buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE * synth->channel_count; + *buffer_length = synth->last_buffer_length = dur * SYNTHIO_BYTES_PER_SAMPLE * synth->base.channel_count; *bufptr = (uint8_t *)out_buffer16; } @@ -364,17 +365,14 @@ void synthio_synth_reset_buffer(synthio_synth_t *synth, bool single_channel_outp 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) { synth->buffers[0] = NULL; synth->buffers[1] = NULL; + audiosample_mark_deinit(&synth->base); } void synthio_synth_envelope_set(synthio_synth_t *synth, mp_obj_t envelope_obj) { - synthio_envelope_definition_set(&synth->global_envelope_definition, envelope_obj, synth->sample_rate); + synthio_envelope_definition_set(&synth->global_envelope_definition, envelope_obj, synth->base.sample_rate); synth->envelope_obj = envelope_obj; } @@ -388,10 +386,14 @@ void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channe synth->buffer_length = SYNTHIO_MAX_DUR * SYNTHIO_BYTES_PER_SAMPLE * channel_count; synth->buffers[0] = m_malloc(synth->buffer_length); synth->buffers[1] = m_malloc(synth->buffer_length); - synth->channel_count = channel_count; + synth->base.channel_count = channel_count; + synth->base.single_buffer = false; synth->other_channel = -1; synth->waveform_obj = waveform_obj; - synth->sample_rate = sample_rate; + synth->base.sample_rate = sample_rate; + synth->base.bits_per_sample = 16; + synth->base.samples_signed = true; + synth->base.max_buffer_length = synth->buffer_length; synthio_synth_envelope_set(synth, envelope_obj); for (size_t i = 0; i < CIRCUITPY_SYNTHIO_MAX_CHANNELS; i++) { @@ -399,18 +401,6 @@ void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channe } } -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; - if (single_channel_output) { - *spacing = synth->channel_count; - } else { - *spacing = 1; - } -} - static void parse_common(mp_buffer_info_t *bufinfo, mp_obj_t o, int16_t what, mp_int_t max_len) { if (o != mp_const_none) { mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ); diff --git a/shared-module/synthio/__init__.h b/shared-module/synthio/__init__.h index 686a144472579..5fff4749270fc 100644 --- a/shared-module/synthio/__init__.h +++ b/shared-module/synthio/__init__.h @@ -41,10 +41,9 @@ typedef struct { } synthio_envelope_state_t; typedef struct synthio_synth { - uint32_t sample_rate; + audiosample_base_t base; uint32_t total_envelope; int16_t *buffers[2]; - uint8_t channel_count; uint16_t buffer_length; uint16_t last_buffer_length; uint8_t other_channel, buffer_index, other_buffer_index; @@ -71,8 +70,6 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **buffer, uint32_t void synthio_synth_deinit(synthio_synth_t *synth); bool synthio_synth_deinited(synthio_synth_t *synth); void synthio_synth_init(synthio_synth_t *synth, uint32_t sample_rate, int channel_count, mp_obj_t waveform_obj, mp_obj_t envelope); -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); void synthio_synth_parse_filter(mp_buffer_info_t *bufinfo_filter, mp_obj_t filter_obj);