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:
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.
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.
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:
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.
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.