python-3.xraspberry-pispeech-recognitionwavwave

Create and use WAV file as an object Python


I am creating a personal assistant in Python. I am using Snowboy to record audio, and it works very well. Snowboy has a saveMessage() method that creates and writes a wav file to the disk. This wav file is later read and used as an AudioFile object by Speech_Recognition. I find it very inefficient that the program has to write and read wav files to the disk. I would much rather have the wav file be passed around as an object without EVER saving it to the disk.

Here is the snowboy saveMessage() module that I would like to reweite.

def saveMessage(self):
    """
    Save the message stored in self.recordedData to a timestamped file.
    """
    filename = 'output' + str(int(time.time())) + '.wav'
    data = b''.join(self.recordedData)

    #use wave to save data
    wf = wave.open(filename, 'wb')
    wf.setnchannels(1)
    wf.setsampwidth(self.audio.get_sample_size(
        self.audio.get_format_from_width(
            self.detector.BitsPerSample() / 8)))
    wf.setframerate(self.detector.SampleRate())
    wf.writeframes(data)
    wf.close()
    logger.debug("finished saving: " + filename)
    return filename #INSTEAD OF RETURNING filename I WANT THIS TO RETURN THE wav file object

Please note that the AudioFile class requires that the path for the wave file OR a "file-like" object must be passed into it. I am not sure what a "file-like" object is, so I will provide the AudioFile assert statement for the wav file argument:

assert isinstance(filename_or_fileobject, (type(""), type(u""))) or hasattr(filename_or_fileobject, "read"), "Given audio file must be a filename string or a file-like object"

I have tried to use an instance of BytesIO to save the wav data, BytesIO is apparently not a file-like object. Here was what I tried:

def saveMessage(self):
    filename = 'output' + str(int(time.time())) + '.wav'
    data = b''.join(self.recordedData)

    #use wave to save data
    with io.BytesIO() as wav_file:
        wav_writer = wave.open(wav_file, "wb")
        try:
            wav_writer.setnchannels(1)
            wav_writer.setsampwidth(self.audio.get_sample_size(
                self.audio.get_format_from_width(
                    self.detector.BitsPerSample() / 8)))
            wav_writer.setframerate(self.detector.SampleRate())
            wav_writer.writeframes(data)
            wav_data = wav_file.getvalue()
        finally:
            wav_writer.close()
            logger.debug("finished saving: " + filename)
    return wav_data

The error I got was: AssertionError: Given audio file must be a filename string or a file-like object

I am using python 3.7 on a Raspberry PI 3B+ running Raspbian Buster Lite kernel version 4.19.36.

If I can provide any additional information or clarify anything, please ask.

Thanks so much!


Solution

  • Something like this should work:

    from speech_recognition import AudioData
    
    def saveMessage(self):
        filename = 'output' + str(int(time.time())) + '.wav'
        data = b''.join(self.recordedData)
        ad = AudioData(data, 16000, 2)
        result = recognizer.recognize_google(ad)
    

    Note that speech_recognition.listen can invoke snowboy internally, so you probably don't have to use external snowboy, you can just use listen with parameter snowboy_configuration.