iamlicun
Posts: 4
Joined: Tue Oct 31, 2017 1:41 pm

arecord through subprocess works randomly in raspberry pi

Tue Oct 31, 2017 1:48 pm

I am using pyaudio to record in raspberry pi, press joystick button to start recording and press button again to stop recording.it could run and no error,but the output file size is always 44 bytes and couldn't be played.here is the code: Please suggest the best solution for my ploblem?? much thanks

Code: Select all

def record_audio(going_to_record):
    CHUNK = 1024
    FORMAT =pyaudio.paInt16
    CHANNELS = 1
    RATE = 44100
    WAVE_OUTPUT_FILENAME = "output.wav"


    p = pyaudio.PyAudio()

    stream = p.open(
        format=FORMAT,
        channels=CHANNELS,
        rate=RATE,
        input_device_index=1,
        input=True,
        frames_per_buffer=CHUNK
        )

    frames = []

    if going_to_record:
        print (" Recoding")
        index = 0

        while True:

            if joystick.get_button(0) == 0:

                print ("stop recording")
                stream.stop_stream()
                stream.close()
                p.terminate()

                wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
                wf.setnchannels(CHANNELS)
                wf.setsampwidth(p.get_sample_size(FORMAT))
                wf.setframerate(RATE)
                wf.writeframes(b''.join(frames))
                wf.close()

                break

            else:
                print (index)
                index = index + 1
                data = stream.read(CHUNK)
                frames.append(data)`
Last edited by iamlicun on Mon Nov 20, 2017 10:32 am, edited 2 times in total.

User avatar
paddyg
Posts: 2013
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: how to use pyaudio to record audio by pressing buttons?

Tue Oct 31, 2017 11:03 pm

I would have thought you needed a variable to hold states representing: button not pressed yet, button pressed once, button pressed more than once (i.e. 0,1,2 or more). You then increment this variable each time the buttons is pressed and replace your condition (that looks at the button state) with a check on the number of presses. You probably need to look for changes in the button state and only increment when the state is pressed and the previous state was not pressed. Better still use an on change callback system.

Code: Select all

def record_audio(going_to_record):
    CHUNK = 1024
    FORMAT =pyaudio.paInt16
    CHANNELS = 1
    RATE = 44100
    WAVE_OUTPUT_FILENAME = "output.wav"


    p = pyaudio.PyAudio()

    stream = p.open(
        format=FORMAT,
        channels=CHANNELS,
        rate=RATE,
        input_device_index=1,
        input=True,
        frames_per_buffer=CHUNK
        )

    frames = []
    presses = 0
    last_state = None

    if going_to_record:
        print (" Recoding")
        index = 0

        while True:
            if presses >= 2:
                print ("stop recording")
                stream.stop_stream()
                stream.close()
                p.terminate()

                wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
                wf.setnchannels(CHANNELS)
                wf.setsampwidth(p.get_sample_size(FORMAT))
                wf.setframerate(RATE)
                wf.writeframes(b''.join(frames))
                wf.close()

                break # this could be a return as inside a function

            elif presses == 1:
                print (index)
                index = index + 1
                data = stream.read(CHUNK)
                frames.append(data)

            state = joystick.get_button(0)
            if state == 0 and last_state != 0:
                presses += 1

            last_state = state
            time.sleep(0.01)
Last edited by paddyg on Thu Nov 02, 2017 4:34 pm, edited 1 time in total.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

iamlicun
Posts: 4
Joined: Tue Oct 31, 2017 1:41 pm

Re: how to use pyaudio to record audio by pressing buttons?

Wed Nov 01, 2017 9:00 am

Thanks so much, I am really a noob in coding and python.do you think my code of recording is correct or not? In the official documentation of pyaduio, it gives an example of recording a fixed 5 seconds audio, but in my case, the recording time is responsible. Official case is here:

"""PyAudio example: Record a few seconds of audio and save to a WAVE file."""

Code: Select all

import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

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

print("* recording")

frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

print("* done recording")

stream.stop_stream()
stream.close()
p.terminate()

wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()


paddyg wrote:
Tue Oct 31, 2017 11:03 pm
I would have thought you needed a variable to hold states representing: button not pressed yet, button pressed once, button pressed more than once (i.e. 0,1,2 or more). You then increment this variable each time the buttons is pressed and replace your condition (that looks at the button state) with a check on the number of presses. You probably need to look for changes in the button state and only increment when the state is pressed and the previous state was not pressed. Better still use an on change callback system.

Code: Select all

            if presses >= 2:

                print ("stop recording")
                stream.stop_stream()
...
                break
            elif presses == 1:
                print (index)
                index = index + 1
            state = joystick.get_button(0)
            if state == 0 and last_state != 0:
                presses += 1
            last_state = state
time.sleep(0.01)

User avatar
paddyg
Posts: 2013
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: how to use pyaudio to record audio controlled by pressing buttons?

Wed Nov 01, 2017 9:25 am

I haven't used pyaudio for years so can't give very specific advice on that. However if you follow the official example it should be OK. One thing that might be an issue on the RPi is the size of the list frames (if you leave it recording for a long time). The good thing about python is that you can just run it and see what happens and if something looks odd, add some print() lines to see what values variables have in them (or joysticks are returning etc).
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

iamlicun
Posts: 4
Joined: Tue Oct 31, 2017 1:41 pm

Re: how to use pyaudio to record audio controlled by pressing buttons?

Thu Nov 02, 2017 9:39 am

thanks, but i get new error: input overflow

thanks anyway
paddyg wrote:
Wed Nov 01, 2017 9:25 am
I haven't used pyaudio for years so can't give very specific advice on that. However if you follow the official example it should be OK. One thing that might be an issue on the RPi is the size of the list frames (if you leave it recording for a long time). The good thing about python is that you can just run it and see what happens and if something looks odd, add some print() lines to see what values variables have in them (or joysticks are returning etc).

User avatar
paddyg
Posts: 2013
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: how to use pyaudio to record audio controlled by pressing buttons?

Thu Nov 02, 2017 4:17 pm

Well that sounds like progress. How many times did print(index) run?

By the way, you did include the lines that I didn't bother to re-write (i.e. reading from the stream and appending to the frames list variable? (I will edit my previous post to make it clearer, also fix the line that got the wrong side of the closing code tag!)

If the process still isn't fast enough or you want to record long sounds and memory becomes an issue then it would probably be quite feasible to write directly to file.

PS I see you've started another thread on essentially this subject which may cause general confusion for people trying to help. If the example code you started from works ok then I would suggest you move from that in small stages, making sure that your code runs as expected before adding more complexity. i.e. stick with the same CHUNK size and just get the recording to stop when you press the joystick button. Then figure out the logic to keep track of the number of times the button has been pressed so you can start and then stop the recording. etc. etc.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

iamlicun
Posts: 4
Joined: Tue Oct 31, 2017 1:41 pm

Re: how to use pyaudio to record audio controlled by pressing buttons?

Mon Nov 20, 2017 10:15 am

Thanks,I deleted the other post. I tried pyaudio many many many many times but it didn't work. then I tried the arecord through subprocess. : press joystick button to start recording and press button again to stop recording, It works randomly: when I press the button, the background picture changes successfully but sometimes it couldn't record. really strange to me.

Code: Select all

 #detect button press
    if joystick.get_numbuttons() >= 1 and joystick.get_button( 0 ) == 0 and button_pressed:
        button_pressed = False
        is_recording = not is_recording
        print(is_recording)
        
        #start recording
        if is_recording:
            dotting = dotting + 1
            #recording code
            filename = "%s.wav" % datetime.now().strftime("%Y%m%d_%H%M%S")
            p=subprocess.Popen(['arecord', '--device=hw:1,0', '--format', 'S16_LE', '--rate', '44100-c1', filename], shell=False)
            
            #change background
            background = pygame.image.load(background_image2).convert()
            #start timer
            stopFlag = Event()
            timer = MyTimer(stopFlag,time.clock())
            #timer.start()
            text2 = font.render('.', True, BLACK)
            
            screen.blit(background, (0,0))
            
            stopFlag.set()

            #record, remaining here


        #stop recording
        else:
            #stop recording, save record
            
            #back to previous question
            timer.do_run = False
            backToPreviousQuestion()
            background = pygame.image.load(background_image).convert()
            #kill console
            #os.killpg(os.getpgid(p.pid), signal.SIGTERM
            p.terminate()
    pygame.display.update()
really strange.
paddyg wrote:
Thu Nov 02, 2017 4:17 pm
Well that sounds like progress. How many times did print(index) run?

By the way, you did include the lines that I didn't bother to re-write (i.e. reading from the stream and appending to the frames list variable? (I will edit my previous post to make it clearer, also fix the line that got the wrong side of the closing code tag!)

If the process still isn't fast enough or you want to record long sounds and memory becomes an issue then it would probably be quite feasible to write directly to file.

PS I see you've started another thread on essentially this subject which may cause general confusion for people trying to help. If the example code you started from works ok then I would suggest you move from that in small stages, making sure that your code runs as expected before adding more complexity. i.e. stick with the same CHUNK size and just get the recording to stop when you press the joystick button. Then figure out the logic to keep track of the number of times the button has been pressed so you can start and then stop the recording. etc. etc.

Return to “Python”

Who is online

Users browsing this forum: No registered users and 18 guests