@@ -63,6 +63,16 @@ MicroBitAudio::MicroBitAudio(NRF52Pin &pin, NRF52Pin &speaker, NRF52ADC &adc, NR
63
63
adc.setSamplePeriod ( 1e6 / 22000 );
64
64
mic->setGain (7 ,0 );
65
65
66
+ // Implementers note: The order that the pipeline comes up here is quite senitive. If we connect up to splitters after starting to
67
+ // listen for events from them, we'll see channel startup events (which are valid!) that we don't want. So roughly always follow
68
+ // the following schema:
69
+ //
70
+ // 1. Create the splitter
71
+ // 2. Attach any stages to the splitter
72
+ // 3. Start listening for splitter events
73
+ //
74
+ // This prevents any cases where the pipeline stages cause a connect() message to be emitted, which then auto-activates the mic.
75
+
66
76
// Initialialise the microphone filter
67
77
micFilter = new LowPassFilter (mic->output , 0 .1f , true );
68
78
@@ -72,6 +82,10 @@ MicroBitAudio::MicroBitAudio(NRF52Pin &pin, NRF52Pin &speaker, NRF52ADC &adc, NR
72
82
// Initilise stream normalizer
73
83
processor = new StreamNormalizer (*rawSplitter->createChannel (), 0 .08f , true , DATASTREAM_FORMAT_8BIT_SIGNED, 10 );
74
84
85
+ // Connect to the rawSplitter. This must come AFTER the processor, to prevent the processor's channel activation starting the microphone
86
+ if (EventModel::defaultEventBus)
87
+ EventModel::defaultEventBus->listen (rawSplitter->id , DEVICE_EVT_ANY, this , &MicroBitAudio::onSplitterEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
88
+
75
89
// Initilise stream splitter
76
90
splitter = new StreamSplitter (processor->output , DEVICE_ID_SPLITTER);
77
91
@@ -81,21 +95,22 @@ MicroBitAudio::MicroBitAudio(NRF52Pin &pin, NRF52Pin &speaker, NRF52ADC &adc, NR
81
95
// Initilise level detector SPL and attach to splitter
82
96
levelSPL = new LevelDetectorSPL (*rawSplitter->createChannel (), 85.0 , 65.0 , 16.0 , 0 , DEVICE_ID_MICROPHONE, false );
83
97
84
- // Register listener for splitter events
85
- if (EventModel::defaultEventBus){
86
- EventModel::defaultEventBus-> listen (rawSplitter-> id , DEVICE_EVT_ANY, this , &MicroBitAudio::onSplitterEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
98
+ // Connect to the splitter - this COULD come after we create it, before we add any stages, as these are dynamic and will only connect on-demand, but just in case
99
+ // we're going to follow the schema set out above, to be 100% sure.
100
+ if ( EventModel::defaultEventBus)
87
101
EventModel::defaultEventBus->listen (DEVICE_ID_SPLITTER, DEVICE_EVT_ANY, this , &MicroBitAudio::onSplitterEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
88
- }
89
102
}
90
103
91
104
/* *
92
105
* Handle events from splitter
93
106
*/
94
107
void MicroBitAudio::onSplitterEvent (MicroBitEvent e){
95
- if (e.value == SPLITTER_ACTIVATE_CHANNEL )
108
+ if ( e.value == SPLITTER_CHANNEL_CONNECT )
96
109
activateMic ();
97
- else if (e.value == SPLITTER_DEACTIVATE_CHANNEL)
98
- if ( splitter->numberChannels <= 0 && rawSplitter->numberChannels <= 0 ) // Only deactivate if we have no more channels to serve!
110
+
111
+ // Note: The processor will always be present on the rawSplitter, hence the <= 1.
112
+ else if ( e.value == SPLITTER_CHANNEL_DISCONNECT )
113
+ if ( splitter->numberActiveChannels <= 0 && rawSplitter->numberActiveChannels <= 1 )
99
114
deactivateMic ();
100
115
}
101
116
0 commit comments