Search code examples
iosswifttext-to-speechavspeechsynthesizer

Analyse string for text-to-Speech in iOS


I want to analyse String and check whether it contains certain keywords like "1 minute" during text is pronounced by system.

I'm facing issue when AVSpeechSynthesizer takes the whole string at a time and perform its operation. I don't have control to analyse string during the playing time to check those keywords occurs.

My code as follow for text-to-speech:

func Speech()  {
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
        try AVAudioSession.sharedInstance().setActive(true)
        print("Session is Active")
    } catch {
        print(error)
    }

    if !speechSynthesizer.isSpeaking {
        self.VoiceString = self.VoiceString+self.DirectionsString
        let speechUtterance = AVSpeechUtterance(string: self.VoiceString)
        var voiceToUse: AVSpeechSynthesisVoice?
        speechUtterance.voice = voiceToUse
        speechUtterance.rate = Float(self.RangeSlider.selectedMinValue/2)
        speechSynthesizer.speak(speechUtterance)
    }
    else {
        speechSynthesizer.continueSpeaking()
    }
    animateActionButtonAppearance(shouldHideSpeakButton: true)
}

Is it possible to detect specific string by using AVSpeechSynthesizer or have you any other approach?


Solution

  • You should implement delegate of AVSpeechSynthesizer and add following code:

    var myText = "This is my text, which will be detect on text-to-speech operation"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        speechSynthesizer.delegate = self
    }
    

    Implemented willSpeakRangeOfSpeechString which will called every spoken word by system in text string. You can implement String type's contains() method to detect particular string in your text.

    extension TextToSpeechVC: AVSpeechSynthesizerDelegate {
    
        func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
    
            let string = self.myText[characterRange.lowerBound..<characterRange.upperBound]
    
            if string.trim == "operation" {
                print("string = \(string)")
            }
        }
    }
    

    Add String extension for subscript of range.

    extension String {
    
        var trim: String {
            return self.trimmingCharacters(in: .whitespacesAndNewlines)
        }
    
    
        subscript (bounds: CountableClosedRange<Int>) -> String {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return String(self[start...end])
        }
    
        subscript (bounds: CountableRange<Int>) -> String {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return String(self[start..<end])
        }
    }
    

    I hope this will help you.