Learn AppleScriptObjC
SpeechSynth この章では、簡単な Web ブラウザを作ろうと思っていましたが、今は、App SandBox を設定しないと、外部にアクセスするアプリを試すことができないのですね。そこで、予定を変更して、テキストを読み上げる SpeechSynthesizer を使って、いくつかの GUI パーツの使い方を紹介します。この章では次のことを学習しようと思っています。
- NSSpeechSynthesizer の使い方
- NSTextField からのテキストの読み込み
- NSComboBox の取り扱い
- NSSlider の使い方
- クラスファイルのインポート
このうち、NSSpeechSynthesizer 以外はすべて GUI パーツのクラスです。すべて名前の先頭に NS が付いています。これは NeXTSTEP という会社の略称です。Objective-C はブラッド・コックスという人が作り、スティーブ・ジョブズが自身の会社である NeXTSTEP の主力開発言語としてブラッド・コックスから買い取りました。
AppleScriptObjC では、Objective-C のクラスをそのまま使いますので、Objective-C の導入などを、あらためて考える必要はありません。ただし、いくつかのことについて は、AppleScript 固有のコマンドを使ったほうが便利な時があるみたいです。また、逆に、Objective-C のすべてのクラスが AppleScriptObjC でも使えるとは限らないみたいです。
では、SpeechSynth という Cocoa-AppleScriptプロジェクトを作ってください。そしてウィンドウを次のようにレイアウトします。レイアウトを始める前には、MainMenu.xib の Use Autolayout のチェックは外しておいたほうが良いでしょう。AppleScriptObjC での GUI ファイルは xib だけです。Storyboard はサポートされていません。
使っているパーツは左上が Label、その右横が TextField、左下が Label、そこから右へ、ComboBox、Label、Slider、PushButton となります。そしてスライダーを選択して、右上ペインで、左から4番目の Attributes inspector タブで、次のように設定してください。
- Tick Marks で Position Below を選択し、その下のアップダウンアローフィールドで数値を7にしてください。なおこの設定は、アプリケーションの動作には影響がありません。デフォルトのままでも構いません。
- Value の Minimum を 100 に、Maxmum を 700 に、Current を 200 に設定してください。ここでの設定はアプリケーションの動作に影響します。必ず設定してください。
ターゲットアクションとアウトレットの作成 アクションは、何かをコントロールする目的で作られた GUI パーツに、一つだけ割り当ててることのできるメソッドです。プッシュボタンであればクリックした時に呼び出されるメソッドになります。そしてこのアクションが実際に何をするのかは、別のクラスファイルににコーディング (記述) します。このコーディングをされたクラスファイルをターゲットと呼ぶことから、ターゲットアクションという名前が付いています。アクションは GUI パーツから発せられるイベント (event、出来事) の一つですが、アクションとして指定された以外のイベントは、デリゲート (delegate、委任) という方法でクラスファイルに伝えます。デリゲートについては、のちの章で説明いたします。このターゲットアクションとは逆に、プログラムが実際に何をするかをコーディングされたクラスファイルから、GUI パーツを参照することも必要です。この仕組みをアウトレットといいます。では、AppDelegate.applescript を次のようにコーディングしてください。赤い部分が追加するコードです。
AppDelegate.applescript
script AppDelegate property parent : class "NSObject" -- IBOutlets property theWindow : missing value property textField : missing value property comboBox : missing value property slider : missing value on speech_(object) end speech_コード説明
- property textField : missing value
- テキストフィールドへのアウトレットを宣言しています。
- property comboBox : missing value
- コンボボックスへのアウトレットを宣言しています。
- property slider : missing value
- スライダーへのアウトレットを宣言しています。
- on speech_(object) 〜 end speech_
- プッシュボタンからのアクションを定義しています。内容はまだありません。
Objective-C のコードとは違い、IBAction や IBOutlet という記述は見られません。しかし、これで xib ファイルは認識してくれるみたいです。では、第1章を参照して、xib ファイルでの接続を行ってください。
アプリケーションの初期化 アプリケーションは、起動した時に初期化が必要な場合があります。第1章では Label に、アプリケーションが起動した日時を表示しました。今回は、コンボボックスに、システムが揃えているボイス名の一覧を読み込むようにします。
前章までは、アプリケーションの初期化に awakeFromNib メソッドを使っていました。しかし今では、AppDelegate.applescript に最初から用意されている applicationWillFinishLaunching を使っほうが良いでしょう。このメソッドは、アプリケーションが起動した直後に呼び出されます。-- Insert code here to initialize your application before any files are opened というコメントも書いてありますので、awakeFromNib を使うよりは、こちらを使ったほうが良いでしょう。では、次のようにコードを追加します。赤い部分が追加するコードです。
AppDelegate.applescript
property SpeechSynth : class "NSSpeechSynthesizer" script AppDelegate property parent : class "NSObject" -- IBOutlets property theWindow : missing value property textField : missing value property comboBox : missing value property slider : missing value on speech_(object) end speech_ on applicationWillFinishLaunching_(aNotification) -- Insert code here to initialize your application before any files are opened set voiceNames to {} set voiceStrs to SpeechSynth's availableVoices repeat with obj1 in voiceStrs set voiceNames to voiceNames & (SpeechSynth's attributesForVoice_(obj1))'s VoiceName end repeat comboBox's addItemsWithObjectValues_(voiceNames) end applicationWillFinishLaunching on applicationShouldTerminate_(sender) -- Insert code here to do any housekeeping before your application quits return current application's NSTerminateNow end applicationShouldTerminate_ end scriptコード説明
- 1行目:property SpeechSynth : class "NSSpeechSynthesizer"
- NSSpeechSynthesizer のクラスヘッダファイルを読み込んでいます。この記述がなければ、「SpeechSynth が未定義です」というアラートが出て、アプリケーションをビルドできません。なお、ここを「property SpeechSynth : class "Cocoa"」と記述して Cocoa 関連のすべてのクラスを読み込むこともできます。すべてを読み込んでも、アプリケーションのファイルサイズが、大きくなることはないはずです。
- 13行目: set voiceNames to {}
- 空のリスト (配列) を定義しています。このリストに、お使いのシステム (OS X) に準備されているSpeechSynthesizer のボイス名 (複数で多数) が格納されます。
- 14行目: set voiceStrs to SpeechSynth's availableVoices
- SpeechSynthesizer の availableVoices というメソッドを使って、ボイス識別子の配列を取得しています。そしてその配列を、voiceStrs という変数に格納しています。AppleScriptObjC では、Objective-C の配列 (NSArray) は自動的に AppleScript のリストに変換されます。また、Objective-C の辞書 (NSDictionary) は自動的に AppleScript のレコードに変換されます。なお、ボイス識別子は、文字列ですが非常に長いものです。
- 15行目: repeat with obj1 in voiceStrs
- repeat 文 (繰り返し文) を使って、voiceStrs に収められている値を一つずつ取得しています。この繰り返し文は、voiceStrs から取得するべき値がなくなった時に、自動的に終了します。なお、取得する順番は、in の後が、リストの場合には順番どおりですが、レコードの場合は、予測できません。もともとレコードには、順番という概念がありません。
- 16行目: set voiceNames to voiceNames & (SpeechSynth's attributesForVoice_(obj1))'s
- 13行目で作成した voiceNames リストにボイス名を追加してきます。ボイス名は、15行目で取得した音声識別子を指定して、SpeechSynthesizer に用意されている 特性辞書 (attributesForVoice) から、VoiceName メソッドを使って取得します。
- 17行目: end repeat
- repeat で始まった一連のコードは end repeat で終わらせなければなりません。
- 18行目: comboBox's addItemsWithObjectValues_(voiceNames)
- コンボボックスに addItemsWithObjectValues メソッドを使って、音声名の一覧を表示するように設定しています。このメソッドの引数 (parameter) には、NSArray を渡しますが、ここでもリストから NSArray へ、自動的に変換されます。
ここまできたら、一度ビルドしてみてください。コンボボックスをクリックして、現れるプルダウンメニューに、音声名の一覧が読み込まれていれば、順調に進んでいます。
アクションメソッドの実装 では、最後に、プッシュボタンのアクションメソッドを実装します。今回、実装する メソッドは speech_() です。内容はまだ記述していませんでした。次のように speech__() メソッドを記述してください。赤い箇所が今回追加する部分です。
AppDelegate.applescript
property SpeechSynth : class "Cocoa" script AppDelegate property parent : class "NSObject" -- IBOutlets property theWindow : missing value property textField : missing value property comboBox : missing value property slider : missing value on speech_(object) set voiceNameStr to (comboBox's stringValue()) as strings if voiceNameStr is "Default" then set voiceNameStr to "" end if say ((textField's stringValue()) as strings) speaking rate slider's integerValue() ¬ using voiceNameStr as text end speech_ on applicationWillFinishLaunching_(aNotification) -- Insert code here to initialize your application before any files are opened set voiceNames to {} set voiceStrs to SpeechSynth's availableVoices repeat with obj1 in voiceStrs set voiceNames to voiceNames & (SpeechSynth's attributesForVoice_(obj1))'s VoiceName end repeat comboBox's addItemsWithObjectValues_(voiceNames) end applicationWillFinishLaunching on applicationShouldTerminate_(sender) -- Insert code here to do any housekeeping before your application quits return current application's NSTerminateNow end applicationShouldTerminate_ end scriptコード説明
- 10行目:set voiceNameStr to (comboBox's stringValue()) as strings
- CombBox の stringValue メソッドを使って、現在選択されているコンボボックスの文字列 (ボイス名) を取得しています。コンボボックスから返される文字列は NSString です。そのままでは AppleScript では理解できないので as strings で AppleScript で理解できる文字列に変換しています。そしてその取得した値 (AppleScript の文字列) を voiceNameStr 変数に代入しています。
- 11行目: if voiceNameStr is "Default" then
- 「もし voiceNameStr が "Default" という文字列なら」という if 文です。
- 12行目: set voiceNameStr to ""
- 全行での if 文どおりなら (true) なら voiceNameStr は "" (空の文字列) に置き換えられます。
- 13行目: end if
- if 文は必ず end if で終わらなければなりません。なお、この if 文は、該当しなかった場合 (false) は何もしません。
- 14行目: say ((textField's stringValue()) as strings) speaking rate slider's integerValue() ¬
- AppleScript 固有の say コマンドを使って、テキストフィールドから stringValue で取得した文字列を読み上げています。その際に、NSString を as strings を使って、AppleScript で認識できる文字列に変換しています。speaking rate では、読み上げるスピードを、スライダーから integerValue で取得した値で設定しています。そして、最後の ¬ は、次の行も一行として みなすという AppleScript で用いられる記号です。AppleScript は文の途中で改行するとエラーになります。どうしても改行する場合は、この ¬ 記号を使います。
- 15行目: using voiceNameStr as text
- 前行の終わりで ¬ 記号を使っていますので、この行は、本来、前の行の続きになります。using オプションで読み上げに使う音声を文字列で指定します。ここでは voiceNameStr 変数を指定していますので、コンボボックスで指定したボイス名で読み上げることになります。using オブションが "" (空の文字列) の場合は、システム (お使いの OS X)でデフォルトとして設定されている音声で読み上げることになります。
コーディングが完成しましたら、ビルドして実行してみください。テキストフィールドには読み上げるテキストを入力します。コンボボックスでは読み上げる音声を指定し、スライダーでは読み上げる速度を指定します。
なお、音声によっては、スピード調整がきかないものがあります。これらの音声は、スピードを変えると、その音声の特色がなくなるもののようです。また、音声自体が発声されないものもあります。これらについては、英語や日本語では発音できない言語、例えば中国語やアラビア語などの音声ではないかと思います。
第4章の終わりに 第5章では、この SpeechSynth に、読み上げるテキストを登録したり、登録したテキストを削除したりする機能を追加したいと思います。つまり、アプリケーションにとって重要な機能である、データの追加と削除を実装します。(その前に第3章の「コード説明」をしようと思っています)
無断転載禁止
Copyright 2014. applescript.jp All right reserved.