|
@@ -12,13 +12,13 @@ import pyaudio
|
12
|
12
|
import numpy as np
|
13
|
13
|
|
14
|
14
|
class AudioVisualizer:
|
15
|
|
- def __init__(self, g, f = 20, t = 60.0):
|
|
15
|
+ def __init__(self, g, f = 20, t = 60.0, fft = True):
|
16
|
16
|
self.gui = g
|
17
|
17
|
self.interval = 1.0 / f
|
18
|
18
|
self.timeout = t
|
|
19
|
+ self.do_fft = fft
|
19
|
20
|
|
20
|
21
|
self.chunk = 1024 * 2 # stereo
|
21
|
|
- self.do_fft = False
|
22
|
22
|
|
23
|
23
|
self.p = pyaudio.PyAudio()
|
24
|
24
|
self.s = self.p.open(format=pyaudio.paInt16, channels=2, rate=44100, input=True)
|
|
@@ -37,11 +37,30 @@ class AudioVisualizer:
|
37
|
37
|
h = int(val) / 32768.0 * self.gui.height / 2
|
38
|
38
|
self.gui.set_pixel(x, y_off + (16 - h), (255, 255, 255))
|
39
|
39
|
|
40
|
|
- def draw_bar(self, x, val, y_off):
|
41
|
|
- h = int(val) / (32768.0 * 2) * (self.gui.height / 2)
|
|
40
|
+ def draw_bar(self, x, val, y_off, max_val):
|
|
41
|
+ if max_val <= 0.0:
|
|
42
|
+ max_val = 1.0
|
|
43
|
+ h = int(val) / float(max_val) * self.gui.height / 2
|
42
|
44
|
for y in range(0, int(h)):
|
43
|
45
|
self.gui.set_pixel(x, y_off + (32 - y), (255, 255, 255))
|
44
|
46
|
|
|
47
|
+ # stolen from https://github.com/aiXander/Realtime_PyAudio_FFT/blob/master/src/fft.py
|
|
48
|
+ def calc_fft(self, data):
|
|
49
|
+ data = data * np.hamming(len(data))
|
|
50
|
+ try:
|
|
51
|
+ fft = np.abs(np.fft.rfft(data)[1:])
|
|
52
|
+ except:
|
|
53
|
+ fft = np.fft.fft(data)
|
|
54
|
+ left, right = np.split(np.abs(fft), 2)
|
|
55
|
+ fft = np.add(left, right[::-1])
|
|
56
|
+
|
|
57
|
+ #try:
|
|
58
|
+ # fft = np.multiply(20, np.log10(fft))
|
|
59
|
+ #except:
|
|
60
|
+ # pass
|
|
61
|
+
|
|
62
|
+ return fft
|
|
63
|
+
|
45
|
64
|
def draw(self):
|
46
|
65
|
frames = self.s.read(self.chunk)
|
47
|
66
|
|
|
@@ -53,18 +72,23 @@ class AudioVisualizer:
|
53
|
72
|
|
54
|
73
|
if self.do_fft:
|
55
|
74
|
# FFT
|
56
|
|
- left = np.fft.fft(left)
|
57
|
|
- right = np.fft.fft(right)
|
|
75
|
+ left = self.calc_fft(left)
|
|
76
|
+ right = self.calc_fft(right)
|
58
|
77
|
|
59
|
78
|
# average down to fit screen
|
60
|
79
|
m = self.chunk / 2 / self.gui.width # stereo
|
|
80
|
+ if self.do_fft:
|
|
81
|
+ m = m / 2
|
61
|
82
|
left = left.reshape(-1, int(m)).mean(axis=1)
|
62
|
83
|
right = right.reshape(-1, int(m)).mean(axis=1)
|
63
|
84
|
|
|
85
|
+ l_max = max(left)
|
|
86
|
+ r_max = max(right)
|
|
87
|
+
|
64
|
88
|
for x in range(0, self.gui.width):
|
65
|
89
|
if self.do_fft:
|
66
|
|
- self.draw_bar(x, left[x], 0)
|
67
|
|
- self.draw_bar(x, right[x], self.gui.height / 2)
|
|
90
|
+ self.draw_bar(x, left[x], 0, l_max)
|
|
91
|
+ self.draw_bar(x, right[x], self.gui.height / 2, r_max)
|
68
|
92
|
else:
|
69
|
93
|
self.draw_line(x, left[x], 0)
|
70
|
94
|
self.draw_line(x, right[x], self.gui.height / 2)
|