3.1 Реализация интерфейса плеера
Наш проект будет состоять из двух файлов, один будет содержать описания интерфейса, а второй – основную программу, реализующую звуковой поток. Файл для описания интерфейса называется playerinterf.c, файл для самой программы gsprog.c
Для подробного описания своих действий я буду прикладывать кусочки кода и комментировать свои действия. Для начала обсудим создание интерфейса плеера.
Подключаем библиотеки, необходимые для реализации.
#include <stdio.h> //Подключаем стандартные функции i/o
#include <gtk/gtk.h> //библиотеки интерфейса
#include <gst/gst.h> //библиотеки gstreamer
#include "gsprog.c" //ссылка на основную программу
//описание функции выбора музыкального файла
static void file_select(GtkFileChooser *selector, gpointer data);
//объявление глобальных переменных в виде указателей
GtkAdjustment *adj[7], *adj_progress;
GtkWidget *window, *hbox1, *hbox2, *hbox3, *hbox4, *vbox;
GtkWidget *scale[7], *check, *explorer, *progress, *file_filter, *time_display;
GtkToolItem *btnPlay, *btnStop, *btnPause;
ToolItem – уже библиотечные кнопки для проигрывания, паузы и остановки
Widget – самые разные объекты интерфейса, окна, контейнеры, кнопки и т.д.
Теперь начинается выполнение главной функции:
int main(int argc, char **argv)
{
//инициализируем GTK+ и GStreamer
gtk_init(&argc, &argv);
gst_init(&argc, &argv);
Две последнии строчки необходимы для инициализации наших библиотек.
/*-----------------------------------------------------
СОЗДАЕМ ЭЛЕМЕНТЫ ИНТЕРФЕЙСА
------------------------------------------------------*/
//наше основное окно
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//сразу устанавливаем отступы 10 пикселей от края окна
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
//основной контейнер, куда всё будет заполняться
//VERTICAL - все элементы будут заполняться вертикально
//Параметр 10 указывает на расстояние между элементами в этом //контейнере
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
//контейнер для кнопки выборки файла
hbox4 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 70);
//контейнер для кнопок play, stop и pause
hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 50);
//контейнер для ползунка поиска по треку, кнопки эффекта phaser и //громкости
hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 15);
//контейнер для ползунков эквалайзера
hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 20);
//задаем размер для основного контейнера
gtk_widget_set_size_request(vbox, 500, 300);
//размер для окна с эквалайзером
gtk_widget_set_size_request(hbox3, 100, 200);
//кнопка включения и выключения эффекта phaser
check = gtk_check_button_new_with_label("phaser");
//кнопка регулировки громкости
GtkWidget *volume;
volume = gtk_volume_button_new();
//кнопка выбора файла
explorer = gtk_file_chooser_button_new("select file", GTK_FILE_CHOOSER_ACTION_OPEN);
//кнопки воспроизведение, стоп и пауза
btnPlay = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
btnStop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
btnPause = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PAUSE);
//этими функциями мы масштабируем данные кнопки при растяжении окна
gtk_widget_set_hexpand (btnPlay, TRUE);
gtk_widget_set_hexpand (btnStop, TRUE);
gtk_widget_set_hexpand (btnPause, TRUE);
//создаем лэйбл для отображения времени трека
time_display = gtk_label_new ("0:00 / 0:00");
//задаем регулятор (value, lower, upper, step_incr, page_incr, page_size)
adj_progress = gtk_adjustment_new (0.0, 0.0, 100.0, 0.1, 1.0, 0.0);
//привязываем его к горизонтальному ползунку
progress = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adj_progress);
//масштабирование ползунка
gtk_widget_set_hexpand(progress, TRUE);
//масштабирование кнопки
gtk_widget_set_hexpand(explorer, TRUE);
//вывод времени прогресса
gtk_scale_set_draw_value (GTK_SCALE(progress), FALSE);
//фильтр файлов создание и название
file_filter = GTK_WIDGET(gtk_file_filter_new());
gtk_file_filter_set_name (GTK_FILE_FILTER(explorer), "Music");
//возможные музыкальные форматы для воспроизведения и
gtk_file_filter_add_pattern (GTK_FILE_FILTER(file_filter), "*.flac");
gtk_file_filter_add_pattern (GTK_FILE_FILTER(file_filter), "*.mp3");
//реализация фильтра
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(explorer), GTK_FILE_FILTER(file_filter));
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(explorer), DEFAULT_FILE);
//зарисовка 7 полос эквалайзера
int i;
for (i = 0; i < 7; i ++) {
//7 регулируемых значений от -12 до 10 с шагом 1.0
adj[i] = gtk_adjustment_new(0.0, -12.0, 10.0, 1.0, 1.0, 0.0);
//7 ползунков вертикальной ориентации
scale[i] = gtk_scale_new(GTK_ORIENTATION_VERTICAL, adj[i]);
//максимум сверху, минимум снизу
gtk_range_set_inverted(GTK_RANGE(scale[i]), TRUE);
//сразу добавляем в контейнер hbox3
gtk_container_add(GTK_CONTAINER(hbox3), scale[i]);
//масштабирование ползунков
gtk_widget_set_vexpand(scale[i], TRUE);
gtk_widget_set_hexpand(scale[i], TRUE);
}
/*--------------------------------------------------------------------------------
ЗАПОЛНЯЕМ КОНТЕЙНЕР, НАНОСИМ КНОПКИ НА ФОРМУ
---------------------------------------------------------------------------------*/
//элементы наносятся в порядке выполнения кода, один за другим
gtk_container_add(GTK_CONTAINER(hbox1), btnPlay);
gtk_container_add(GTK_CONTAINER(hbox1), btnPause);
gtk_container_add(GTK_CONTAINER(hbox1), btnStop);
gtk_container_add(GTK_CONTAINER(hbox2), time_display);
gtk_container_add(GTK_CONTAINER(hbox2), progress);
gtk_container_add(GTK_CONTAINER(hbox2), check);
gtk_container_add(GTK_CONTAINER(hbox2), volume);
gtk_container_add(GTK_CONTAINER(hbox4), explorer);
gtk_container_add(GTK_CONTAINER(vbox),hbox4);
gtk_container_add(GTK_CONTAINER(vbox),hbox2);
gtk_container_add(GTK_CONTAINER(vbox),hbox3);
gtk_container_add(GTK_CONTAINER(vbox),hbox1);
//основной контейнер добавляется в окно
gtk_container_add(GTK_CONTAINER(window),vbox);
Следующий кусок кода может показаться не совсем понятным без привязки к основной функции, просто представьте сейчас, что там существуют какие-то функции, куда происходит передача параметров из интерфейса.
/*-----------------------------------------------------------------------------------
ОБРАБОТКА СИГНАЛОВ, СВЯЗЬ ИНТЕРФЕЙСА С GSTREAMER
--------------------------------------------------------------------------------------*/
//обработчик ползунка по треку
g_signal_connect(adj_progress, "value-changed", G_CALLBACK(gstreamer_seek_to_time), NULL);
//обработчик громкости сигнала
g_signal_connect(volume, "value-changed", G_CALLBACK(gstreamer_volume), NULL);
//обработчик выбора файла
g_signal_connect(explorer, "selection_changed", G_CALLBACK(file_select), NULL);
//обработчик эквалайзера
int n;
gpointer num;
for (n = 0; n < 7; n ++) {
num = GINT_TO_POINTER(n);
//передает значение усиления снятое с ползунка g_signal_connect(adj[n], "value-changed", G_CALLBACK(gstreamer_equalizer), num);
}
//обработчик эффекта phaser, следит, включен ли он
g_signal_connect(check, "toggled", G_CALLBACK(gstreamer_toggle), NULL);
//обработчик воспроизведения
g_signal_connect(btnStop, "clicked", G_CALLBACK(gstreamer_stop), NULL);
g_signal_connect(btnPause, "clicked", G_CALLBACK(gstreamer_pause), NULL);
g_signal_connect(btnPlay, "clicked", G_CALLBACK(gstreamer_play), NULL);
//показать все на форме
gtk_widget_show_all(window);
//вызываем gstreamer
gstreamer();
return 0;
}
//функция реализует выбор файла
static void file_select(GtkFileChooser *selector, gpointer data) {
char *path; //путь к файлу
path = gtk_file_chooser_get_filename(selector);
g_print("file location:%s\n", path);
if (path != NULL) {
//если произошло изменение, выполнение следующих действий:
gstreamer_stop(); //остановка потока
g_object_set(G_OBJECT(filesrc), "location", path, NULL); //изменение файла
gstreamer_stop();
g_object_set(G_OBJECT(adj_progress), "value", 0.0, NULL);
gstreamer_play(); //воспроизведение
}
}
Внешний вид плеера можете посмотреть в п. 3.3