How can I play sound system with text? - ios

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)
}

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")

Play audio buffers generated by AVSpeechSynthesizer directly

We have a requirement for audio processing on the output of AVSpeechSynthesizer. So we started with using the write method of AVSpeechSynthesizer class to apply processing on top. of it. What we currently have:
var synthesizer = AVSpeechSynthesizer()
var playerNode: AVAudioPlayerNode = AVAudioPlayerNode()
fun play(audioCue: String){
let utterance = AVSpeechUtterance(string: audioCue)
synthesizer.write(utterance, toBufferCallback: {[weak self] buffer in
// We do our processing including conversion from pcmFormatFloat16 format to pcmFormatFloat32 format which is supported by AVAudioPlayerNode
self.playerNode.scheduleBuffer(buffer as! AVAudioPCMBuffer, completionCallbackType: .dataPlayedBack)
}
}
All of it was working fine before iOS 16 but with iOS 16 we started getting this exception:
[AXTTSCommon] TTSPlaybackEnqueueFullAudioQueueBuffer: error -66686 enqueueing buffer
Not sure what this exception means exactly. So we are looking for a way of addressing this exception or may be a better way of playing the buffers.
UPDATE:
Created an empty project for testing and it turns out the write method if called with an empty bloc generates these logs:
Code I have used for Swift project :
let synth = AVSpeechSynthesizer()
let myUtterance = AVSpeechUtterance(string: message)
myUtterance.rate = 0.4
synth.speak(myUtterance)
Can move let synth = AVSpeechSynthesizer() out of this method and declare on top for this class and use.
Settings to enable for Xcode14 & iOS 16 : If you are using XCode14 and iOS16, it may be voices under spoken content is not downloaded and you will get an error on console saying identifier, source, content nil. All you need to do is, go to accessiblity in settings -> Spoken content -> Voices -> Select any language and download any profile. After this run ur voice and you will be able to hear the speech from passed text.
It is working for me now.

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.)

Text to speech conversion in Swift 4

I'm trying to integrate text to speech functionality in my iOS app.
For this I'm using AVSpeechUtterance and AVSpeechSynthesisVoice classes of AVFoundation framework.
extension String {
func speech(with pronunciation: String) {
let utterance = AVSpeechUtterance(attributedString: NSAttributedString(string: self, attributes: [.accessibilitySpeechIPANotation : pronunciation]))
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
let synth = AVSpeechSynthesizer()
DispatchQueue.main.async {
synth.speak(utterance)
}
}
}
The problem I'm facing is with the pronunciation of wind word as verb and noun, i.e.
wind as a verb is pronounced: waɪnd
and wind as a noun is pronounced: wɪnd
The above pronunciation strings follow the International Phonetic Alphabet (IPA).
But, I'm not getting the expected results.
If you want an IPA translation of a specific spelling, I suggest to use the iOS feature located at:
Settings > General > Accessibility > Speech > Pronunciations (iOS 12).
Settings > Accessibility > Spoken Content > Pronunciations (iOS 13)
Once you choose the desired result, you can use it in your code to be vocalized by the speech synthesizer.
EDIT
this solution also doesn't work for me.
I'm quite surprised by your comment because when I follow every steps of the provided link, I get the code snippet hereunder:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let pronunciationKey = NSAttributedString.Key(rawValue: AVSpeechSynthesisIPANotationAttribute)
// let attrStr = NSMutableAttributedString(string: "blablablaNOUN",
// attributes: [pronunciationKey: "ˈwɪnd"])
let attrStr = NSMutableAttributedString(string: "blablablaVERB",
attributes: [pronunciationKey: "ˈwa͡ɪnd"])
let utterance = AVSpeechUtterance(attributedString: attrStr)
let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(utterance)
}
... and when I launch this blank app after changing the iPhone Language in the Settings - General - Language & Region menu, I get the correct pronunciations for the verb and the noun.
Copy-paste the code snippet hereabove and test it by yourself.

AVSpeechSynthesizer High Quality Voices

Is it possible to use the enhanced/high quality voices (Alex in the U.S.) with the speech synthesizer? I have downloaded the voices but find no way to tell the synthesizer to use it rather than the default voice.
Since voices are generally selected by BCP-47 codes and there is only on for US English, it appears there is no way to further differentiate voices. Am I missing something? (One would think Apple might have considered a need for different dialects, but I am not seeing it).
TIA.
Yes, possible to pick from the 2 that seem to be available on my system, like this:
class Speak {
let voices = AVSpeechSynthesisVoice.speechVoices()
let voiceSynth = AVSpeechSynthesizer()
var voiceToUse: AVSpeechSynthesisVoice?
init(){
for voice in voices {
if voice.name == "Samantha (Enhanced)" && voice.quality == .enhanced {
voiceToUse = voice
}
}
}
func sayThis(_ phrase: String){
let utterance = AVSpeechUtterance(string: phrase)
utterance.voice = voiceToUse
utterance.rate = 0.5
voiceSynth.speak(utterance)
}
}
Then, somewhere in your app, do something like this:
let voice = Speak()
voice.sayThis("I'm speaking better Seppo, now!")
This was a bug in the previous versions of iOS that the apps using the synthesiser weren't using the enhanced voices. This bug has been fixed in iOS10. iOS10 now uses the enhanced voices.

Resources