Created
January 8, 2017 18:19
-
-
Save nomelif/db58aaf8989085bd5e1a1f6acb77d0b3 to your computer and use it in GitHub Desktop.
This transforms microphone input into MIDI data in real time and spits it over ALSA.
This file contains 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 alsaseq | |
import numpy as np | |
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) | |
# Variable to hold data about the previous note | |
previous = None | |
# Open a socket one can connect to via alsa | |
alsaseq.client("Midify", 0, 1, False) | |
# The contents of the previous chunk | |
olddata = np.array([]) | |
try: | |
while True: | |
# Get the last two chunks into numpydata | |
data = stream.read(CHUNKSIZE) | |
newdata = np.fromstring(data, dtype=np.int16) | |
numpydata = np.append(olddata, newdata) | |
olddata = newdata | |
# Print the last guessed note | |
print(previous) | |
if np.max(numpydata) < 500: | |
if previous != None: | |
# Midi meaning that the last note has ended | |
alsaseq.output( (7, 0, 0, 253, (0, 0), (130, 0), (128, 0), (0, previous, 0, 0, 0)) ) | |
previous = None | |
else: | |
# Extract the maximal frequency using numpy-sorcery | |
w = np.fft.fft(numpydata) | |
freqs = np.fft.fftfreq(len(w)) | |
idx = np.argmax(np.abs(w)) | |
freq = freqs[idx] | |
try: | |
# Get the note number from the frequency | |
note = int(round(12*np.log2(abs(freq*44100)/440)+49)) | |
if previous != note: | |
if previous != None: | |
# Tell the listener of our midi stream to silence the old note... | |
alsaseq.output( (7, 0, 0, 253, (0, 0), (130, 0), (128, 0), (0, previous, 0, 0, 0)) ) | |
# ...and start playing the new one | |
alsaseq.output( (6, 0, 0, 253, (0, 0), (0, 0), (0, 0), (0, note, 100, 0, 0)) ) | |
previous = note | |
except OverflowError: | |
pass | |
except KeyboardInterrupt: | |
pass | |
# Cleanup | |
stream.stop_stream() | |
stream.close() | |
p.terminate() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment