Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Unable to use sound module
-
In order to read a Chinese story via TTS, the speech module is not perfect in reading Chinese because of multiple pronunciation.
So I use a online speech API to generate MP3.def online_speech(text, vol, per, spd, pit): #api code ... #generate text speech link from API urllib.request.urlretrieve(url,'temp.mp3') #save mp3 sound.play_effect('temp.mp3') #read mp3 if __name__ == '__main__': online_speech('Hello',5,'woman',2,5)
the result was, whatever the text I'd changed, it always said the same word 'Hello'
for example, if I changed the code below after running the code aboveonline_speech('Hello world',5,'woman',2,5)
it said 'Hello'. if I deleted the 'temp.mp3' and run again, it said 'Hello' again!!
I had no idea... what was going on, then I tried to use sound.player()
def online_speech(text, vol, per, spd, pit): #api code ... #generate text speech link from API urllib.request.urlretrieve(url,'temp.mp3') #save mp3 player = sound.Player('temp.mp3') player.play() #read mp3 if __name__ == '__main__': online_speech('Hello',5,'woman',2,5)
it didn't say anything!!
the player only works like this:def online_speech(text, vol, per, spd, pit): #api code ... #generate text speech link from API urllib.request.urlretrieve(url,'temp.mp3') #save mp3 if __name__ == '__main__': online_speech('Hello',5,'woman',2,5) player = sound.Player('temp.mp3') player.play() #read mp3
I have a class for reading story. so when I write like this:
def read_story(self,text): from online_speech import * online_speech(text,5,'woman',2,5) player = sound.Player('temp.mp3') player.play() #read mp3
it kept silent .... I really don't know what to do here.... does anyone meet this before?
It really doesn't make any sense. -
The problem is basically that
player
is a local variable of your function, and it gets garbage-collected (i.e. removed from memory) as soon as the function returns (which also stops playback). You either need to ensure that the function doesn't return before the player has finished playback, or you need to keep a reference that is valid beyond the scope of your function, i.e. make it either a global variable (as in your third snippet), or perhaps a member of the class that contains theread_story
method.It might be as simple as replacing
player = ...
withself.player = ...
in theread_story
method. -
Thanks for your reply. @omz
Yeah, in theread_story()
, i forgot to typeself.
in the post. And I tried it before, it didn't work.
Yesterday I tried using a global variable and it succeeded!!!!here's the code for anyone who also need it:
# -*- coding: utf-8 -*- import requests,urllib import sound,os,time import ui player = sound.Player('./sources/sound/temp.mp3') class baidu_speech (ui.View): def __init__(self): self.width,self.height = ui.get_screen_size() self.img = ui.ImageView( image = ui.Image('iob:chatbubble_working_32')) self.img.x,self.img.y = (self.width-self.img.width)/2,(self.height-self.img.height)/2 self.add_subview(self.img) @ui.in_background def speech(self,text,name,vol=5,per='lady',spd=2,pit=5): path = './sources/sound/' if os.path.exists(path+name+'.mp3') and name != 'temp': pass else: person = {'woman':0,'man':1,'man2':2,'actor':3,'girl':4,'lady':5} #start effect client_id = '********' secret = '********' token_url = 'https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s'%(client_id,secret) token = eval(requests.get(token_url).content)['access_token'] convert_text = urllib.parse.quote(text) url = 'http://tsn.baidu.com/text2audio?lan=zh&ctp=1&cuid=abcdxxx&tok=%s&&tex=%s&vol=%d&per=%d&spd=%d&pit=%d'%(token,convert_text,vol,person[per],spd,pit) urllib.request.urlretrieve(url,path+name+'.mp3') #end effect if name == 'temp': global player player = sound.Player(path+'temp.mp3') player.play() else: sound.play_effect(path+name+'.mp3') self.superview.remove_subview(self) if __name__ == '__main__': pass
the global variable is super super super important....
player = sound.Player('./sources/sound/temp.mp3')
and use it in the method:global player
-
Does it work to change:
token = eval(requests.get(token_url).content)['access_token'] # to token = requests.get(token_url).json()['access_token']
It is a security issue to run eval() on content from a remote source that you do not control.
-
@ccc very nice, many thanks!!