audio_visualize.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. from mpl_toolkits.mplot3d import Axes3D
  2. import pyaudio
  3. import numpy as np
  4. import matplotlib.pyplot as plt
  5. import struct
  6. from scipy.signal import detrend
  7. from _tkinter import TclError
  8. from matplotlib.animation import FuncAnimation
  9. from pydub import AudioSegment
  10. from matplotlib.collections import LineCollection
  11. class AudioVisualize(object):
  12. def __init__(self, filename: str = None, rate=1., delay=4.):
  13. p = pyaudio.PyAudio()
  14. self.record_delay = delay
  15. if filename is None:
  16. self.channels = 1
  17. self.rate = 48000
  18. self.window = int(self.rate * 0.02)
  19. self.fwhm = 20
  20. self.stream = p.open(
  21. format=pyaudio.paInt16,
  22. channels=self.channels,
  23. rate=self.rate,
  24. input=True,
  25. )
  26. else:
  27. sound = AudioSegment.from_file(filename)
  28. self.left = sound.split_to_mono()[0]
  29. self.size = len(self.left.get_array_of_samples())
  30. self.rate = self.left.frame_rate
  31. self.window = int(self.rate * 0.02)
  32. self.stream = p.open(
  33. format=p.get_format_from_width(self.left.sample_width),
  34. channels=self.left.channels,
  35. rate=int(self.rate * rate),
  36. output=True,
  37. )
  38. self.stream.start_stream()
  39. def audio_visualize_1d(self):
  40. xf = np.linspace(20, self.rate / 2, self.window)
  41. fig, ax = plt.subplots(figsize=(14, 5))
  42. lf, = ax.semilogx(xf, np.zeros(self.window), lw=1, color='lightblue')
  43. ax.set_ylim(-0.5, 1.5)
  44. ax.set_axis_off()
  45. plt.show(block=False)
  46. plt.pause(self.record_delay)
  47. while self.stream.is_active():
  48. data = self.stream.read(self.window)
  49. data_int = struct.unpack(str(self.window * 2) + 'B', data)
  50. y_detrend = detrend(data_int)
  51. box = np.ones(self.fwhm) / self.fwhm
  52. y_smooth = np.convolve(y_detrend, box, mode='same')
  53. yft = np.abs(np.fft.fft(y_smooth))
  54. y_vals = yft[:self.window] / (64 * self.window)
  55. ind = np.where(y_vals > (np.max(y_vals) + np.min(y_vals)) / 2)
  56. y_vals[ind[0]] *= 4
  57. lf.set_ydata(y_vals)
  58. try:
  59. ax.figure.canvas.draw()
  60. ax.figure.canvas.flush_events()
  61. except TclError:
  62. self.stream.stop_stream()
  63. self.stream.close()
  64. break
  65. def audio_visualize_2d(self):
  66. t = np.linspace(0, 2. * np.pi, self.window * 2)
  67. xf = np.cos(t)
  68. yf = np.sin(t)
  69. fig, ax = plt.subplots(figsize=(7, 7))
  70. lf, = ax.plot(xf, yf, lw=1, color='lightblue')
  71. ax.set_xlim(-3, 3)
  72. ax.set_ylim(-3, 3)
  73. ax.set_axis_off()
  74. plt.show(block=False)
  75. plt.pause(self.record_delay)
  76. while self.stream.is_active():
  77. data = self.stream.read(self.window)
  78. data_int = struct.unpack(str(self.window * 2) + 'B', data)
  79. y_detrend = detrend(data_int)
  80. yft = np.abs(np.fft.fft(y_detrend))
  81. y_vals = yft / (64 * self.window)
  82. ind = np.where(y_vals > (np.max(y_vals) + np.min(y_vals)) / 2)
  83. y_vals[ind[0]] *= 4
  84. lf.set_xdata(xf + y_vals * np.cos(t))
  85. lf.set_ydata(yf + y_vals * np.sin(t))
  86. try:
  87. ax.figure.canvas.draw()
  88. ax.figure.canvas.flush_events()
  89. except TclError:
  90. self.stream.stop_stream()
  91. self.stream.close()
  92. break
  93. def audio_visualize_3d(self):
  94. t = np.linspace(0, 2. * np.pi, self.window * 2)
  95. xf = np.cos(t)
  96. yf = np.sin(t)
  97. fig = plt.figure()
  98. ax = fig.gca(projection='3d')
  99. lf, = ax.plot(xf, yf, np.zeros(self.window * 2), lw=1, color='lightblue')
  100. ax.set_zlim(-0.2, 1.2)
  101. ax.set_axis_off()
  102. plt.show(block=False)
  103. plt.pause(self.record_delay)
  104. while self.stream.is_active():
  105. data = self.stream.read(self.window)
  106. data_int = struct.unpack(str(self.window * 2) + 'B', data)
  107. z_detrend = detrend(data_int)
  108. zf = np.abs(np.fft.fft(z_detrend))
  109. z_vals = zf / (64 * self.window)
  110. ind = np.where(z_vals > (np.max(z_vals) + np.min(z_vals)) / 2)
  111. z_vals[ind[0]] *= 4
  112. lf.set_xdata(xf)
  113. lf.set_ydata(yf)
  114. lf.set_3d_properties(z_vals)
  115. try:
  116. ax.figure.canvas.draw()
  117. ax.figure.canvas.flush_events()
  118. except TclError:
  119. self.stream.stop_stream()
  120. self.stream.close()
  121. break
  122. def music_visualize_1d(self):
  123. fig = plt.figure(facecolor='black')
  124. ax = fig.gca()
  125. norm = plt.Normalize(-1., 1.)
  126. lc = LineCollection([], cmap='cool', norm=norm)
  127. ax.set_ylim(-1.5, 1.5)
  128. ax.set_axis_off()
  129. time = np.linspace(0, 2 * np.pi, self.window)
  130. ax.add_collection(lc)
  131. plt.pause(self.record_delay)
  132. def update(frames):
  133. if self.stream.is_active():
  134. slice = self.left.get_sample_slice(frames, frames + self.window)
  135. self.stream.write(slice.raw_data)
  136. y = np.array(slice.get_array_of_samples()) / 30000
  137. points = np.array([np.cos(time), y]).T.reshape((-1, 1, 2)) # 控制曲线精细程度和振幅
  138. segments = np.concatenate([points[:-1], points[1:]], axis=1)
  139. lc.set_segments(segments)
  140. lc.set_array(y) # 控制颜色
  141. return lc,
  142. ani = FuncAnimation(fig, update, frames=range(0, self.size, self.window), interval=0, blit=True)
  143. plt.show()
  144. def music_visualize_2d(self):
  145. t = np.linspace(0, 2 * np.pi, self.window)
  146. fig = plt.figure(facecolor='black')
  147. ax = fig.gca(projection='polar')
  148. ax.set_axis_off()
  149. lf, = ax.plot(t, np.zeros(self.window), lw=1, color='lightblue')
  150. plt.pause(self.record_delay)
  151. def update(frames):
  152. if self.stream.is_active():
  153. slice = self.left.get_sample_slice(frames, frames + self.window)
  154. self.stream.write(slice.raw_data)
  155. y = np.array(slice.get_array_of_samples()) / 1000000
  156. # yft = np.abs(np.fft.fft(y)) / self.window
  157. lf.set_ydata(y)
  158. return lf,
  159. ani = FuncAnimation(fig, update, frames=range(0, self.size, self.window), interval=0, blit=True)
  160. plt.show()
  161. def music_visualize_3d(self):
  162. t = np.linspace(0, 2 * np.pi, self.window)
  163. x, y = np.cos(t), np.sin(t)
  164. fig = plt.figure()
  165. ax = fig.gca(projection='3d')
  166. ax.set_axis_off()
  167. lf, = ax.plot(x, y, np.zeros(self.window), lw=1, color='lightblue')
  168. lf2, = ax.plot(x, y, np.zeros(self.window), lw=1, color='orange')
  169. plt.pause(self.record_delay)
  170. def update(frames):
  171. if self.stream.is_active():
  172. slice = self.left.get_sample_slice(frames, frames + self.window)
  173. self.stream.write(slice.raw_data)
  174. z = np.array(slice.get_array_of_samples())
  175. zft = np.abs(np.fft.fft(z / max(z))) / (self.window * 4)
  176. lf.set_xdata(x)
  177. lf.set_ydata(y)
  178. lf.set_3d_properties(zft)
  179. lf2.set_xdata(x)
  180. lf2.set_ydata(y)
  181. lf2.set_3d_properties(z / 1000000)
  182. return lf, lf2,
  183. ani = FuncAnimation(fig, update, frames=range(0, self.size, self.window), interval=0, blit=True)
  184. plt.show()