@@ -41,6 +41,7 @@ extern "C" {
4141#include " py/obj.h"
4242#include " py/objstr.h"
4343#include " py/mphal.h"
44+ #include " py/gc.h"
4445#include " microbit/modaudio.h"
4546#include " microbit/microbitobj.h"
4647#include " microbit/microbitpin.h"
@@ -126,7 +127,7 @@ static volatile bool running = false;
126127static bool sample = false ;
127128static volatile bool fetcher_ready = true ;
128129static bool double_pin = true ;
129- volatile int32_t audio_buffer_read_index;
130+ static volatile int32_t audio_buffer_read_index;
130131static PinName pin0 = P0_3;
131132static PinName pin1 = P0_2;
132133
@@ -181,14 +182,24 @@ static void audio_data_fetcher(void) {
181182 /* WARNING: We are executing in an interrupt handler.
182183 * If an exception is raised here then we must hand it to the VM. */
183184 mp_obj_t buffer_obj;
185+ gc_lock ();
184186 nlr_buf_t nlr;
185187 if (nlr_push (&nlr) == 0 ) {
186188 buffer_obj = mp_iternext_allow_raise (audio_source_iter);
187189 nlr_pop ();
190+ gc_unlock ();
188191 } else {
192+ gc_unlock ();
189193 if (!mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (((mp_obj_base_t *)nlr.ret_val )->type ),
190194 MP_OBJ_FROM_PTR (&mp_type_StopIteration))) {
191195 // an exception other than StopIteration, so set it for the VM to raise later
196+ // If memory error, add appropriate message.
197+ mp_obj_exception_t *ex = (mp_obj_exception_t *)nlr.ret_val ;
198+ if (mp_obj_get_type (nlr.ret_val ) == &mp_type_MemoryError) {
199+ ex->args = (mp_obj_tuple_t *)mp_obj_new_tuple (1 , NULL );
200+ ex->args ->items [0 ] = mp_obj_new_str (" Allocation in interrupt handler" ,
201+ strlen (" Allocation in interrupt handler" ), false );
202+ }
192203 MP_STATE_VM (mp_pending_exception) = MP_OBJ_FROM_PTR (nlr.ret_val );
193204 }
194205 buffer_obj = MP_OBJ_STOP_ITERATION;
@@ -455,7 +466,7 @@ STATIC mp_obj_t audio_frame_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t
455466 }
456467}
457468
458- STATIC mp_obj_t mp_obj_audio_frame_unary_op (mp_uint_t op, mp_obj_t self_in) {
469+ static mp_obj_t audio_frame_unary_op (mp_uint_t op, mp_obj_t self_in) {
459470 (void )self_in;
460471 switch (op) {
461472 case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT (32 );
@@ -472,22 +483,123 @@ static mp_int_t audio_frame_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufin
472483 return 0 ;
473484}
474485
486+ static void add_into (microbit_audio_frame_obj_t *self, microbit_audio_frame_obj_t *other, bool add) {
487+ int mult = add ? 1 : -1 ;
488+ for (int i = 0 ; i < AUDIO_CHUNK_SIZE; i++) {
489+ unsigned val = (int )self->data [i] + mult*(other->data [i]-128 );
490+ // Clamp to 0-255
491+ if (val > 255 ) {
492+ val = (1 -(val>>31 ))*255 ;
493+ }
494+ self->data [i] = val;
495+ }
496+ }
497+
498+ static microbit_audio_frame_obj_t *copy (microbit_audio_frame_obj_t *self) {
499+ microbit_audio_frame_obj_t *result = new_microbit_audio_frame ();
500+ for (int i = 0 ; i < AUDIO_CHUNK_SIZE; i++) {
501+ result->data [i] = self->data [i];
502+ }
503+ return result;
504+ }
505+
506+ mp_obj_t copyfrom (mp_obj_t self_in, mp_obj_t other) {
507+ microbit_audio_frame_obj_t *self = (microbit_audio_frame_obj_t *)self_in;
508+ if (mp_obj_get_type (other) != µbit_audio_frame_type) {
509+ nlr_raise (mp_obj_new_exception_msg (&mp_type_TypeError, " Must be an AudioBuffer" ));
510+ }
511+ for (int i = 0 ; i < AUDIO_CHUNK_SIZE; i++) {
512+ self->data [i] = ((microbit_audio_frame_obj_t *)other)->data [i];
513+ }
514+ return mp_const_none;
515+ }
516+ MP_DEFINE_CONST_FUN_OBJ_2 (copyfrom_obj, copyfrom);
517+
518+ union _i2f {
519+ int32_t bits;
520+ float value;
521+ };
522+
523+ /* Convert a small float to a fixed-point number */
524+ int32_t float_to_fixed (float f, uint32_t scale) {
525+ union _i2f x;
526+ x.value = f;
527+ int32_t sign = 1 -((x.bits >>30 )&2 );
528+ /* Subtract 127 from exponent for IEEE-754 and 23 for mantissa scaling */
529+ int32_t exponent = ((x.bits >>23 )&255 )-150 ;
530+ /* Mantissa scaled by 2**23, including implicit 1 */
531+ int32_t mantissa = (1 <<23 ) | ((x.bits )&((1 <<23 )-1 ));
532+ int32_t shift = scale+exponent;
533+ int32_t result;
534+ if (shift > 0 ) {
535+ result = sign*(mantissa<<shift);
536+ } else if (shift < -31 ) {
537+ result = 0 ;
538+ } else {
539+ result = sign*(mantissa>>(-shift));
540+ }
541+ // printf("Float %f: %d %d %x (scale %d) => %d\n", f, sign, exponent, mantissa, scale, result);
542+ return result;
543+ }
544+
545+ static void mult (microbit_audio_frame_obj_t *self, float f) {
546+ int scaled = float_to_fixed (f, 15 );
547+ for (int i = 0 ; i < AUDIO_CHUNK_SIZE; i++) {
548+ unsigned val = ((((int )self->data [i]-128 ) * scaled) >> 15 )+128 ;
549+ if (val > 255 ) {
550+ val = (1 -(val>>31 ))*255 ;
551+ }
552+ self->data [i] = val;
553+ }
554+ }
555+
556+ STATIC mp_obj_t audio_frame_binary_op (mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
557+ if (mp_obj_get_type (lhs_in) != µbit_audio_frame_type) {
558+ return MP_OBJ_NULL; // op not supported
559+ }
560+ microbit_audio_frame_obj_t *lhs = (microbit_audio_frame_obj_t *)lhs_in;
561+ switch (op) {
562+ case MP_BINARY_OP_ADD:
563+ case MP_BINARY_OP_SUBTRACT:
564+ lhs = copy (lhs);
565+ case MP_BINARY_OP_INPLACE_ADD:
566+ case MP_BINARY_OP_INPLACE_SUBTRACT:
567+ if (mp_obj_get_type (rhs_in) != µbit_audio_frame_type) {
568+ return MP_OBJ_NULL; // op not supported
569+ }
570+ add_into (lhs, (microbit_audio_frame_obj_t *)rhs_in, op==MP_BINARY_OP_ADD||op==MP_BINARY_OP_INPLACE_ADD);
571+ return lhs;
572+ case MP_BINARY_OP_MULTIPLY:
573+ lhs = copy (lhs);
574+ case MP_BINARY_OP_INPLACE_MULTIPLY:
575+ mult (lhs, mp_obj_get_float (rhs_in));
576+ return lhs;
577+ }
578+ return MP_OBJ_NULL; // op not supported
579+ }
580+
581+ STATIC const mp_map_elem_t microbit_audio_frame_locals_dict_table[] = {
582+ { MP_OBJ_NEW_QSTR (MP_QSTR_copyfrom), (mp_obj_t )©from_obj },
583+ };
584+ STATIC MP_DEFINE_CONST_DICT (microbit_audio_frame_locals_dict, microbit_audio_frame_locals_dict_table);
585+
586+
475587const mp_obj_type_t microbit_audio_frame_type = {
476588 { &mp_type_type },
477589 .name = MP_QSTR_AudioFrame,
478590 .print = NULL ,
479591 .make_new = microbit_audio_frame_new,
480592 .call = NULL ,
481- .unary_op = mp_obj_audio_frame_unary_op ,
482- .binary_op = NULL ,
593+ .unary_op = audio_frame_unary_op ,
594+ .binary_op = audio_frame_binary_op ,
483595 .attr = NULL ,
484596 .subscr = audio_frame_subscr,
485597 .getiter = NULL ,
486598 .iternext = NULL ,
487599 .buffer_p = { .get_buffer = audio_frame_get_buffer },
488600 .stream_p = NULL ,
489601 .bases_tuple = NULL ,
490- .locals_dict = NULL ,
602+ .locals_dict = ( mp_obj_dict_t *)µbit_audio_frame_locals_dict_table ,
491603};
492604
493605microbit_audio_frame_obj_t *new_microbit_audio_frame (void ) {
0 commit comments