iOS

[Swift]AVSpeechSynthesizerで音声再生

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

はじめに

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

 

実装

コード

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

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

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

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

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

呼び出し

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

さいごに

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

blog-page_footer_336




blog-page_footer_336




-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

[Swift3] ナビゲーションバーとステータスバーの色変更

1 はじめに1.1 前提条件2 ナビゲーションアイテムの色変更3 ナビゲーションバーの色変更4 ナビゲーションタイトルの色変更5 ステータスバーの色変更6 さいごに はじめに どうも、はじめです。 今 ...

【Swift】WKWebViewのWKUserContentControllerで循環参照

1 はじめに2 循環参照が起きた原因2.1 実装2.2 実装の問題の箇所2.3 修正方法3 さいごに4 おすすめ書籍 はじめに こんにちはsuzukiです。今回はwebviewのWKUserConte ...

swift

Swiftでのパーミッション取得を簡単に

1 はじめに2 準備3 実装3.1 とりあえず表示3.2 カスタマイズ4 さいごに はじめに こんにちは、nukkyです。 今回は、アプリにはつきもののユーザへのパーミッションの確認を 簡単に行えるラ ...

【Swift】Tesseract-OCR-iOSを使って文字の読み取り

1 はじめに2 導入準備2.1 ライブラリのインポート2.2 言語モデルのインポート2.3 カメラを利用する準備3 レイアウト作成4 カメラ撮影5 データ解析5.1 UIImageのエクステンション5 ...

swift

[Swift3] ScrollViewを使ってみた!

1 はじめに2 縦スクロール3 横スクロール4 横スライドでページング5 さいごに6 おすすめ書籍 はじめに どーもはじめです。 ずっと苦手意識というかあまり使いたくないイメージを持っていたのですが、 ...

フォロー

blog-page_side_responsive

2017年12月
 12
3456789
10111213141516
17181920212223
24252627282930
31  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。