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()
halfer
  • 19,824
  • 17
  • 99
  • 186
ZeroG
  • 137
  • 1
  • 3
  • 10
  • May or may not be related, but I don't think calling `listen()` does what you think it does. If you intend on having this run for an extended period of time, even if it does work it is guaranteed to eventually crash due to infinite recursion. – Brian Sep 05 '13 at 16:20

1 Answers1

0

I would strongly recommend you read what follows BUT, it appears that WriteSpeech stops and closes stream, which is never reopened. This is likely being masked by your try/except block.

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

This now says,

  1. try to read from the stream.
  2. If there is an exception, go back to the top of the loop.
  3. Repeat steps 1-2 ad-nauseum

To fix this you can try reopening the stream within your except block.


The Rant I Wrote Before I Tried to Answer Your Question

At the risk of being downvoted for not actually providing an answer to the question, I think you need to restructure some code before this can be resolved. What follows is intended to be entirely constructive and please, please let me know if it comes off any other way.

Your listen() function has several recursive calls to itself, which does not seem to be what you intended it to be. This is not like a jump or goto command that transfers control to that part of your code. This actually creates another stack frame for a separate execution of your listen() function. This has several effects on your code overall.

  1. All local variables are getting redefined within the local scope of every stack frame for listen(). This will cause a drastic increase in memory usage. You actually have many, many, many SHORT_NORMALIZE variables in memory, for example.

  2. The closures that you define (functions within functions) are being redefined for the local scope of every listen(). Same issue.

  3. In a section like this:

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

    nothing after the initial call to listen() ever gets executed, since you have no exit condition (return) anywhere in listen.

So, what I would suggest, before trying to solve this issue and then run into performance/stability issues down the road:

  1. Wrap all of the code inside listen() (but not the variable declarations) in a while loop like while True:

  2. Everywhere that you currently have listen() inside the listen function itself, replace this with continue. This will tell python to not execute any more code from the loop, but instead to just move on to the next loop iteration, bringing execution back to the top of the loop.

  3. Add an exit condition to this main loop:

    if exit:
        print 'Terminating normally'
        break
    
  4. Don't have KeepRecord call listen() at the bottom. Just allow it to finish executing. Execution will return to listen when it is finished since that is where the call to KeepRecord was made.

  5. Find a way to move the Time = Time + 1 section somewhere else so it actually gets executed. Even after steps 1-4 here, this code will still never, ever execute.

Once you have this implemented, verify that your current results are the same. Somewhere along the line of restructuring this code you might actually fix your issue. I would copy your code to a new script and work in that one to preserve what you currently have.

P.S.

If this is your first foray into coding, you shouldn't at all be ashamed of posting this and asking for help. You have a LOT going on here, and as a first attempt at programming it's actually quite impressive.

Brian
  • 3,091
  • 16
  • 29
  • I see where you are coming from but you have got to understand that everyone starts coding somewhere I am very new to Python and trying my best to get a really functional program written for everyone, I wish I had'nt of posted now as everyone just seems to be down voting this post as they were all up voting my last post where the question was asked if this could be done. All I am trying to achieve is a solution to my problem. and not start a rant over code formatting! P.S. Thanks Brian I will try and take on board what you have to say – ZeroG Sep 05 '13 at 17:08
  • I don't mean to put you down. I just mean to head these things off before you go down that road and get frustrated. My intention here is really to have you take a step back and tackle this stuff before it drives you nuts. I'm really sorry if it came off any other way as I only wanted to help – Brian Sep 05 '13 at 17:10
  • @zerog and it's not code formatting. It's logically not doing what you think it is. – Brian Sep 05 '13 at 17:11
  • yeah no problem brian I am just thinking instaead of trying to be complicated and like in your comment. I agree things that our in a never ending loop tend to always crash out. How about this get the program terminate after every record and then use some kind of exit command which restarts the python program or bash script,, because it works absolutly perfectly once. I only implemented listen() to try to get a functional loop going :) – ZeroG Sep 05 '13 at 17:21
  • I have entered a restart program function as a work around for now but not ideal? – ZeroG Sep 05 '13 at 21:16