forked from Geertex/midioke
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMIDIoke.py
126 lines (104 loc) · 3.03 KB
/
MIDIoke.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# -*- coding: utf-8 -*-
"""
Created on a Sunday
@author: Georgios Kyziridis and Geerten Verweij
"""
import pyaudio
import struct
import math
import matplotlib.pyplot as plt
import numpy as np
from midiutil import MIDIFile
from scipy.signal import fftconvolve
from matplotlib.mlab import find
CHUNK = 4096
FORMAT = pyaudio.paInt16
SHORT_NORMALIZE = (1.0/32768.0)
CHANNELS = 1
RATE = 44100
MIDIout = MIDIFile(1)
MIDIout.addTempo(0, 0, 60)
THRESHOLD = 10
def getRms(block):
"""
Standard method to calculate the energy in one chunk
This code is not made by us
"""
count = len(block)/2
format = "%dh"%(count)
shorts = struct.unpack( format, block )
sum_squares = 0.0
for sample in shorts:
n = sample * SHORT_NORMALIZE
sum_squares += n*n
return math.sqrt( sum_squares / count )
def parabolic(f, x):
"""
Quadratic interpolation for estimating the true position of an
inter-sample maximum which gives us better frequency estimation
This code is not made by us
"""
xv = 1/2. * (f[x-1] - f[x+1]) / (f[x-1] - 2 * f[x] + f[x+1]) + x
yv = f[x] - 1/4. * (f[x-1] - f[x+1]) * (xv - x)
return (xv, yv)
def getFrequencies(sig, fs):
"""
ready made fundemental frequency detection method that works much better
than what we tried manually with fft and autocorrelation
"""
corr = fftconvolve(sig, sig[::-1], mode='full')
corr = corr[len(corr)//2:]
d = np.diff(corr)
start = find(d > 0)[0]
peak = np.argmax(corr[start:]) + start
px, py = parabolic(corr, peak)
return fs / px
def freqToMidi(freqValue):
"""
convert a frequency in Hertz to a midi pitch
frequencies are limited between 20 and 4000 Hz to match expected input
"""
midiValue = int(round(69+12*math.log(max([(min([freqValue, 4000])), 20])/440,2)))
return midiValue
p = pyaudio.PyAudio()
plotPitch = [0] * 100
plotEnergy = [0] * 100
plotThreshold = [THRESHOLD] * 100
x = range(100)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
plt.ion()
time = 0;
endTime = input("\nProvide how long (in sec) to record: ")
print("It is Recording.....")
while time < int(endTime):
chunk = stream.read(CHUNK)
data = np.fromstring(chunk,np.int16)
freq = getFrequencies(data, RATE)
pitch = freqToMidi(freq)
energy = getRms(chunk)* 1000
plotPitch.insert(0,pitch)
plotPitch.pop()
plotEnergy.insert(0,energy)
plotEnergy.pop()
if energy > THRESHOLD:
MIDIout.addNote(0, 0, pitch, time, CHUNK/RATE, 100)
time = time + (CHUNK/RATE)
plt.clf()
plt.plot(x, plotPitch, label='Pitch')
plt.plot(x, plotEnergy, label='Energy')
plt.plot(x, plotThreshold, label='Threshold')
plt.legend()
plt.draw()
plt.pause(0.01)
plt.show(block=True)
stream.stop_stream()
stream.close()
p.terminate()
with open("outPut.mid", "wb") as output_file:
MIDIout.writeFile(output_file)
print("\nMidi is exported as outPut.mid in your file directory")
print("\n ||Support MIDIOKE||")