-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwavPlayer.py
More file actions
161 lines (123 loc) · 4.37 KB
/
wavPlayer.py
File metadata and controls
161 lines (123 loc) · 4.37 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
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
import numpy as np
import pyaudio
import wave
import sys
import getopt
import matplotlib.pyplot as plt
def play_audio(file, device_index, volume, chunksize=4096):
""" Play an audio file """
wf = wave.open(file, 'rb')
p = pyaudio.PyAudio()
stream = p.open(
format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True,
output_device_index=device_index
)
data = wf.readframes(chunksize)
def fadefunc(x, rate=2):
"""
Channel fade function.
Parameters
----------
x : ndarray of sample positions
rate : rate of fade in samples
Returns
-------
ndarray of values 0-1, for relative fade between left and right channels
"""
return (np.sin(rate * x * np.pi / wf.getframerate()) + 1) / 2
def exp_distort(v, window=2):
"""
Exponential distortion function.
Parameters
----------
x : ndarray of sample positions
rate : rate of distortion in samples
Returns
-------
ndarray of values 0-1, for relative distortion
"""
ratio = 1 - np.exp(v-window) - np.exp(-v-window)
return ratio
last_max = 0
fig, ax = plt.subplots()
ax.set_xlim(0, chunksize)
ax.set_ylim(0, 1)
# ax.set_aspect('equal')
# stores the position of each sample (in frames)
count = np.arange(0, chunksize)
count_x = np.arange(0, chunksize)
plot_points = ax.plot(count_x, fadefunc(count), 'b-')[0]
plt.ion()
plt.show()
plt.pause(0.001)
# cache background
background = fig.canvas.copy_from_bbox(ax.bbox)
while len(data) > 0:
# read data from buffer into a mutable numpy array
buffer = np.frombuffer(data, dtype=np.int16).copy()
max_value = np.max(np.abs(buffer))
if max_value > last_max:
last_max = max_value
buffer = buffer / last_max
# isolates the left channel. [::2] will take every other element, starting at 0
left = buffer[::2]
# isolates the right channel. [1::2] will take every other element, starting at 1
right = buffer[1::2]
fade = fadefunc(count, 2)[:len(buffer) // 2]
count += chunksize
# multiply the left and right channels by the fade value
# left[:] will modify the left channel in place, mutating the original buffer array
# note the cast to np.int16, numpy really wants it to be a float32
left[:] = (left[:] * fade)
# right[:] will modify the right channel in place, mutating the original buffer array
right[:] = (right[:] * (1-fade))
# distort the output
distort = exp_distort(buffer, 2)[:len(buffer)]
buffer = buffer * distort
buffer *= volume
# buffer tobytes() will convert the now mutated buffer array back to a python bytes object
# stream.write() will play the entire buffer (chunksize bytes)
stream.write(buffer.astype(np.int16, copy=False).tobytes())
# read the next chunk of data from the file
data = wf.readframes(chunksize)
plot_points.set_data(np.arange(fade.shape[0]), fade)
fig.canvas.restore_region(background)
ax.draw_artist(plot_points)
fig.canvas.blit(ax.bbox)
plt.pause(0.0001)
print("* done *")
stream.stop_stream()
stream.close()
p.terminate()
def main(argv):
file = ''
device_index = 0
volume = 25000
try:
opts, args = getopt.getopt(
argv, "hi:d:v:", ["ifile=", "device=", "volume="])
except getopt.GetoptError:
print('wavPlayer.py -i <inputfile> -d <device_index>')
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print('wavPlayer.py -i <inputfile> -d <device_index>')
sys.exit()
elif opt in ("-i", "--ifile"):
file = arg
elif opt in ("-d", "--device"):
device_index = int(arg)
elif opt in ("-v", "--volume"):
volume = int(arg)
if file == '':
print('wavPlayer.py -i <inputfile> -d <device_index> -v <volume>')
sys.exit(2)
print('Input file is "', file)
print('Device index is ', device_index)
play_audio(file, device_index, volume)
sys.exit(0)
if __name__ == "__main__":
main(sys.argv[1:])