Skip to content

Instantly share code, notes, and snippets.

@ryanlintott
Last active October 12, 2022 13:47
Show Gist options
  • Save ryanlintott/e1284682216d4e4a90fa474a676fb453 to your computer and use it in GitHub Desktop.
Save ryanlintott/e1284682216d4e4a90fa474a676fb453 to your computer and use it in GitHub Desktop.
Extension to AVSpeechSynthesizer that will speak IPA (International Phonetic Alphabet) strings
import Foundation
import AVFoundation
@available(iOS 10.0, *)
extension AVSpeechSynthesizer {
func speakIPA(_ ipaString: String, voiceIdentifier: String, willSpeak: ((String) -> Void)? = nil) {
//Set the audio session to playback to ignore mute switch on device
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [.interruptSpokenAudioAndMixWithOthers, .duckOthers])
} catch {
print("Error: \(error.localizedDescription)")
}
let mutableAttributedString = NSMutableAttributedString(string: ipaString)
let range = NSString(string: ipaString).range(of: ipaString)
let pronunciationKey = NSAttributedString.Key(rawValue: AVSpeechSynthesisIPANotationAttribute)
mutableAttributedString.setAttributes([pronunciationKey: ipaString], range: range)
let utterance = AVSpeechUtterance(attributedString: mutableAttributedString)
let voice = AVSpeechSynthesisVoice(identifier: voiceIdentifier)
utterance.voice = voice
// Pausing first is safer and may prevent bugs
self.pauseSpeaking(at: .immediate)
self.stopSpeaking(at: .immediate)
// Run some code just before speaking
willSpeak?(utterance.speechString)
print("speakIPA: \(ipaString) voice: \(voice?.identifier ?? "?")")
self.speak(utterance)
}
}
@ryanlintott
Copy link
Author

This code is a bit older and I found a few bugs since. Mainly if you have a different region set on your phone the IPA might sound very strange. The latest version that works better is included in this package > OEVoice

@jhoughjr
Copy link

jhoughjr commented Apr 21, 2022 via email

@jhoughjr
Copy link

jhoughjr commented Apr 21, 2022 via email

@ryanlintott
Copy link
Author

Apple's version of IPA is quite limited. Each voice is mostly limited to the sounds used in the language and accent it was created for. I started with the voice that worked best initially then used a bunch of substitutions to alter the base OE IPA pronunciations and fix various errors as I found them. Often combinations of symbols just wouldn't work so I would swap with similar sounds until I got something close enough. If you check out this file you'll see all the substitutions I used to fine tune the pronunciation. OEVoice.swift

@jhoughjr
Copy link

jhoughjr commented Oct 11, 2022 via email

@ryanlintott
Copy link
Author

The only way to ensure your pronunciations are correct would be to add IPA pronunciations to each word. You need to use IPA symbols (I find this helpful: https://ipa.typeit.org) and there will be some combinations that Apple might not pronounce correctly. If Toki Pona is purely phonetic then maybe you could do a substitution swapping letters for IPA symbols. If however it's more like English where letters may sound different depending on the context you'll probably need to translate each word as the rules would be too complex to code. Either way, once you have IPA pronunciations you think are accurate, then I would try testing with voices, finding one that is the closest fit, then testing with words and making any voice-specific adjustments to IPA characters (like I've done with Old English).

When picking IPA symbols I found this app very helpful as you could hear the different sounds:
https://apps.apple.com/app/id869642260

Also this web app was helpful for testing even though it's using non-Apple voices as it's pretty accurate.
http://ipa-reader.xyz

@jhoughjr
Copy link

jhoughjr commented Oct 12, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment