kivy/PyAudioで録音アプリを作ってみた

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

kivyはモバイルにも対応したGUIアプリ開発ライブラリです。今回はモバイルアプリを意識して別ページで用意した設定画面をスワイプで呼び出せる録音アプリの作り方を紹介します。録音はPyAudio、波形表示はmatplotlibと連携しています。

こんにちは。wat(@watlablog)です。今回はkivyによるモバイル用録音アプリのPythonコード例を紹介します

この記事の目標と前提知識

目標:動画で完成イメージを確認する

アプリの仕様を色々説明する前に、完成イメージを動画で確認してみましょう。以下のYouTube動画に本アプリをデスクトップ環境で動作させた結果を示します。

詳細は記事の後半で解説しますが、「REC」ボタンをクリックしてマイクによる録音を行うだけのアプリです。

測定時間やフレームサイズといった計測に関係する設定値をスワイプ画面で変更可能としているところにモバイルっぽさを出してみました。

モバイル環境での動作確認はまだですが、設定と録音イベントというシンプルなGUI構成を学ぶことをこの記事の目標とします。

前提知識

kivyの基本コーディングスタイル

kivyPythonコードとkv言語によるコードを組み合わせてGUIアプリを開発します。このページでは基本の書き方の説明をしないので、インストールを含む基礎は以下の記事を参照してください。

Python/kivyでGUIアプリ開発!基本の書き方を学ぶ

matplotlibとの連携方法

録音したデータはmatplotlibを使ってプロットします。kivyでmatplotlibを埋め込む方法は少しやっかいな要素があります。matplotlibをkivy上で使うためには、以下の記事の内容を把握しておいてください。

kivyでmatplotlibを使う時にハマったので解決の備忘録

PyAudioによる録音方法

クロスプラットフォームの録音ライブラリとして、PythonではPyAudioが有名です。WATLABブログでも録音関係のコードはPyAudioで書いていました。

PyAudioはPythonのバージョンやOSによってはインストール時にエラー発生する可能性があります。「Python3.7でPyAudioがインストールできない時の解決法」の記事ではその辺の説明をしています。

録音に関する基本は「PythonのPyAudioで音声録音する簡単な方法」、また今回のアプリでマイクチャンネルを自動取得する方法は「Python/PyAudioでマイクのチャンネルを確認する方法!」に記載しました。

classの知識

GUIアプリを作る時はclassを使って効率よく記述することがほぼ不可欠です。
classとは設計図のようなもので、実際に使うためにはインスタンス化(実体化)させる必要がありました。

Pythonにおけるclassの考え方、初期化時に実行されるコンストラクタメソッドの考え方は「Pythonのクラスの使い方とオブジェクト指向の考え方を理解する」にまとめましたので、こちらも前提知識としています。

また、WATLABブログでは過去に信号処理アプリをwxPythonというGUIアプリ開発ライブラリで作ってみました。

この時はGUIに関する機能(ボタンのクリックやファイルの取り扱い)、信号処理に関する機能…と機能毎にファイルを分けていました。今回もその考え方を踏襲してプログラミングをします。詳しくは以下の記事を参考にしてください。

アプリ完成編:wxPythonで信号処理のGUIアプリをつくろう⑥

しかしこの考え方はIT初心者の筆者が我流でやっているだけなので、もしかしたらもっとスマートな方法があるかも知れません。その点はご了承ください。

kivyとPyAudioで作る録音アプリのPythonコード

動作環境

この記事のコードは以下のPC環境とPython環境で動作を確認しました。今回はデスクトップ環境における動作確認のみとなります。

Mac OS macOS Catalina 10.15.7
CPU 1.4[GHz]
メモリ 8[GB]
Python Python 3.9.6
PyCharm (IDE) PyCharm CE 2020.1
Numpy 1.21.1
Scipy 1.4.1
Pandas 1.0.5
matplotlib 3.4.3
PySoundFile 0.9.0.post1
kivy 2.1.0
Kivy-Garden 0.1.5

コード

my.kv

ボタンやラベルといったウィジェットを記述するkvファイルを以下に示します。ここではPageLayoutを使ってスワイプによる画面遷移を設定しています。kvファイルの名称は「my.kv」です。

スワイプして持ってくる2ページ目はBoxLayoutLabelTextInputを設置しています。設定画面をスワイプで持ってくると、背景色が設定されていないウィジェット(ここではLabel)の背景に1ページ目の画面が映り込みます。

これを防ぐためにcanvas.before:を書いて背景を四角形で作成しました(アルファチャンネルを0.9にすることで少し透明にしています)。

TextInputにはy方向にPaddingを入れていますが、これはデフォルトだとテキストが一番上にはりついて見えるため、少し下げる意味で設定しました(valignでは中央揃えができない)。

Buttonのイベント(on_release)やTextInputの値参照の兼ね合いから、今回はRootクラスのみでGUIを表現しました(idsで検索しやすくしている)。

dspToolkit.py

dspToolkit.pyは信号処理関係の機能をclassにまとめたPythonファイルです。「アプリ完成編:wxPythonで信号処理のGUIアプリをつくろう⑥」で作成したものに録音機能のメソッド(record()get_mic_index())を追加してあります。

使っていないメソッドも一緒に記載していますが、今後のためにそのままにしています。

過去に作ったclassファイルがそのまま使えることに感動!これがオブジェクト指向の強みでしょうか。

main.py

最後はメインの処理を記述するPythonファイルです。このファイルを実行することでプログラムが動作します。

過去記事ではmatplotlibを連携させるために、PlotWidgetRootの2つのclassを使っていました。しかし、それだとそれぞれのクラス間でデータのやり取りを行うのが難しかったので、今回はRootのみを使って主要のイベント処理を行う構成にしました。

Rootの中でDspToolkitクラスをインスタンス化し、self.dsp…を使ってDspToolkitクラス内のプロパティ値を更新していくやり方が個人的には腑に落ちたからです。

クラスが2つ以上あると共通の実体を使うことができないため、データのやり取りに苦労しました(グローバル変数は使いたくない…)。

TextInputに入力させていた計測時間フレームサイズ(1回の録音チャンクで取得するデータポイント数)を読み込んで録音しますが、無効な値とならないようにon_buttonメソッドのif文で制限をかけました(計測時間はとりあえず60を設定。長すぎるとメモリやストレージを圧迫するため)。

実行結果

プログラムを実行すると、冒頭の動画で示したとおりの結果を得ます。
GIF動画も参考に載せておきます。

まとめ

kivyとmatplotlib、PyAudioを連携させてスワイプ機能付きの録音アプリを作ってみました。

wavファイルへの保存や周波数分析といった機能追加は既に過去記事で行っているので、あとはそれほど難しくないでしょう。

今回はできるだけシンプルな構成にまとめたかったのでここで終わりですが、録音結果の周波数分析機能追加等は別記事にしようと思います。

最終的にはiOSアプリまでできると良いのですが、それはまだ未知なので今後に期待。

こんなに短時間で録音アプリができるとは思いませんでした!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

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

SNSでもご購読できます。

コメントを残す

*