使用Pydub实时连续发出声音

时间:2018-10-02 07:47:57

标签: python audio real-time pyaudio pydub

我正在尝试创建一个程序,该程序从wifi探测器日志中生成声音,以使一定数量范围内的设备数量生成音调,而rssi将成为频率。

我正在尝试使其尽可能实时,但无法弄清楚如何使音调连续并根据值的变化来改变频率。

'''
This program takes a log file from a
wifi probe and translates it into sound
'''

import time
import math        #import needed modules
import pyaudio     #sudo apt-get install python-pyaudio
import threading
from threading import Thread
from pydub import AudioSegment
from pydub.generators import Sine
from pydub.playback import play
import signal


def logData():
    '''
    Takes log file data and puts it into database
    updates every 1 sec
    '''
    global dic
    global tone
    tone = []
    dic = {}
    while True:
        with open("/Users/CWT/Documents/VÆRKER/probemon.log") as f:
            for line in f:
                (key, val) = line.split()
                if val <= str(-50):
                    dic[(key)] = val
        print (dic)
        time.sleep(1)



def sound():

    '''
    Generate sounds
    '''

    # Play final tone
    while (True):
        with open("/Users/CWT/Documents/VÆRKER/probemon.log") as i:
            try:
                tone1 = Sine(abs(int(list(dic.values())[0]))).to_audio_segment(3000)            
                tone2 = Sine(abs(int(list(dic.values())[1]))).to_audio_segment(3000)        
                tone3 = Sine(abs(int(list(dic.values())[2]))).to_audio_segment(3000)
            except:
                print('Index error')
            try:
                multitone1 = tone1
                multitone2 = tone1.overlay(tone2)
                multitone3 = tone3.overlay(multitone2)
            except:
                print('Multitone error')


            try:
                if len(dic) <= 1:
                    play(multitone1.fade_in(250).fade_out(250))
                elif len(dic) == 2:
                    play(multitone2.fade_in(250).fade_out(250))
                elif len(dic) >= 3:
                    play(multitone3.fade_in(250).fade_out(250))
            except:
                print('Playback error')

if __name__ == '__main__':
    try:
        Thread(target = logData).start()
        time.sleep(1)
        Thread(target = sound).start()
    except KeyboardInterrupt:
        print('Interrupted')

1 个答案:

答案 0 :(得分:0)

我能够设计出样板解决方案,您可以根据自己的需要进行量身定制。

这是中心思想

1)使用let i = [ { "text": "Title 1", "value": "1" }, { "text": "Title 2", "value": "2" } ]; function getByValueFrom(value, array) { let a = []; a = array.filter(e => { return e.value === value; }); return a; } let retVal = getByValueFrom('2', i) console.log(retVal); 在每秒重复一次的连续循环中读取日志文件的最后一行

2)RSSI值非常小,这些值之间的差异也很小。我们在此处将其乘以常数os.popen来创建明显的差异。您可以尝试其他值。

3)使用pydub,我们创建正弦音并播放它们

代码

100

我通过从另一终端逐行填充from pydub.generators import Sine from pydub import AudioSegment from pydub.playback import play import os import time sr = 44100 # sample rate bd = 16 # bit depth l = 50.0 # duration in millisec last_line = "" #to avoid same line played again log_file = "probemon.log" while True: line = os.popen('tail -n 1 {}'.format(log_file)).read() if last_line == line: pass else: key, val = line.split() f = abs(int(val)) * 100 #create sine wave of given freq sine_wave = Sine(f, sample_rate=sr, bit_depth=bd) #Convert waveform to audio_segment for playback and export sine_segment = sine_wave.to_audio_segment(duration=l) print "mac:{} , rssi:{}".format(key,val) #Play audio segment play(sine_segment) last_line = line time.sleep(1) #sleep 1 sec, synch this with log file fill 文件来进行测试,延迟时间为1秒。如果没有新数据,循环将等待。

EDIT1

音频“音频”具有“频率”,当您更改频率时,音频也会改变。 根据我们的讨论,由于我们需要实时改变音调,因此不能使用probemon.log,它最适合离线操作。

pydub具有使用回调的非阻塞方法,该方法允许在实时播放流数据时对其进行处理。

此解决方案会根据日志的最后一行连续播放音频,直到日志数据更改为止。

此解决方案还消除了合并两个音调时出现的爆裂/开裂声音。

here的启示。

pyaudio

结果

import pyaudio
import numpy as np
from time import time,sleep
import os

CHANNELS = 2
RATE = 44100

TT = time()
freq = 100
newfreq = 100
phase = 0
log_file = "probemon.log"

def callback(in_data, frame_count, time_info, status):
    global TT,phase,freq,newfreq
    if newfreq != freq:
        phase = 2*np.pi*TT*(freq-newfreq)+phase
        freq=newfreq
    left = (np.sin(phase+2*np.pi*freq*(TT+np.arange(frame_count)/float(RATE))))
    data = np.zeros((left.shape[0]*2,),np.float32)
    data[0::2] = left  #left data
    data[1::2] = left  #right data
    TT+=frame_count/float(RATE)
    return (data, pyaudio.paContinue)

p = pyaudio.PyAudio()

stream = p.open(format=pyaudio.paFloat32,
                channels=CHANNELS,
                rate=RATE,
                output=True,
                stream_callback=callback)

stream.start_stream()
tmphold = ""
try:
    while True:
        line = os.popen('tail -n 1 {}'.format(log_file)).read()
        try:
            key, val = line.split()
        except:
            key, val = "default", 0.0

        f = abs(int(val))  
        newfreq = f * 10  #update freq per log
        if newfreq != tmphold:
            tmphold = newfreq
            print "mac:{} , rssi:{} , freq:{} 
finally:
    stream.stop_stream()
    stream.close()
    p.terminate()