SwiftUI/iOSアプリ:録音データをChartsでグラフ化する

  • このエントリーをはてなブックマークに追加

iOSデバイスのマイクをAVFoundationで制御し録音機能を使えるようになりました。さらにSwiftUI標準のグラフ表示ライブラリであるChartsも学んだので、いよいよ録音した結果をグラフ表示させたいと思います。ここでは録音やグラフ表示に必要なSwiftUIコードを紹介します。

こんにちは。wat(@watlablog)です。ここでは今まで学んだことを組み合わせて、iOSデバイスへ録音データをグラフ表示させる方法を紹介します

事前準備

Swiftの基本文法

Swift言語で色々なアプリを作るためには、最低限の構造体関数制御構文分岐構文を覚えておく必要があります(それ以外は必要になった時に都度覚えれば良いかと)。

この記事を書いている筆者もSwiftを始めたばかりの初心者であるため、まずは以下の記事で簡単に基礎をまとめました。同じく初心者の人に参考になると思いますので是非ご覧ください。
Swift入門:最低限覚えておく基礎文法の備忘録

Chartsの使い方

SwiftUIには2022年後半にグラフ描画の標準ライブラリとして追加されたChartsがあります。標準なので特にインストールは必要なく、import Chartsで使えます。

Pythonに慣れた筆者としてはなかなか扱いづらいのですが、公式ページとChatGPT-4の助けを借りながらなんとか使い方を以下の記事にまとめました。
SwiftUI:iOS16から追加されたChartsでグラフを作成

AVFoundationの使い方

録音機能の実装にはAVFoundationを使います。コーディングは上記記事に比べChatGPT-4の力を借りる比率が高くなってきた内容ですが、以下の記事に使い方をまとめました。
SwiftでiOSデバイスのマイクを使って録音機能を追加する方法

紹介した上記記事ではボタンを使って録音開始と停止を行い、wavファイルを使って波形を確認してきましたが、このページではようやくChartsを使ったグラフ表示と組み合わせてみます。

AVFoundationで録音したデータをChartsで表示するコード例

動作環境

この記事のコードは以下の環境で動作確認を行いました。Chartsを使う時にXcodeのバージョンについて注意点がありました。エラーが出る方は先ほど紹介したChartsの記事をもう一度参照してください。

                                                            
Mac OSmacOS Ventura 13.2.1
CPU1.4[GHz]
メモリ8[GB]
Xcode Version14.3(14E222b)
Swift Version5.8(swiftlang-5.8.0.124.2 clang-1403.0.22.11.100)
iPhone SE2 OSiOS 16.3.1

全コード

以下に全コードを示します。サンプリングレートを変数として宣言して録音とChartsの両方で共用したり、先ほど紹介した記事とは少し異なりますが基本的には組み合わせです。新規の内容は後述します。

詰まったところ

処理が遅い→処理のスレッドを分けた

Pythonではmatplotlibを用いて直接配列データを可視化できました。これが使いやすかったのですがSwiftとChartsでは自分で構造体のデータ型を定義して(xValueとyValue)、どんな配列サイズでも対応できるよう動的にデータを.mapする必要がありました。

.mapも結局は繰り返し処理でありforと同じです。forループはPythonほどでないにしてもCと比べると遅いです。できれば使いたくないですね。

少しだけ高速化する方法として、データ処理は別スレッドで処理するようにしてみました。「DispatchQueue.global(qos: .userInitiated).async {}」と「DispatchQueue.main.async {}」で非同期処理ができるとのことです。

まだ理解が追いついていない感覚ですが、調べたところこちらのページがわかりやすいと思いました。

Swiftでの非同期処理GDP|ディスパッチキューの解説|DispatchQueue.globalとmain

ボタンの有効化と無効化のタイミング

このアプリはStart RecordingをクリックしたらボタンがStop Recordingに変わり、Stop Recordingをクリックすると録音が停止され文字も元に戻ります。しかしグラフ描画処理にやや時間がかかっており、まだグラフが更新されていないのにStart Recordingを押せてしまいます。

ボタンは.opacityで透明化、.disabledで無効化が可能なため、組み合わせれば視覚的にも機能的にもボタンをユーザーにクリックさせないようにできます。しかし「グラフが更新し終わった時」というタイミングに適切に再度クリック可能な状態に戻す必要があり、このタイミング調査がやや大変でした。

結果的にはisDisplayingDataという変数を用意してプログラム内でtrueとfalseを切り替えたり、.opacityや.disabledの引数に渡したりすることでうまくいったような動作をしています(詳細なデバッグはできていません…)。

録音データをChartsに渡す

結果的にはChatGPT-4に書いてもらったのですが、この部分が最もやっかいだと思います。自分では書けない…。多分本職のプログラマからするともっと良い書き方があると思います。

completionという無名関数のクロージャを使っていたり色々していますが、この関数は録音されたデータを配列とし、その配列を引数にcompletionを実行することにあります。

実行結果(iPhone実機で収録)

こちらが実行結果の例です。自分のiPhone端末にアプリをインストールして実機テストを行ってみました(画面上部に「収録」とありますが、これはiPhone実機で動画を撮ったからです)。画面の縦横変換もスムーズです。

実行結果の動画

ちなみにシミュレータ上で動かすと、僕のPCでは処理がめちゃくちゃ遅くなりました。シミュレータに割り当てられたリソースがしょぼいのか、iPhoneの方がサクサク動きます。
サンプリングレートは4096となっていますが、ここをコード上で12800、44100(Hz)等に変更することでより細かい時間刻みの録音が可能です。

FFT分析をするのであれば、分析したい周波数の2.56倍を設定しておくと良いでしょう。この辺の信号処理的な話は「信号処理」カテゴリを参照してください。

まとめ

今回もChatGPT-4先生におおまかにプログラムを作ってもらい、それを少しずつ紐解いていったり修正したりしてコーディングを行いました。そのため筆者自身はまだまだ初心者の感覚です。

この記事ではこれまで覚えた録音機能とグラフ表示機能を組み合わせたSwiftコードを紹介しました。
AVFoundationやChartsの使い方について、少しでも参考になれば幸いです。録音データをグラフ表示させる…Pythonでは何気なくできたものですが、Swiftだとまだまだ難しいですね。

でも自分のモバイル端末で実際にプログラムが走っているのを見ることができ、久々にワクワク感がこみ上げてきました!
いっぱしのアプリになるまでいろいろいじってみます。

録音機能がそれっぽいアプリになりました!難しいけど面白い…そんな感覚!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。

コメントを残す

*