|
6 | 6 | # Code written by Adafruit Industries |
7 | 7 | # Adafruit Circuit Playground Express Bluefruit |
8 | 8 |
|
| 9 | +# pylint: disable=global-statement |
| 10 | + |
9 | 11 | import time |
10 | 12 | import math |
11 | 13 | import array |
@@ -117,19 +119,29 @@ def normalized_rms(values): |
117 | 119 |
|
118 | 120 | def update_vu(): |
119 | 121 | """Update NeoPixels based on mic input level with smooth rise and fall.""" |
120 | | - global last_vu_input, vu_level |
| 122 | + global last_vu_input, vu_level, input_floor, input_ceiling |
121 | 123 | if not active_vu: |
122 | 124 | return |
123 | 125 | mic.record(samples, len(samples)) |
124 | 126 | magnitude = normalized_rms(samples) |
| 127 | + # Adaptive noise floor: continuously tracks ambient noise |
| 128 | + # (including BLE radio EMI) so the meter stays zeroed. |
| 129 | + if magnitude < input_floor: |
| 130 | + # Below floor — floor drifts down slowly |
| 131 | + input_floor = input_floor * 0.999 + magnitude * 0.001 |
| 132 | + elif magnitude < input_floor + 4: |
| 133 | + # Near the floor — this is still noise, nudge floor up |
| 134 | + input_floor = input_floor * 0.9 + magnitude * 0.1 |
| 135 | + input_ceiling = input_floor + 15.0 |
125 | 136 | # Compute scaled logarithmic reading in the range 0 to NUM_LEDS |
126 | | - target = log_scale(constrain(magnitude, input_floor, input_ceiling), |
127 | | - input_floor, input_ceiling, 0, NUM_LEDS) |
| 137 | + target = log_scale( |
| 138 | + constrain(magnitude, input_floor, input_ceiling), |
| 139 | + input_floor, input_ceiling, 0, NUM_LEDS) |
128 | 140 | # Smooth: rise slowly, fall even slower |
129 | 141 | if target > vu_level: |
130 | | - vu_level = vu_level + (target - vu_level) * 0.4 # rise speed |
| 142 | + vu_level = vu_level + (target - vu_level) * 0.3 |
131 | 143 | else: |
132 | | - vu_level = vu_level + (target - vu_level) * 0.15 # fall speed |
| 144 | + vu_level = vu_level + (target - vu_level) * 0.12 |
133 | 145 | input_val = int(vu_level) |
134 | 146 | if last_vu_input != input_val: |
135 | 147 | pixels.fill(VU_OFF) |
@@ -180,10 +192,10 @@ def update_light(): |
180 | 192 | # Sentinel for Light meter mode in animation list |
181 | 193 | LIGHT_METER = "LIGHT_METER" |
182 | 194 |
|
183 | | -# Calibrate: record initial sample to get ambient noise floor |
| 195 | +# Calibrate: seed the adaptive noise floor |
184 | 196 | mic.record(samples, len(samples)) |
185 | | -input_floor = normalized_rms(samples) + 2 |
186 | | -input_ceiling = input_floor + .5 |
| 197 | +input_floor = normalized_rms(samples) + 10 |
| 198 | +input_ceiling = input_floor + 15.0 |
187 | 199 |
|
188 | 200 | # setup bluetooth |
189 | 201 | ble = BLERadio() |
@@ -236,14 +248,13 @@ def apply_mode(selection): |
236 | 248 | last_vu_input = 0 |
237 | 249 | pixels.fill(VU_OFF) |
238 | 250 | pixels.show() |
239 | | - # Let tap vibration settle before listening |
| 251 | + # Brief settle, then seed the adaptive floor |
240 | 252 | time.sleep(0.15) |
241 | | - # Flush stale mic data, then recalibrate noise floor |
242 | 253 | for _ in range(3): |
243 | 254 | mic.record(samples, len(samples)) |
244 | 255 | mic.record(samples, len(samples)) |
245 | | - input_floor = normalized_rms(samples) + 2 |
246 | | - input_ceiling = input_floor + 0.5 |
| 256 | + input_floor = normalized_rms(samples) + 10 |
| 257 | + input_ceiling = input_floor + 15.0 |
247 | 258 | active_vu = True |
248 | 259 | elif selection == LIGHT_METER: |
249 | 260 | light_level = 0.0 |
@@ -336,8 +347,8 @@ def apply_mode(selection): |
336 | 347 | apply_mode(PALETTE_RAINBOW) |
337 | 348 | if packet.button == ButtonPacket.BUTTON_2: # VU Meter |
338 | 349 | apply_mode(VU_METER) |
339 | | - if packet.button == ButtonPacket.BUTTON_3: # Light Meter |
340 | | - apply_mode(LIGHT_METER) |
| 350 | + if packet.button == ButtonPacket.BUTTON_3: # Purple |
| 351 | + apply_mode(PURPLE) |
341 | 352 | if packet.button == ButtonPacket.BUTTON_4: # Light Meter |
342 | 353 | apply_mode(LIGHT_METER) |
343 | 354 | if packet.button == ButtonPacket.UP: # Brighten |
|
0 commit comments