How to convert text to speech for OSX in Swift playground
NSSpeechSynthesizer
's .startSpeaking
needs to execute in a background task, but by default this is not possible in a Playground.
You can enable it by importing PlaygroundSupport
and setting asynchronous mode, like this:
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
Swift playgrounds ios 10 text to speech command code
utterance: AVSpeechUtterance
is just an editor placeholder that tells you what you should put there:
synthesizer.speak(utterance: AVSpeechUtterance)
You need to call it passing it the utterance object you created:
synthesizer.speak(utterance)
To get it to speak, you need a few more lines. Here is the complete code:
import AVFoundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: "Say Hello")
utterance.rate = 0.5
synthesizer.speak(utterance)
speech to text macOS swift playground
It seems like the Speech library is only available on iOS, so you're out of luck with SFSpeechRecognizer. NSSpeechRecognizer
could be an alternative but requires you to give a list of words for it to recognize from (rather than recognizing from any arbitrary word).
Where are the reference strings for NSVoiceLocaleIdentifier?
Stitching together a few things--first credit where credit is due, thanks to Eric Aya for explaining how to get an Xcode playground to do speech synthesis, George Warner for sample code printing out the available voices and locations, and of course Matt in the comment above who oriented me to a working path. Unless I have this very wrong, it would appear that various voices are oriented around specific languages. So I believe you set the voice for the location.
Here's a setup for an Xcode playground:
import Cocoa
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
Here's how to get a voice speaking in Spanish:
let synth = NSSpeechSynthesizer()
synth.setVoice( "com.apple.speech.synthesis.voice.paulina.premium" )
synth.startSpeaking( "Hola Mundo mañana" )
How did I know that com.apple.speech.synthesis.voice.paulina.premium spoke in Spanish?
for voiceIdentifierString: String in NSSpeechSynthesizer.availableVoices() {
var voiceLocaleIdentifier = ( NSSpeechSynthesizer.attributes( forVoice: voiceIdentifierString )[ NSVoiceLocaleIdentifier ] as! String )
print( "\(voiceIdentifierString) speaks \(voiceLocaleIdentifier)" )
}
If I'm wrong in my assumptions, please correct me. I'm posting this for anyone who may encounter a similar need.
iOS Text To Speech Api
Since iOS 7 you have a new TTS Api.
In Objective C
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc]init];
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"Some text"];
[utterance setRate:0.2f];
[synthesizer speakUtterance:utterance];
In Swift
let synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: "Some text")
utterance.rate = 0.2
You can also change the voice like this :
utterance.voice = AVSpeechSynthesisVoice(language: "fr-FR")
And then speek
In Swift 2
synthesizer.speakUtterance(utterance)
In Swift 3
synthesizer.speak(utterance)
Don't forget to import AVFoundation
Helpful methods
You can Stop or Pause all speech using these two methods :
- (BOOL)pauseSpeakingAtBoundary:(AVSpeechBoundary)boundary;
- (BOOL)stopSpeakingAtBoundary:(AVSpeechBoundary)boundary;
The AVSpeechBoundary
indicates if the speech should pause or stop immediately (AVSpeechBoundaryImmediate
) or it should pause or stop after the word currently being spoken (AVSpeechBoundaryWord
).
Check the AVSpeechSynthesizer Doc
NSSpeechSynthesizer get Siri voices on macOS
Siri voice
I'm not aware of any trick to make the Siri voice available and I'm afraid it's impossible to make it working via public API.
- Both
NSSpeechSynthesizer
andAVSpeechSynthesizer
do utilizeSpeechSynthesis.framework
(included in theApplicationServices.framework
). - Quickly checked it and the function
BuildDefaultVoiceList(bool)
checks bundle identifier (viaPermitAllVoices
which compares it withcom.apple.VoiceOverUtility
,com.apple.VoiceOver
,com.apple.VoiceOverUtilityCacheBuilder
). - There're other checks probably.
All the voices are stored in the /System/Library/Speech/Voices
folder. Tried to copy the voice, change Info.plist
values to make it look like another voice, but still not available/working.
How far do you want to go? Do you want to disable SIP, modify framework, preload your stuff, ... Is it worth it?
AVSpeechSynthesizer
on macOS
It works, but it's buggy and you have to kill the service from time to time.
List of available voices
AVSpeechSynthesisVoice.speechVoices().forEach { voice in
print("Name: \(voice.name) Language: \(voice.language) Identifier: \(voice.identifier)")
}
Speak
let utterance = AVSpeechUtterance(string: "Ahoj, jak se máš?")
utterance.voice = AVSpeechSynthesisVoice(identifier: "com.apple.speech.synthesis.voice.zuzana.premium")
let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(utterance)
Doesn't speak?
All the following methods (delegate) are called when you call speak(utterance)
and it works as it should:
speechSynthesizer(_:didStart:)
speechSynthesizer(_:willSpeakRangeOfSpeechString:utterance:)
speechSynthesizer(_:didFinish:)
Something's wrong if you get just the speechSynthesizer(_:didCancel:)
method call and you have to kill the speechsynthesisd
process:
kill `pgrep speechsynthesisd`
Then try again, it fixes the issue for me.
Additional voices installation
- System Preferences - Accessibility - Speech
- System Voice - click & scroll down & select Customize...
- Select additional voice to install
Xcode: Any way to refresh/re-run the playground?
Try Editor
> Execute Playground
from Xcode menu
I don't know what Reset Playground
is, by the way.
Converting a Vision VNTextObservation to a String
Apple finally updated Vision to do OCR. Open a playground and dump a couple of test images in the Resources folder. In my case, I called them "demoDocument.jpg" and "demoLicensePlate.jpg".
The new class is called VNRecognizeTextRequest
. Dump this in a playground and give it a whirl:
import Vision
enum DemoImage: String {
case document = "demoDocument"
case licensePlate = "demoLicensePlate"
}
class OCRReader {
func performOCR(on url: URL?, recognitionLevel: VNRequestTextRecognitionLevel) {
guard let url = url else { return }
let requestHandler = VNImageRequestHandler(url: url, options: [:])
let request = VNRecognizeTextRequest { (request, error) in
if let error = error {
print(error)
return
}
guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
for currentObservation in observations {
let topCandidate = currentObservation.topCandidates(1)
if let recognizedText = topCandidate.first {
print(recognizedText.string)
}
}
}
request.recognitionLevel = recognitionLevel
try? requestHandler.perform([request])
}
}
func url(for image: DemoImage) -> URL? {
return Bundle.main.url(forResource: image.rawValue, withExtension: "jpg")
}
let ocrReader = OCRReader()
ocrReader.performOCR(on: url(for: .document), recognitionLevel: .fast)
There's an in-depth discussion of this from WWDC19
Related Topics
Sending an Email from Your App with an Image Attached in Swift
Metal Ray Tracing - Scenekit or Realitykit
Swiftui Scroll/List Scrolling Events
Non Exhaustive List When Handling Errors Inside a Class Function in Swift
Anyobject Try Cast to Equatable
Create JSON Object from Class in Swift
How to Get Data from a Swift Nsurlsession
Add Skin Tone Modifier to an Emoji Programmatically
Swift Pattern Matching with Enum and Optional Tuple Associated Values
Using Vapor-Fluent to Upsert Models
Core Data: Rename Attribute Without Having Issues with Users and Their Current Data
Xctestcase Optional Instance Variable
Using State Variables as Inputs to a Func in Swiftui
Is There a Technical Reason to Use Swift's Caseless Enum Instead of Real Cases
What Is the Markup Format for Documentation on the Parameters of a Block in Swift