【问题标题】:How to make this equalizer more efficient?如何让这个均衡器更有效率?
【发布时间】:2018-11-07 15:15:01
【问题描述】:

所以我一直致力于制作均衡器,我面临的问题是 pyaudio 流的传输速度比 eq.正在查找音频文件的低音部分。我将简要概述实现:
我创建了两个额外的线程并使用 tkinter 作为 gui。线程 1 以 50 毫秒的数据块计算声音的低音分量 (fn bass() )。
线程 2 通过在 tkinter 中实际创建一个具有不同左上角坐标的矩形来绘制该图。
flag2 保持主线程运行,而 flag 同步 bass() 和 plot() 函数。代码的最后一部分是确保显示速度不会比歌曲本身快(但现在正好相反)。


我在这里附上代码:
import numpy as np
from scipy.io import wavfile 
from numpy import fft as fft
import time
import tkinter as tk
import threading
import pyaudio
import wave

CHUNK = 1024
wf = wave.open("test3.wav", 'rb')
p = pyaudio.PyAudio()

###
def callback(in_data, frame_count, time_info, status):
    data = wf.readframes(frame_count)
    return (data, pyaudio.paContinue)

stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                channels=wf.getnchannels(),
                rate=wf.getframerate(),
                output=True,
                stream_callback=callback)

####

rate,audData = wavfile.read("test3.wav")

print ("Rate "+str(rate))
print ("Length of wav file(in s) = " + str(audData.shape[0]/rate))

ch1=audData[:]
tim = 0.050
pt=int(tim*rate)

flag2 = True
flag = False
cnt = 0
value=0

def bass():
    global pt
    global cnt
    global audData
    global value
    global flag2
    global flag

    cnt +=1
    fourier=fft.fft(ch1[((cnt-1)*pt):((cnt)*pt)])
    fourier = abs(fourier) / float(pt)
    fourier = fourier[0:25]
    fourier = fourier**2

    if (cnt+1)*pt > len(audData[:]) :
        flag2 = False

    value = (np.sum(fourier))/pt
    flag= True
    return

def plot():
    global value
    global flag

    root=tk.Tk()

    canvas =tk.Canvas(root,width=200,height=500)
    canvas.pack()

    while True:
        if flag:
            canvas.delete("all")
            flag=False
            greenbox = canvas.create_rectangle(50,500-(value/80),150,500,fill="green")
            print(value/80) # to check whether it excees 500
        root.update_idletasks()    
        root.update()

    return

def sound():
    global data
    global stream
    global wf
    global CHUNK

    stream.start_stream()

    while stream.is_active():
        time.sleep(0.1)

    stream.stop_stream()
    stream.close()
    wf.close()
    p.terminate()


bass()
t1 = threading.Thread(target=plot, name='t_1')
t2 = threading.Thread(target=sound, name='t_2')
t1.start()
t2.start()

while flag2:
    a = time.time()
    bass()
    b=time.time()
    while (b-a) < tim :
        time.sleep(0.015)
        b=time.time()

为了克服这个处理速度问题,我尝试在每 3 个块中处理 1 个:

cnt +=1
    fourier=fft.fft(ch1[((3*cnt-3)*pt):((3*cnt-2)*pt)])
    fourier = abs(fourier) / float(pt)
    fourier = fourier[0:25]
    fourier = fourier**2

    if (3*cnt+1)*pt > len(audData[:]) :
        flag2 = False
#######
 while (b-a) < 3*tim :
        time.sleep(0.015)
        b=time.time()

但这甚至还达不到标准。几秒钟后可以看到滞后。关于如何改进这一点的任何想法?

【问题讨论】:

  • 编写自己的 FFT 函数?对于任何 2^N 块,算法都非常简单(其中的除法部分是二进制移位,比常规除法运算要快得多)。其他解决方案是将上面的块减少到例如512.跨度>
  • 虽然我不知道这是否与您的问题有关,但您的线程间通信不是线程安全的,这总是会导致奇怪的效果。例如,您应该将布尔值flagflag2 替换为threading.Events。除此之外,GIL 基本上无论如何都会序列化你的线程,所以多线程可能根本没有帮助,性能方面。

标签: python python-3.x audio signal-processing equalizer


【解决方案1】:

除了效率之外,更现实的解决方案可能是延迟匹配。如果您可以确定 FFT 和显示(等)过程的延迟,您可以延迟声音输出(使用一些音频样本的 fifo),或者让可视化过程在由相同数量的样本。

【讨论】:

    猜你喜欢
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多