利用 AVSpeechSynthesizer 講話

前期提要:

利用 AVSpeechSynthesizer 講話

首先要import 才能使用AVSpeechSynthesizer這個函示庫

import AVFoundation

再來把元件連結Storyboard

@IBOutlet weak var speakTextfield: UITextField!@IBOutlet weak var speakSpeed: UISlider!@IBOutlet weak var speakRate: UISlider!@IBOutlet weak var speakHistoryTableView: UITableView!@IBOutlet weak var speakPlayButton: UIButton!

因為有加入歷史資料功能,所以有UITableView。

宣告變數(兩個內建語音合聲器與發聲器以及預設歷史資料)

var speakUtterance = AVSpeechUtterance()var speakSynthesizer = AVSpeechSynthesizer()var speakHistory : [SpeakHistory] = [SpeakHistory(speakText: "I Love Swift", speakRate: 1.0, speakSpeed: 1.0)]

我們在viewDidLoad畫面跑完的時候修改預設值,並委託TableView的delegate以及dataSource和AVSpeechSynthesizer的delegate給ViewController

speakRate.minimumValue = 0.5speakRate.maximumValue = 2.0speakRate.value = 1.0// [0.5 - 2] Default = 1speakSpeed.minimumValue = 0.0speakSpeed.maximumValue = 1.0speakSpeed.value = 1.0// [0-1] Default = 1self.speakHistoryTableView.delegate = selfself.speakHistoryTableView.dataSource = selfself.speakSynthesizer.delegate = self

建立語音的類別

class SpeakHistory{var speakText: Stringvar speakRate: Floatvar speakSpeed: Floatinit(speakText: String, speakRate: Float, speakSpeed: Float) {self.speakText = speakTextself.speakRate = speakRateself.speakSpeed = speakSpeed}}

Xcode 14的新功能不用打init直接幫我們建立好,真的很棒!!

播放程式碼:

if(speakSynthesizer.isPaused){speakSynthesizer.continueSpeaking()}else if(speakSynthesizer.isSpeaking){speakSynthesizer.pauseSpeaking(at: AVSpeechBoundary.immediate)}else{if let speakText = speakTextfield.text, !speakText.isEmpty{speakUtterance = AVSpeechUtterance(string: speakText)speakUtterance.pitchMultiplier = speakRate.valuespeakUtterance.rate = speakRate.valuespeakUtterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")speakSynthesizer.speak(speakUtterance)speakHistory.insert(SpeakHistory(speakText: speakText, speakRate: speakRate.value, speakSpeed: speakSpeed.value),at: 0)speakHistoryTableView.reloadData()}}

這裡有判斷speakSynthesizer是否為暫停、播放中,沒有的話就播放新內容,並且抓Slider的Value(包含語速及語調),當speakSynthesizer播放就新增一筆資料在TableView的頂端使用

陣列.insert(你的資料,at: 陣列的第幾個位置)

speakHistory.insert(SpeakHistory(speakText: speakText, speakRate: speakRate.value, speakSpeed: speakSpeed.value),at: 0)

TableView 回傳有幾個Cell,我們回傳陣列的數量

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return  speakHistory.count}

TableView的資料處理,把speakHistory[第幾筆資料]帶進去cell

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {guard let cell = speakHistoryTableView.dequeueReusableCell(withIdentifier: "speakHistoryCell", for: indexPath) as? SpeakTableViewCell else {return UITableViewCell()}cell.speakText.text = speakHistory[indexPath.row].speakTextcell.speakRate.text = "\(speakHistory[indexPath.row].speakRate)"cell.speakSpeed.text = "\(speakHistory[indexPath.row].speakSpeed)"print("init cell")return cell}

如果點擊Cell,資料會帶入Slider以及Textfield

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {let speak = speakHistory[indexPath.row]speakTextfield.text = speak.speakTextspeakRate.value = speak.speakRatespeakSpeed.value = speak.speakSpeed}

如果向左滑,並點擊刪除

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {if(editingStyle == .delete){speakHistory.remove(at: indexPath.row)speakHistoryTableView.reloadData()}}

輸入AVSpeechSynthesizerDelegate並點選Jump to Definition

或者在 官網文件找到 AVSpeechSynthesizerDelegate

在這裡我們可以看到AVSpeechSynthesizer 開放的Protocol,我們就可以委託ViewController 幫我們監聽 speechSynthesizer的delegate

self.speakSynthesizer.delegate = self

透過委託的方式幫我們更改播放按鈕的Title

delegate程式碼

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {self.speakPlayButton.setTitle("播放", for: .normal)}func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {self.speakPlayButton.setTitle("暫停", for: .normal)}func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {self.speakPlayButton.setTitle("繼續播放", for: .normal)}func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didContinue utterance: AVSpeechUtterance) {self.speakPlayButton.setTitle("暫停", for: .normal)}

Github:

--

--