iOS

[Swift]AVSpeechSynthesizerで音声再生

投稿日:2017年12月6日 更新日:

はじめに

こんにちは、nukkyです。
音声読み上げはちょっと今更感が漂いますが、案件で使用したばっかというのと、備忘録兼、初心者向けということで書いていきたいと思います。

 

実装

コード

今回は、シングルトンでどこでも即音声読み上げみたいな形で作りました。
細かい説明は後でとりあえずコードを貼ります。

音声の再生処理は以下の処理です、
引数にAVSpeechUtteranceを指定しますがこのクラスで読み上げの声や言語の設定を行います。

喋らせるテキストと言語を設定します。

音声の読み上げ速度を設定します、3段階ありますが正直Default以外は設定しないかと思います。。。

読み上げる声の高さを設定します、0.5〜2.0の範囲で設定できます
1.0で標準のSiriと同じ高さです、個人の感想ですが1.5だと○ッパーみたいな声になります。

呼び出し

サンプルコードを呼び出す際は以下の呼び出し方になります。

さいごに

音声読み上げいかがでしょうか、ウォークスルーやチュートリアルなどちょっとしたところで使ってみたくなりますね。

page_footer_300rect




page_footer_300rect




-iOS
-

執筆者:


  1. kk より:

    nukky様
    初めてコメントを送付いたします、当方、大阪在住のアプリ開発初心者:kkです。
    非常にわかりやすい記事をありがとうございます。
    独学でアプリ開発をする中で、WEB上の色々な記事を検索、勉強してきましたが、
    なかなかうまく行かず、限界を感じているところですが、『RE:ENGINES』の活動を
    読ませて頂き、一度相談させて頂こうと思い、本コメントを送信させて頂いております。
    見当違いであれば大変失礼となってしまい申し訳ありません。

    私は、下記のような質問があるのですが、本内容に対する回答を頂くにあたり、
    有料で受け取れる場合は、そのお見積り金額を頂ければありがたいです。
    また、他に必要な事項があればご指摘下さい。
    お手数をおかけしますが、どうか、よろしくお願いします。

    私は、現在、
    ・自分で入力した文章を、iPhoneに喋ってもらうアプリを作っております。
    その中で、下記の2つの課題が起こり、アプリ開発が止まってしまっております。

    課題1:for文を使った、繰り返し発声をしたいが、pre/postUtteranceDelayを
        使った待機時間を設定した場合、発声開始、停止を繰り返すと、簡単に
        動かなくなってしまう。
        (開始、停止、一時停止等が動かなくなり、アプリ再起動しないと復帰しない)
    アプリは以下の簡単な構成です。
     ①文章を、指定した回数で、幾度か(10回等)発声させる
     ②開始、停止、一時停止ボタンで制御する
     ③発声の前または後に、待機時間を作る
    という簡単なアプリを作ったのですが、上記③の機能を
    使うと、発声開始と停止を何度か繰り返す(ボタンを押す)と、
    アプリが簡単に止まってしまい、動かなくなってしまします。
    上記③をゼロにすると、止まってしまう現象は起こりません。
    何か、足りないコマンドがあるのでしょうか。

    サンプルコードは、以下の通りです。
    環境は、swift4(Xcode9.4.1)です。
    —————————————————————————————————————
    import UIKit
    import AVFoundation
    class ViewController: UIViewController, AVSpeechSynthesizerDelegate{
    var talker = AVSpeechSynthesizer()
    let utterance = AVSpeechUtterance()
    var counter = 0
    @IBOutlet weak var label: UILabel!
    @IBAction func didTapButton(_ sender: UIButton){ //Start/Pause button
    if talker.isPaused{
    talker.continueSpeaking()
    print(“continue”)
    }else{
    talker.continueSpeaking()
    print(“play”)
    }
    for n in 0…10{ //for(1)
    label.text = “I’m looking forward to seeing you.”
    let utterance = AVSpeechUtterance(string:self.label.text!)
    utterance.voice = AVSpeechSynthesisVoice(language: “en-US”)
    utterance.rate = 0.5
    utterance.pitchMultiplier = 0.5

    //読み上げ前の待機時間
    utterance.preUtteranceDelay = 0
    //読み上げ後の待機時間
    utterance.postUtteranceDelay = 1

    self.talker.speak(utterance)
    self.talker.delegate = self

    }// for(1)
    } //Start/Pause

    //playback finish
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance)
    {
    print(“***Finish***”)
    }

    //STOP
    @IBAction func speechStop(_ sender: UIButton) {//Stop Button
    talker.stopSpeaking(at: AVSpeechBoundary.immediate)
    print(“stop”)
    }
    //Pause
    @IBAction func speechPause(_ sender: UIButton) {//Pause Button
    talker.pauseSpeaking(at: AVSpeechBoundary.immediate)
    print(“pause”)
    }

    override func viewDidLoad() {
    super.viewDidLoad()
    self.talker.delegate = self
    }

    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    }
    }
    ———————————————————————————————————
    課題2:ヘッドフォンを使用してアプリを動作させている場合に、ヘッドフォンが
        抜けたら動作を停止させたいが、WEBで見つけた下記コマンドを、class下に
        実装したが動作しない。

    参考記事は、swift3対応と書かれており、実装後、Xcodeの指示通りにswift4対応に
    書き直したのですが、動作しておりません。
    また、swift4対応の記事を見つけることができず、間違い等のご指摘、動作原理を
    御教示頂けないでしょうか。

    参考URL:https://nackpan.net/blog/2015/09/29/ios-swift-phone-call-and-route-change/
    ————————————————————————————————————————————
    //ここから、ヘッドフォン抜き差し対応追加(9/1)
    /// 電話による割り込みと、オーディオルートの変化を監視します
    func addAudioSessionObservers() {
    AVAudioSession.sharedInstance()
    let center = NotificationCenter.default
    center.addObserver(self, selector: #selector(self.handleInterruption), name: NSNotification.Name.AVAudioSessionInterruption, object: nil)
    center.addObserver(self, selector: #selector(self.audioSessionRouteChanged), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil)
    //center.addObserver(self, selector: #selector(ViewController.handleInterruption(_:)), name: NSNotification.Name.AVAudioSessionInterruption, object: nil)
    //center.addObserver(self, selector: #selector(ViewController.audioSessionRouteChanged(_:)), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil)
    }
    /// Interruption : 電話による割り込み
    @objc func handleInterruption(_ notification: Notification) {

    let interruptionTypeObj = (notification as NSNotification).userInfo![AVAudioSessionInterruptionTypeKey] as! NSNumber
    if let interruptionType = AVAudioSessionInterruptionType(rawValue:
    interruptionTypeObj.uintValue) {

    switch interruptionType {
    case .began:
    // interruptionが開始した時(電話がかかってきたなど)
    // 音楽は自動的に停止される
    // (ここにUI更新処理などを書きます)

    //
    break
    case .ended:
    // interruptionが終了した時の処理
    //
    break
    }
    }
    }
    /// Audio Session Route Change : ルートが変化した(ヘッドセットが抜き差しされた)
    @objc func audioSessionRouteChanged(_ notification: Notification) {
    let reasonObj = (notification as NSNotification).userInfo![AVAudioSessionRouteChangeReasonKey] as! NSNumber
    if let reason = AVAudioSessionRouteChangeReason(rawValue: reasonObj.uintValue) {
    switch reason {
    case .newDeviceAvailable:
    print(“New connect”)
    // 新たなデバイスのルートが使用可能になった
    // (ヘッドセットが差し込まれた)
    break
    case .oldDeviceUnavailable:
    print(“Disconnected”)
    // 従来のルートが使えなくなった
    // (ヘッドセットが抜かれた)
    // 音楽は自動的に停止される
    // (ここにUI更新処理などを書きます)
    break
    default:
    break
    }
    }
    }
    ——————————————————————————————————————
    以上、一方的に送信させて頂くため、失礼等があればご指摘下さい。
    何卒よろしくお願い致します。

    • nukky より:

      kk様
      コメント拝見させていただきました。
      全体がわからないため予測にはなりますが頂いているコードから予測した結果をお返しします。
      課題1に関してですがおそらく、Delayをしている最中が再生状態じゃないのでpauseSpeakingがうまく働いていないのだと思います。
      また、一時停止からの再生など制御を行うならばfor文を使った再生ではなく、AVSpeechSynthesizerDelegateで状態を管理した方が良いと思います。
      (例えば連続で再生するならば再生回数の状態を保持しdidFinishのタイミングで次の再生を行うなど現在の再生状況を管理する)
      課題2に関しては動作しないという状態がどのような状態を指しているのかがわからないのですが、addObserverに関しては問題なさそうに見えるので
      AVAudioSessionRouteChangeのタイミングでselectorに指定したメソッドが呼び出せない状況が考えられます。
      一旦AppDelegateでaddObserverを用意してみて、そもそもAVAudioSessionRouteChangeが呼ばれているのか切り出して確認してみると良いかもしれません。

      こちらの内容に関して引き続き確認事項がある場合や、ブログ記事以外にも私たちの活動への興味や個人の学習、ご依頼などあれば、下記よりお問い合わせください。
      https://re-engines.com/about/

      • kk より:

        nukky様
        kkです。
        返信、ありがとうございました。
        頂いたアドバイスで、再検討して見ます。
        取り急ぎ、返信いたします。

comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

swift

SnapKItをつかってコードでも簡単にAutoLayout実装

1 はじめに2 準備3 実装3.1 準備3.2 AutoLayoutを指定3.3 UIAlertControllerのカスタム4 さいごに はじめに こんにちは、nukkyです。 iOSの実装中にコー ...

swift

UITableViewでTableViewCell(Xib)を使ってみた

1 はじめに1.1 前提条件1.2 事前準備2 TableViewを準備3 Xibを準備4 tableviewに表示するcellにxibを指定する5 さいごに はじめに どうも、はじめです。 今回はX ...

swift

Swift3でRealmを使ってみる

1 はじめに1.1 前提条件2 事前準備2.1 Realmのインストール・設定2.1.1 Carthageファイルの生成2.1.2 CarhageにてRealmをインストール2.1.3 Realmをイ ...

swift

[Swift]PDFKitでPDFの表示

1 はじめに1.1 前提条件2 PDKitの概要3 実装3.1 PDFの表示4 さいごに はじめに こんにちは、nukkyです。 以前、PDFKitを使わないでPDFを表示する方法を書きましたが、今回 ...

[初心者向け]Xcodeの使い方(よく使うショートカットキーとエディタ)

1 はじめに1.1 前提条件2 ショートカットキー2.1 コメントアウト2.2 インデント2.3 ファイル内検索2.4 プロジェクト内検索2.5 クリーン2.6 ビルド2.7 ラン3 エディタ3.1 ...

フォロー

follow us in feedly

AppLink

英語

page_side_300rect

2017年12月
« 11月 1月 »
 12
3456789
10111213141516
17181920212223
24252627282930
31 

アプリ情報

目標を達成したい方を応援する、TODOアプリもリリースしております。 下記のアイコンから無料でダウンロードできます。

Web版MyCoach

私たちはより広い方にコーチングを知ってもらいたいと考えています。 下記のサイトにて、コーチの方々を紹介しておりますので、よろしければご覧ください。