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 が欲しいな〜。