Skip to content

Instantly share code, notes, and snippets.

@nomelif
Last active December 15, 2021 13:41
Show Gist options
  • Save nomelif/9da3b4b1041dd8fa59c22f6b04b015d7 to your computer and use it in GitHub Desktop.
Save nomelif/9da3b4b1041dd8fa59c22f6b04b015d7 to your computer and use it in GitHub Desktop.
Decompose a microphone input by frequency. Depends on PyAudio, Matplotib and NumPy
import pyaudio
import numpy as np
import matplotlib.pyplot as plt
CHUNKSIZE = 1024*2 # fixed chunk size
# initialize portaudio
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=CHUNKSIZE)
# Wait to start recording
input("Press [Enter] to start recording")
result = np.array([], dtype=np.int16)
try:
print("Press [Ctrl] + [C] to stop recording")
while True:
# Get the last two chunks into numpydata
data = stream.read(CHUNKSIZE)
newdata = np.fromstring(data, dtype=np.int16)
result = np.append(result, newdata)
except KeyboardInterrupt:
pass
print("Cleaning up...")
# Cleanup
stream.stop_stream()
stream.close()
p.terminate()
print("Parsing frequencies")
w = np.fft.fft(result)
freqs = np.abs((np.fft.fftfreq(len(w))*44100))
w = np.abs(w)
indices = np.argsort(w)[int(len(w)*0.99):]
bin_const = 10
indices = indices[len(indices)%bin_const:]
w = w[indices]
freqs = freqs[indices]
w = w[np.argsort(freqs)]
freqs = np.sort(freqs)
w = np.reshape(w, (-1, bin_const)).sum(axis=1)
freqs = np.average(np.reshape(freqs, (-1, bin_const)), axis=1)
w = w / np.sum(w)
freqdict = dict(zip(freqs, w))
import json
data = json.dumps(freqdict)
#print(data)
plt.plot(freqs, w, zorder=-1)
plt.plot(freqs, np.array([np.min(w)*2]*len(freqs)))
result = []
insidePeak = False
t = np.min(w)*3
row = []
for height, freq in zip(w, freqs):
if freq < 100:
continue
if height > t:
insidePeak = True
else:
if insidePeak:
result.append(sorted(row)[-1])
row = []
insidePeak = False
if insidePeak:
row.append((height, freq))
#x = []
#y = []
#c = []
#for i, f in enumerate(np.convolve(w, [1, -0.5, -0.7, -1, 0, 1, 0.7, 0.5, -1])):
# if f > 0:
# try:
# x.append(freqs[i-6])
# y.append(w[i-6])
# c.append(f*5000)
# except:
# pass
#peaks = sorted(list(zip(c, zip(x, y))))[-10:]
#x = [d[1][0] for d in peaks]
#y = [d[1][1] for d in peaks]
#c = [d[0] for d in peaks]
plt.scatter(np.array([x[1] for x in result]), np.array([x[0] for x in result]))
mul = 1/np.sum(np.array([x[0] for x in result]))
resarr = []
for x in result:
resarr.append({"Freq":x[1], "Volume":mul*x[0]})
#print("========================")
#print("Frequency: "+str(x[1]))
#print("Volume: "+str(mul*x[0]))
#print("========================")
plt.show()
import sys
import json
if len(sys.argv[0]) > 1:
with open(sys.argv[1], "w") as f:
f.write(json.dumps(resarr))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment