見出し画像

【Xcode】【SwiftUi】簡単!音声認識(文字起こし)(リアルタイム)

SwiftUiで音声認識処理をなるべく簡単に実装します。
完成イメージは下記の動画です。

※認識結果自体はXcodeのLogに出力しています。

Speech Framework を使用して音声認識(文字起こし)をおこなっていきます。
今回もなるべく簡単にまとめます。
※ "#"はNote読者向けのコメントになります。

参考:Apple Developer サイト
https://developer.apple.com/documentation/speech >

まずは音声認識用のクラスを作成し、init処理で権限の確認を行います。

    init(){
        //音声認識 : 権限を求めるダイアログを表示する
        SFSpeechRecognizer.requestAuthorization { status in
            switch status {
            case .notDetermined:
                print("許可されていない")
            case .denied:
                print("拒否された")
            case .restricted:
                print("端末が音声認識に対応していない")
            case .authorized:
                print("許可された")
            @unknown default:
                print("その他")
            }
        }
    }

1.続いてAVAudioSessionの設定とAudioのInputNodeを取得します。

#クラスのメンバ変数にAVAudioEngineを定義する。

    //オーディオクラス
    private let mAudio = AVAudioEngine()
#音声認識準備の関数を作成する。

    //音声認識準備処理
    public func prepareRecording(){
        //Audio Session取得
        let audiosession = AVAudioSession.sharedInstance()
        
        do {
            // 1.AVAudioSession設定(オーディオの利用方法をOSに伝える)
            // .record = オーディオ録音用
            // mode: .measurement = オーディオ入出力の測定での利用
            // options: .duckOthers = オーディオ再生時に、バックグラウンドオーディオの音量を下げるオプション。
            try audiosession.setCategory(.record , mode: .measurement , options: .duckOthers )
            
            // options: .notifyOthersOnDeactivation = アプリのオーディオセッションを無効化したことを、システムが他のアプリに通知
            try audiosession.setActive(true, options: .notifyOthersOnDeactivation)
            
            // Audio InputNode 生成
            let inputNode = mAudio.inputNode

            #2.に続く
        } catch let error {
            print("Start Recording Error!!")
            print(error)
        }
    }

2.音声認識リクエストの設定を行います。
 今回はローカル認識かつ中間結果を出力する設定を行います。

#クラスのメンバ変数にSFSpeechAudioBufferRecognitionRequestを定義する。

    //音声認識要求
    private var mRecognitionRequest : SFSpeechAudioBufferRecognitionRequest?
#1.に続けて記述する

            //2.音声認識リクエスト
            //音声認識リクエスト生成
            mRecognitionRequest = SFSpeechAudioBufferRecognitionRequest()
            guard let mRecognitionRequest = mRecognitionRequest else { fatalError("Unable to create a SFSpeechAudioBufferRecognitionRequest object") }
            
            //中間結果取得 有効
            mRecognitionRequest.shouldReportPartialResults = true
            //ローカル認識 有効
            mRecognitionRequest.requiresOnDeviceRecognition = true

            #3.に続く

3.4.重複開始を防ぐため初期化処理を挟みつつ、音声認識イベントの作成を行う。

#クラスのメンバ変数にSFSpeechRecognizer,SFSpeechRecognitionTaskを定義する。
#SFSpeechRecognizerのlocaleには日本語に対応するため"ja_JP"を設定する。

    //音声認識クラス
    private let mRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "ja_JP"))!

    //音声認識状況管理クラス
    private var mRecognitionTalk : SFSpeechRecognitionTask?
#クラスのメンバ変数に終了を検知するためのフラグを作成する。

    //終了フラグ (true = 終了)
    @Published public var isFinal = true
#2.に続けて記述する

            //3.既に開始している場合、一度キャンセルする。
            self.mRecognitionTalk?.cancel()
            self.mRecognitionTalk = nil

            //4.音声認識イベント処理
            self.mRecognitionTalk = mRecognizer.recognitionTask(with: mRecognitionRequest) { result,error in
                //音声認識開始の結果を確認する
                if let result = result {
                    self.isFinal = result.isFinal
                    // 認識結果をプリント
                    print("RecognizedText: \(result.bestTranscription.formattedString)")
                }
                
                //エラー または 終了フラグが設定されている場合は処理を修了する
                if error != nil || self.isFinal {
                    //オーディオ取得を停止する
                    self.mAudio.stop()
                    //inputNodeを空にする
                    inputNode.removeTap(onBus: 0)
                    //音声認識を修了する
                    self.mRecognitionRequest = nil
                    self.mRecognitionTalk?.cancel()
                    self.mRecognitionTalk = nil
                    
                    //音声取得を停止する
                    self.stopRecording()
                }
            }

            #5.に続く

5.InputNodeから取得した音声データを音声認識に渡す

#4.に続けて記述する

            //5.Input Nodeから音声データを取得する。
            let recordingFormat = inputNode.outputFormat(forBus: 0)
            inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
                // 音声を取得したら
                self.mRecognitionRequest?.append(buffer) // 認識リクエストに取得した音声を加える
            }

最後に録音の開始・終了関数を作成することで実装自体は完了となります。

    /// 録音開始
    public func startRecording(){
        do{
            //終了フラグにfalseを設定する
            self.isFinal = false
            
            //1.音声の取得を開始
            mAudio.prepare()
            try mAudio.start()
        }
        catch let error
        {
            print(error)
        }
    }
    
    
    /// 録音停止
    public func stopRecording(){
        //終了フラグをtrueに設定する
        self.isFinal = true
        
        //1.音声の取得を終了
        mAudio.stop()
    }

■認証設定
プロジェクトファイルの TARGETS > Info > Custom iOS Target Properties に2つ追加してください。

#マイク使用
Privacy - Microphone Usage Description

#Speech Framework使用
Privacy - Speech Recognition Usage Description

最後に参考用のソースを有料として置いておきますが上記にiPhone側処理(SwiftUI部分)を付け足しただけなので購入の必要はありませんが、いいねと思った方は購入をぜひお願いします。

ここから先は

6,248字 / 2ファイル

¥ 500

この記事が気に入ったらサポートをしてみませんか?