Skip to content

Commit 015bbdc

Browse files
committed
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.
1 parent 469e88d commit 015bbdc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+369
-816
lines changed

ports/atmel-samd/audio_dma.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
251251
}
252252

253253

254-
if (audiosample_bits_per_sample(sample) == 16) {
254+
if (audiosample_get_bits_per_sample(sample) == 16) {
255255
dma->beat_size = 2;
256256
dma->bytes_per_sample = 2;
257257
} else {
@@ -262,7 +262,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
262262
}
263263
}
264264
// Transfer both channels at once.
265-
if (!single_channel_output && audiosample_channel_count(sample) == 2) {
265+
if (!single_channel_output && audiosample_get_channel_count(sample) == 2) {
266266
dma->beat_size *= 2;
267267
}
268268

ports/atmel-samd/audio_dma.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "py/obj.h"
1111
#include "shared-module/audiocore/RawSample.h"
1212
#include "shared-module/audiocore/WaveFile.h"
13+
#include "shared-module/audiocore/__init__.h"
1314
#include "supervisor/background_callback.h"
1415

1516
typedef struct {
@@ -40,10 +41,6 @@ typedef enum {
4041
AUDIO_DMA_MEMORY_ERROR,
4142
} audio_dma_result;
4243

43-
uint32_t audiosample_sample_rate(mp_obj_t sample_obj);
44-
uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj);
45-
uint8_t audiosample_channel_count(mp_obj_t sample_obj);
46-
4744
void audio_dma_init(audio_dma_t *dma);
4845
void audio_dma_reset(void);
4946

ports/atmel-samd/common-hal/audioio/AudioOut.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
333333
common_hal_audioio_audioout_stop(self);
334334
}
335335
audio_dma_result result = AUDIO_DMA_OK;
336-
uint32_t sample_rate = audiosample_sample_rate(sample);
336+
uint32_t sample_rate = audiosample_get_sample_rate(sample);
337337
#ifdef SAMD21
338338
const uint32_t max_sample_rate = 350000;
339339
#endif
@@ -364,12 +364,12 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
364364
right_channel_reg = (uint32_t)&DAC->DATABUF[0].reg;
365365
}
366366

367-
size_t num_channels = audiosample_channel_count(sample);
367+
size_t num_channels = audiosample_get_channel_count(sample);
368368

369369
if (num_channels == 2 &&
370370
// Are DAC channels sequential?
371371
left_channel_reg + 2 == right_channel_reg &&
372-
audiosample_bits_per_sample(sample) == 16) {
372+
audiosample_get_bits_per_sample(sample) == 16) {
373373
result = audio_dma_setup_playback(&self->left_dma, sample, loop, false, 0,
374374
false /* output unsigned */,
375375
left_channel_reg,
@@ -403,7 +403,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
403403
}
404404
}
405405
Tc *timer = tc_insts[self->tc_index];
406-
set_timer_frequency(timer, audiosample_sample_rate(sample));
406+
set_timer_frequency(timer, audiosample_get_sample_rate(sample));
407407
timer->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
408408
while (timer->COUNT16.STATUS.bit.STOP == 1) {
409409
}

ports/raspberrypi/audio_dma.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ audio_dma_result audio_dma_setup_playback(
203203
dma->output_signed = output_signed;
204204
dma->sample_spacing = 1;
205205
dma->output_resolution = output_resolution;
206-
dma->sample_resolution = audiosample_bits_per_sample(sample);
206+
dma->sample_resolution = audiosample_get_bits_per_sample(sample);
207207
dma->output_register_address = output_register_address;
208208
dma->swap_channel = swap_channel;
209209

@@ -250,7 +250,7 @@ audio_dma_result audio_dma_setup_playback(
250250
dma->output_size = 1;
251251
}
252252
// Transfer both channels at once.
253-
if (!single_channel_output && audiosample_channel_count(sample) == 2) {
253+
if (!single_channel_output && audiosample_get_channel_count(sample) == 2) {
254254
dma->output_size *= 2;
255255
}
256256
enum dma_channel_transfer_size dma_size = DMA_SIZE_8;

ports/raspberrypi/common-hal/audiobusio/I2SOut.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self,
232232
common_hal_audiobusio_i2sout_stop(self);
233233
}
234234

235-
uint8_t bits_per_sample = audiosample_bits_per_sample(sample);
235+
uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample);
236236
// Make sure we transmit a minimum of 16 bits.
237237
// TODO: Maybe we need an intermediate object to upsample instead. This is
238238
// 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,
242242
// We always output stereo so output twice as many bits.
243243
uint16_t bits_per_sample_output = bits_per_sample * 2;
244244
size_t clocks_per_bit = 6;
245-
uint32_t frequency = bits_per_sample_output * audiosample_sample_rate(sample);
246-
uint8_t channel_count = audiosample_channel_count(sample);
245+
uint32_t frequency = bits_per_sample_output * audiosample_get_sample_rate(sample);
246+
uint8_t channel_count = audiosample_get_channel_count(sample);
247247
if (channel_count > 2) {
248248
mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample."));
249249
}

ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self,
187187
// to trigger the DMA. Each has a 16 bit fractional divisor system clock * X / Y where X and Y
188188
// are 16-bit.
189189

190-
uint32_t sample_rate = audiosample_sample_rate(sample);
190+
uint32_t sample_rate = audiosample_get_sample_rate(sample);
191191

192192
uint32_t system_clock = common_hal_mcu_processor_get_frequency();
193193
uint32_t best_denominator;

shared-bindings/audiocore/RawSample.c

+2-29
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "py/runtime.h"
1313
#include "shared-bindings/util.h"
1414
#include "shared-bindings/audiocore/RawSample.h"
15+
#include "shared-bindings/audiocore/__init__.h"
1516

1617
//| class RawSample:
1718
//| """A raw audio sample buffer in memory"""
@@ -120,12 +121,6 @@ static mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) {
120121
}
121122
static MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit);
122123

123-
static void check_for_deinit(audioio_rawsample_obj_t *self) {
124-
if (common_hal_audioio_rawsample_deinited(self)) {
125-
raise_deinited_error();
126-
}
127-
}
128-
129124
//| def __enter__(self) -> RawSample:
130125
//| """No-op used by Context Managers."""
131126
//| ...
@@ -151,24 +146,6 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4,
151146
//| change it."""
152147
//|
153148
//|
154-
static mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) {
155-
audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
156-
check_for_deinit(self);
157-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self));
158-
}
159-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate);
160-
161-
static mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
162-
audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
163-
check_for_deinit(self);
164-
common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate));
165-
return mp_const_none;
166-
}
167-
MP_DEFINE_CONST_FUN_OBJ_2(audioio_rawsample_set_sample_rate_obj, audioio_rawsample_obj_set_sample_rate);
168-
169-
MP_PROPERTY_GETSET(audioio_rawsample_sample_rate_obj,
170-
(mp_obj_t)&audioio_rawsample_get_sample_rate_obj,
171-
(mp_obj_t)&audioio_rawsample_set_sample_rate_obj);
172149

173150
static const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = {
174151
// Methods
@@ -177,18 +154,14 @@ static const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = {
177154
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_rawsample___exit___obj) },
178155

179156
// Properties
180-
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_rawsample_sample_rate_obj) },
157+
AUDIOSAMPLE_FIELDS,
181158
};
182159
static MP_DEFINE_CONST_DICT(audioio_rawsample_locals_dict, audioio_rawsample_locals_dict_table);
183160

184161
static const audiosample_p_t audioio_rawsample_proto = {
185162
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
186-
.sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_rawsample_get_sample_rate,
187-
.bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_rawsample_get_bits_per_sample,
188-
.channel_count = (audiosample_channel_count_fun)common_hal_audioio_rawsample_get_channel_count,
189163
.reset_buffer = (audiosample_reset_buffer_fun)audioio_rawsample_reset_buffer,
190164
.get_buffer = (audiosample_get_buffer_fun)audioio_rawsample_get_buffer,
191-
.get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_rawsample_get_buffer_structure,
192165
};
193166

194167
MP_DEFINE_CONST_OBJ_TYPE(

shared-bindings/audiocore/WaveFile.c

+3-50
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "py/objproperty.h"
1111
#include "py/runtime.h"
1212
#include "shared-bindings/audiocore/WaveFile.h"
13+
#include "shared-bindings/audiocore/__init__.h"
1314
#include "shared-bindings/util.h"
1415
#include "extmod/vfs_posix.h"
1516

@@ -88,12 +89,6 @@ static mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) {
8889
}
8990
static MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit);
9091

91-
static void check_for_deinit(audioio_wavefile_obj_t *self) {
92-
if (common_hal_audioio_wavefile_deinited(self)) {
93-
raise_deinited_error();
94-
}
95-
}
96-
9792
//| def __enter__(self) -> WaveFile:
9893
//| """No-op used by Context Managers."""
9994
//| ...
@@ -116,50 +111,14 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4,
116111
//| """32 bit value that dictates how quickly samples are loaded into the DAC
117112
//| in Hertz (cycles per second). When the sample is looped, this can change
118113
//| the pitch output without changing the underlying sample."""
119-
static mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) {
120-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
121-
check_for_deinit(self);
122-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self));
123-
}
124-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate);
125-
126-
static mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
127-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
128-
check_for_deinit(self);
129-
common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate));
130-
return mp_const_none;
131-
}
132-
MP_DEFINE_CONST_FUN_OBJ_2(audioio_wavefile_set_sample_rate_obj, audioio_wavefile_obj_set_sample_rate);
133-
134-
MP_PROPERTY_GETSET(audioio_wavefile_sample_rate_obj,
135-
(mp_obj_t)&audioio_wavefile_get_sample_rate_obj,
136-
(mp_obj_t)&audioio_wavefile_set_sample_rate_obj);
137114

138115
//| bits_per_sample: int
139116
//| """Bits per sample. (read only)"""
140-
static mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) {
141-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
142-
check_for_deinit(self);
143-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self));
144-
}
145-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample);
146-
147-
MP_PROPERTY_GETTER(audioio_wavefile_bits_per_sample_obj,
148-
(mp_obj_t)&audioio_wavefile_get_bits_per_sample_obj);
117+
//
149118
//| channel_count: int
150119
//| """Number of audio channels. (read only)"""
151120
//|
152121
//|
153-
static mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) {
154-
audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
155-
check_for_deinit(self);
156-
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self));
157-
}
158-
MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count);
159-
160-
MP_PROPERTY_GETTER(audioio_wavefile_channel_count_obj,
161-
(mp_obj_t)&audioio_wavefile_get_channel_count_obj);
162-
163122

164123
static const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = {
165124
// Methods
@@ -168,20 +127,14 @@ static const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = {
168127
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_wavefile___exit___obj) },
169128

170129
// Properties
171-
{ MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_wavefile_sample_rate_obj) },
172-
{ MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audioio_wavefile_bits_per_sample_obj) },
173-
{ MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audioio_wavefile_channel_count_obj) },
130+
AUDIOSAMPLE_FIELDS,
174131
};
175132
static MP_DEFINE_CONST_DICT(audioio_wavefile_locals_dict, audioio_wavefile_locals_dict_table);
176133

177134
static const audiosample_p_t audioio_wavefile_proto = {
178135
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
179-
.sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_wavefile_get_sample_rate,
180-
.bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_wavefile_get_bits_per_sample,
181-
.channel_count = (audiosample_channel_count_fun)common_hal_audioio_wavefile_get_channel_count,
182136
.reset_buffer = (audiosample_reset_buffer_fun)audioio_wavefile_reset_buffer,
183137
.get_buffer = (audiosample_get_buffer_fun)audioio_wavefile_get_buffer,
184-
.get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_wavefile_get_buffer_structure,
185138
};
186139

187140

shared-bindings/audiocore/__init__.c

+65-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
#include <stdint.h>
88

99
#include "py/obj.h"
10+
#include "py/objproperty.h"
1011
#include "py/gc.h"
1112
#include "py/runtime.h"
1213

1314
#include "shared-bindings/audiocore/__init__.h"
1415
#include "shared-bindings/audiocore/RawSample.h"
1516
#include "shared-bindings/audiocore/WaveFile.h"
17+
#include "shared-bindings/util.h"
1618
// #include "shared-bindings/audiomixer/Mixer.h"
1719

1820
//| """Support for audio samples"""
@@ -24,15 +26,18 @@ static mp_obj_t audiocore_get_buffer(mp_obj_t sample_in) {
2426
uint32_t buffer_length = 0;
2527
audioio_get_buffer_result_t gbr = audiosample_get_buffer(sample_in, false, 0, &buffer, &buffer_length);
2628

29+
// audiosample_get_buffer checked that we're a sample so this is a safe cast
30+
audiosample_base_t *sample = MP_OBJ_TO_PTR(sample_in);
31+
2732
mp_obj_t result[2] = {mp_obj_new_int_from_uint(gbr), mp_const_none};
2833

2934
if (gbr != GET_BUFFER_ERROR) {
3035
bool single_buffer, samples_signed;
3136
uint32_t max_buffer_length;
3237
uint8_t spacing;
3338

34-
uint8_t bits_per_sample = audiosample_bits_per_sample(sample_in);
35-
audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
39+
uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample);
40+
audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
3641
// copies the data because the gc semantics of get_buffer are unclear
3742
void *result_buf = m_malloc(buffer_length);
3843
memcpy(result_buf, buffer, buffer_length);
@@ -55,7 +60,7 @@ static mp_obj_t audiocore_get_structure(mp_obj_t sample_in) {
5560
uint32_t max_buffer_length;
5661
uint8_t spacing;
5762

58-
audiosample_get_buffer_structure(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
63+
audiosample_get_buffer_structure_checked(sample_in, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
5964
mp_obj_t result[4] = {
6065
mp_obj_new_int_from_uint(single_buffer),
6166
mp_obj_new_int_from_uint(samples_signed),
@@ -92,4 +97,61 @@ const mp_obj_module_t audiocore_module = {
9297
.globals = (mp_obj_dict_t *)&audiocore_module_globals,
9398
};
9499

100+
bool audiosample_deinited(const audiosample_base_t *self) {
101+
return self->channel_count == 0;
102+
}
103+
104+
void audiosample_check_for_deinit(const audiosample_base_t *self) {
105+
if (audiosample_deinited(self)) {
106+
raise_deinited_error();
107+
}
108+
}
109+
110+
void audiosample_mark_deinit(audiosample_base_t *self) {
111+
self->channel_count = 0;
112+
}
113+
114+
// common implementation of channel_count property for audio samples
115+
static mp_obj_t audiosample_obj_get_channel_count(mp_obj_t self_in) {
116+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
117+
audiosample_check_for_deinit(self);
118+
return MP_OBJ_NEW_SMALL_INT(audiosample_get_channel_count(self));
119+
}
120+
MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_channel_count_obj, audiosample_obj_get_channel_count);
121+
122+
MP_PROPERTY_GETTER(audiosample_channel_count_obj,
123+
(mp_obj_t)&audiosample_get_channel_count_obj);
124+
125+
126+
// common implementation of bits_per_sample property for audio samples
127+
static mp_obj_t audiosample_obj_get_bits_per_sample(mp_obj_t self_in) {
128+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
129+
audiosample_check_for_deinit(self);
130+
return MP_OBJ_NEW_SMALL_INT(audiosample_get_bits_per_sample(self));
131+
}
132+
MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_bits_per_sample_obj, audiosample_obj_get_bits_per_sample);
133+
134+
MP_PROPERTY_GETTER(audiosample_bits_per_sample_obj,
135+
(mp_obj_t)&audiosample_get_bits_per_sample_obj);
136+
137+
// common implementation of sample_rate property for audio samples
138+
static mp_obj_t audiosample_obj_get_sample_rate(mp_obj_t self_in) {
139+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
140+
audiosample_check_for_deinit(self);
141+
return MP_OBJ_NEW_SMALL_INT(audiosample_get_sample_rate(audiosample_check(self_in)));
142+
}
143+
MP_DEFINE_CONST_FUN_OBJ_1(audiosample_get_sample_rate_obj, audiosample_obj_get_sample_rate);
144+
145+
static mp_obj_t audiosample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
146+
audiosample_base_t *self = MP_OBJ_TO_PTR(self_in);
147+
audiosample_check_for_deinit(self);
148+
audiosample_set_sample_rate(audiosample_check(self_in), mp_obj_get_int(sample_rate));
149+
return mp_const_none;
150+
}
151+
MP_DEFINE_CONST_FUN_OBJ_2(audiosample_set_sample_rate_obj, audiosample_obj_set_sample_rate);
152+
153+
MP_PROPERTY_GETSET(audiosample_sample_rate_obj,
154+
(mp_obj_t)&audiosample_get_sample_rate_obj,
155+
(mp_obj_t)&audiosample_set_sample_rate_obj);
156+
95157
MP_REGISTER_MODULE(MP_QSTR_audiocore, audiocore_module);

0 commit comments

Comments
 (0)