0

This is a follow-on from the post: Python record audio on detected sound

I have most of it sorted now but continue to have one bug.

After the program runs once saves one recording and enters it into the DB, it returns to print listening and waiting for speech. no matter how loud the volume then goes it doesn't record again you have to the break out of the program?

I have removed the listen() function so now back to basics looking for a way to after the recording has finished start from the beginning and wait for next audio.

Here with the present code:

import pyaudio
import math
import struct
import wave
import datetime
import os
import sys
import MySQLdb

utc_datetime = datetime.datetime.utcnow()
FileTime = utc_datetime.strftime("%Y-%m-%d-%H%M")

#Assuming Energy threshold upper than 30 dB
Threshold = 30

SHORT_NORMALIZE = (1.0/32768.0)
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 16000
swidth = 2
Max_Seconds = 5
TimeoutSignal=((RATE / chunk * Max_Seconds) + 2)
silence = True
FileNameTmp = '/var/www/Recordings/'+FileTime+'.wav'
FileNameWWW = 'Recordings/'+FileTime+'.wav'
Time=0
all =[]


p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
    channels = CHANNELS,
    rate = RATE,
    input = True,
    output = True,
    frames_per_buffer = chunk)


# SQL DB Connection
db = MySQLdb.connect("localhost","root","*****","radiolink" )
cursor = db.cursor()


def GetStream(chunk):
    return stream.read(chunk)



def rms(frame):
        count = len(frame)/swidth
        format = "%dh"%(count)
        shorts = struct.unpack( format, frame )

        sum_squares = 0.0
        for sample in shorts:
            n = sample * SHORT_NORMALIZE
            sum_squares += n*n
        rms = math.pow(sum_squares/count,0.5);

        return rms * 1000


# Define What to Do When WriteSpeech is Called 
def WriteSpeech(WriteData):
    stream.stop_stream()
    stream.close()
    p.terminate()
    wf = wave.open(FileNameTmp, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(WriteData)
    wf.close()



def KeepRecord(TimeoutSignal, LastBlock):


    all.append(LastBlock)
    for i in range(0, TimeoutSignal):
        try:
            data = GetStream(chunk)
        except:
            continue

        all.append(data)

    print "end record after timeout";
    data = ''.join(all)
    print "Creating File " +FileNameTmp;

    WriteSpeech(data)
    print "Entering Record into DB";
    File = FileNameWWW  
    query ="""
        INSERT INTO recordings
        (`id`, `time`,`filename`,`active`,`status`)
        VALUES
        (NULL,NOW(), %s,1,1) """


    cursor.execute(query,(File))
    db.commit()
    silence = True
    Time=0




print "Listening......"
print "Waiting for Speech"
while silence:

    try:

         input = GetStream(chunk)

    except:

        continue


    rms_value = rms(input)

    if (rms_value > Threshold):

        silence=False

        LastBlock=input

        print "Recording...."
        KeepRecord(TimeoutSignal, LastBlock)

Time = Time + 1
if (Time > TimeoutSignal):
    print "Waiting No Speech Detected"
    sys.exit()
4

1 回答 1

0

我强烈建议您阅读以下内容,但是,似乎WriteSpeechstop 和 closesstream从未重新打开过。这很可能被您的 try/except 块所掩盖。

while silence:
    try:
        input = GetStream(chunk)
    except:
        continue

这现在说,

  1. 尝试从流中读取。
  2. 如果有异常,返回循环顶部。
  3. 重复步骤 1-2 ad-nauseum

要解决此问题,您可以尝试在 except 块中重新打开流。


在我试图回答你的问题之前我写的咆哮

冒着因为没有实际提供问题的答案而被否决的风险,我认为您需要重组一些代码才能解决这个问题。以下内容旨在完全具有建设性,如果它以其他方式出现,请告诉我。

您的listen()函数对其自身有几个递归调用,这似乎不是您想要的。这与将控制权转移到代码的那部分的jumpor命令不同。这实际上为您的函数goto的单独执行创建了另一个堆栈帧。listen()这对您的代码整体有几个影响。

  1. 所有局部变量都在每个堆栈帧的局部范围内重新定义listen()。这将导致内存使用量急剧增加。例如,您实际上在内存中有很多很多很多SHORT_NORMALIZE变量。

  2. 您定义的闭包(函数中的函数)正在为 each 的本地范围重新定义listen()。同样的问题。

  3. 在这样的部分:

    listen()
    Time = Time + 1
    
    if (Time > TimeoutSignal):
        print "Waiting No Speech Detected"
        listen()
    

    初始调用listen()ever 后什么都没有执行,因为returnlisten.

因此,在尝试解决此问题然后遇到性能/稳定性问题之前,我的建议是:

  1. 将所有代码listen()(但不是变量声明)包装在一个while循环中while True:

  2. 您当前在函数本身listen()内部的任何地方,将listen其替换为continue. 这将告诉 python 不再执行循环中的任何代码,而是继续进行下一个循环迭代,将执行带回到循环的顶部。

  3. 向这个主循环添加退出条件:

    if exit:
        print 'Terminating normally'
        break
    
  4. 不要在底部KeepRecord打电话。listen()让它完成执行。执行将在完成时返回,listen因为这是调用的地方KeepRecord

  5. 找到一种方法将Time = Time + 1部分移动到其他位置,以便实际执行。即使在此处的步骤 1-4 之后,此代码仍然永远不会执行。

实施此操作后,请验证您当前的结果是否相同。在重构此代码的过程中,您实际上可能会解决您的问题。我会将您的代码复制到一个新脚本并在该脚本中工作以保留您当前拥有的内容。

附言

如果这是您第一次涉足编码领域,您完全不应该因为发布此内容并寻求帮助而感到羞耻。你在这里做了很多事情,作为第一次编程尝试,它实际上非常令人印象深刻。

于 2013-09-05T16:58:07.463 回答