Ok, so after playing a bit with this cool feature I wasn't aware of, I found out a way to change the rate of utterance. The main problem is that the utterance is currently enqueued by synthetizer, the rate
can't be changed. Corresponds to the documentation:
/* Setting these values after a speech utterance has been enqueued will have no effect. */
open var rate: Float // Values are pinned between AVSpeechUtteranceMinimumSpeechRate and AVSpeechUtteranceMaximumSpeechRate.
open var pitchMultiplier: Float // [0.5 - 2] Default = 1
open var volume: Float // [0-1] Default = 1
So the workaround would be to stop the synthesizer and feed him new utterance with trimmed string.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var synthesizer: AVSpeechSynthesizer!
var string: String!
var currentRange: NSRange = NSRange(location: 0, length: 0)
@IBAction func sl(_ sender: UISlider) {
synthesizer.stopSpeaking(at: .immediate)
if currentRange.length > 0 {
let startIndex = string.index(string.startIndex, offsetBy: NSMaxRange(currentRange))
let newString = string.substring(from: startIndex)
string = newString
synthesizer.speak(buildUtterance(for: sender.value, with: string))
}
}
func buildUtterance(for rate: Float, with str: String) -> AVSpeechUtterance {
let utterance = AVSpeechUtterance(string: str)
utterance.rate = rate
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
return utterance
}
override func viewDidLoad() {
super.viewDidLoad()
string = "I am currently developing an iOS app that converts text to speech using AVSynthesizer.What I want to do is that while the synthesizer is speaking, utterance rate can be changed and with a slider and the speed of the speaking changes. I am doing this in the IBAction of the slider: self.utterance = sender.value but the synthesizer doesn't change the speed. Ive been looking for information but I haven't found something yet. What can I do? Thanks in advance."
synthesizer = AVSpeechSynthesizer()
synthesizer.delegate = self
synthesizer.speak(buildUtterance(for: AVSpeechUtteranceDefaultSpeechRate, with: string))
}
}
extension ViewController: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
debugPrint(characterRange.toRange())
currentRange = characterRange
}
}
implement the delegate method willSpeakRangeOfSpeechString
of AVSpeechSynthesizerDelegate
and define the delegate of synthesizer as self: synthesizer.delegate = self
In that delegate method, save the characterRange which would be spoken next.
Bind IBAction func sl(_ sender: UISlider)
to your slider's event touchUpInside.
in that IBAction, stop speaking, and get the substring of your current text being spoken from index it would've continue.
Build new utterance and start speaking it
Profit.