Last active
December 15, 2021 13:41
-
-
Save nomelif/9da3b4b1041dd8fa59c22f6b04b015d7 to your computer and use it in GitHub Desktop.
Decompose a microphone input by frequency. Depends on PyAudio, Matplotib and NumPy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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