--- a/OSXOperatingSystem.st Sun May 20 09:50:05 2018 +0200
+++ b/OSXOperatingSystem.st Sun May 20 09:50:13 2018 +0200
@@ -885,13 +885,72 @@
"
!
-speak:aString
- "use 'say ...'"
+speak:aString voiceName:voiceName
+ "uses 'say ...'
+ The given voiceName is translated via the voiceMapping to one of
+ my installed standard voices, or passed as-is, if no mapping is found."
+
+ |mapping voiceUsed cmd|
+
+ mapping := self voiceMapping detect:[:v | v key = voiceName] ifNone:[(voiceName -> voiceName)].
+ voiceUsed := mapping value.
+ (voiceUsed isNil or:[voiceUsed = 'default']) ifTrue:[
+ cmd := 'say "%2"'
+ ] ifFalse:[
+ cmd := 'say -v "%1" "%2"'
+ ].
+ ^ self executeCommand:(cmd bindWith:voiceUsed with:aString withCEscapes)
+
+ "portable:
+ self speak:'hello world - this is the default voice' voiceName:nil
+ self speak:'hello world - this is a computer voice' voiceName:'computer'
+ self speak:'hello world - this is a male voice' voiceName:'male'
+ self speak:'hello world - this is a female voice' voiceName:'female'
+
+ non-portable (OSX only):
+ self speak:'hello world - this is a scottish female voice' voiceName:'Fiona'
+ self speak:'hello world - this is a german female voice' voiceName:'Anna'
+ self speak:'hello world - this is a chinese female voice' voiceName:'Ting-Ting'
+ self speak:'hello world - this is an indian female voice' voiceName:'Veena'
+ self speak:'hello world - this is a french female voice' voiceName:'Amelie'
+ self speak:'hello world - this is an italian female voice' voiceName:'Alice'
+ self speak:'hello world - this is a russian female voice' voiceName:'Milena'
- ^ self executeCommand:('say "%1"' bindWith:aString)
+ self speak:'hello world - this is a pipe organ speaking' voiceName:'Pipe Organ'
+ self speak:'hello world - happy birthday to you' voiceName:'Good News'
+ "
+!
+
+voiceInfo
+ "return a list of available voices plus info:
+ for each available voice, a triple is returned, containing:
+ voiceName language_territory comment/description
+ "
+
+ ^ (PipeStream outputFromCommand:'say -v ?')
+ asCollectionOfLines
+ collect:[:l |
+ |s name lang comment|
+
+ s := l readStream.
+ "/ skip forward for two separators
+ [
+ [s next isLetterOrDigit] whileTrue:[].
+ s peek isLetterOrDigit
+ ] whileTrue.
+ name := l copyFrom:1 to:s position - 1.
+ s skipSeparators.
+ lang := s upToSeparator.
+ s skipSeparators.
+ s next == $# ifTrue:[
+ s skipSeparators.
+ comment := s upToEnd utf8Decoded.
+ ].
+ { name . lang . comment }
+ ]
"
- self speak:'hello world'
+ OperatingSystem voiceInfo
"
! !