Search code examples
pythonpyaudiosox

Play audio and get current second of playback using Python?


I am working on speech interface with python. I am having trouble with audio playback.

What do you use to black back simple mp3 files on the raspberry pi?

I need to play audio and 2 seconds before the end of the playback I need to start another task (opening the stream of the microphone) How can I archive this? May problem is that I haven't found a way to read the current seconds of the playback yet. If I could read this, I would just start a new thread when the currenttime is audiolength - 2 seconds.

I hope you can help me or have any experience with this.


Solution

  • I found a solution to this. PyAudio is providing a way to play audio chunk by chunk. Through that you can read the current chunk and compare it to the overall size of the audio.

    class AudioPlayer():
        """AudioPlayer class"""
        def __init__(self):
            self.chunk = 1024
            self.audio = pyaudio.PyAudio()
            self._running = True
    
    
        def play(self, audiopath):
            self._running = True
            #storing how much we have read already
            self.chunktotal = 0
            wf = wave.open(audiopath, 'rb')
            stream = self.audio.open(format =self.audio.get_format_from_width(wf.getsampwidth()),channels = wf.getnchannels(),rate = wf.getframerate(),output = True)
            print(wf.getframerate())
            # read data (based on the chunk size)
            data = wf.readframes(self.chunk)
            #THIS IS THE TOTAL LENGTH OF THE AUDIO
            audiolength = wf.getnframes() / float(wf.getframerate())
    
            while self._running:
                if data != '':
                    stream.write(data)
                    self.chunktotal = self.chunktotal + self.chunk
                    #calculating the percentage
                    percentage = (self.chunktotal/wf.getnframes())*100
                    #calculating the current seconds
                    current_seconds = self.chunktotal/float(wf.getframerate())
                    data = wf.readframes(self.chunk)
    
                if data == b'':
                    break
    
            # cleanup stream
            stream.close()
    
        def stop(self):
            self._running = False
    

    Hope it helps someone, Alex