I am writing an OS X application which uses NSSpeechSynthesizer to read text to the user and highlights the word it is reading in the text field (NSTextView). This is done by implementing the speechSynthesizer:willSpeakWord:ofString: method of the NSSpeechSynthesizerDelegate protocol. This method provides the range (NSRange) of the word it is about to speak which I forward to the setSelectedRange method of my NSTextView.
All is well until I stop the reading with the stopSpeaking method. If I set it to read again after this, the ranges provided by speechSynthesizer:willSpeakWord:ofString: seem to be out of sync. It seems that it hesitates calling speechSynthesizer:willSpeakWord:ofString: for a few seconds resulting in the ranges being somewhat behind the speech when it finally does.
I have written a simple application illustrating the issue, which can be found here:
http://dl.dropbox.com/u/12516679/SpeechTest.zip
I hope that someone will look at this code (it really is simple) and either confirm that this indeed seems to be a bug, or (hopefully) tell me what I am doing wrong.
– UPDATE –
It turns out that the problem occurs with non-english voices. I was originally using Ida, which is a Danish voice. I have now tested it with many different voices and I can confirm that it works well with all English voices. However it fell out of sync with Danish, Swedish, Norwegian and Dutch. It probably affects other languages as well, but these are the ones I have tested so far.
Ok, I have found the source of the problem and a workaround. It has nothing to do with the language as such, but the fact that most non-English voices in OS X Lion are Nuance voices (made by Nuance Communications). I have confirmed this by testing with English Nuance voices and they indeed have the same problem. It looks like there is something wrong in the api for voices provided by Nuance.
I have created a workaround for the problem by instantiating a new
NSSpeechSynthesizerobject after the reading has been stopped. It’s not pretty but it works 🙂