Audacityのエフェクトが足りなかったのはladspaを入れてなかったから

表題の通り、Audacityエフェクターが少ないなと思ったら、ladspaを入れていなかったからみたい。

$ rpm -qa | grep ladspa
ladspa-autotalent-plugins-0.2-7.fc19.x86_64
ladspa-1.13-10.fc19.x86_64
ladspa-wasp-plugins-0.9.5.1-6.fc19.x86_64
ladspa-guitarix-plugins-0.27.1-1.fc19.x86_64
ladspa-cmt-plugins-1.16-6.fc19.x86_64
ladspa-swh-plugins-0.4.15-20.fc19.x86_64
ladspa-tap-plugins-0.7.0-11.fc19.x86_64
ladspa-rev-plugins-0.3.1-10.fc19.x86_64
ladspa-fil-plugins-0.3.0-6.fc19.x86_64
ladspa-mcp-plugins-0.4.0-7.fc19.x86_64
ladspa-caps-plugins-0.9.10-1.fc19.x86_64
ladspa-vco-plugins-debuginfo-0.3.0-12.fc19.x86_64
ladspa-vco-plugins-0.3.0-12.fc19.x86_64
ladspa-amb-plugins-0.6.1-5.fc19.x86_64
ladspa-calf-plugins-0.0.19-3.fc19.x86_64

こんな状態にしたら、大量にエフェクターが増えた。
リバーブやディレイ、その他大量に増えたのはいいけど、調整方法はこれから調査。パラ録音したら、結構いじれそうです。

PowerShell画像ビュアーの改造(コード削減)

前回 http://d.hatena.ne.jp/fut_nis/20130816/1376614302 のプログラムのイベントハンドラが長すぎたので、ちょっと修正。

Add-Type -Assembly System.Windows.Forms
$w = New-Object System.Windows.Forms.Form
#
$ms = New-Object System.Windows.Forms.MenuStrip
$w.Controls.Add($ms)
#
$mi_file = New-Object System.Windows.Forms.ToolStripMenuItem("ファイル")
$ms.Items.Add($mi_file)
#
$pb = New-Object System.Windows.Forms.PictureBox
$pb.Location = New-Object System.Drawing.Point(0, $ms.Height)
$pb.AutoSize = $true
$w.Controls.Add($pb)
#
$mi_open = New-Object System.Windows.Forms.ToolStripMenuItem("開く")
$mi_file.DropDownItems.Add($mi_open)
#
$mi_separator = New-Object System.Windows.Forms.ToolStripSeparator
$ofd = New-Object System.Windows.Forms.OpenFileDialog
$ofd.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*"
$on_open_click = {if ($ofd.ShowDialog() -eq "OK"){$w.Text = $ofd.FileName; $img = New-Object System.Drawing.Bitmap($ofd.FileName); $pb.Image = $img}}
$mi_open.Add_Click($on_open_click)
$mi_file.DropDownItems.Add($mi_separator)
#
$mi_exit = New-Object System.Windows.Forms.ToolStripMenuItem("終了")
$mi_exit.Add_Click({$w.Dispose()})
$mi_file.DropDownItems.Add($mi_exit)
#
$w.ShowDialog()

修正点は、System.WIndows.Forms.PictureBoxのAutoSizeプロパティを$trueにしたこと。PowerShellの真偽値は$true と $faluse で指定できるみたい。おかげで、画像サイズに合わせてPictureBoxの大きさを変えるコード(ステートメントひとつ)が減りました。

スクロールバーを付けるには、System.Windows.Forms.FormのAutoScrollプロパティを $true にするのが簡単だと思ったら、メニューまでスクロールアウトされてしまいました。当たり前ですね。
メニューと表示部を分割するか、UserControlクラスを使ってそこに張り込んでいくか、できるだけコードが少なくなる、且つ一行が短くなる方法を探してみます。

PowerShellで画像表示の改良(ファイルを選択できるようにする)

今回はメニューをつけて、ファイルを選択できるようにしました。しかし、ワンライナー限定なので、一行で長い関数を書くことになります。

Add-Type -Assembly System.Windows.Forms
$w = New-Object System.Windows.Forms.Form
#
$ms = New-Object System.Windows.Forms.MenuStrip
$w.Controls.Add($ms)
#
$mi_file = New-Object System.Windows.Forms.ToolStripMenuItem("ファイル")
$ms.Items.Add($mi_file)
#
$pb = New-Object System.Windows.Forms.PictureBox
$pb.Location = New-Object System.Drawing.Point(0, $ms.Height)
$w.Controls.Add($pb)
#
$mi_open = New-Object System.Windows.Forms.ToolStripMenuItem("開く")
$mi_file.DropDownItems.Add($mi_open)
#
$mi_separator = New-Object System.Windows.Forms.ToolStripSeparator
$on_open_click = {$ofd = New-Object System.Windows.Forms.OpenFileDialog; $ofd.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*"; if ($ofd.ShowDialog() -eq "OK"){$w.Text = $ofd.FileName; $img = New-Object System.Drawing.Bitmap($ofd.FileName); $pb.Image = $img; $pb.ClientSize = $img.Size}}
$mi_open.Add_Click($on_open_click)
$mi_file.DropDownItems.Add($mi_separator)
#
$mi_exit = New-Object System.Windows.Forms.ToolStripMenuItem("終了")
$mi_exit.Add_Click({$w.Dispose()})
$mi_file.DropDownItems.Add($mi_exit)
#
$w.ShowDialog()

$on_open_click というのが処理内容です。空白行が禁止なのでコメント行にしているし見辛いことこの上ないです。OpenFileDialogオブジェクトをあらかじめ作っておくと多少ましになりますが、あまりうれしくないかもしれません。

Add-Type -Assembly System.Windows.Forms
$w = New-Object System.Windows.Forms.Form
#
$ms = New-Object System.Windows.Forms.MenuStrip
$w.Controls.Add($ms)
#
$mi_file = New-Object System.Windows.Forms.ToolStripMenuItem("ファイル")
$ms.Items.Add($mi_file)
#
$pb = New-Object System.Windows.Forms.PictureBox
$pb.Location = New-Object System.Drawing.Point(0, $ms.Height)
$w.Controls.Add($pb)
#
$mi_open = New-Object System.Windows.Forms.ToolStripMenuItem("開く")
$mi_file.DropDownItems.Add($mi_open)
#
$mi_separator = New-Object System.Windows.Forms.ToolStripSeparator
$ofd = New-Object System.Windows.Forms.OpenFileDialog
$ofd.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*"
$on_open_click = {if ($ofd.ShowDialog() -eq "OK"){$w.Text = $ofd.FileName; $img = New-Object System.Drawing.Bitmap($ofd.FileName); $pb.Image = $img; $pb.ClientSize = $img.Size}}
$mi_open.Add_Click($on_open_click)
$mi_file.DropDownItems.Add($mi_separator)
#
$mi_exit = New-Object System.Windows.Forms.ToolStripMenuItem("終了")
$mi_exit.Add_Click({$w.Dispose()})
$mi_file.DropDownItems.Add($mi_exit)
#
$w.ShowDialog()

本来ならスクロールバーをつけるべきなんでしょうね。。。。それは気が向いたら作ってみます。

PowerShell で 画像表示

今日は面倒なので、FormにBitmapを貼り付けたPictureBoxを追加するだけ。気が向いたらメニューを考えます。.ps1ファイルと同じ場所にtest.bmpって画像ファイルをおいてください。

Add-Type -Assembly System.Windows.Forms
$w = New-Object System.Windows.Forms.Form
$pb = New-Object System.Windows.Forms.PictureBox
$img = New-Object System.Drawing.Bitmap("test.bmp")
$pb.ClientSize = $img.Size
$w.ClientSize = $img.Size
$pb.Image = $img
$w.Controls.Add($pb)
$w.ShowDialog()

ま、こんな感じで表示できるので、後はOpenFileDialogと終了メニューぐらいを作ろうと思います。

PowerShell 2.0 でのMessageBox

PowerShellGUIアプリを作るには、基本的にはオブジェクトを作成してメソッドを実行することになりますが、コンストラクタが無いオブジェクトはクラスメソッドを使うことになるようです。
今回は、MessageBoxを開くため、Showメソッドを使ってみます。MessageBox1.ps1というファイル名で保存します。

Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("テスト")

実行すると、「テスト」と書かれたダイアログボックスが開きますがあまりにもシンプルですね。
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.messagebox.aspx を見ながらShow()メソッドをいろいろ試してみます。

スクリプトの実行がシステムで無効になっているため、ファイル MessageBox1.ps1 を読み込めません。詳細については、「get-help about_signing」と入力してヘルプを参照してください。
At line:0 char:0

みたいになる場合は、rub.batというファイルを作って、そこにDrag & Dropしてください。run.batは以下のとおり。

PowerShell -Sta -WindowStyle Hidden -Command "Get-Content %1 | Invoke-Expression"

さて、Showメソッドって、たくさんあります。第一引数が文字列の場合とIWin32Windowの場合で挙動が異なりますが、IWin32Windowsの場合はその前面にMessageBoxを表示するものになるようです。今回はMessageBoxを表示するだけなので、IWin32Windowsを使いませんが、実際にプログラムを作るときには、MessageBoxが後ろに表示されて見えなくなるので、必ずIWin32Windowsを第一引数にとるように記述したほうがよいでしょう。

では、第一引数が文字列の場合からの説明です。この第一引数は、MessageBoxに表示される文字列になります。最初に書いたスクリプトでは"テスト"と表示されました。

第二引数がある場合は、それがウィンドウのタイトルバーに表示される文字列になります。

Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("テスト", "キャプション")

第三引数がある場合は、ボタンの種類になります。しかし、MessageBoxButtonsの指定方法が分からないので、強引なことをやってみます。

Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("テスト", "キャプション", "")

このように第三引数を""というから文字列にすると、エラー表示してくれます。

"Show" の引数 "2" (値 "") を型 "System.Windows.Forms.MessageBoxButtons" に変換できません: "列挙値が無効なため、値 "" を型 "System.Windows.Forms.MessageBoxButtons" に変換できません。次のいずれかの列挙値を指定し、再試行してください。有効な列挙値: "OK、OKCancel、AbortRetryIgnore、YesNoCancel、YesNo、RetryCancel"。"
発生場所 行:1 文字:40
+ [System.Windows.Forms.MessageBox]::Show <<<< ("テスト", "キャプション", "")
    + CategoryInfo          : NotSpecified: (:) []、MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

エラーを見ると、"OK" "OKCancel" "AbortRetryIgnore" "YesNoCancel" "YesNo" RetryCancel"の6種類が使えるようです。早速"YesNoCancel"にしてみます。

Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("テスト", "キャプション", "YesNoCancel")

ボタンが3つあるメッセージボックスが表示されました。

第四引数は、アイコンです。同じように第四引数を空文字列にして実行し、有効な値を調べます。"None" "Hand" "Error" "Stop" "Question" "Exclamation" "Warning" "Asterisk" "Information"の9個あるようです。"None"では何も表示されないので、"Asterisk"にしてみます。

Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("テスト", "キャプション", "YesNoCancel", "Asterisk")

InformationとAsteriskの違いがよく分かりませんが、一応アイコンは表示されました。

第五引数は、デフォルトボタンです。有効な値は、"Button1" "Button2" "Button3"の3つです。MessageBoxに並んだボタンの左から指定できるようです。ボタンの数より大きい数字を指定すると、一番左がデフォルトボタンになるようです。今回はYesNoCancelの3つボタンを用意しているので、Button3にしてみます。

Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("テスト", "キャプション", "YesNoCancel", "Asterisk", "Button3")

正しく3番目のキャンセルボタンがデフォルト表示になってます。

第六引数は、MessageBoxOptionsだそうです。よく分かりませんね。有効な値は、"DefaultDesktopOnly" "RightAlign" "RtlReading" "ServiceNotification"のようです。試してみると右揃えになったり、左右反転したりするようで、、、指定する必要はないのかな?"ServiceNotification"だけはよくわかりません。

第七引数以降はヘルプメッセージのようです。しかし、この辺からはよく分からないので、今回はここまでです。

New-Objectでインスタンスを作成するのではなく、クラスの静的メソッドを使う場合はクラスを[System.Windows.Forms.MessageBox]のように指定し、そのメソッドを::Show()のように書くことで、.NET FrameWorkをたたけることと、列挙子の指定は文字列で行うことが分かりました。分からない場合は空の文字列を突っ込んで、エラー表示を出すとそこにヒントが隠されています。Windowsのエラーメッセージって親切になったんだな〜と感じた今日この頃です。

Get-ExecutionPolicy が Restricted な PowerShell (Windows 7) な環境でのスクリプト実行

権限がまったくないWindows 7マシンで PowerShell 2.0 環境でプログラムを書こうとして悪戦苦闘したので、備忘録を記述。
まず、Restrictedな環境では.ps1で保存したPowerShell Scriptは動作しない。このため、バッチファイルを作成し、そこにスクリプトファイルを Drag & Drop することで実行できるようにした。
run.bat としてデスクトップに作成。

PowerShell -Sta -WindowStyle Hidden -Command "Get-Content %1 | Invoke-Expression"

デバッグ用は debug.batとしてデスクトップに。

PowerShell -Sta -Command "Get-Content %1 | Invoke-Expression"
Pause

PowerShell 2.0 では MTA(Multi-Threaded Apartment)モードにデフォルトでなっているため、.NET FrameWork の CommonDialog クラスが使えない。回避するため -Sta とした。CommonDialog は OpenFileDialog や FolderBrowserDialog があるので、使えないと困る。次の -WindowStyle Hidden は、コマンドラインPowerShell プログラムを非表示にするため。私は GUI プログラムにしか興味がないので、コマンドラインは消えてなくなってほしい。そして、 -Command 以下に実行する PowerShell コマンドレットを書くことになる。
バッチファイルの引数は %1 になるので、Get-Content %1 でPowerShell スクリプトファイルを読み込み一行ずつパイプラインで送っていく。次に Invoke-Expression で一行ずつコマンドレットを実行する。

この方法の問題は、if 文だろうが関数だろうが、全て一行で記述しなければならないこと(ワンライナーってやつ)。コマンドレットのステートメント区切りはセミコロン ; なので、関数内やif文で複数の命令を実行する場合は、セミコロンで区切った長い行になってしまう。何かいい方法がないか探しているところ。
もうひとつの問題は、空白行を使うと、

Invoke-Expression : 引数が空の文字列であるため、パラメーター 'Command' にバインドできません。

なんてエラーが出るので、行頭に#を付けてコメント行にする必要がある。これで、多少は見やすいスクリプトになった。

というところで、ウィンドウを表示するだけのプログラムをひとつ。
FirstForm.ps1というファイルで作成してみた。

Add-Type -Assembly System.Windows.Forms
$w = New-Object System.Windows.Forms.Form
$w.ShowDialog()

なんとなく動作している。

Gstreamer でスペクトラムアナライザーもどきを作ってみた

久々の更新ということに気づいた。

今回は、基本的に gst-plugins-good の spectrum を使っただけで、しかもほとんどが devhelp からのコピペです。なのでソースの説明はしません。

今回困ったのは、 gst-plugins-base の audiotestsrc のプロパティ "wave" と "freq" の設定。"wave" は enum GstAudioTestSrcWave で定義されているのですが、ヘッダがインストールされないので、折角命名している名前があっても使えないんです。だから、GST_AUDIO_TEST_SRC_WAVE_SINE ではなく 0 にする必要があります。つまり、それぞれ数字で指定することになるみたい。gst-launch-1.0 では名前が使えるのにね。"freq"は、#define する時に小数点を明示しないとダメみたいです。880Hzにしたい場合は、880ではなく880.0にする必要があります。

その他では、サンプルでは、caps(ケーパビリティ?)で audio/x-raw-int と指定していますが、このままでは以下のエラーになります。

GStreamer-WARNING **: 0.10-style raw audio caps are being created. Should be audio/x-raw,format=(string).. now.
Error: gst_element_link_filterd audioconvert spectrun caps

そのため、ソースでは、 audio/x-raw にしています。以下、ソースです。wave を blue-noise にしているので、freq に意味がなかったりします。

#include <stdlib.h>
#include <gst/gst.h>
#include <gtk/gtk.h>

#define NUM_BANDS 20
#define MIN_LEVEL -60
#define MAX_LEVEL 0
#define STEP 1

#define AUDIOFREQ 32000
#define WAVE_NAME 11
#define WAVE_FREQ 8800.0

// #define G_DISABLE_ASSERT

/* GstBusFunc */
static gboolean
gst_bus_handler (GstBus *bus, GstMessage *message, gpointer user_data)
{
	GtkWidget ***vscale = user_data;
	
	if (message->type == GST_MESSAGE_ELEMENT)
	{
		const GstStructure *structure = gst_message_get_structure (message);
		const gchar *name = gst_structure_get_name (structure);

		if (g_strcmp0 (name, "spectrum") == 0)
		{
			const GValue *magnitude = gst_structure_get_value (structure, "magnitude");
			guint i;

			for (i = 0; i < NUM_BANDS; i++)
			{
				const GValue *mag = gst_value_list_get_value (magnitude, i);

				if (mag != NULL && GTK_IS_SCALE (vscale[i]))
				{
					gtk_range_set_value (GTK_RANGE (vscale[i]), g_value_get_float (mag));
				}
			}
		}
	}
	return TRUE;
}

int
main (int argc, char *argv[])
{
	GtkWidget *vscale[NUM_BANDS];
	GstElement *bin;

	gtk_init (&argc, &argv);
	gst_init (&argc, &argv);

	/* init gui */
	{
		GtkWidget *win, *hbox;
		guint i;

		win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
		g_assert (win);
		g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);
		
		hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
		g_assert (hbox);
		
		for (i = 0; i < NUM_BANDS; i++)
		{
			vscale[i] = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL, MIN_LEVEL, MAX_LEVEL, STEP);
			g_assert (vscale[i]);
			gtk_range_set_inverted (GTK_RANGE (vscale[i]), TRUE);
			gtk_range_set_min_slider_size (GTK_RANGE (vscale[i]), (MAX_LEVEL - MIN_LEVEL) * 10);
			gtk_box_pack_start (GTK_BOX (hbox), vscale[i], TRUE, TRUE, 0);
		}
		gtk_container_add (GTK_CONTAINER (win), hbox);
		gtk_widget_show_all (win);
	}
	
	/* setup gstreamer */
	{
		GstElement *src, *audioconvert, *spectrum, *sink;
		GstBus *bus;
		GstCaps *caps;
		
		bin = gst_pipeline_new ("bin");
		g_assert (bin);
		
		src = gst_element_factory_make ("audiotestsrc", "src");
		g_assert (src);
		g_object_set (G_OBJECT (src), "freq", WAVE_FREQ, "wave", WAVE_NAME, "volume", 1.0, NULL);
		
		audioconvert = gst_element_factory_make ("audioconvert", NULL);
		g_assert (audioconvert);
		
		spectrum = gst_element_factory_make ("spectrum", "spectrum");
		g_assert (spectrum);
		g_object_set (G_OBJECT (spectrum), "bands", NUM_BANDS, NULL);
		
		sink = gst_element_factory_make ("autoaudiosink", "sink");
		g_assert (sink);
		
		gst_bin_add_many (GST_BIN (bin), src, audioconvert, spectrum, sink, NULL);
		caps = gst_caps_new_simple ("audio/x-raw", "rate", G_TYPE_INT, AUDIOFREQ, NULL);
		g_assert (caps);
		if (!gst_element_link (src, audioconvert))
		{
			g_printf ("Error: gst_element_link src audioconvert\n");
			return EXIT_FAILURE;
		}
		if (!gst_element_link_filtered (audioconvert, spectrum, caps))
		{
			g_printf ("Error: gst_element_link_filterd audioconvert spectrun caps\n");
			return EXIT_FAILURE;
		}
		if (!gst_element_link (spectrum, sink))
		{
			g_printf ("Error: gst_element_link spectrum sink\n");
			return EXIT_FAILURE;
		}
		gst_caps_unref (caps);

		bus = gst_element_get_bus (bin);
		g_assert (bin);
		gst_bus_add_watch (bus, gst_bus_handler, (gpointer) &vscale);
		gst_object_unref (bus);
		
		gst_element_set_state (bin, GST_STATE_PLAYING);
	}
	
	gtk_main ();
	
	gst_element_set_state (bin, GST_STATE_NULL);
	gst_object_unref (bin);
	
	return EXIT_SUCCESS;
}

オーディオ用だから、横軸を対数にしなきゃダメなんだよな〜。あと、 GtkScale はコントロール用なので、表示用の Widget が欲しいな〜。