|
| 1 | +import array |
| 2 | +import audiobusio |
| 3 | +import board |
| 4 | +import math |
| 5 | +import neopixel |
| 6 | + |
| 7 | +CURVE = 2 |
| 8 | +SCALE_EXPONENT = math.pow(10, CURVE * -0.1) |
| 9 | + |
| 10 | +PEAK_COLOR = (80, 0, 255) |
| 11 | +NUM_PIXELS = 10 |
| 12 | +NUM_SAMPLES = 160 |
| 13 | + |
| 14 | + |
| 15 | +def constrain(value, floor, ceiling): |
| 16 | + return max(floor, min(value, ceiling)) |
| 17 | + |
| 18 | + |
| 19 | +def log_scale(input_value, input_min, input_max, output_min, output_max): |
| 20 | + normalized_input_value = (input_value - input_min) / (input_max - input_min) |
| 21 | + return output_min + math.pow(normalized_input_value, SCALE_EXPONENT) * (output_max - output_min) |
| 22 | + |
| 23 | + |
| 24 | +def normalized_rms(values): |
| 25 | + minbuf = int(mean(values)) |
| 26 | + return math.sqrt(sum(float(sample - minbuf) * (sample - minbuf) for sample in values) / len(values)) |
| 27 | + |
| 28 | + |
| 29 | +def mean(values): |
| 30 | + return sum(values) / len(values) |
| 31 | + |
| 32 | + |
| 33 | +def volume_color(i): |
| 34 | + return i * (255 // NUM_PIXELS), 50, 0 |
| 35 | + |
| 36 | + |
| 37 | +pixels = neopixel.NeoPixel(board.NEOPIXEL, NUM_PIXELS, brightness=0.1, auto_write=False) |
| 38 | +pixels.fill(0) |
| 39 | +pixels.show() |
| 40 | + |
| 41 | +mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, frequency=16000, bit_depth=16) |
| 42 | +samples = array.array('H', [0] * NUM_SAMPLES) |
| 43 | +mic.record(samples, len(samples)) |
| 44 | +input_floor = normalized_rms(samples) + 10 |
| 45 | + |
| 46 | +# Lower number means more sensitive - more LEDs will light up with less sound. |
| 47 | +sensitivity = 500 |
| 48 | +input_ceiling = input_floor + sensitivity |
| 49 | + |
| 50 | +peak = 0 |
| 51 | +while True: |
| 52 | + mic.record(samples, len(samples)) |
| 53 | + magnitude = normalized_rms(samples) |
| 54 | + print(magnitude) |
| 55 | + |
| 56 | + c = log_scale(constrain(magnitude, input_floor, input_ceiling), |
| 57 | + input_floor, input_ceiling, 0, NUM_PIXELS) |
| 58 | + |
| 59 | + pixels.fill(0) |
| 60 | + for i in range(NUM_PIXELS): |
| 61 | + if i < c: |
| 62 | + pixels[i] = volume_color(i) |
| 63 | + if c >= peak: |
| 64 | + peak = min(c, NUM_PIXELS - 1) |
| 65 | + elif peak > 0: |
| 66 | + peak = peak - 1 |
| 67 | + if peak > 0: |
| 68 | + pixels[int(peak)] = PEAK_COLOR |
| 69 | + pixels.show() |
0 commit comments