見出し画像

MATLABでGUI付きアプリ開発 ~ App Designer を使おう(1)~フィルター特性を変えてグラフ表示

MATLABでGUI付きアプリ開発 ~ App Designer を使おう(2)~ストリーミングオーディオをフィルター処理

MATLABでGUI付きアプリ開発 ~ App Designer を使おう(3)~タイマー割り込みでスペクトル表示(非同期FIFOを使う)

MATLABでGUI付きアプリ開発 ~ App Designer を使おう(4)~ フィルター周波数・バンド幅をマウスで操作


前書き

MATLABでGUI付きプログラムを書く方法は何種類かあります。

SimulinkDashboardカスタムGUI
SimulinkでカスタムGUI

ちょっと試すなら Live Editor

オーディオ系の処理で、操作GUIのみで良いから高速化したいときは VST化(要 AudioToolbox)、
MATLABでVSTプラグイン開発 [初級編]~数分?で作れるVST~LMSで無相関プラグイン
夏休みはVST! MATLABで楽々(?)VSTプラグイン開発

しかし、もう少しGUIに凝りたい場合や、他の人と共有したい場合は App Designer が適しています。

MathWorks のオススメも App Designer です。
Getting Started with App Designer

複雑すぎると編集動作もかなり遅くなったりとかしますが。(;¬_¬)
(15000行超えたヤツ、エディターが終了できない・・。)

以前の記事 MATLAB/Simulink で気軽に始める音響信号処理 ~ App Designer で GUIアプリも簡単開発!でも App Designer には触れているのですが、そこそこ機能を詰め込んだのにろくに説明もしていなかったので、今回はもっと単純な例で順を追って解説したいと思います。

一部重複する部分もありますがご容赦ください。

デモの関係で Audio Toolbox を使っていますが、App Designer 自体は MATLAB の基本機能なので、同様のやり方で何にでも使えると思います。

MATLAB Compiler があればスタンドアローンアプリ化できますが、HOME版にはMATLAB Compiler製品自体がないので、HOME版では毎回 appdesigner から、もしくはMATLABコマンドウィンドウからmlappファイルを起動(拡張子なしのファイル名で起動)する形になります。


実際にコードを書いてみよう!

オクターブフィルター

スクリプトで

> octFilt = octaveFilter();
> visualize(octFilt);

とすれば、デフォルトの中心周波数 = 1kHz、バンド幅 = 1 octave のフィルターオブジェクトが生成され、その周波数特性が表示されます。

オクターブフィルター
デフォルト周波数特性

ここでさらに、

> octFilt.CenterFrequency = 100;
> octFilt.Bandwidth = '1/12 octave';

とすれば、特性が変わりグラフも更新されます。

オクターブフィルター
特性を変更

このオブジェクトには、
freqz():周波数応答
getFilter():biquadフィルターオブジェクト変換
なども使用できます。

もちろん、オーディオデータに対して処理を掛けることもできます。

とても便利な関数なので、これを題材に使います。

起動

> appdesigner

で起動し、目的に近いテンプレート、もしくは空のテンプレートから作ることができます。ここで短い対話式チュートリアルを見ることもできます。

App Designer スタートページ

メニューの 新規 -> アプリ または アプリタブの「アプリの設計」でも起動できます。

今回は、「空のアプリ」を選択します。
「名前を付けて保存」で、OctaveFilter1.mlapp として保存します。

次回からは、コマンドウインドウで

> appdesigner OctaveFilter1

と打つか、
ファイルビューで mlapp ファイルをダブルクリックします。

GUIコンポーネントの追加

左ペインのコンポーネントライブラリからコンポーネントを選んでキャンバスに置き、右ペインでラベル等プロパティを書き換えます。

コンポーネントライブラリ 1/2
コンポーネントライブラリ 2/2


・ドロップダウン(BandwidthDropDown)
 ラベル:Bandwidth
 Value、Items を消します(後でコード内で設定します)

BandwidthDropDown

・スピナー(CenterFrequencySpinner)
 ラベル:CenterFrequency
 Value:1000
 Limits:20,20000
 Step:100
 RoundFractionalValues:✔
 とします

CenterFrequencySpinner

・座標軸(UIAxes)
 Title String:Octave Filter
 XLavel String:Frequency (Hz)
 YLabel String:Gain (dB)
 とします

座標軸

右ペイン最上部に表示されているのがコンポーネント名ですが、ダブルクリックで書き換えることもできます。コードを書いた後でも、ここで変更するとコードは自動的に修正されるので、自分でいちいち直す必要はありません。


ここから「コードビュー」に切り替えて、実際のコードを書いていきます。

プロパティ

使用する変数やオブジェクト等の宣言をします。

左ペインのコードブラウザー -> プロパティ -> ➕ とすると

Property % Description

と表示されて自動的にそこに移動するので、以下のように書き換えます。

properties (Access = private)
    fs = 44100; % sampling frequency
    octFilt % octave filter object
end


コールバック

各GUIコンポーネントを操作したときの動作を記述します。
一旦「設計ビュー」に戻り、各コンポーネントを右クリック -> コールバック -> ~コールバックの追加、でコールバックを生成します。

作成後は、
 各コンポーネントを右クリック -> コールバック -> ~コールバックに移動
でそのコード部分に飛べます。

・BandwidthDropDown
 
Bandwidth で選択した値をオクターブフィルターにセットし、周波数応答描画関数(後述)を呼び出します。

function BandwidthDropDownValueChanged(app, event)
    value = app.BandwidthDropDown.Value;
    app.octFilt.Bandwidth = value;
    drawFrequencyResponse(app);
end


・CenterFrequencySpinner
 同様に CenterFrequency で設定した値をオクターブフィルターにセットし、周波数応答描画関数を呼び出します。

function CenterFrequencySpinnerValueChanged(app, event)
    value = app.CenterFrequencySpinner.Value;
    app.octFilt.CenterFrequency = value;
    drawFrequencyResponse(app);
end

コールバックを消したいときは右クリックで削除します。

コードビューで勝手に書いたり消したりしてしまうと、コードブラウザーと整合が取れなくなることがあるので注意してください。


内部関数

内部で使うサブルーチンを定義します。
左ペインのコードブラウザー -> 関数 -> ➕
drawFrequencyResponse と入力して、周波数応答グラフを描画する関数を定義します。
返り値は必要ないので削除します。

function drawFrequencyResponse(app)
    [h,w] = freqz(app.octFilt);
    hdB = 20*log10(abs(h));
    semilogx(app.UIAxes, w/(2*pi)*app.fs, hdB);
    grid(app.UIAxes, "on")
    xlim(app.UIAxes, [20, app.fs/2])
    ylim(app.UIAxes, [-80 0])
end


startupFcn

アプリ起動時に実行されるブロックです。

右ペイン[コンポーネント ブラウザー] の階層最上位のアプリノード(OctaveFilter1)を右クリックし、[コールバック] 、 [StartupFcn コールバックの追加] で追加します。

startupFcn の追加

先ほど消した BandwidthDropDown の設定(Items、 Value)と、デフォルト設定での周波数特性グラフを描画します。

function startupFcn(app)
    app.BandwidthDropDown.Items = {'1 octave', '2/3 octave', '1/2 octave', ...
        '1/3 octave', '1/6 octave', '1/12 octave', '1/24 octave', '1/48 octave'};
     app.BandwidthDropDown.Value = '1 octave';

    app.octFilt = octaveFilter; % octave filter object 

    drawFrequencyResponse(app);
end

BandwidthDropDown.Items は「設計ビュー」の右ペインで手動で入れても良いのですが、今回は長いのでコード上で入れています。セル形式で入れます。
こちらも返り値は必要ないので削除します。


UIFigureCloseRequest

最後に、設計ビューのコンポーネントがないところで右クリック -> コールバック で、UIFigureCloseRequest を追加し、
 release(app.octFilt)
を入れておきます。

CloseRequestFcn の追加
function UIFigureCloseRequest(app, event)
  release(app.octFilt)
  delete(app)
end

これでオクターブフィルターの中心周波数とバンド幅を指定して、その周波数応答を表示するGUIアプリができました。

自分で追加したコードは以下の部分のみです。

    fs = 44100; % sampling frequency
    octFilt % octave filter object

    
    function drawFrequencyResponse(app)
        [h,w] = freqz(app.octFilt);
        hdB = 20*log10(abs(h));
        semilogx(app.UIAxes, w/(2*pi)*app.fs, hdB);
        grid(app.UIAxes, "on")
        xlim(app.UIAxes, [20, app.fs/2])
        ylim(app.UIAxes, [-80 0])
    end
    

        app.BandwidthDropDown.Items = {'1 octave', '2/3 octave', '1/2 octave', ...
            '1/3 octave', '1/6 octave', '1/12 octave', '1/24 octave', '1/48 octave'};
        app.BandwidthDropDown.Value = '1 octave';

        app.octFilt = octaveFilter; % octave filter object 

        drawFrequencyResponse(app);

        app.octFilt.Bandwidth = value;
        drawFrequencyResponse(app);

        app.octFilt.CenterFrequency = value;
        drawFrequencyResponse(app);

        release(app.octFilt)


実行結果

GIFがアップロードされないので動画で(音声なし)。


実行結果

まとめ


いかがでしたでしょうか?

フィルターの周波数特性を表示させるだけとは言え、わずか20行足らずで一応インタラクティブな GUI アプリが作れてしまいます。

中には、「MATLABでGUIアプリが作れること自体知らなかった!」という方もいらっしゃるのではないでしょうか?

動作スピードや編集時の反応はイマイチな部分もあるのですが、コードの補間機能等もあるモダンな作りで、昔の GUIDE に比べると各段に開発効率が上がっています。

まだ使ったことがない方がいらっしゃったら、ぜひお試しください!


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