Непрерывные звуки в реальном времени с Pydub - PullRequest
0 голосов
/ 02 октября 2018

Я пытаюсь создать программу, которая генерирует звуки из журнала зондов Wi-Fi, чтобы количество устройств (в пределах определенного расстояния) генерировало тон, и чтобы 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 голосов
/ 27 октября 2018

Мне удалось создать решение для котельной, которое вы можете адаптировать под свои нужды.

Вот основная идея

1) Считайте последнюю строку файла журнала, используя os.popen внепрерывный цикл, который повторяется каждую секунду

2) значение RSSI очень мало, и разница между этими значениями также мала.Мы умножаем это на константу 100 здесь, чтобы создать заметную разницу.Вы можете попробовать разные значения.

3) Используя pydub, мы создаем синусоиды и воспроизводим их

Код

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

Я тестировал, заполняяprobemon.log файл построчно с другого терминала с задержкой в ​​1 секунду.Цикл будет ждать, если нет новых данных.

EDIT1

Звуковой «тон» имеет «частоту», при изменении частоты тональный сигнал меняется.Исходя из нашего обсуждения, поскольку нам нужно, чтобы тональность изменялась в режиме реального времени, мы не можем использовать pydub, что в основном хорошо для автономной манипуляции.

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()

Результат

mac:default , rssi:0.0 , freq:0 Hz
mac:d8:8f:76:1a:cb:65 , rssi:-43 , freq:430 Hz
mac:04:4f:4c:77:72:8f , rssi:-51 , freq:510 Hz
mac:20:39:56:af:51:49 , rssi:-39 , freq:390 Hz
mac:20:39:56:af:51:49 , rssi:-45 , freq:450 Hz
mac:5e:e2:1d:a3:d2:da , rssi:-47 , freq:470 Hz
mac:5e:e2:1d:a3:d2:da , rssi:-49 , freq:490 Hz
mac:12:84:16:9c:75:ee , rssi:-43 , freq:430 Hz
mac:da:a1:19:71:4d:0c , rssi:-55 , freq:550 Hz
mac:d8:8f:76:1a:cb:65 , rssi:-49 , freq:490 Hz
...