@@ -41,6 +41,7 @@ extern "C" {
41
41
#include " py/obj.h"
42
42
#include " py/objstr.h"
43
43
#include " py/mphal.h"
44
+ #include " py/gc.h"
44
45
#include " microbit/modaudio.h"
45
46
#include " microbit/microbitobj.h"
46
47
#include " microbit/microbitpin.h"
@@ -126,7 +127,7 @@ static volatile bool running = false;
126
127
static bool sample = false ;
127
128
static volatile bool fetcher_ready = true ;
128
129
static bool double_pin = true ;
129
- volatile int32_t audio_buffer_read_index;
130
+ static volatile int32_t audio_buffer_read_index;
130
131
static PinName pin0 = P0_3;
131
132
static PinName pin1 = P0_2;
132
133
@@ -181,14 +182,24 @@ static void audio_data_fetcher(void) {
181
182
/* WARNING: We are executing in an interrupt handler.
182
183
* If an exception is raised here then we must hand it to the VM. */
183
184
mp_obj_t buffer_obj;
185
+ gc_lock ();
184
186
nlr_buf_t nlr;
185
187
if (nlr_push (&nlr) == 0 ) {
186
188
buffer_obj = mp_iternext_allow_raise (audio_source_iter);
187
189
nlr_pop ();
190
+ gc_unlock ();
188
191
} else {
192
+ gc_unlock ();
189
193
if (!mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (((mp_obj_base_t *)nlr.ret_val )->type ),
190
194
MP_OBJ_FROM_PTR (&mp_type_StopIteration))) {
191
195
// 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
+ }
192
203
MP_STATE_VM (mp_pending_exception) = MP_OBJ_FROM_PTR (nlr.ret_val );
193
204
}
194
205
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
455
466
}
456
467
}
457
468
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) {
459
470
(void )self_in;
460
471
switch (op) {
461
472
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
472
483
return 0 ;
473
484
}
474
485
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
+
475
587
const mp_obj_type_t microbit_audio_frame_type = {
476
588
{ &mp_type_type },
477
589
.name = MP_QSTR_AudioFrame,
478
590
.print = NULL ,
479
591
.make_new = microbit_audio_frame_new,
480
592
.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 ,
483
595
.attr = NULL ,
484
596
.subscr = audio_frame_subscr,
485
597
.getiter = NULL ,
486
598
.iternext = NULL ,
487
599
.buffer_p = { .get_buffer = audio_frame_get_buffer },
488
600
.stream_p = NULL ,
489
601
.bases_tuple = NULL ,
490
- .locals_dict = NULL ,
602
+ .locals_dict = ( mp_obj_dict_t *)µbit_audio_frame_locals_dict_table ,
491
603
};
492
604
493
605
microbit_audio_frame_obj_t *new_microbit_audio_frame (void ) {
0 commit comments