From 81c38f2296e4629f97a47a0ed5eef756a2d49fdc Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Feb 2025 21:53:05 -0600 Subject: [PATCH 1/3] makefiles: remove remaining references to CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR --- ports/espressif/mpconfigport.mk | 1 - ports/unix/variants/coverage/mpconfigvariant.mk | 1 - 2 files changed, 2 deletions(-) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 339e899b80612..cf849534f75bc 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -339,4 +339,3 @@ USB_NUM_IN_ENDPOINTS = 5 CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 -CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR ?= 1 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 \ From 79797e49de7fad2c50845165f258306ed1ef3d88 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Feb 2025 21:55:29 -0600 Subject: [PATCH 2/3] espressif: don't enable AUDIOMP3 without AUDIOCORE there are some lines above that set it OFF if needed; the top level logic will set it ON if audiocore is enabled. Before this, some boards without any audio capability (e.g., pycamera with esp32s3, lacking both audioio and i2s) enabled mp3. This was not useful, and with other changes it will become a build error. --- ports/espressif/mpconfigport.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index cf849534f75bc..502e7bf90fdce 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -337,5 +337,3 @@ USB_NUM_IN_ENDPOINTS = 5 # Usually lots of flash space available CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 - -CIRCUITPY_AUDIOMP3 ?= 1 From e15eba0d33f4b09490d5d4ce2431b5bd8e225e16 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Feb 2025 19:00:46 -0600 Subject: [PATCH 3/3] audio: reduce code size By placing certain fields in a fixed location in all sample types, code can be reduced & reused. For instance, the same property object can be used for every sample type's `sample_rate` property. The sample proto functions like `sample_rate` become superfluous since once an object is verified to support the audiosample protocol, direct access to the fields in the base object is possible. --- ports/atmel-samd/audio_dma.c | 4 +- ports/atmel-samd/audio_dma.h | 5 +- .../atmel-samd/common-hal/audiobusio/I2SOut.c | 8 +- .../atmel-samd/common-hal/audioio/AudioOut.c | 8 +- .../common-hal/audiobusio/__init__.c | 6 +- ports/espressif/common-hal/audioio/AudioOut.c | 6 +- .../common-hal/audiobusio/__init__.c | 6 +- ports/nordic/common-hal/audiobusio/I2SOut.c | 4 +- .../common-hal/audiopwmio/PWMAudioOut.c | 6 +- ports/raspberrypi/audio_dma.c | 4 +- .../common-hal/audiobusio/I2SOut.c | 6 +- .../common-hal/audiopwmio/PWMAudioOut.c | 2 +- ports/stm/common-hal/audiopwmio/PWMAudioOut.c | 6 +- shared-bindings/audiocore/RawSample.c | 31 +---- shared-bindings/audiocore/WaveFile.c | 53 +-------- shared-bindings/audiocore/__init__.c | 68 ++++++++++- shared-bindings/audiocore/__init__.h | 15 +++ shared-bindings/audiodelays/Echo.c | 10 +- shared-bindings/audiofilters/Distortion.c | 10 +- shared-bindings/audiofilters/Filter.c | 10 +- shared-bindings/audiomixer/Mixer.c | 22 +--- shared-bindings/audiomp3/MP3Decoder.c | 49 +------- shared-bindings/audiomp3/MP3Decoder.h | 1 - shared-bindings/synthio/MidiTrack.c | 20 +--- shared-bindings/synthio/MidiTrack.h | 1 - shared-bindings/synthio/Synthesizer.c | 26 +---- shared-bindings/synthio/Synthesizer.h | 1 - shared-module/audiocore/RawSample.c | 59 +++------- shared-module/audiocore/RawSample.h | 11 +- shared-module/audiocore/WaveFile.c | 52 ++------- shared-module/audiocore/WaveFile.h | 9 +- shared-module/audiocore/__init__.c | 40 +++---- shared-module/audiocore/__init__.h | 70 +++++++++--- shared-module/audiodelays/Echo.c | 107 +++++------------- shared-module/audiodelays/Echo.h | 11 +- shared-module/audiofilters/Distortion.c | 95 ++++------------ shared-module/audiofilters/Distortion.h | 11 +- shared-module/audiofilters/Filter.c | 93 ++++----------- shared-module/audiofilters/Filter.h | 11 +- shared-module/audiomixer/Mixer.c | 57 +++------- shared-module/audiomixer/Mixer.h | 9 +- shared-module/audiomixer/MixerVoice.c | 23 +--- shared-module/audiomp3/MP3Decoder.c | 59 +++------- shared-module/audiomp3/MP3Decoder.h | 8 +- shared-module/synthio/MidiTrack.c | 24 +--- shared-module/synthio/MidiTrack.h | 5 - shared-module/synthio/Synthesizer.c | 25 +--- shared-module/synthio/Synthesizer.h | 5 - shared-module/synthio/__init__.c | 42 +++---- shared-module/synthio/__init__.h | 5 +- 50 files changed, 388 insertions(+), 831 deletions(-) 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/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/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);