-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmusicFourierTransform_demo.py
237 lines (190 loc) · 7.61 KB
/
musicFourierTransform_demo.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
"""
This file is meant to feed an Arduino Blend Micro with data.
A fast fourier transform is performed on an imcoming music file,
and then subsequentely averaged and normalized to the number of LEDs attached to the Arduino.
I have 60 (-1, I broke one pixel) neopixels attached and have 6 buckets, so 10 LEDs/bucket.
I normalize my data from 0-10.
Created by Brittany L. Walentin October 2015
"""
# Dependencies/libraries to import
from scipy import fft, arange
from scipy.io import wavfile # for chunking sounds into time slices
import pyaudio # to play audio
import wave # for opening wavefiles
import serial # for serial communication
import time # for timing things/time delays on python side
# -------------------------------------------------
def returnSpectrum(y,Fs):
"""
Plots a Single-Sided Amplitude Spectrum of y(t)
y = wavefile in array form
Fs = sample frequency, sometimes called sampling rate; likely 44100
"""
n = len(y) # length of the signal
k = arange(n) # array from [0, 1, 2, ... n-1]
T = n/float(Fs) # need to make Fs a float so T can be 0.xx decimal
if y.ndim > 1: # stereo music has more than one dimension for stereo sound
y = y[:,0] # taking 1st dimension, slice of matrix
frq = k/T # two sides frequency range
# take array, divide by num secs
frq = frq[range(n/2)] # one side frequency range
Y = fft(y)/n # fft computing and normalization
Y = Y[range(n/2)]
zipped = zip(frq, abs(Y)) # takes 2 arrays of same size & combines
frequencies = dict(zipped)
return frequencies
# -------------------------------------------------
def averaging(min, max, spectrum):
"""normalizing a bucket, returns a number from 0-1"""
length = 0
sum = 0
for key in spectrum:
if key > min and key <= max:
length += 1
sum += spectrum[key]
average = sum/length
return average
# -------------------------------------------------
def formatData(array):
"""takes an array and adds a leading zero
then joins all into a string of length 12
so we'll consistentely send a chunk of data of length 12 to the Arduino"""
stringArray = []
for n in array:
# convert number into a string
numAsString = str(n)
if len(numAsString) < 2:
# add leading zeros to numbers
numAsString = '0' + numAsString
stringArray.append(numAsString)
# join array items into a string of length 12
return ''.join(stringArray)
# -------------------------------------------------
def buckets(spectrumHash):
"""Mundges data from a huge list of frequency data into 6 distinct buckets"""
equalizer = []
normalized = []
LEDS = 10 # scaling factor, number of leds in each 'frequency bucket'
SUBBASS = [50, 100] # Sub Bass: 50 to 100 Hz
BASS1 = [100, 250] # Bass1: 100 to 250 Hz
BASS2 = [250, 300] # Bass2: 250 to 300 Hz
LOWMIDRANGE = [300, 400] # Low Midrange: 300 to 400 Hz
MIDRANGE = [400, 500] # Midrange: 400 to 500 Hz
TREBLE = [500, 1500] # Treble: 500 Hz to 1.5 kHz
subBass = averaging(SUBBASS[0], SUBBASS[1], spectrumHash)
bass1 = averaging(BASS1[0], BASS1[1], spectrumHash)
bass2 = averaging(BASS2[0], BASS2[1], spectrumHash)
lowMidrange = averaging(LOWMIDRANGE[0], LOWMIDRANGE[1], spectrumHash)
midrange = averaging(MIDRANGE[0], MIDRANGE[1], spectrumHash)
treble = averaging(TREBLE[0], TREBLE[1], spectrumHash)
# normalizing buckets - 0 is no leds lit, 10 is all 10 leds in a strip lit
beforeNormalization = [subBass, bass1, bass2, lowMidrange, midrange, treble]
hi = max(beforeNormalization)
lo = min(beforeNormalization)
for n in beforeNormalization:
norms = int((((n-lo)/(hi-lo)))*LEDS)
normalized.append(norms)
return normalized
# -------------------------------------------------
# test files to play
baseFolder = './AudioFiles/'
rock = baseFolder +'rockinthefreeworld.wav'
piano = baseFolder +'piano2.wav'
boom = baseFolder +'01 Boom Boom Pow.wav'
bassNectar = baseFolder +'05 - Lights (Bassnectar Remix).wav'
aha = baseFolder + '10 Aha!.wav'
nin = baseFolder + '1-11 La Mer.wav'
dave = baseFolder + '2-07 Ants Marching.wav'
white = baseFolder + '01 Seven Nation Army.wav'
white30 = baseFolder + '01 Seven Nation Army_30.wav'
sweep = baseFolder +'sweep20-20k.wav'
jj = baseFolder + '03 Joints & Jam.wav'
hz40 = baseFolder +'40hz.wav'
hz60 = baseFolder +'60hz.wav'
hz125 = baseFolder +'125hz.wav'
hz200 = baseFolder +'200hz.wav'
hz300 = baseFolder +'300hz.wav' # questionable that this is 300hz
hz400 = baseFolder +'400hz.wav'
hz1000 = baseFolder +'1000hz.wav'
hz3000 = baseFolder +'3000hz.wav'
drum = baseFolder +'drum.wav'
light30 = baseFolder + 'light-30s.wav'
light60 = baseFolder + 'light-1m.wav'
# -------------------------------------------------
""" Below is where we execute the code to run the fft
and send the arrays of LEDs to light to the Arduino"""
sampFreq, snd = wavfile.read(light30)
second = sampFreq # sampling frequency is = second of data
fps = 40 # frames per second
window_size = second/fps # want 40 frames per second (fps), so want 40 windows/second
connection = '/dev/cu.usbmodem1411'
ser = serial.Serial(connection, 115200, timeout=1)
#open a wav format music
f = wave.open(light30,"rb") #rb - read binary
#instantiate PyAudio
p = pyaudio.PyAudio()
# define callback
def callback(in_data, frame_count, time_info, status):
data = f.readframes(frame_count)
return (data, pyaudio.paContinue)
#open stream
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),
channels = f.getnchannels(),
rate = f.getframerate(),
output = True,
stream_callback=callback)
stream.start_stream()
for i in range(0, len(snd)-window_size, (window_size)): # range makes an array auto
spectrum = returnSpectrum(snd[i:i+window_size], sampFreq)
array = buckets(spectrum)
data = formatData(array)
ser.write(data)
time.sleep(0.020) # delay of 1/40fps
while stream.is_active():
time.sleep(0.1)
ser.write("000000000000") # turn LEDs off
#stop stream
stream.stop_stream()
stream.close()
f.close()
#close PyAudio
p.terminate()
# ////////////////////
""" Below is where we execute the code to run the fft
and send the arrays of LEDs to light to the Arduino"""
sampFreq, snd = wavfile.read(white30)
second = sampFreq # sampling frequency is = second of data
fps = 40 # frames per second
window_size = second/fps # want 40 frames per second (fps), so want 40 windows/second
connection = '/dev/cu.usbmodem1411'
ser = serial.Serial(connection, 115200, timeout=1)
#open a wav format music
f = wave.open(white30,"rb") #rb - read binary
#instantiate PyAudio
p = pyaudio.PyAudio()
# define callback
def callback(in_data, frame_count, time_info, status):
data = f.readframes(frame_count)
return (data, pyaudio.paContinue)
#open stream
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),
channels = f.getnchannels(),
rate = f.getframerate(),
output = True,
stream_callback=callback)
stream.start_stream()
for i in range(0, len(snd)-window_size, (window_size)): # range makes an array auto
spectrum = returnSpectrum(snd[i:i+window_size], sampFreq)
array = buckets(spectrum)
data = formatData(array)
ser.write(data)
time.sleep(0.020) # delay of 1/40fps
while stream.is_active():
time.sleep(0.1)
ser.write("000000000000") # turn LEDs off
#stop stream
stream.stop_stream()
stream.close()
f.close()
#close PyAudio
p.terminate()