Skip to content

Commit ab084f4

Browse files
committed
codal_port/microbit_soundeffect: Update SoundEffect class.
Signed-off-by: Damien George <[email protected]>
1 parent 12b179d commit ab084f4

File tree

1 file changed

+137
-106
lines changed

1 file changed

+137
-106
lines changed

src/codal_port/microbit_soundeffect.c

+137-106
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,52 @@
5252
#define SOUND_EXPR_FX_STEPS_OFFSET (40)
5353
#define SOUND_EXPR_FX_STEPS_LENGTH (4)
5454

55-
#define SOUND_EXPR_ENCODE_VOLUME(v) ((v) * 1023 / 255)
56-
#define SOUND_EXPR_DECODE_VOLUME(v) ((v) * 255 / 1023)
55+
#define SOUND_EXPR_ENCODE_VOLUME(v) (((v) * 1023 + 127) / 255)
56+
#define SOUND_EXPR_DECODE_VOLUME(v) (((v) * 255 + 511) / 1023)
5757

58-
#define SOUND_EXPR_DEFAULT "3""1023""0500""0500""18""000""2500""0000""0000""0128""00""0001""0024""0000000000000000000000000000"
58+
// #define SOUND_EXPR_DEFAULT "3""1023""0500""0500""18""000""2500""0000""0000""0128""00""0001""0024""0000000000000000000000000000"
59+
// 310230500050018000250000000000012800000100240000000000000000000000000000
60+
// 310230500050018000250000000000000000000000000000000000000000000000000000
61+
// 30=steps
62+
// 36=fx-param
63+
// 40=fx-steps
5964

6065
#define SOUND_EFFECT_WAVE_SINE (0)
6166
#define SOUND_EFFECT_WAVE_SAWTOOTH (1)
6267
#define SOUND_EFFECT_WAVE_TRIANGLE (2)
6368
#define SOUND_EFFECT_WAVE_SQUARE (3)
6469
#define SOUND_EFFECT_WAVE_NOISE (4)
6570

66-
#define SOUND_EFFECT_INTER_LINEAR (1)
67-
#define SOUND_EFFECT_INTER_CURVE (2)
68-
#define SOUND_EFFECT_INTER_LOG (18)
71+
#define SOUND_EFFECT_SHAPE_LINEAR (1)
72+
#define SOUND_EFFECT_SHAPE_CURVE (2)
73+
#define SOUND_EFFECT_SHAPE_LOG (18)
6974

70-
#define SOUND_EFFECT_FX_NONE (0) // Python "None" object
75+
#define SOUND_EFFECT_FX_NONE (0)
7176
#define SOUND_EFFECT_FX_TREMOLO (2)
7277
#define SOUND_EFFECT_FX_VIBRATO (1)
7378
#define SOUND_EFFECT_FX_WARBLE (3)
7479

80+
#define SOUND_EFFECT_DEFAULT_FREQ_START (500)
81+
#define SOUND_EFFECT_DEFAULT_FREQ_END (2500)
82+
#define SOUND_EFFECT_DEFAULT_DURATION (500)
83+
#define SOUND_EFFECT_DEFAULT_VOL_START (255)
84+
#define SOUND_EFFECT_DEFAULT_VOL_END (0)
85+
#define SOUND_EFFECT_DEFAULT_WAVE (SOUND_EFFECT_WAVE_SQUARE)
86+
#define SOUND_EFFECT_DEFAULT_FX (SOUND_EFFECT_FX_NONE)
87+
#define SOUND_EFFECT_DEFAULT_SHAPE (SOUND_EFFECT_SHAPE_LOG)
88+
7589
typedef struct _microbit_soundeffect_obj_t {
7690
mp_obj_base_t base;
7791
bool is_mutable;
7892
char sound_expr[SOUND_EXPR_TOTAL_LENGTH];
7993
} microbit_soundeffect_obj_t;
8094

95+
typedef struct _soundeffect_attr_t {
96+
uint16_t qst;
97+
uint8_t offset;
98+
uint8_t length;
99+
} soundeffect_attr_t;
100+
81101
STATIC const uint16_t wave_to_qstr_table[5] = {
82102
[SOUND_EFFECT_WAVE_SINE] = MP_QSTR_WAVE_SINE,
83103
[SOUND_EFFECT_WAVE_SAWTOOTH] = MP_QSTR_WAVE_SAWTOOTH,
@@ -87,12 +107,23 @@ STATIC const uint16_t wave_to_qstr_table[5] = {
87107
};
88108

89109
STATIC const uint16_t fx_to_qstr_table[4] = {
90-
[0] = MP_QSTR_None,
110+
[SOUND_EFFECT_FX_NONE] = MP_QSTR_FX_NONE,
91111
[SOUND_EFFECT_FX_TREMOLO] = MP_QSTR_FX_TREMOLO,
92112
[SOUND_EFFECT_FX_VIBRATO] = MP_QSTR_FX_VIBRATO,
93113
[SOUND_EFFECT_FX_WARBLE] = MP_QSTR_FX_WARBLE,
94114
};
95115

116+
STATIC const soundeffect_attr_t soundeffect_attr_table[] = {
117+
{ MP_QSTR_freq_start, SOUND_EXPR_FREQUENCY_START_OFFSET, SOUND_EXPR_FREQUENCY_START_LENGTH },
118+
{ MP_QSTR_freq_end, SOUND_EXPR_FREQUENCY_END_OFFSET, SOUND_EXPR_FREQUENCY_END_LENGTH },
119+
{ MP_QSTR_duration, SOUND_EXPR_DURATION_OFFSET, SOUND_EXPR_DURATION_LENGTH },
120+
{ MP_QSTR_vol_start, SOUND_EXPR_VOLUME_START_OFFSET, SOUND_EXPR_VOLUME_START_LENGTH },
121+
{ MP_QSTR_vol_end, SOUND_EXPR_VOLUME_END_OFFSET, SOUND_EXPR_VOLUME_END_LENGTH },
122+
{ MP_QSTR_wave, SOUND_EXPR_WAVE_OFFSET, SOUND_EXPR_WAVE_LENGTH },
123+
{ MP_QSTR_fx, SOUND_EXPR_FX_CHOICE_OFFSET, SOUND_EXPR_FX_CHOICE_LENGTH },
124+
{ MP_QSTR_shape, SOUND_EXPR_SHAPE_OFFSET, SOUND_EXPR_SHAPE_LENGTH },
125+
};
126+
96127
const char *microbit_soundeffect_get_sound_expr_data(mp_obj_t self_in) {
97128
const microbit_soundeffect_obj_t *self = MP_OBJ_TO_PTR(self_in);
98129
return &self->sound_expr[0];
@@ -131,54 +162,59 @@ STATIC void microbit_soundeffect_print(const mp_print_t *print, mp_obj_t self_in
131162
unsigned int fx = sound_expr_decode(self, SOUND_EXPR_FX_CHOICE_OFFSET, SOUND_EXPR_FX_CHOICE_LENGTH);
132163
unsigned int shape = sound_expr_decode(self, SOUND_EXPR_SHAPE_OFFSET, SOUND_EXPR_SHAPE_LENGTH);
133164

134-
mp_printf(print, "SoundEffect("
135-
"freq_start=%d, "
136-
"freq_end=%d, "
137-
"duration=%d, "
138-
"vol_start=%d, "
139-
"vol_end=%d, "
140-
"wave=%q, "
141-
"fx=%q, ",
142-
freq_start,
143-
freq_end,
144-
duration,
145-
vol_start,
146-
vol_end,
147-
wave_to_qstr_table[wave],
148-
fx_to_qstr_table[fx]
149-
);
150-
151-
// Support shape values that don't have a corresponding constant assigned.
152-
switch (shape) {
153-
case SOUND_EFFECT_INTER_LINEAR:
154-
mp_printf(print, "interpolation=INTER_LINEAR)");
155-
break;
156-
case SOUND_EFFECT_INTER_CURVE:
157-
mp_printf(print, "interpolation=INTER_CURVE)");
158-
break;
159-
case SOUND_EFFECT_INTER_LOG:
160-
mp_printf(print, "interpolation=INTER_LOG)");
161-
break;
162-
default:
163-
mp_printf(print, "interpolation=%d)", shape);
164-
break;
165+
if (kind == PRINT_STR) {
166+
mp_printf(print, "SoundEffect("
167+
"freq_start=%d, "
168+
"freq_end=%d, "
169+
"duration=%d, "
170+
"vol_start=%d, "
171+
"vol_end=%d, "
172+
"wave=%q, "
173+
"fx=%q, ",
174+
freq_start,
175+
freq_end,
176+
duration,
177+
vol_start,
178+
vol_end,
179+
wave_to_qstr_table[wave],
180+
fx_to_qstr_table[fx]
181+
);
182+
183+
// Support shape values that don't have a corresponding constant assigned.
184+
switch (shape) {
185+
case SOUND_EFFECT_SHAPE_LINEAR:
186+
mp_printf(print, "shape=SHAPE_LINEAR)");
187+
break;
188+
case SOUND_EFFECT_SHAPE_CURVE:
189+
mp_printf(print, "shape=SHAPE_CURVE)");
190+
break;
191+
case SOUND_EFFECT_SHAPE_LOG:
192+
mp_printf(print, "shape=SHAPE_LOG)");
193+
break;
194+
default:
195+
mp_printf(print, "shape=%d)", shape);
196+
break;
197+
}
198+
} else {
199+
// PRINT_REPR
200+
mp_printf(print, "SoundEffect(%d, %d, %d, %d, %d, %d, %d, %d)",
201+
freq_start, freq_end, duration, vol_start, vol_end, wave, fx, shape);
165202
}
166203
}
167204

168205
// Constructor:
169-
// SoundEffect(preset=None, *, freq_start, freq_end, duration, vol_start, vol_end, wave, fx, interpolation)
206+
// SoundEffect(freq_start, freq_end, duration, vol_start, vol_end, wave, fx, shape)
170207
STATIC mp_obj_t microbit_soundeffect_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
171-
enum { ARG_preset, ARG_freq_start, ARG_freq_end, ARG_duration, ARG_vol_start, ARG_vol_end, ARG_wave, ARG_fx, ARG_interpolation };
208+
enum { ARG_freq_start, ARG_freq_end, ARG_duration, ARG_vol_start, ARG_vol_end, ARG_wave, ARG_fx, ARG_shape };
172209
static const mp_arg_t allowed_args[] = {
173-
{ MP_QSTR_preset, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
174-
{ MP_QSTR_freq_start, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
175-
{ MP_QSTR_freq_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
176-
{ MP_QSTR_duration, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
177-
{ MP_QSTR_vol_start, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
178-
{ MP_QSTR_vol_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
179-
{ MP_QSTR_wave, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
180-
{ MP_QSTR_fx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
181-
{ MP_QSTR_interpolation, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
210+
{ MP_QSTR_freq_start, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_FREQ_START} },
211+
{ MP_QSTR_freq_end, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_FREQ_END} },
212+
{ MP_QSTR_duration, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_DURATION} },
213+
{ MP_QSTR_vol_start, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_VOL_START} },
214+
{ MP_QSTR_vol_end, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_VOL_END} },
215+
{ MP_QSTR_wave, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_WAVE} },
216+
{ MP_QSTR_fx, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_FX} },
217+
{ MP_QSTR_shape, MP_ARG_INT, {.u_int = SOUND_EFFECT_DEFAULT_SHAPE} },
182218
};
183219

184220
// Parse arguments.
@@ -191,63 +227,23 @@ STATIC mp_obj_t microbit_soundeffect_make_new(const mp_obj_type_t *type, size_t
191227
self->is_mutable = true;
192228

193229
// Initialise the sound expression data with the preset values.
194-
const char *sound_expr_preset = SOUND_EXPR_DEFAULT;
195-
if (args[ARG_preset].u_obj != mp_const_none) {
196-
if (mp_obj_is_type(args[ARG_preset].u_obj, &microbit_soundeffect_type)) {
197-
sound_expr_preset = microbit_soundeffect_get_sound_expr_data(args[ARG_preset].u_obj);
198-
} else {
199-
sound_expr_preset = mp_obj_str_get_str(args[ARG_preset].u_obj);
200-
}
201-
}
202-
memcpy(&self->sound_expr[0], sound_expr_preset, SOUND_EXPR_TOTAL_LENGTH);
230+
memset(&self->sound_expr[0], '0', SOUND_EXPR_TOTAL_LENGTH);
231+
sound_expr_encode(self, SOUND_EXPR_STEPS_OFFSET, SOUND_EXPR_STEPS_LENGTH, 128);
203232

204233
// Modify any given parameters.
205-
if (args[ARG_freq_start].u_obj != MP_OBJ_NULL) {
206-
sound_expr_encode(self, SOUND_EXPR_FREQUENCY_START_OFFSET, SOUND_EXPR_FREQUENCY_START_LENGTH, mp_obj_get_int(args[ARG_freq_start].u_obj));
207-
}
208-
if (args[ARG_freq_end].u_obj != MP_OBJ_NULL) {
209-
sound_expr_encode(self, SOUND_EXPR_FREQUENCY_END_OFFSET, SOUND_EXPR_FREQUENCY_END_LENGTH, mp_obj_get_int(args[ARG_freq_end].u_obj));
210-
}
211-
if (args[ARG_duration].u_obj != MP_OBJ_NULL) {
212-
sound_expr_encode(self, SOUND_EXPR_DURATION_OFFSET, SOUND_EXPR_DURATION_LENGTH, mp_obj_get_int(args[ARG_duration].u_obj));
213-
}
214-
if (args[ARG_vol_start].u_obj != MP_OBJ_NULL) {
215-
sound_expr_encode(self, SOUND_EXPR_VOLUME_START_OFFSET, SOUND_EXPR_VOLUME_START_LENGTH, mp_obj_get_int(args[ARG_vol_start].u_obj));
216-
}
217-
if (args[ARG_vol_end].u_obj != MP_OBJ_NULL) {
218-
sound_expr_encode(self, SOUND_EXPR_VOLUME_END_OFFSET, SOUND_EXPR_VOLUME_END_LENGTH, mp_obj_get_int(args[ARG_vol_end].u_obj));
219-
}
220-
if (args[ARG_wave].u_obj != MP_OBJ_NULL) {
221-
sound_expr_encode(self, SOUND_EXPR_WAVE_OFFSET, SOUND_EXPR_WAVE_LENGTH, mp_obj_get_int(args[ARG_wave].u_obj));
222-
}
223-
if (args[ARG_fx].u_obj != MP_OBJ_NULL) {
224-
sound_expr_encode(self, SOUND_EXPR_FX_CHOICE_OFFSET, SOUND_EXPR_FX_CHOICE_LENGTH, args[ARG_fx].u_obj == mp_const_none ? 0 : mp_obj_get_int(args[ARG_fx].u_obj));
225-
}
226-
if (args[ARG_interpolation].u_obj != MP_OBJ_NULL) {
227-
sound_expr_encode(self, SOUND_EXPR_SHAPE_OFFSET, SOUND_EXPR_SHAPE_LENGTH, mp_obj_get_int(args[ARG_interpolation].u_obj));
228-
}
234+
sound_expr_encode(self, SOUND_EXPR_FREQUENCY_START_OFFSET, SOUND_EXPR_FREQUENCY_START_LENGTH, args[ARG_freq_start].u_int);
235+
sound_expr_encode(self, SOUND_EXPR_FREQUENCY_END_OFFSET, SOUND_EXPR_FREQUENCY_END_LENGTH, args[ARG_freq_end].u_int);
236+
sound_expr_encode(self, SOUND_EXPR_DURATION_OFFSET, SOUND_EXPR_DURATION_LENGTH, args[ARG_duration].u_int);
237+
sound_expr_encode(self, SOUND_EXPR_VOLUME_START_OFFSET, SOUND_EXPR_VOLUME_START_LENGTH, args[ARG_vol_start].u_int);
238+
sound_expr_encode(self, SOUND_EXPR_VOLUME_END_OFFSET, SOUND_EXPR_VOLUME_END_LENGTH, args[ARG_vol_end].u_int);
239+
sound_expr_encode(self, SOUND_EXPR_WAVE_OFFSET, SOUND_EXPR_WAVE_LENGTH, args[ARG_wave].u_int);
240+
sound_expr_encode(self, SOUND_EXPR_FX_CHOICE_OFFSET, SOUND_EXPR_FX_CHOICE_LENGTH, args[ARG_fx].u_int);
241+
sound_expr_encode(self, SOUND_EXPR_SHAPE_OFFSET, SOUND_EXPR_SHAPE_LENGTH, args[ARG_shape].u_int);
229242

230243
// Return new sound effect object
231244
return MP_OBJ_FROM_PTR(self);
232245
}
233246

234-
typedef struct _soundeffect_attr_t {
235-
uint16_t qst;
236-
uint8_t offset;
237-
uint8_t length;
238-
} soundeffect_attr_t;
239-
240-
STATIC const soundeffect_attr_t soundeffect_attr_table[] = {
241-
{ MP_QSTR_freq_start, SOUND_EXPR_FREQUENCY_START_OFFSET, SOUND_EXPR_FREQUENCY_START_LENGTH },
242-
{ MP_QSTR_freq_end, SOUND_EXPR_FREQUENCY_END_OFFSET, SOUND_EXPR_FREQUENCY_END_LENGTH },
243-
{ MP_QSTR_duration, SOUND_EXPR_DURATION_OFFSET, SOUND_EXPR_DURATION_LENGTH },
244-
{ MP_QSTR_vol_start, SOUND_EXPR_VOLUME_START_OFFSET, SOUND_EXPR_VOLUME_START_LENGTH },
245-
{ MP_QSTR_vol_end, SOUND_EXPR_VOLUME_END_OFFSET, SOUND_EXPR_VOLUME_END_LENGTH },
246-
{ MP_QSTR_wave, SOUND_EXPR_WAVE_OFFSET, SOUND_EXPR_WAVE_LENGTH },
247-
{ MP_QSTR_fx, SOUND_EXPR_FX_CHOICE_OFFSET, SOUND_EXPR_FX_CHOICE_LENGTH },
248-
{ MP_QSTR_interpolation, SOUND_EXPR_SHAPE_OFFSET, SOUND_EXPR_SHAPE_LENGTH },
249-
};
250-
251247
STATIC void microbit_soundeffect_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
252248
microbit_soundeffect_obj_t *self = MP_OBJ_TO_PTR(self_in);
253249
const soundeffect_attr_t *soundeffect_attr = NULL;
@@ -258,7 +254,8 @@ STATIC void microbit_soundeffect_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
258254
}
259255
}
260256
if (soundeffect_attr == NULL) {
261-
// Invalid attribute.
257+
// Invalid attribute, set MP_OBJ_SENTINEL to continue lookup in locals dict.
258+
dest[1] = MP_OBJ_SENTINEL;
262259
return;
263260
}
264261
if (dest[0] == MP_OBJ_NULL) {
@@ -282,9 +279,43 @@ STATIC void microbit_soundeffect_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
282279
}
283280
}
284281

285-
// Note: these locals are only accessible as SoundEffect.xxx, because
286-
// microbit_soundeffect_attr handles attribute lookups on instances.
282+
STATIC mp_obj_t microbit_soundeffect_from_string(mp_obj_t str_in) {
283+
microbit_soundeffect_obj_t *self = m_new_obj(microbit_soundeffect_obj_t);
284+
self->base.type = &microbit_soundeffect_type;
285+
self->is_mutable = true;
286+
287+
// Initialise the sound expression data with the preset values.
288+
memset(&self->sound_expr[0], '0', SOUND_EXPR_TOTAL_LENGTH);
289+
size_t len;
290+
const char *str = mp_obj_str_get_data(str_in, &len);
291+
if (len > SOUND_EXPR_TOTAL_LENGTH) {
292+
len = SOUND_EXPR_TOTAL_LENGTH;
293+
}
294+
memcpy(&self->sound_expr[0], str, len);
295+
296+
return MP_OBJ_FROM_PTR(self);
297+
}
298+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(microbit_soundeffect_from_string_obj, microbit_soundeffect_from_string);
299+
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(microbit_soundeffect_from_string_staticmethod_obj, MP_ROM_PTR(&microbit_soundeffect_from_string_obj));
300+
301+
STATIC mp_obj_t microbit_soundeffect_copy(mp_obj_t self_in) {
302+
microbit_soundeffect_obj_t *self = MP_OBJ_TO_PTR(self_in);
303+
microbit_soundeffect_obj_t *copy = m_new_obj(microbit_soundeffect_obj_t);
304+
copy->base.type = self->base.type;
305+
copy->is_mutable = true;
306+
memcpy(&copy->sound_expr[0], &self->sound_expr[0], SOUND_EXPR_TOTAL_LENGTH);
307+
308+
return MP_OBJ_FROM_PTR(copy);
309+
}
310+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(microbit_soundeffect_copy_obj, microbit_soundeffect_copy);
311+
287312
STATIC const mp_rom_map_elem_t microbit_soundeffect_locals_dict_table[] = {
313+
// Static methods.
314+
{ MP_ROM_QSTR(MP_QSTR__from_string), MP_ROM_PTR(&microbit_soundeffect_from_string_staticmethod_obj) },
315+
316+
// Instance methods.
317+
{ MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&microbit_soundeffect_copy_obj) },
318+
288319
// Class constants.
289320
#define C(NAME) { MP_ROM_QSTR(MP_QSTR_ ## NAME), MP_ROM_INT(SOUND_EFFECT_ ## NAME) }
290321

@@ -294,9 +325,9 @@ STATIC const mp_rom_map_elem_t microbit_soundeffect_locals_dict_table[] = {
294325
C(WAVE_SQUARE),
295326
C(WAVE_NOISE),
296327

297-
C(INTER_LINEAR),
298-
C(INTER_CURVE),
299-
C(INTER_LOG),
328+
C(SHAPE_LINEAR),
329+
C(SHAPE_CURVE),
330+
C(SHAPE_LOG),
300331

301332
C(FX_NONE),
302333
C(FX_TREMOLO),

0 commit comments

Comments
 (0)