#31 使用 AVSpeechSynthesizer 我們一起學兔子叫
用 AVSpeechSynthesizer 做出進階的語音告白與動物叫聲的 APP
初始 APP 規劃
這個作業原本是設計講笑話的APP,會加入下列功能(但最後換成別的內容)
- 唸出 text field 輸入的文字。
- 利用 slider 控制講話的速度。
- 利用 slider 控制講話的音調。
- 利用 label 顯示 slider 的數值。
- 利用 slider 控制講話的音量。
- 加入多個講話的 button。
講笑話的APP 的版面規劃
但是因為規劃為三個頁面,控制播放的元件是放在第三頁
如果要拉線開雙視窗,右邊那頁開出來的頁面,不是我們要的 ViewController.swift 那頁
請教彼得潘後有給作法,課程還沒教到多頁面拉線的方法,但是因為看起來有點複雜還是先留著以後教到多頁面再做
彼得潘給的資料 做多畫面時 作法參考
新的畫面類別會是 UIViewControler ,要改的話要自訂類別,因為目前我們只教到一個畫面,所以如果做多個畫面會比較難
APP 重新設計 一起學兔子叫:
重新設計單頁面的APP,修修改改加上之前笑話 APP 做到這個 APP 已經是第四版了
加上自己很龜毛,畫面設計一定要找可愛的插圖,所以花了點時間
內容參考自己之前做過的作業以及同學的作業
之前寫的簡單版講話機器人:
規劃二個區塊為
- 任意輸入文字講話
- 點擊動物圖案講話:(有三種發音) 叫聲、動物中文名、動物英文名
Xcode 排版完的畫面
在 storyboard 做小動物們的排版有點小技巧,遇到這種一個區塊很多物件的設計時,最好開一個 View 把他們都包進去。
這樣如果要移動位置、調整座標時,可以只移動外層的 View 就好,不用每隻動物都要移動
連結元件與程式,拉 Outlet
完成第一部分任意輸入文字,由APP播放語音
語音必須要載入 AVFoundation
import UIKit
import AVFoundationclass ViewController: UIViewController {@IBAction func changeSlider(_ sender: Any) {
speakRateText.text = String(format: "%.2f", speakRate.value)
speakMultiplierText.text = String(format: "%.2f", speakMultiplier.value)
}
@IBOutlet weak var sayTextField: UITextField!
@IBOutlet weak var speakMultiplierText: UILabel!
@IBOutlet weak var speakRateText: UILabel!
@IBOutlet weak var speakMultiplier: UISlider!
@IBOutlet weak var speakRate: UISlider!
@IBAction func SpeakButton(_ sender: UIButton) {
let utterance = AVSpeechUtterance(string: sayTextField.text!)
let synthesizer = AVSpeechSynthesizer()
utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
utterance.rate = speakRate.value
utterance.pitchMultiplier = speakMultiplier.value
synthesizer.speak(utterance)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}}
動物按鈕分別拉 Outlet
Button 命名:拉 Outlet 之前都一樣叫 Button,拉過 Outlet 之後會依照給元件的命名呈現
拉 Outlet 連結畫面跟程式,可以從 Storyboard 上的元件按下 Control + 滑鼠拉線,但最好是從左側的列表拉,比較不會跑掉或拉動到元件的位置
動物的叫聲
在英文裡的擬聲詞
🐰 兔子 mumble
🐱 貓咪 meow
🐶 狗狗 woof
🐣 小雞 cluck
🐒 猴子 screech, gibber
🦁 獅子 roar
🐻 小熊 growl
🐯 老虎 roar, howl
🐷 小豬 oink
🐘 大象 pawoo
🐮 母牛 moo
🐦 小鳥 tweet tweet
把APP安裝到手機上測
安裝到手機的操作方式與錯誤處理
手機截圖
這邊還有個問題要處理,上方任意輸入文字完成後,鍵盤要收起來才不會擋到下面的小動物們
點擊畫面空白處讓鍵盤收起
override func viewDidLoad() {
super.viewDidLoad()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyBoard))
self.view.addGestureRecognizer(tap) // to Replace "TouchesBegan"
}
@objc func dismissKeyBoard() {
self.view.endEditing(true)
}
操作影片錄影
語音輸入「王老先生有塊地」結果辨識成「王老先生有快遞」
其實有快遞也是很合理的😂
完整程式碼
import UIKit
import AVFoundationclass ViewController: UIViewController {
// 輸入文字、音調速度
@IBOutlet weak var sayTextField: UITextField!
@IBOutlet weak var speakMultiplierText: UILabel!
@IBOutlet weak var speakRateText: UILabel!
@IBOutlet weak var speakMultiplier: UISlider!
@IBOutlet weak var speakRate: UISlider!
// 播放告白
@IBOutlet weak var talkButton: UIButton!
// 叫聲、中英文
@IBOutlet weak var languageSegment: UISegmentedControl!
// 動物按鈕
@IBOutlet weak var rabbitBtn: UIButton!
@IBOutlet weak var chickBtn: UIButton!
@IBOutlet weak var bearBtn: UIButton!
@IBOutlet weak var elephantBtn: UIButton!
@IBOutlet weak var cowBtn: UIButton!
@IBOutlet weak var lionBtn: UIButton!
@IBOutlet weak var tigerBtn: UIButton!
@IBOutlet weak var monkeyBtn: UIButton!
@IBOutlet weak var dogBtn: UIButton!
@IBOutlet weak var catBtn: UIButton!
@IBOutlet weak var pigBtn: UIButton!
@IBOutlet weak var birdBtn: UIButton!
// 音調速度
@IBAction func changeSlider(_ sender: Any) {
speakRateText.text = String(format: "%.2f", speakRate.value)
speakMultiplierText.text = String(format: "%.2f", speakMultiplier.value)
}
// 告白按鈕
@IBAction func SpeakButton(_ sender: UIButton) {
let utterance = AVSpeechUtterance(string: sayTextField.text!)
let synthesizer = AVSpeechSynthesizer()
utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
utterance.rate = speakRate.value
utterance.pitchMultiplier = speakMultiplier.value
synthesizer.speak(utterance)
}
// 動物名稱的觸發,是點選按鈕發聲所以不用做segment的func
@IBAction func animalTalk(_ sender: UIButton) {
var animalmessage = AVSpeechUtterance()
// 用if做中文選項後做動物按鈕定義
if languageSegment.selectedSegmentIndex == 0{
if sender == catBtn{
animalmessage = AVSpeechUtterance(string: "貓咪")
}
if sender == rabbitBtn{
animalmessage = AVSpeechUtterance(string: "兔子")
}
if sender == dogBtn {
animalmessage = AVSpeechUtterance(string: "狗狗")
}
if sender == chickBtn{
animalmessage = AVSpeechUtterance(string: "小雞")
}
if sender == monkeyBtn{
animalmessage = AVSpeechUtterance(string: "猴子")
}
if sender == lionBtn{
animalmessage = AVSpeechUtterance(string: "獅子")
}
if sender == pigBtn{
animalmessage = AVSpeechUtterance(string: "小豬")
}
if sender == bearBtn{
animalmessage = AVSpeechUtterance(string: "小熊")
}
if sender == tigerBtn{
animalmessage = AVSpeechUtterance(string: "老虎")
}
if sender == elephantBtn{
animalmessage = AVSpeechUtterance(string: "大象")
}
if sender == cowBtn{
animalmessage = AVSpeechUtterance(string: "牛")
}
if sender == birdBtn{
animalmessage = AVSpeechUtterance(string: "小鳥")
}
// 語言設定一定要放發音後面
animalmessage.voice = AVSpeechSynthesisVoice(language: "zh-TW")
}
// 接著做英文發音
else if languageSegment.selectedSegmentIndex == 1{
if sender == catBtn{
animalmessage = AVSpeechUtterance(string: "cat")
}
if sender == rabbitBtn{
animalmessage = AVSpeechUtterance(string: "rabbit")
}
if sender == dogBtn {
animalmessage = AVSpeechUtterance(string: "dog")
}
if sender == chickBtn{
animalmessage = AVSpeechUtterance(string: "chick")
}
if sender == monkeyBtn{
animalmessage = AVSpeechUtterance(string: "monkey")
}
if sender == lionBtn{
animalmessage = AVSpeechUtterance(string: "lion")
}
if sender == pigBtn{
animalmessage = AVSpeechUtterance(string: "pig")
}
if sender == bearBtn{
animalmessage = AVSpeechUtterance(string: "bear")
}
if sender == tigerBtn{
animalmessage = AVSpeechUtterance(string: "tiger")
}
if sender == elephantBtn{
animalmessage = AVSpeechUtterance(string: "elephant")
}
if sender == cowBtn{
animalmessage = AVSpeechUtterance(string: "cow")
}
if sender == birdBtn{
animalmessage = AVSpeechUtterance(string: "bird")
}
animalmessage.voice = AVSpeechSynthesisVoice(language: "en-US")
}
// 叫聲
else{
if sender == catBtn{
animalmessage = AVSpeechUtterance(string: "meow meow meow")
}
if sender == rabbitBtn{
animalmessage = AVSpeechUtterance(string: "mumble mumble mumble")
}
if sender == dogBtn {
animalmessage = AVSpeechUtterance(string: "woof woof woof")
}
if sender == chickBtn{
animalmessage = AVSpeechUtterance(string: "cluck cluck cluck")
}
if sender == monkeyBtn{
animalmessage = AVSpeechUtterance(string: "gibber gibber gibber")
}
if sender == lionBtn{
animalmessage = AVSpeechUtterance(string: "roar roar roar")
}
if sender == pigBtn{
animalmessage = AVSpeechUtterance(string: "oink oink oink")
}
if sender == bearBtn{
animalmessage = AVSpeechUtterance(string: "growl growl growl")
}
if sender == tigerBtn{
animalmessage = AVSpeechUtterance(string: "howl howl howl")
}
if sender == elephantBtn{
animalmessage = AVSpeechUtterance(string: "pawoo pawoo pawoo")
}
if sender == cowBtn{
animalmessage = AVSpeechUtterance(string: "moo moo moo")
}
if sender == birdBtn{
animalmessage = AVSpeechUtterance(string: "tweet tweet tweet")
}
animalmessage.voice = AVSpeechSynthesisVoice(language: "en-US")
}let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(animalmessage)
}
override func viewDidLoad() {
super.viewDidLoad()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyBoard))
self.view.addGestureRecognizer(tap) // to Replace "TouchesBegan"
}
@objc func dismissKeyBoard() {
self.view.endEditing(true)
}}