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+
7589typedef 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+
81101STATIC 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
89109STATIC 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+
96127const 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 )
170207STATIC 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-
251247STATIC 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+
287312STATIC 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