音乐频谱可视化

现成的projectM项目能做到这件事情。

自己写出来的代码,应该能在linux系统上运行。就是播放现成的音频文件,同时读取音频数据,绘制频谱图

from pydub import AudioSegment
from pydub.playback import play
import multiprocessing
import wave
import numpy as np
import scipy
import matplotlib.pyplot as plt
import matplotlib.animation as animation

music_fn='zaifeixing.wav'
times=4

class Scope:
    def __init__(self,ax,times,fr,frames):
        self.ax=ax
        self.times=times
        self.fr=fr
        self.frames=frames
        self.i=0

    def paint(self,j):
        self.ax.cla()
        n=self.fr//self.times
        freq_spectra=scipy.fft.fft(self.frames[self.i*n:(self.i+1)*n])
        abs_freq=np.abs(freq_spectra)
        x=np.arange(n//2)*self.fr*2/n
        x[0]*=2
        self.ax.plot(x,abs_freq[:n//2])
        self.i+=1

def visualize_freq_spectra(times,fr,frames):
    fig,ax=plt.subplots()
    scope=Scope(ax,times,fr,frames)
    ani=animation.FuncAnimation(fig,scope.paint,interval=1000//times)
    plt.show()

def play_music(music_fn):
    song=AudioSegment.from_wav(music_fn)
    play(song-15)

wav=wave.open(music_fn,'rb')
frames=wav.readframes(wav.getnframes())
frames=np.frombuffer(frames,dtype=np.short).reshape((-1,2)).T[0]
fr=wav.getframerate()
t=multiprocessing.Process(target=visualize_freq_spectra,args=(times,fr,frames))
t.daemon=True # 非阻塞
t.start()
play_music(music_fn)

北桥苏写的代码,根据系统的混响声音(扬声器加麦克风?)进行律动,首先,在系统设置-系统-声音-所有声音设备-立体声混音-属性里设置允许应用和Windows将此设备用于音频,且在更多声音设置里面将立体声混音设为默认设备,在立体声混音的属性-高级里取消勾选允许程序独占控制此设备,然后运行下述代码,但是pyaudio还是无法采集到系统声音,因此此段代码无法实现预期的功能。

import pyaudio
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import wave
 
FORMAT = pyaudio.paInt16
CHANNELS = 1 
RATE = 44100 
CHUNK = 4096 
# CHUNK = 1024 
WAVE_OUTPUT_FILENAME = 'audio_output.wav'
 
# 获取内录设备序号,在windows操作系统上测试通过,hostAPI = 0 表明是MME设备
def findInternalRecordingDevice(p):
    # 要找查的设备名称中的关键字
    target = '立体声混音'
    # 逐一查找声音设备
    for i in range(p.get_device_count()):
        devInfo = p.get_device_info_by_index(i)
        print(devInfo)
        if devInfo['name'].find(target) >= 0 and devInfo['hostApi'] == 0:
            # print('已找到内录设备,序号是 ',i)
            return i
    print('无法找到内录设备!')
    return -1
 
# Initialize PyAudio
audio = pyaudio.PyAudio()
 
# 这里input_device_index的2就是系统内录设备索引
stream = audio.open(input_device_index=findInternalRecordingDevice(audio),
                    format=FORMAT,
                    channels=1,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)
 
plt.ion()
fig, ax = plt.subplots()
x = np.arange(0, CHUNK)
line, = ax.plot(x, np.zeros(CHUNK))
ax.set_xlim(0, CHUNK)
ax.set_ylim(-32768, 32767)
 
wave_output_file = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wave_output_file.setnchannels(CHANNELS)
wave_output_file.setsampwidth(audio.get_sample_size(FORMAT))
wave_output_file.setframerate(RATE)
 
def update_plot(data):
    print(data)
    line.set_ydata(data)
    fig.canvas.draw()
    fig.canvas.flush_events()
 
def display_audio_waveform():
    while True:
        try:
            audio_data = np.frombuffer(stream.read(CHUNK), dtype=np.int16)
            # update_plot(audio_data*500)
            update_plot(audio_data)
            wave_output_file.writeframes(audio_data)
        except KeyboardInterrupt:
            break
 
display_audio_waveform()
 
stream.stop_stream()
stream.close()
audio.terminate()
 
wave_output_file.close()
print('Audio saved to', WAVE_OUTPUT_FILENAME)

参考链接:

如何用 Python 实现一个 “系统声音” 的实时律动挂件

创建于2407111417,修改于2407111417

posted @ 2024-07-11 14:18  园糯  阅读(12)  评论(0编辑  收藏  举报