Python – _ctypes.COMError -2147287038 (comtypes module)

Question:

EDIT: I came here by chance and realized I didn’t put here who the code is from (???). Sorry about that… I knew programming only for 2 or 3 months when I published this question. Didn’t even think on that. The library is called TTS and is from DeepHorizons (thank you so much for the library!): https://github.com/DeepHorizons/tts – and seems it was updated since I asked this.

I’ve been trying to record all words from the english dictionary with a python module I found on github (modified by me). I’m trying to record every word from IVONA 2 Brian to the case that the internet fails, I can have the same voice on my Raspberry Pi and not espeak or pico tts voices. But my problem is that I can record only about 81.000 on the first time, then it goes to 7.000 and then to 2.000 and I need 479.000. The file with the list of words is found on github too (each word is in a new line). My script’s code is:

#!/usr/bin/env python3
"""
This ia a helper to use the Microsoft SAPI

Needs to run on a windows system
Requires comtypes
"""

import os
import comtypes.client  # Importing comtypes.client will make the gen subpackage
try:
    from comtypes.gen import SpeechLib  # comtypes
except ImportError:
    # Generate the SpeechLib lib and any associated files
    engine = comtypes.client.CreateObject("SAPI.SpVoice")
    stream = comtypes.client.CreateObject("SAPI.SpFileStream")
    from comtypes.gen import SpeechLib


class Sapi(object):
    """A speech API using Microsofts SAPI through COM"""

    def __init__(self):
        super().__init__()
        self.voice = comtypes.client.CreateObject('Sapi.SpVoice')

    def get_voices(self, name=''):
        """Get a list of voices, search by name optional"""
        voice_list = []
        voices = self.voice.GetVoices()

        if name is not '':
            for voice in voices:
                if name in voice.GetDescription():
                    voice_list.append(voice)
                    break
            else:
                print('Voice not found')
        else:
            for voice in voices:
                voice_list.append(voice)

        return voice_list

    def get_voice_names(self):
        """Get the names of all the voices"""
        return [voice.GetDescription() for voice in self.get_voices()]

    def set_voice(self, voice):
        """Set the voice to the given voice"""
        if type(voice) is str:
            self.voice.Voice = self.get_voices(voice)[0]
        else:
            self.voice.Voice = voice
        return

    def get_audio_outputs(self, name=''):
        """Get the audio outputs, search for the one with the name if given"""
        output_list = []
        outputs = self.voice.GetAudioOutputs()

        if name is not '':
            for output in outputs:
                if name in output.GetDescription():
                    output_list.append(output)
                    break
            else:
                print('Audio output not found')
        else:
            for output in outputs:
                output_list.append(output)

        return output_list

    def get_audio_output_names(self):
        """Get the names of all the audio outpus"""
        return [output.GetDescription() for output in self.get_audio_outputs()]

    def set_audio_output(self, output):
        if type(output) is str:
            self.voice.AudioOutput = self.get_audio_outputs(output)[0]
        else:
            self.voice.AudioOutput = output
        return

    def say(self, message):
        self.voice.Speak(message)
        return
    
    def set_rate(self, rate):
        """Set the speed of the speaker
        -10 is slowest, 10 is fastest"""
        self.voice.Rate = rate

    def _create_stream(self, filename):
        """Create a file stream handler"""
        stream = comtypes.client.CreateObject('Sapi.SpFileStream')
        stream.Open(filename, SpeechLib.SSFMCreateForWrite)
        return stream

    def create_recording(self, filename, message):
        """Make a recording of the given message to the file
        The file should be a .wav as the output is
        PCM 22050 Hz 16 bit, Little engianness, Signed"""
        stream = self._create_stream(filename)
        temp_stream = self.voice.AudioOutputStream
        self.voice.AudioOutputStream = stream
        self.say(message)
        self.voice.AudioOutputStream = temp_stream


if __name__ == '__main__':
    v = Sapi()
#From here is my code, above is the code from the module I found.
with open("words.txt","r") as words:
    lines=words.read().splitlines()
words.close()
num_total=(len(lines))
os.mkdir("list")
num=0
for e in lines:
    word=""
    for i in e:
        if i=="/" or i==":" or i=="*" or i=="?" or i=="<" or i==">" or i=="|":
            word+=" "
        else:
            word+=i
    v.set_voice("Brian")
    v.set_rate(+1)
    v.create_recording("list/"+word+".wav", e)

I’m using Sublime Text 3 and what shows up in the interpreter is:
enter image description here

I have no idea of why this is stopping. It stops, I delete the words recorded from the file and then I run the script and it can run, but it lowers the number of recorded words.

Can someone please explain me why this is happening?

EDIT: The same happens with Microsoft Anna, if it helps anyone to understand this…

Thanks in advance.

Asked By: DADi590

||

Answers:

After some time, I thought I should divide the words.txt file in smaller ones (10.000 words each) with a python script and print each word before it was recorded to see what was the problem. It stopped for some seconds on ‘aux’ and then on ‘aux.’ (with no errors and I don’t know why), and it didn’t recorded those ones. It gave the error with ‘con’ and ‘con.’. Knowing that, I tried to record those 4 words with eSpeak TTS App. It recorded them, but I couldn’t save them in anywhere because those names of files are protected by Windows to be used by it. So, now the script looks like so:

#!/usr/bin/env python3
"""
This ia a helper to use the Microsoft SAPI

Needs to run on a windows system
Requires comtypes
"""

import os
import comtypes.client  # Importing comtypes.client will make the gen subpackage
try:
    from comtypes.gen import SpeechLib  # comtypes
except ImportError:
    # Generate the SpeechLib lib and any associated files
    engine = comtypes.client.CreateObject("SAPI.SpVoice")
    stream = comtypes.client.CreateObject("SAPI.SpFileStream")
    from comtypes.gen import SpeechLib


class Sapi(object):
    """A speech API using Microsofts SAPI through COM"""

    def __init__(self):
        super().__init__()
        self.voice = comtypes.client.CreateObject('Sapi.SpVoice')

    def get_voices(self, name=''):
        """Get a list of voices, search by name optional"""
        voice_list = []
        voices = self.voice.GetVoices()

        if name is not '':
            for voice in voices:
                if name in voice.GetDescription():
                    voice_list.append(voice)
                    break
            else:
                print('Voice not found')
        else:
            for voice in voices:
                voice_list.append(voice)

        return voice_list

    def get_voice_names(self):
        """Get the names of all the voices"""
        return [voice.GetDescription() for voice in self.get_voices()]

    def set_voice(self, voice):
        """Set the voice to the given voice"""
        if type(voice) is str:
            self.voice.Voice = self.get_voices(voice)[0]
        else:
            self.voice.Voice = voice
        return

    def get_audio_outputs(self, name=''):
        """Get the audio outputs, search for the one with the name if given"""
        output_list = []
        outputs = self.voice.GetAudioOutputs()

        if name is not '':
            for output in outputs:
                if name in output.GetDescription():
                    output_list.append(output)
                    break
            else:
                print('Audio output not found')
        else:
            for output in outputs:
                output_list.append(output)

        return output_list

    def get_audio_output_names(self):
        """Get the names of all the audio outpus"""
        return [output.GetDescription() for output in self.get_audio_outputs()]

    def set_audio_output(self, output):
        if type(output) is str:
            self.voice.AudioOutput = self.get_audio_outputs(output)[0]
        else:
            self.voice.AudioOutput = output
        return

    def say(self, message):
        self.voice.Speak(message)
        return

    def set_rate(self, rate):
        """Set the speed of the speaker
        -10 is slowest, 10 is fastest"""
        self.voice.Rate = rate

    def _create_stream(self, filename):
        """Create a file stream handler"""
        stream = comtypes.client.CreateObject('Sapi.SpFileStream')
        stream.Open(filename, SpeechLib.SSFMCreateForWrite)
        return stream

    def create_recording(self, filename, message):
        """Make a recording of the given message to the file
        The file should be a .wav as the output is
        PCM 22050 Hz 16 bit, Little engianness, Signed"""
        stream = self._create_stream(filename)
        temp_stream = self.voice.AudioOutputStream
        self.voice.AudioOutputStream = stream
        self.say(message)
        self.voice.AudioOutputStream = temp_stream


if __name__ == '__main__':
    v = Sapi()
#From here is my code, above is the code from the module I found.
num=9
print("Started!")
print()
for i in range(0,47):
    print(num)
    print()
    words=open("list_words/words"+str(num)+".txt","r")
    linhas=words.read().splitlines()
    num_total=(len(linhas))
    os.mkdir("list_words/list"+str(num))
    for e in linhas:
        word=""
        for i in e:
            if i=="/" or i==":" or i=="*" or i=="?" or i=="<" or i==">" or i=="|":
                word+=" "
            else:
                word+=i
        v.set_voice("Brian")
        v.set_rate(+1)
        #I added the try and except way, so every time it can't save the recorded file with its original name, it will save it with 'ERROR - ' before and save the word on a file (backup)
        try:
            v.create_recording("list_words/list"+str(num)+"/"+word+".wav", e)
        except comtypes.COMError:
            v.create_recording("list_words/list"+str(num)+"/ERROR - "+word+".wav", e)
            erros=open("errors_recorder.txt","a")
            erros.write("n"+word)
    num+=1
print("Finished!")

It can now record all the words without interrupting the process. I still have the words.txt file divided, because I didn’t finish the recording and I want to make sure that if any error is raised again, I don’t have to search everything trying to find it (only in 10.000 words, printing every word).

Maybe this can help anyone else having trouble with this (because I didn’t know Windows doesn’t allow to save files with specific names).

Thanks anyways.

Answered By: DADi590
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.