Python音频功能无法按预期工作

Posted

技术标签:

【中文标题】Python音频功能无法按预期工作【英文标题】:Python audio function not working as expected 【发布时间】:2013-09-05 15:46:34 【问题描述】:

这是该帖子的后续内容: Python record audio on detected sound

我现在已经对大部分内容进行了排序,但仍有一个错误。

程序运行一次保存一个录音并进入DB后,返回打印监听等待语音。再大的音量也不会再录了 你要退出程序吗?

我已经删除了listen() 功能,所以现在回到基础,寻找一种在录制完成后从头开始并等待下一个音频的方法。

这里是当前代码:

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

【问题讨论】:

可能相关也可能不相关,但我认为调用listen() 不会像您认为的那样。如果您打算长时间运行此操作,即使它确实有效,也保证最终会由于无限递归而崩溃。 【参考方案1】:

我强烈建议您阅读以下内容,但是,WriteSpeech 似乎停止并关闭了从未重新打开过的 stream。这很可能被您的 try/except 块所掩盖。

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

现在说,

    尝试从流中读取。 如果出现异常,返回循环顶部。 重复步骤 1-2 令人作呕

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


我在尝试回答您的问题之前写的咆哮

冒着因为没有真正提供问题的答案而被否决的风险,我认为您需要重组一些代码才能解决这个问题。以下内容完全是建设性的,如果有任何其他问题,请告诉我。

您的listen() 函数对自身有几个recursive 调用,这似乎不是您想要的。这不像jumpgoto 命令将控制权转移到代码的那一部分。这实际上为您的listen() 函数的单独执行创建了另一个堆栈帧。这会对您的代码整体产生多种影响。

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

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

    在这样的部分:

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

    在对listen() 的初始调用之后没有任何内容被执行,因为您在listen 的任何地方都没有退出条件 (return)。

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

    listen() 中的所有代码(但不包括变量声明)包装在像while True: 这样的while 循环中

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

    给这个主循环添加一个退出条件:

    if exit:
        print 'Terminating normally'
        break
    

    底部不要有KeepRecord 调用listen()。让它完成执行。执行完成后将返回到listen,因为这是对KeepRecord 的调用。

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

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

附言

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

【讨论】:

我知道你从哪里来,但你必须明白每个人都从某个地方开始编码现在没有发布,因为每个人似乎都对这篇文章投了反对票,因为他们都在投票给我最后一个帖子,在这个帖子被问到是否可以这样做。我想要实现的只是解决我的问题。不要对代码格式大发雷霆!附言谢谢布赖恩,我会尽力接受你要说的话 我并不是要贬低你。我只是想在你走上这条路并感到沮丧之前阻止这些事情。我的目的是让你退后一步,在它把你逼疯之前解决这些问题。如果它以任何其他方式出现,我真的很抱歉,因为我只是想提供帮助 @zerog 这不是代码格式。从逻辑上讲,它并没有按照您的想法行事。 是的,没问题,布赖恩,我只是想在你的评论中尝试变得复杂和喜欢。我同意我们在一个永无止境的循环中往往总是崩溃的事情。这如何让程序在每条记录后终止,然后使用某种退出命令重新启动 python 程序或 bash 脚本,因为它绝对完美地工作一次。我只实现了listen() 来尝试使功能循环运行:) 我已经进入了重启程序功能作为暂时的解决方法,但不理想?

以上是关于Python音频功能无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

我的音频和搜索功能未按预期运行

PyCharm 类型检查无法按预期工作

My-Sql 中的窗口化功能无法按预期工作

Angular:为组件字段提供对服务功能的引用并从模板调用它无法按预期工作

.play() 在 React 组件上无法按预期工作

播放 HTML5 音频标签,但控件未按预期工作