Skip to content

Instantly share code, notes, and snippets.

@BenjaminSantiago
Created October 23, 2023 18:18
Show Gist options
  • Save BenjaminSantiago/204a98e9da8d0c5cf4ca3e7eb6f76b52 to your computer and use it in GitHub Desktop.
Save BenjaminSantiago/204a98e9da8d0c5cf4ca3e7eb6f76b52 to your computer and use it in GitHub Desktop.
SOUND METER (Annotated)
#importz
#-----------------------------------------------------------------
import array
import math
import audiobusio
import board
from adafruit_circuitplayground.express import cpx
#-----------------------------------------------------------------
#functions
#mathy stuff
#-----------------------------------------------------------------
def constrain(value, floor, ceiling):
return max(floor, min(value, ceiling))
def log_scale(input_value, input_min, input_max, output_min, output_max):
normalized_input_value = (input_value - input_min) / (input_max - input_min)
return output_min + math.pow(normalized_input_value, 0.630957) * (output_max - output_min)
def normalized_rms(values):
minbuf = int(sum(values) / len(values))
return math.sqrt(sum(float(sample - minbuf) *
(sample - minbuf) for sample in values) / len(values))
#-----------------------------------------------------------------
#-----------------------------------------------------------------
# For CircuitPython 2.x:
mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA,
frequency=16000, bit_depth=16)
# For CircuitPython 3.0 and up, "frequency" is now called "sample_rate".
# Comment out the mic and frequency lines above and uncomment those lines below.
# mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA,
# sample_rate=16000, bit_depth=16)
samples = array.array('H', [0] * 160)
mic.record(samples, len(samples))
input_floor = normalized_rms(samples) + 10
# Lower number means more sensitive - more LEDs will light up with less sound.
sensitivity = 500
input_ceiling = input_floor + sensitivity
peak = 0
#-----------------------------------------------------------------
#MAIN LOOP
#-----------------------------------------------------------------
while True:
#THIS CODE "RECORDS" or takes in sound
#----------------------------------------
#record something
mic.record(samples, len(samples))
#normalize the values
magnitude = normalized_rms(samples)
#show us what is happening
#(this syntax means we can use the plotter in mu)
print((magnitude,))
#----------------------------------------
#convert audio to linear values
"""
audio volume is in a unit called a decibel
decibels scale logarithmically rather than linearly
This is to make more intrinsic sense to
how humans perceive audio
(when we perceive something as "twice as loud" as it was before
the actual volume of that sound was more than twice as loud as it
was before. Logarithmic values are helpful for aligning with
our perception of reality, however this means we must
CONVERT the values to scale linearly. This code does that)
"""
c = log_scale(constrain(magnitude, input_floor, input_ceiling),
input_floor, input_ceiling, 0, 10)
#clear everything out each loop through
cpx.pixels.fill((0, 0, 0))
#go through all pixels
for i in range(10):
#if the current pixel is not the value we are trying to
#represent, show the color
if i < c:
#make the pixel "redness" proportional
#to the curent value of i
cpx.pixels[i] = (i * (255 // 10), 50, 0)
#now we're finding the peak or highest value
#peak starts at 0 (see above)
# this looks like it is needed to figure out,
# how many pixels to light up
if c >= peak:
peak = min(c, 10 - 1)
elif peak > 0:
peak = peak - 1
if peak > 0:
cpx.pixels[int(peak)] = (80, 0, 255)
#I was trying to ascertain if this is a deprecated
#(old) function, not sure exactly happens here.
cpx.pixels.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment