Skip to content

Commit a950349

Browse files
committed
Changes to properly handle samples
1 parent 5e92303 commit a950349

File tree

5 files changed

+184
-38
lines changed

5 files changed

+184
-38
lines changed

locale/circuitpython.pot

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,18 +1956,34 @@ msgstr ""
19561956
msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
19571957
msgstr ""
19581958

1959+
#: shared-module/audioeffects/Echo.c
1960+
msgid "The sample's bits_per_sample does not match the effect's"
1961+
msgstr ""
1962+
19591963
#: shared-module/audiomixer/MixerVoice.c
19601964
msgid "The sample's bits_per_sample does not match the mixer's"
19611965
msgstr ""
19621966

1967+
#: shared-module/audioeffects/Echo.c
1968+
msgid "The sample's channel count does not match the effect's"
1969+
msgstr ""
1970+
19631971
#: shared-module/audiomixer/MixerVoice.c
19641972
msgid "The sample's channel count does not match the mixer's"
19651973
msgstr ""
19661974

1975+
#: shared-module/audioeffects/Echo.c
1976+
msgid "The sample's sample rate does not match the effect's"
1977+
msgstr ""
1978+
19671979
#: shared-module/audiomixer/MixerVoice.c
19681980
msgid "The sample's sample rate does not match the mixer's"
19691981
msgstr ""
19701982

1983+
#: shared-module/audioeffects/Echo.c
1984+
msgid "The sample's signedness does not match the effect's"
1985+
msgstr ""
1986+
19711987
#: shared-module/audiomixer/MixerVoice.c
19721988
msgid "The sample's signedness does not match the mixer's"
19731989
msgstr ""

ports/raspberrypi/boards/raspberry_pi_pico2/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ CHIP_FAMILY = rp2
1010
EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ"
1111

1212
CIRCUITPY__EVE = 1
13+
CIRCUITPY_AUDIOEFFECTS = 1
1314
CIRCUITPY_ALARM = 0

shared-module/audioeffects/Echo.c

Lines changed: 128 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void common_hal_audioeffects_echo_construct(audioeffects_echo_obj_t *self, uint3
3131

3232
// calculate buffer size for the set delay
3333
self->delay_ms = delay_ms;
34-
self->echo_buffer_len = self->sample_rate / 1000.0f * self->delay_ms * sizeof(uint32_t);
34+
self->echo_buffer_len = self->sample_rate / 1000.0f * self->delay_ms * (self->channel_count * (self->bits_per_sample / 8));
3535

3636
self->echo_buffer = m_malloc(self->echo_buffer_len);
3737
if (self->echo_buffer == NULL) {
@@ -44,6 +44,12 @@ void common_hal_audioeffects_echo_construct(audioeffects_echo_obj_t *self, uint3
4444
// write is what we send to the outgoing buffer
4545
self->echo_buffer_read_pos = self->buffer_len / sizeof(uint32_t);
4646
self->echo_buffer_write_pos = 0;
47+
48+
self->sample = NULL;
49+
self->sample_remaining_buffer = NULL;
50+
self->sample_buffer_length = 0;
51+
self->loop = false;
52+
self->more_data = false;
4753
}
4854

4955
bool common_hal_audioeffects_echo_deinited(audioeffects_echo_obj_t *self) {
@@ -68,7 +74,7 @@ uint32_t common_hal_audioeffects_echo_get_delay_ms(audioeffects_echo_obj_t *self
6874

6975
void common_hal_audioeffects_echo_set_delay_ms(audioeffects_echo_obj_t *self, uint32_t delay_ms) {
7076
self->delay_ms = delay_ms;
71-
self->echo_buffer_len = self->sample_rate / 1000.0f * self->delay_ms * sizeof(uint32_t);
77+
self->echo_buffer_len = self->sample_rate / 1000.0f * self->delay_ms * (self->channel_count * (self->bits_per_sample / 8));
7278

7379
self->echo_buffer = m_realloc(self->echo_buffer, self->echo_buffer_len);
7480
if (self->echo_buffer == NULL) {
@@ -118,59 +124,138 @@ bool common_hal_audioeffects_echo_get_playing(audioeffects_echo_obj_t *self) {
118124
}
119125

120126
void common_hal_audioeffects_echo_play(audioeffects_echo_obj_t *self, mp_obj_t sample, bool loop) {
121-
// check buffer size vs our buffer length
127+
if (audiosample_sample_rate(sample) != self->sample_rate) {
128+
mp_raise_ValueError(MP_ERROR_TEXT("The sample's sample rate does not match the effect's"));
129+
}
130+
if (audiosample_channel_count(sample) != self->channel_count) {
131+
mp_raise_ValueError(MP_ERROR_TEXT("The sample's channel count does not match the effect's"));
132+
}
133+
if (audiosample_bits_per_sample(sample) != self->bits_per_sample) {
134+
mp_raise_ValueError(MP_ERROR_TEXT("The sample's bits_per_sample does not match the effect's"));
135+
}
136+
bool single_buffer;
137+
bool samples_signed;
138+
uint32_t max_buffer_length;
139+
uint8_t spacing;
140+
audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, &max_buffer_length, &spacing);
141+
if (samples_signed != self->samples_signed) {
142+
mp_raise_ValueError(MP_ERROR_TEXT("The sample's signedness does not match the effect's"));
143+
}
122144
self->sample = sample;
145+
self->loop = loop;
146+
147+
audiosample_reset_buffer(self->sample, false, 0);
148+
audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length);
149+
// Track length in terms of words.
150+
self->sample_buffer_length /= sizeof(uint32_t);
151+
self->more_data = result == GET_BUFFER_MORE_DATA;
152+
123153
return;
124154
}
125155

126156
void common_hal_audioeffects_echo_stop(audioeffects_echo_obj_t *self) {
127157
self->sample = NULL;
128-
memset(self->echo_buffer, 0, self->echo_buffer_len); // clear echo
158+
// memset(self->echo_buffer, 0, self->echo_buffer_len); // clear echo
159+
// memset(self->buffer, 0, self->buffer_len);
129160
return;
130161
}
131162

132163
audioio_get_buffer_result_t audioeffects_echo_get_buffer(audioeffects_echo_obj_t *self, bool single_channel_output, uint8_t channel,
133164
uint8_t **buffer, uint32_t *buffer_length) {
134165

135-
*buffer_length = self->buffer_len;
136-
*buffer = (uint8_t *)self->buffer;
137-
138-
if (self->sample == NULL) {
139-
140-
} else {
141-
// Get the sample's buffer
142-
uint32_t *sample_buffer;
143-
uint32_t sample_buffer_len;
144-
145-
// audioio_get_buffer_result_t result =
146-
audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&sample_buffer, &sample_buffer_len);
147-
148-
uint32_t n = MIN(sample_buffer_len / sizeof(uint32_t), (self->buffer_len / sizeof(uint32_t)));
149-
*buffer_length = n * sizeof(uint32_t);
150-
151-
uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint32_t);
152-
153-
// pass the sample thru to our buffer adding in the echo
154-
for (uint32_t i = 0; i < n; i++) {
155-
if (self->echo_buffer_read_pos >= echo_buf_len) {
156-
self->echo_buffer_read_pos = 0;
166+
uint32_t *word_buffer = (uint32_t *)self->buffer;
167+
uint32_t length = self->buffer_len / sizeof(uint32_t);
168+
uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint32_t);
169+
170+
while (length != 0) {
171+
if (self->sample_buffer_length == 0) {
172+
if (!self->more_data) {
173+
if (self->loop) {
174+
if (self->sample) {
175+
audiosample_reset_buffer(self->sample, false, 0);
176+
}
177+
} else {
178+
self->sample = NULL;
179+
}
180+
}
181+
if (self->sample) {
182+
// Load another buffer
183+
audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length);
184+
// Track length in terms of words.
185+
self->sample_buffer_length /= sizeof(uint32_t);
186+
self->more_data = result == GET_BUFFER_MORE_DATA;
157187
}
158-
159-
uint32_t echo = self->echo_buffer[self->echo_buffer_read_pos++];
160-
self->buffer[i] = add16signed(mult16signed(echo, self->decay), sample_buffer[i]);
161188
}
162189

163-
// copy sample buffer to echo buf to play back later
164-
// This now includes our current sound + previous echos
165-
for (uint32_t i = 0; i < n; i++) {
166-
if (self->echo_buffer_write_pos >= echo_buf_len) {
167-
self->echo_buffer_write_pos = 0;
190+
// If we have no sample keep the echo echoing
191+
if (self->sample == NULL) {
192+
if (MP_LIKELY(self->bits_per_sample == 16)) {
193+
if (MP_LIKELY(self->samples_signed)) {
194+
for (uint32_t i = 0; i < length; i++) {
195+
if (self->echo_buffer_read_pos >= echo_buf_len) {
196+
self->echo_buffer_read_pos = 0;
197+
}
198+
199+
uint32_t echo = self->echo_buffer[self->echo_buffer_read_pos++];
200+
word_buffer[i] = mult16signed(echo, self->decay);
201+
202+
if (self->echo_buffer_write_pos >= echo_buf_len) {
203+
self->echo_buffer_write_pos = 0;
204+
}
205+
206+
self->echo_buffer[self->echo_buffer_write_pos++] = word_buffer[i];
207+
}
208+
}
209+
}
210+
length = 0;
211+
} else {
212+
uint32_t n = MIN(self->sample_buffer_length, length);
213+
uint32_t *sample_src = self->sample_remaining_buffer;
214+
215+
if (MP_LIKELY(self->bits_per_sample == 16)) {
216+
if (MP_LIKELY(self->samples_signed)) {
217+
for (uint32_t i = 0; i < n; i++) {
218+
uint32_t sample_word = sample_src[i];
219+
uint32_t echo = self->echo_buffer[self->echo_buffer_read_pos++];
220+
word_buffer[i] = add16signed(mult16signed(echo, self->decay), sample_word);
221+
self->echo_buffer[self->echo_buffer_write_pos++] = add16signed(sample_word, word_buffer[i]);
222+
223+
if (self->echo_buffer_read_pos >= echo_buf_len) {
224+
self->echo_buffer_read_pos = 0;
225+
}
226+
if (self->echo_buffer_write_pos >= echo_buf_len) {
227+
self->echo_buffer_write_pos = 0;
228+
}
229+
}
230+
} else {
231+
// for (uint32_t i = 0; i < n; i++) {
232+
// uint32_t sample_word = sample_src[i];
233+
// sample_word = tosigned16(sample_word);
234+
// word_buffer[i] = add16signed(mult16signed(sample_word, self->decay), word_buffer[i]);
235+
// }
236+
}
237+
} else {
238+
// uint16_t *hword_buffer = (uint16_t *)word_buffer;
239+
// uint16_t *sample_hsrc = (uint16_t *)sample_src;
240+
// for (uint32_t i = 0; i < n * 2; i++) {
241+
// uint32_t sample_word = unpack8(sample_hsrc[i]);
242+
// if (MP_LIKELY(!self->samples_signed)) {
243+
// sample_word = tosigned16(sample_word);
244+
// }
245+
// sample_word = mult16signed(sample_word, self->decay);
246+
// sample_word = add16signed(sample_word, unpack8(hword_buffer[i]));
247+
// hword_buffer[i] = pack8(sample_word);
248+
// }
168249
}
169250

170-
self->echo_buffer[self->echo_buffer_write_pos++] = add16signed(sample_buffer[i], self->buffer[i]);
251+
length -= n;
252+
word_buffer += n;
253+
self->sample_remaining_buffer += n;
254+
self->sample_buffer_length -= n;
171255
}
172256
}
173-
257+
*buffer = (uint8_t *)self->buffer;
258+
*buffer_length = self->buffer_len;
174259
return GET_BUFFER_MORE_DATA;
175260
}
176261

@@ -179,11 +264,16 @@ void audioeffects_echo_get_buffer_structure(audioeffects_echo_obj_t *self, bool
179264

180265
if (self->sample != NULL) {
181266
audiosample_get_buffer_structure(self->sample, single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing);
267+
*single_buffer = false;
182268
*max_buffer_length = self->buffer_len;
183269
} else {
184-
*single_buffer = false;
270+
*single_buffer = true;
185271
*samples_signed = true;
186272
*max_buffer_length = self->buffer_len;
187-
*spacing = 1;
273+
if (single_channel_output) {
274+
*spacing = self->channel_count;
275+
} else {
276+
*spacing = 1;
277+
}
188278
}
189279
}

shared-module/audioeffects/Echo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ typedef struct {
2323
uint32_t *buffer;
2424
uint32_t buffer_len; // buffer in bytes
2525

26+
uint32_t *sample_remaining_buffer;
27+
uint32_t sample_buffer_length;
28+
29+
bool loop;
30+
bool more_data;
31+
2632
uint32_t *echo_buffer;
2733
uint32_t echo_buffer_len; // bytes
2834

shared-module/audioeffects/effects_utils.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,36 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
5656
return result;
5757
#endif
5858
}
59+
60+
61+
static inline uint32_t tounsigned8(uint32_t val) {
62+
#if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))
63+
return __UADD8(val, 0x80808080);
64+
#else
65+
return val ^ 0x80808080;
66+
#endif
67+
}
68+
69+
static inline uint32_t tounsigned16(uint32_t val) {
70+
#if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))
71+
return __UADD16(val, 0x80008000);
72+
#else
73+
return val ^ 0x80008000;
74+
#endif
75+
}
76+
77+
static inline uint32_t tosigned16(uint32_t val) {
78+
#if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1))
79+
return __UADD16(val, 0x80008000);
80+
#else
81+
return val ^ 0x80008000;
82+
#endif
83+
}
84+
85+
static inline uint32_t unpack8(uint16_t val) {
86+
return ((val & 0xff00) << 16) | ((val & 0x00ff) << 8);
87+
}
88+
89+
static inline uint32_t pack8(uint32_t val) {
90+
return ((val & 0xff000000) >> 16) | ((val & 0xff00) >> 8);
91+
}

0 commit comments

Comments
 (0)