We'll look at determining musical notes in a bit. But for making the NeoPixels respond to the mic data, we can just work in terms of frequency. The idea is pretty simple - we'll set a LOW frequency and a HIGH frequency. The NeoPixels will then light up individually for any frequency in this range.
Here's the complete code:
# SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries # # SPDX-License-Identifier: MIT import time import array import board import audiobusio import simpleio import neopixel #---| User Configuration |--------------------------- SAMPLERATE = 16000 SAMPLES = 1024 THRESHOLD = 100 MIN_DELTAS = 5 DELAY = 0.2 FREQ_LOW = 520 FREQ_HIGH = 990 COLORS = ( (0xFF, 0x00, 0x00) , # pixel 0 (0xFF, 0x71, 0x00) , # pixel 1 (0xFF, 0xE2, 0x00) , # pixel 2 (0xAA, 0xFF, 0x00) , # pixel 3 (0x38, 0xFF, 0x00) , # pixel 4 (0x00, 0xFF, 0x38) , # pixel 5 (0x00, 0xFF, 0xA9) , # pixel 6 (0x00, 0xE2, 0xFF) , # pixel 7 (0x00, 0x71, 0xFF) , # pixel 8 (0x00, 0x00, 0xFF) , # pixel 9 ) #---------------------------------------------------- # Create a buffer to record into samples = array.array('H', [0] * SAMPLES) # Setup the mic input mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate=SAMPLERATE, bit_depth=16) # Setup NeoPixels pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, auto_write=False) while True: # Get raw mic data mic.record(samples, SAMPLES) # Compute DC offset (mean) and threshold level mean = int(sum(samples) / len(samples) + 0.5) threshold = mean + THRESHOLD # Compute deltas between mean crossing points # (this bit by Dan Halbert) deltas = [] last_xing_point = None crossed_threshold = False for i in range(SAMPLES-1): sample = samples[i] if sample > threshold: crossed_threshold = True if crossed_threshold and sample < mean: if last_xing_point: deltas.append(i - last_xing_point) last_xing_point = i crossed_threshold = False # Try again if not enough deltas if len(deltas) < MIN_DELTAS: continue # Average the deltas mean = sum(deltas) / len(deltas) # Compute frequency freq = SAMPLERATE / mean print("crossings: {} mean: {} freq: {} ".format(len(deltas), mean, freq)) # Show on NeoPixels pixels.fill(0) pixel = round(simpleio.map_range(freq, FREQ_LOW, FREQ_HIGH, 0, 9)) pixels[pixel] = COLORS[pixel] pixels.show() time.sleep(DELAY)
This code is largely the same as the previous example. All that has been added is some NeoPixel output based on frequency. You can set the LOW and HIGH frequency and the NeoPixel COLORS at the top of the code in these lines:
FREQ_LOW = 520 FREQ_HIGH = 990 COLORS = ( (0xFF, 0x00, 0x00) , # pixel 0 (0xFF, 0x71, 0x00) , # pixel 1 (0xFF, 0xE2, 0x00) , # pixel 2 (0xAA, 0xFF, 0x00) , # pixel 3 (0x38, 0xFF, 0x00) , # pixel 4 (0x00, 0xFF, 0x38) , # pixel 5 (0x00, 0xFF, 0xA9) , # pixel 6 (0x00, 0xE2, 0xFF) , # pixel 7 (0x00, 0x71, 0xFF) , # pixel 8 (0x00, 0x00, 0xFF) , # pixel 9 )
The part of the code that does the actual NeoPixel lighting is at the bottom:
# Show on NeoPixels pixels.fill(0) pixel = round(simpleio.map_range(freq, FREQ_LOW, FREQ_HIGH, 0, 9)) pixels[pixel] = COLORS[pixel] pixels.show()
It uses the simpleio.map_range() function to map the computed frequency to the range of NeoPixels. So the LOW frequency will light NeoPixel #0, the HIGH frequency will light NeoPixel #9, and any in between frequencies will light the others.
Circuit Playground-O-Phonor
We can use the above sketch to make our Circuit Playground-O-Phonor. As a substitute for a real holophonor, we'll use a very common flute like instrument called a recorder. They look like this:
These come in different shapes and sizes with corresponding differences in their note ranges. You'll need to figure out what range of notes, and in what octave, your recorder produces. The code above has been setup to run from a 5th octave C (~520Hz) to a 5th octave B (~990Hz). If your recorder is different, change these two lines as needed:
FREQ_LOW = 520 FREQ_HIGH = 990
Once you've got that setup, run the code above and try playing notes on your recorder. You should get the NeoPixels to light up.
Text editor powered by tinymce.