1

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. I've been looking for information but I haven't found something yet. What cand I do? Thanks in advance.

4

2 回答 2

6

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
    }
}
  1. implement the delegate method willSpeakRangeOfSpeechString of AVSpeechSynthesizerDelegate and define the delegate of synthesizer as self: synthesizer.delegate = self

  2. In that delegate method, save the characterRange which would be spoken next.

  3. Bind IBAction func sl(_ sender: UISlider) to your slider's event touchUpInside.

  4. in that IBAction, stop speaking, and get the substring of your current text being spoken from index it would've continue.

  5. Build new utterance and start speaking it

  6. Profit.

于 2017-06-12T20:12:49.760 回答
-1

swift 3

import UIKit
import AVFoundation     

class ViewController: UIViewController{

    @IBOutlet weak var sliderVolume: UISlider!  //for volume
    @IBOutlet weak var sliderRate: UISlider!    //for rate
    @IBOutlet weak var sliderPitch: UISlider!   //for pitch
    @IBOutlet weak var txtForSpeak: UITextField!

    let speechSynth = AVSpeechSynthesizer()

    @IBAction func btnStartToSpeak(_ sender: UIButton) {

        let speechUtt = AVSpeechUtterance(string: self.txtForSpeak.text!)

            speechUtt.rate = self.sliderRate.value

            speechUtt.volume = self.sliderVolume.value

            speechUtt.pitchMultiplier = self.sliderPitch.value

        self.speechSynth.speak(speechUtt)
    }
}
于 2017-11-11T11:17:13.087 回答