forked from IRL-CT/Interactive-Lab-Hub
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExampleAudioFFT.py
More file actions
111 lines (76 loc) · 4.74 KB
/
Copy pathExampleAudioFFT.py
File metadata and controls
111 lines (76 loc) · 4.74 KB
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
import pyaudio
import numpy as np
from scipy.fft import rfft, rfftfreq
from scipy.signal.windows import hann
from numpy_ringbuffer import RingBuffer
import queue
import time
## Please change the following number so that it matches to the microphone that you are using.
DEVICE_INDEX = 1
## Compute the audio statistics every `UPDATE_INTERVAL` seconds.
UPDATE_INTERVAL = 1.0
### Things you probably don't need to change
FORMAT=np.float32
SAMPLING_RATE = 44100
CHANNELS=1
def main():
### Setting up all required software elements:
audioQueue = queue.Queue() #In this queue stores the incoming audio data before processing.
pyaudio_instance = pyaudio.PyAudio() #This is the AudioDriver that connects to the microphone for us.
def _callback(in_data, frame_count, time_info, status): # This "callbackfunction" stores the incoming audio data in the `audioQueue`
audioQueue.put(in_data)
return None, pyaudio.paContinue
stream = pyaudio_instance.open(input=True,start=False,format=pyaudio.paFloat32,channels=CHANNELS,rate=SAMPLING_RATE,frames_per_buffer=int(SAMPLING_RATE/2),stream_callback=_callback,input_device_index=DEVICE_INDEX)
# One essential way to keep track of variables overtime is with a ringbuffer.
# As an example the `AudioBuffer` it stores always the last second of audio data.
AudioBuffer = RingBuffer(capacity=SAMPLING_RATE*1, dtype=FORMAT) # 1 second long buffer.
# Another example is the `VolumeHistory` ringbuffer.
VolumeHistory = RingBuffer(capacity=int(20/UPDATE_INTERVAL), dtype=FORMAT) ## This is how you can compute a history to record changes over time
### Here is a good spot to extend other buffers aswell that keeps track of varailbes over a certain period of time.
nextTimeStamp = time.time()
stream.start_stream()
if True:
while True:
frames = audioQueue.get() #Get DataFrom the audioDriver (see _callbackfunction how the data arrives)
if not frames:
continue
framesData = np.frombuffer(frames, dtype=FORMAT)
AudioBuffer.extend(framesData[0::CHANNELS]) #Pick one audio channel and fill the ringbuffer.
if(AudioBuffer.is_full and # Waiting for the ringbuffer to be full at the beginning.
audioQueue.qsize()<2 and # Make sure there is not alot more new data that should be used.
time.time()>nextTimeStamp): # See `UPDATE_INTERVAL` above.
buffer = np.array(AudioBuffer) #Get the last second of audio.
volume = np.rint(np.sqrt(np.mean(buffer**2))*10000) # Compute the rms volume
VolumeHistory.append(volume)
volumneSlow = volume
volumechange = 0.0
if VolumeHistory.is_full:
HalfLength = int(np.round(VolumeHistory.maxlen/2))
vnew = np.array(VolumeHistory)[HalfLength:].mean()
vold = np.array(VolumeHistory)[:VolumeHistory.maxlen-HalfLength].mean()
volumechange =vnew-vold
volumneSlow = np.array(VolumeHistory).mean()
## Computes the Frequency Foruier analysis on the Audio Signal.
N = buffer.shape[0]
window = hann(N)
amplitudes = np.abs(rfft(buffer*window))[25:] #Contains the volume for the different frequency bin.
frequencies = (rfftfreq(N, 1/SAMPLING_RATE)[:N//2])[25:] #Contains the Hz frequency values. for the different frequency bin.
'''
Combining the `amplitudes` and `frequencies` varialbes allows you to understand how loud a certain frequency is.
e.g. If you'd like to know the volume for 500Hz you could do the following.
1. Find the frequency bin in which 500Hz belis closest to with:
FrequencyBin = np.abs(frequencies - 500).argmin()
2. Look up the volume in that bin:
amplitudes[FrequencyBin]
The example below does something similar, just in revers.
It finds the loudest amplitued and its coresponding bin with `argmax()`.
The uses the index to look up the Freqeucny value.
'''
LoudestFrequency = frequencies[amplitudes.argmax()]
print("Loudest Frqeuncy:",LoudestFrequency)
print("RMS volume:",volumneSlow)
print("Volume Change:",volumechange)
nextTimeStamp = UPDATE_INTERVAL+time.time() # See `UPDATE_INTERVAL` above
if __name__ == '__main__':
main()
print("Something happend with the audio example. Stopping!")