#はじめに
音楽編集ソフトでよくある,波形をクリック→ドラッグして範囲選択するというのを実装したい.
今回はpatch
関数を使用して実装を行う.
#ググる
ググったら殆どやりたいことに近いものが出てきた.
App Designer で作成した GUI において,マウスの操作でグラフィックスオブジェクトを動かすことはできますか?
1 つ以上の塗りつぶされた多角形領域のプロット - MATLAB patch
これを参考に作成する.
#AppDesigner実装
以下実装をまとめる.
##コンポーネント配置
以下のコンポーネントを適当に配置する.
コンポーネント名 | 説明 |
---|---|
UIAxes | グラフを表示する |
OpenFileDialogButton | ファイルダイアログを開く |
FilePathEditField | ファイル名を表示 |
##メンバ変数
変数名 | 説明 |
---|---|
h | patchオブジェクト |
mouseStatus | マウスクリック状態 |
clickPos | クリックした座標 |
##コールバック関数
###起動時初期化処理
function startupFcn(app)
% グラフをセットアップ
xlabel(app.UIAxes, '時間[s]');
ylabel(app.UIAxes, '振幅');
% ツールバーを無効にする
app.UIAxes.Toolbar.Visible = 'off';
% 座標軸の組み込み操作を無効にする
disableDefaultInteractivity(app.UIAxes);
% マウス状態を初期化
mouseStatus = "ButtonUp";
end
###ファイル開くボタン押下時
グラフの間引き表示処理として前回投稿した
【MATLAB】plot表示時間短縮のためにデータを間引く
で作成したDecimationProc
を使用する.
(間引き表示しないと表示が重たすぎるので)
function OpenFileDialogButtonPushed(app, event)
% ファイルダイアログを開く
[file1, path1] = uigetfile({'*.wav;*.mp3','Audio Files (*.wav,*.mp3)'});
if(file1 == 0)
% キャンセルで閉じた場合
return
end
% ファイル名をエディットボックスに格納
app.FilePathEditField.Value = file1;
% ファイルを開いてメンバ変数に格納
[y, Fs] = audioread(fullpath1);
y = y(:, 1);% ステレオの場合は片側だけ使用
decimation = 5000;
y = app.DecimationProc(y, decimation);
Fs = Fs/decimation;
% 時間波形をプロット
N = length(y);
t = ((1:N)-1)/Fs;
plot(app.UIAxes, t, y);
% patchオブジェクトを作成
app.h = patch(app.UIAxes,[0, 0, 0, 0],[0, 0, 0, 0],'r');
set(app.h,'FaceAlpha', 0.3); % 透明度
end
マウスボタン押下時の処理
function UIFigureWindowButtonDown(app, event)
app.mouseStatus = "ButtonDown";
app.clickPos = app.UIAxes.CurrentPoint;
% クリック位置が範囲外の場合は範囲内に調整
% clamp処理とか言うらしいですね,よく分かりませんが・・・
if(app.clickPos(1,1) < app.UIAxes.XLim(1))
app.clickPos(1,1) = app.UIAxes.XLim(1);
end
if(app.clickPos(1,1) > app.UIAxes.XLim(2))
app.clickPos(1,1) = app.UIAxes.XLim(2);
end
% patch描画を消す
app.h.XData = [0, 0, 0, 0];
end
###マウスボタンを離した時の処理
function UIFigureWindowButtonUp(app, event)
app.mouseStatus = "ButtonUp";
end
###マウスを移動中の処理
これが本記事でのメインの処理である.
マウスをクリックした位置から現在カーソルの範囲を赤色で重畳表示を行う.
function UIFigureWindowButtonMotion(app, event)
if(app.mouseStatus ~= "ButtonDown")
return
end
Cp = app.UIAxes.CurrentPoint; % get current mouse point on Axes
if(Cp(1,1) < app.UIAxes.XLim(1))
Cp(1,1) = app.UIAxes.XLim(1);
end
if(Cp(1,1) > app.UIAxes.XLim(2))
Cp(1,1) = app.UIAxes.XLim(2);
end
app.h.XData = [app.clickPos(1,1), Cp(1,1), Cp(1,1), app.clickPos(1,1)]; % Update xdata for patch object
drawnow
end
##結果をGIFで
GIFで見ると結果がよく伝わると思うが,かなり重たいので実用レベルでは無いかも.
まぁ,これはキャプチャソフトで録画しながらMATLABアプリを動かしてたのでより重たくなっていたので,録画していない時はもうちょっとサクサクに動くわよ.