swift: AVSpeechUtterance long pause - ios

I have this code to read my text:
var utterance = AVSpeechUtterance()
var synthesizer = AVSpeechSynthesizer()
utterance = AVSpeechUtterance(string: "\(textCount[modeIndex][0])")
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
utterance.rate = 0.4
synthesizer = AVSpeechSynthesizer()
synthesizer.speak(utterance)
But in my text I want do long pause after some words. How to do it? Maybe there are some symbol to do this (this -- is not long)?

Based on the docs at https://developer.apple.com/documentation/avfoundation/avspeechutterance#1668645
You are looking to split your utterance into multiple queued utterances, and use the postUtteranceDelay:
var postUtteranceDelay: TimeInterval
The amount of time a speech synthesizer will wait after the utterance is spoken before handling the next queued utterance.

Related

AVSpeechSynthesizer under ios16 not working (same code fine on iOS 12 / iOS 15) on UIKit

This is what I am using for TextToSpeech using AVSpeechSynthesizer and it seems to be working from iOS 12 & iOS 15, but when I try it on iOS 16.1, no voice can be heard using the below code.
I have confirmed that Spoken Content is working (Accessibility -> spoken content -> Speak Selection -> Enabled) and I can get the phone to speak out whole screen of text.
However, it's just not working for my app.
import Foundation
import AVFoundation
struct TTS {
// let synthesizer = AVSpeechSynthesizer()
static func speak(messages: String) {
let message = "Hello World"
let synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: messages)
utterance.rate = AVSpeechUtteranceDefaultSpeechRate
utterance.postUtteranceDelay = 0.005
synthesizer.speak(utterance)
}
}
This has helped some, but only for the problem of AVSpeechSynthesizer not working under Xcode simulator.
AVSpeechSynthesizer isn't working under ios16 anymore
The other solutions in that SO doesn't seem to be working for my case.
some of the proposed solution is asking to move the let synthesizer = AVSpeechSynthesizer() out of the function, but when I do that, Xcode complains about Instance member 'synthesizer' cannot be used on type 'TTS'
https://developer.apple.com/forums/thread/712809
I think there's possibility something wrong w/ my code for iOS 16
This is for UiKit and not SwiftUI which other SO ( Swift TTS, no audio-output) has a solution for.
Changed my struct to a class since AVSpeechSynthesizer can't be a local variable.
This now works
import Foundation
import AVFoundation
class TTS {
let synthesizer = AVSpeechSynthesizer()
func speak(messages: String) {
print("[TTS][Speak]\n\(messages)")
let utterance = AVSpeechUtterance(string: messages)
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
utterance.postUtteranceDelay = 0.005
synthesizer.speak(utterance)
}
}
How to Use
let tts = TTS()
tts.speak(message: "Hello World")

AVSpeechSynthesizer: how to display in a default player view

I use AVSpeechSynthesizer to play text books via audio.
private lazy var synthesizer: AVSpeechSynthesizer = {
let synthesizer = AVSpeechSynthesizer()
synthesizer.delegate = self
return synthesizer
}()
let utterance = AVSpeechUtterance(string: text)
utterance.voice = AVSpeechSynthesisVoice(
language: languageIdentifier(from: language)
)
synthesizer.speak(utterance)
I want to update information in iPhone's default player view (probably naming is wrong 🙏):
indicate playing Chapter with some text
enable next button to play the next chapter
How can I accomplish this?
I really don't think you want to hack your way through this.. But if you really do I would:
Listen to remote commands (UIApplication.sharedApplication().beginReceivingRemoteControlEvents(), see Apple Sample Project
Set your properties on MPNowPlayingInfoCenter: MPNowPlayingInfoCenter.default().nowPlayingInfo[MPMediaItemPropertyTitle] = "Title"
Implement the AVSpeechSynthesizerDelegate and try to map the delegate functions to playback states and estimate the playback progress using speechSynthesizer(_:willSpeakRangeOfSpeechString:utterance:) (idk if possible)
You might have to play with the usesApplicationAudioSession property of AVSpeechSynthesizer to have more control over the audio session (set categories etc.)

IOS/Swift/AVSpeechSynthesizer: Control Speed of Enqueued Utterances

In order to exert greater control over speech in the spirit of this tutorial for an audiobook although I'm not following it exactly, I have tried sending smaller pieces of a string such as phrases in separate chunks. The speech synthesizer enqueues each utterance and speaks them one after the other. In theory, this is supposed to give you greater control to make speech sound less robotic.
I can get the synthesizer to speak the chunks in order however there is a long delay between each so it sounds way worse than just sending all the text at the same time.
Is there anyway to speed up the queue so that the utterances are spoken one after the other with no delay?
Setting the properties: utt.preUtteranceDelay and utt.postUtteranceDelay to zero seconds does not seem to have any effect
Here is my code:
phraseCounter = 0
func readParagraph(test: String) {
let phrases = test.components(separatedBy: " ")
for phrase in phrases {
phraseCounter = phraseCounter+1
let utt = AVSpeechUtterance(string:phrase)
let preUtteranceDelayInSecond = 0
let postUtteranceDelayInSecond = 0
utt.preUtteranceDelay = TimeInterval.init(exactly:preUtteranceDelayInSecond)!
utt.postUtteranceDelay = TimeInterval.init(exactly:postUtteranceDelayInSecond)!
voice.delegate = self
if (phraseCounter == 2) {
utt.rate = .8
}
voice.speak(utt)
}
}
Is there anyway to speed up the queue so that the utterances are spoken one after the other with no delay?
As you did, the only way is to set the post and pre UtteranceDelay properties to 0 which is the default value by the way.
As recommended here, I implemented the code snippet hereafter (Xcode 10, Swift 5.0 and iOS 12.3.1) to check the impact of different UtteranceDelay values ⟹ 0 is the best solution to improve the speed of enqueued utterances.
var synthesizer = AVSpeechSynthesizer()
var playQueue = [AVSpeechUtterance]()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
for i in 1...10 {
let stringNb = "Sentence number " + String(i) + " of the speech synthesizer."
let utterance = AVSpeechUtterance(string: stringNb)
utterance.rate = AVSpeechUtteranceDefaultSpeechRate
utterance.pitchMultiplier = 1.0
utterance.volume = 1.0
utterance.postUtteranceDelay = 0.0
utterance.preUtteranceDelay = 0.0
playQueue.append(utterance)
}
synthesizer.delegate = self
for utterance in playQueue {
synthesizer.speak(utterance)
}
}
If a delay is too important with the '0' value in your code, the incoming string is maybe the problem? (adapt the code snippet above to your needs)

Image change with every sentence said in iOS?

I want my image view to change with every sentence in str, but it doesn't change
let elements = ["1","2","3"]
var cx = 0
for str in components{
OutImage.image = UIImage(named: elements1[cx+1])
myUtterance = AVSpeechUtterance(string: str)
myUtterance.rate = 0.4
myUtterance.pitchMultiplier = 1.3
myUtterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
myUtterance.voice = voiceToUse
synth.speak(myUtterance)
}
You can't do that in a for loop, because speak is asynchronous, meaning that it will execute in "parallel" with the rest of your code. By the time your for loop finishes, the speech synthesiser probably didn't even start synthesising your first sentence!
The solution, is to use an AVSpeechSynthesizerDelegate. In particular, you need to implement this method:
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer,
didFinish utterance: AVSpeechUtterance)
This delegate method is called when the synthesiser finishes an utterance.
In the method, you can figure out which image should be shown by looking at the cx variable. Then you should increment cx. After that, using cx, get the next utterance to be spoken and call speak. You should also remember to check for whether cx is the end of the array!

How can I play sound system with text?

Do we have any ways to get sound from text?
For example, we have:
let str = "Hello English" .
I want to get sound system from that text.
As Ravy Chheng answered, this uses the built-in AVFoundation library to initialize basic text-to speak function. For more information, check out the documentation by Apple: https://developer.apple.com/reference/avfoundation/avspeechsynthesizer
import AVFoundation
func playSound(str: String) {
let speechSynthesizer = AVSpeechSynthesizer()
let speechUtterance = AVSpeechUtterance(string: str)
speechSynthesizer.speak(speechUtterance)
}

Resources