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
127
128
129
130
131
132
|
# This is a sample Python script.
import struct
# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
from scipy.fftpack import fft
import numpy as np
import pyaudio
import matplotlib.pyplot as plt
class Test(object):
def __init__(self):
# stream constants
self.CHUNK = 2048 * 2
self.FORMAT = pyaudio.paInt32
self.CHANNELS = 1
self.RATE = 44100
self.pause = False
# stream object
self.p = pyaudio.PyAudio()
self.stream = self.p.open(
format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
output=True,
frames_per_buffer=self.CHUNK,
)
self.seenvalues = set()
self.sample_divs = 4
# goal: returns the max frequency of waveform
def get_fundamental_frequency(self, audio_waveform):
spectrum = fft(audio_waveform)
# scale and normalize the spectrum, some are imaginary
scaled_spectrum = np.abs(spectrum)
scaled_spectrum = scaled_spectrum / (np.linalg.norm(scaled_spectrum) + 1e-16)
# FIXME: update to self values, given if ur a sender or receiver
starting_freq = 18000
end_freq = 20000
freq_to_index_ratio = (self.CHUNK - 1) / self.RATE
# only accept the scaled spectrum from our starting range to 20000 Hz
starting_range_index = int(starting_freq * freq_to_index_ratio)
ending_range_index = int(end_freq * freq_to_index_ratio)
print(starting_freq, end_freq, starting_range_index, ending_range_index)
restricted_spectrum = scaled_spectrum[starting_range_index:ending_range_index + 1]
# get the n indices of the max peaks, within our confined spectrum
# FIXME: update to self values
bytes = 1
num_bits = bytes * 8 + 2
top8_indices = np.argpartition(restricted_spectrum, -num_bits)[-num_bits:]
# map the top 8 to indices to frequencies
top8_freqs = [int((top8_indices[i] + starting_freq) / freq_to_index_ratio) for i in range(len(top8_indices))]
# print(index_to_freq[max_index], max_index, max_index * self.RATE / (self.CHUNK - 1))
return top8_freqs[0], scaled_spectrum
def read_audio_stream(self):
data = self.stream.read(self.CHUNK)
data_int = struct.unpack(str(self.CHUNK) + 'i', data)
return data_int
def open_loop(self, graphics=True):
self.init_plots()
while not self.pause:
waveform = self.read_audio_stream()
freq_max, scaled_spectrum = self.get_fundamental_frequency(waveform)
if freq_max not in self.seenvalues:
print(freq_max)
# update figure canvas if wanted
if graphics:
# set top graph
data_np = np.array(waveform) / (np.linalg.norm(waveform) + 1e-16) * 10
self.line.set_ydata(data_np[0:len(data_np)// self.sample_divs])
# set bottom graph
self.line_fft.set_ydata(scaled_spectrum)
# update figures
self.fig.canvas.draw()
self.fig.canvas.flush_events()
def init_plots(self):
# x variables for plotting
x = np.arange(0, self.CHUNK * 2 // self.sample_divs, 2)
xf = np.linspace(0, self.RATE, self.CHUNK)
# create matplotlib figure and axes
self.fig, (ax1, ax2) = plt.subplots(2, figsize=(15, 7))
# create a line object with random data
self.line, = ax1.plot(x, np.random.rand(self.CHUNK // self.sample_divs), '-', lw=2)
# create semilogx line for spectrum
self.line_fft, = ax2.semilogx(
xf, np.random.rand(self.CHUNK), '-', lw=2)
# format waveform axes
ax1.set_title('AUDIO WAVEFORM')
ax1.set_xlabel('samples')
ax1.set_ylabel('volume')
ax1.set_ylim(-1, 1)
ax1.set_xlim(0, self.CHUNK // self.sample_divs)
plt.setp(
ax1,
xticks=[0, self.CHUNK // self.sample_divs, self.CHUNK * 2 // self.sample_divs],
)
plt.setp(ax2, yticks=[0, 1], )
# format spectrum axes
ax2.set_xlim(20, self.RATE / 2)
# show axes
thismanager = plt.get_current_fig_manager()
# thismanager.window.setGeometry(5, 120, 1910, 1070)
plt.show(block=False)
if __name__ == '__main__':
t = Test()
t.open_loop()
|