
3.2 Реализация звукового потока и привязка к интерфейсу
Сразу приступим к обсуждению файла gsprog.c, в котором реализована программа для звука.
#include <stdio.h> //Подключаем стандартные функции i/o
#include <gtk/gtk.h> //библиотеки интерфейса
#include <gdk/gdk.h> //----||----
#include <gdk/gdkx.h> //----||----
#include <gst/gst.h> //библиотеки gstreamer
#define DEFAULT_FILE "/home/" //путь к нашему файлу
//глобальные переменные для перестраховки
extern GtkAdjustment *adj_progress; //значение ползунка поиска
extern GtkWidget *time_display, *window; //основное окно
GstElement *pipeline; //конвейер
GstElement *filesrc; //чтение файла
GstElement *decoder; //преобразование звука в отсчеты
GstElement *dec1;
GstElement *queueaudio;
GstElement *sink; //воспроизведение звука звуковым драйвером
GstElement *volume; //управление громкостью
GstElement *echo; //звуковой эффект эхо
GstElement *equalizer;//эквалайзер
GstElement *vsink;
GstElement *audioconvert1;
GstElement *audioconvert2;
GstElement *audioconvert3;
gboolean playing = FALSE;
gboolean connected = TRUE;
static gboolean gstreamer_print_position();
int gstreamer() {
GMainLoop *loop; //основной цикл
/*--------------------------------------------
СОЗДАЕМ ЗВУКОВОЙ КОНВЕЙЕР
----------------------------------------------*/
//инициализируем объявленные элементы
//этот кусок практически полностью соответствует методическим //указаниям
pipeline = gst_pipeline_new("my_pipe");
filesrc = gst_element_factory_make("filesrc", "mysrc");
decoder = gst_element_factory_make("mad", "mydec");
sink = gst_element_factory_make("autoaudiosink", "sink");
equalizer = gst_element_factory_make("equalizer-10bands", "my_equal");
decoder = gst_element_factory_make("mad", "mydec4");
echo = gst_element_factory_make("audioecho", "echo");
volume = gst_element_factory_make("volume", NULL);
audioconvert1 = gst_element_factory_make("audioconvert", "conv1");
audioconvert2 = gst_element_factory_make("audioconvert", "conv2");
audioconvert3 = gst_element_factory_make("audioconvert", "conv3");
queueaudio = gst_element_factory_make("queue2", "aqueue");
//установка эффекта эхо
g_object_set(G_OBJECT(echo), "max-delay", 1000000000, NULL);
//передаём элементу filesrc параметр location
g_object_set(G_OBJECT(filesrc), "location", DEFAULT_FILE, NULL);
//запускаем конвейер
gst_bin_add_many(GST_BIN(pipeline), filesrc, decoder, audioconvert3,
queueaudio, audioconvert2, equalizer, audioconvert1, echo, volume, sink, NULL);
//соединяем элементы последовательно
gst_element_link_many(filesrc, decoder, audioconvert3, NULL);
gst_element_link(audioconvert3, queueaudio);
gst_element_link_many(queueaudio, audioconvert2, equalizer, audioconvert1, echo, volume, sink, NULL);
//запускаем основной цикл
loop = g_main_loop_new(NULL, FALSE);
g_print("ok\n");
g_main_loop_run(loop);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
return 0;
}
/*--------------------------------------------
ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
----------------------------------------------*/
//функция реализует изменение громкости
void gstreamer_volume(GtkWidget *vol, gpointer data) {
//значение с кнопки громкости
gdouble v = gtk_scale_button_get_value(GTK_SCALE_BUTTON(vol));
//установка громкости
g_object_set(G_OBJECT(volume), "volume", v, NULL);
//вывод громкости в процентах
g_print("vol: %.0lf%\n", v * 100);
}
//функция реализует эффект phaser через echo
void gstreamer_echo() {
guint64 delay = 100000; //задержка в нс
guint64 max_delay = 1; //максимальная задержка
gfloat feedback = 0.0; //обратная связь
gfloat inten = 0.1; //интенсивность
g_print("phaser on\n");
g_object_set(G_OBJECT(echo), "delay", delay, "feedback", feedback, "intensity", inten, "max-delay" , max_delay, NULL );
}
//эта функция работает, когда эффект выключен
void gstreamer_echo_stop() {
//параметры аналогичные предыдущей функции
guint64 delay = 1;
guint64 max_delay = 1;
gfloat feedback = 0.0000;
gfloat inten = 0.0001;
g_print("phaser off\n");
g_object_set(G_OBJECT(echo),"delay", delay, "feedback", feedback, "intensity", inten, "max-delay" , max_delay, NULL );
}
//функция обрабатываетвключение и выключение phaser
void gstreamer_toggle(GtkWidget *check, gpointer data) {
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check))) {
//gstreamer_echo_stop();
gstreamer_echo();
}
else
gstreamer_echo_stop();
}
//функция реализует 7 полосный эквалайзер
void gstreamer_equalizer(GtkAdjustment *adj, gpointer num) {
GstObject *band;
int numBand = GPOINTER_TO_INT(num); //номер полосы
gdouble cs = gtk_adjustment_get_value(adj);
//значения с ползунков
//конструкция с параментрами полос
typedef struct {
gfloat freq; //средняя частота
gfloat width; //ширина полосы
gfloat gain; //усиление в dB
} GstEqualizerBandState;
//инициализируем конструкцию, объявляем значения всех 7 полос
GstEqualizerBandState state[] = {
//графу усиления пока оставляем нулевой
{90.0, 70.0, 0.0},
{400.0, 240.0, 0.0},
{970.0, 330.0, 0.0},
{1900.0, 600.0, 0.0},
{3750.0, 1250.0, 0.0},
{7500.0, 2500.0, 0.0},
{15000.0, 5000.0, 0.0}
};
//теперь заполняем графу усиление, передавая параметры с ползунков
state[numBand].gain = cs;
//изменяем звук в соответствии с полученными данными
band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), numBand);
g_object_set(G_OBJECT(band), "freq", state[numBand].freq, "bandwidth", state [numBand].width, "gain", state[numBand].gain);
g_object_unref (G_OBJECT (band));
}
//функция обрабатывает воспроизведение
int gstreamer_play() {
playing = TRUE;
g_timeout_add(500, (GSourceFunc)gstreamer_print_position, NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_print("action: playing\n");
return 0;
}
//функция обрабатывает паузу
int gstreamer_pause() {
playing = FALSE;
gst_element_set_state(pipeline, GST_STATE_PAUSED);
g_print("action: paused\n");
return 0;
}
//функция обрабатывает остановку
int gstreamer_stop() {
playing = FALSE;
g_timeout_add(500, (GSourceFunc)gstreamer_print_position, NULL);
gst_element_set_state(pipeline, GST_STATE_NULL);
g_print("action: stopped\n");
return 0;
}
//функция обрабатывает поиск по треку
static void gstreamer_seek_to_time(GtkAdjustment *ad) {
if(connected) {
gdouble val = gtk_adjustment_get_value(ad);
gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET, val,
GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
}
}
//функция выводит позицию в песне
static gboolean gstreamer_print_position() {
gint64 pos, dur;
GstFormat time = GST_FORMAT_TIME;
gchar progress_text[100];
gst_element_query_position(pipeline, &time, &pos);
gst_element_query_duration(pipeline, &time, &dur);
gint seconds = pos / GST_SECOND;
gint minutes = seconds / 60;
gint seconds_dur = dur / GST_SECOND;
gint minutes_dur = seconds_dur / 60;
sprintf (progress_text, " %d:%02d / %d:%02d ", minutes,
seconds - minutes * 60, minutes_dur, seconds_dur - minutes_dur * 60);
connected = FALSE;
gtk_adjustment_set_upper(adj_progress, dur);
gtk_adjustment_set_value(adj_progress, pos);
connected = TRUE;
gtk_label_set_label(GTK_LABEL(time_display),progress_text);
return playing;
}
Теперь у нас есть все для работающей программы, можно все это собирать вместе и смотреть на работу плеера.