2016-05-03 2 views
0

Я использую следующий код для немедленной обработки/анализа звука. Он работает, но очень медленный (по сравнению с запланированной скоростью). Я добавил несколько маркеров времени, чтобы узнать, где проблема, и по их словам не должно быть никаких. Типичная продолжительность (см. Ниже) равна < 0,01 с для всех трех вычисленных времен, но для завершения цикла все еще требуется около секунды. В чем проблема?Ускорение алгоритма обработки звука

Редактировать: Обратите внимание, что измерение времени здесь не является реальной проблемой. Чтобы доказать, что: MyPeaks в основном просто находит максимум довольно короткого FFT - ничего дорогого. И проблема сохраняется, даже когда эти процедуры закомментированы.

  • Должен ли я использовать что-то отличное от лямбда-функции, чтобы сделать цикл?
  • Произошла ли ошибка при запуске и записи потока?
  • т.д.

    import pyaudio 
    import struct 
    import mute_alsa 
    import time 
    import numpy as np 
    from Tkinter import * 
    
    
    def snd_process(k=0): 
    if k<1000: 
        t0=time.clock() 
    
        data = stream.read(CHUNK) 
    
        t1=time.clock() 
    
        fl=CHUNK 
        int_data = struct.unpack("%sh" %str(fl),data) 
        ft=np.fft.fft(int_data) 
        ft=np.fft.fftshift(ft) 
        ft=np.abs(ft)  
    
        t2=time.clock() 
    
        pks=MyPeaks(np.log(ft)) 
    
        freq_out.configure(text=str(pks)) 
    
        t3=time.clock() 
    
        print t1-t0, t2-t1, t3-t2  
    
        master.after(1, lambda: snd_process(k+1)) 
    
    CHUNK = 8000 
    FORMAT = pyaudio.paInt16 
    CHANNELS = 1 
    RATE = 4000 
    
    p = pyaudio.PyAudio() 
    
    stream = p.open(format=FORMAT, 
          channels=CHANNELS, 
          rate=RATE, 
          input=True, 
          frames_per_buffer=CHUNK) 
    
    #Tkinter stuff 
    master=Tk() 
    button_play=Button(master, command=snd_process, bg="yellow", text="Analyze") 
    button_play.grid(row=0, column=0) 
    freq_out = Label(master) 
    freq_out.grid(row=0, column=1) 
    freq_out.configure(text='base') 
    mainloop() 
    
+1

Ускорьте свой питон с помощью C! (или cython) – erip

+0

Откуда вы знаете, что время - это время обработки, а не master.after()? Когда я попробовал numpy против raw C, это выглядит довольно быстро. (для точки, которая неудивительно) – paddyg

+0

@paddyg Я этого не делаю, но это не проблема (см. редактирование). –

ответ

4

Вы планируете обратный вызов 1000 в основной теме tk; для каждого обратного вызова вы используете задержку 1 мс (первый аргумент after()). Это означает, что последний цикл начнется после 1000 мс (1 секунда) первого.

Возможно, это способ петли по-прежнему занимает около секунды, чтобы завершить.

Итак, попробуйте использовать after_idle(). Я не думаю, что вам действительно нужно Ускорение алгоритма обработки звука, потому что np уже достаточно эффективен.

[EDIT] Сюрприз !! вы читаете с аудиоканала на каждой итерации 1 секунду 8000 байт в формате 16 бит для 4000 кадров. Для этого вам понадобится секунда.

+0

Спасибо, но - к сожалению - это не работает. 'after_idle' занимает примерно одно и то же время и когда используется тайм-аут 0 мс, он не обновляет поля в Tkinter (' freq_out.configure (text = str (pks)) ') –

+0

Так что, возможно, лучше сделать это в пакетах 20 или 50 Я не думаю, что вам нужна 1 миллисекун ... Подробнее ... –

+0

@ VictorPira Просто примечание: если ваш полный цикл без пользовательского интерфейса занимает (например) 200 мс, вы запрашиваете обновление пользовательского интерфейса 5000 кадров в секунду: возможно TclTk не предназначен для таких задач. –

-1

В зависимости от операционной системы вы работаете на вас может быть моголь время измерения фактического «ВАЛЛ-часов». См. Здесь http://pythoncentral.io/measure-time-in-python-time-time-vs-time-clock/ для некоторых деталей. Обратите внимание, что для python 3.3 time.clock устарел, и рекомендуется использовать time.process_time() или time.perf_counter().

2

Сжатие ввода-вывода и вычислений в основной цикл, как вы делаете, является классическим решением. Но есть альтернативы.

  1. Выполняем сборку и вычисления звука во второй нитке. Поскольку оба ввода/вывода и numpy должны освобождать GIL, это может быть хорошей альтернативой здесь. Здесь есть оговорка. Поскольку инструменты GUI, такие как TKinter, как правило, не являются многопоточными, вы должны не сделать запросы Tkinter со второго потока. Но вы можете настроить функцию, которая вызывается с after, чтобы проверить ход вычисления и обновить пользовательский интерфейс каждые 100 мс.

  2. Сделайте сбор аудио и расчеты в другом multiprocessing.Process. Это делает его полностью отделенным от вашего графического интерфейса. Вам нужно будет настроить канал связи, например, a Queue, чтобы отправить pks обратно в основной процесс. Вы должны использовать функцию after, чтобы проверить, имеются ли у Queue данные и, если это так, обновить дисплей.

Смежные вопросы