2013-03-21 1 views
1

Я разрабатываю чрезвычайно простой аудиоплеер. Он использует Gtk и portaudio/libsndfile. Я создал простой тестовый интерфейс с несколькими кнопками, такими как «Обзор», «Воспроизведение» и т. Д. Мой игрок правильно выбирает имя файла, и после нажатия «Воспроизвести» он начинает играть. Но все ждет завершения воспроизведения. Ничто не является активным, и я задаюсь вопросом, как остановить его, прежде чем он закончится сам собой.Gtk аудиоплеер. Как остановить звук до конца песни

Мой код для Gtk является:

#include <stdio.h> 
#include <gtk\gtk.h> 
static GtkWidget *window; 
const char *filename; 

static void play_file (GtkButton *button, gpointer data) 
{ 
    sndFile_play(filename); 
} 
static gboolean delete_event(GtkWidget *widget, 
           GdkEvent *event, 
           gpointer data) 
{ 
    return FALSE; 
} 

static void destroy(GtkWidget *widget, 
        gpointer data) 
{ 
    gtk_main_quit(); 
} 

int main(int argc, 
      char *argv[]) 
{ 

    GtkWidget *button; 
    GtkWidget *box1; 

    gtk_init (&argc, &argv); 

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    gtk_window_set_title (GTK_WINDOW (window), "MyPlayer"); 

    g_signal_connect (window, "delete-event", 
       G_CALLBACK (delete_event), NULL); 

    g_signal_connect (window, "destroy", 
       G_CALLBACK (destroy), NULL); 

    gtk_container_set_border_width (GTK_CONTAINER (window), 20); 

    box1 = gtk_hbox_new (FALSE, 0); 
    gtk_container_add (GTK_CONTAINER (window), box1); 

    button = gtk_button_new_with_label ("Browse..."); 
    g_signal_connect (button, "clicked", 
     G_CALLBACK (browse_clicked), NULL); //not given here 
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0); 
    gtk_widget_show (button); 

    button = gtk_button_new_with_label ("Play"); 
    g_signal_connect (button, "clicked", 
     G_CALLBACK (play_file), NULL); 
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0); 
    gtk_widget_show (button); 

    gtk_widget_show (box1); 
    gtk_widget_show (window); 

    gtk_main(); 

    return 0; 
} 

Если необходимо Даю код для воспроизведения звука:

#include <stdio.h> 
#include <stdlib.h> 
#include <portaudio.h> 
#include <sndfile.h> 

#define FRAMES_PER_BUFFER (1024) 
#define PA_SAMPLE_TYPE paInt16 
typedef short SAMPLE; 
#define BUFFER_LEN 128 
#define MAX_CHANNELS 2 

int sndFile_play (const char *infilename){ 
    PaStreamParameters outputParameters; 
    PaStream *stream; 
    PaError err; 
    static short data[BUFFER_LEN]; 
    SNDFILE  *infile; 
    SF_INFO  sfinfo; 
    sf_count_t readcount; 
    int channels; 
    int srate; 

    err = Pa_Initialize(); 

    if (!(infile = sf_open(infilename, SFM_READ, &sfinfo))) { 
     printf ("Not able to open input file %s.\n", infilename); 
     puts (sf_strerror (NULL)); 
     return 1; 
    } 

    if (sfinfo.channels > MAX_CHANNELS){ 
     printf ("Not able to process more than %d channels\n", MAX_CHANNELS); 
     return 1; 
    } 
    /* FILE INFO */ 

    channels = sfinfo.channels; // убрать channels 
    printf("number of channels %d\n", sfinfo.channels); 

    srate = sfinfo.samplerate; //убрать 
    printf("sample rate %d\n", sfinfo.samplerate); 

    outputParameters.device = Pa_GetDefaultOutputDevice(); 
    outputParameters.channelCount = sfinfo.channels; 
    outputParameters.sampleFormat = PA_SAMPLE_TYPE; 
    outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; 
    outputParameters.hostApiSpecificStreamInfo = NULL; 

    printf("Begin playback.....\n"); fflush(stdout); 
    err = Pa_OpenStream(
     &stream, 
     NULL, 
     &outputParameters, 
     sfinfo.samplerate, 
     FRAMES_PER_BUFFER, 
     paClipOff, 
     NULL, 
     NULL); 

    if(stream) { 

     err = Pa_StartStream(stream); 
     printf("Waiting for playback to finish....\n"); fflush(stdout); 

     while ((readcount = sf_read_short(infile, data, BUFFER_LEN*sfinfo.channels))){ 
      err = Pa_WriteStream(stream, data, BUFFER_LEN); 
     } 

     err = Pa_CloseStream(stream); 
     printf("Done.\n"); fflush(stdout); 

    } 

    sf_close(infile); 

    Pa_Terminate(); 
    return 0; 
} 

ответ

2

Ваш код

while ((readcount = sf_read_short(infile, data, BUFFER_LEN*sfinfo.channels))){ 
    err = Pa_WriteStream(stream, data, BUFFER_LEN); 
} 

останавливает главного Gtk цикл от прогрессирования. Для приложений с графическим интерфейсом вы не можете долго работать, пока циклы в обратных вызовах или графический интерфейс замерзает. Есть несколько решений

1) Привод на цикл выполнения внутри цикла при использовании что-то вроде

... 

while (gtk_events_pending()) { 
    gtk_main_iteration(); 
} 

... 

Это означает, что каждый раз, когда звуковой цикл выполняется, все GTK события, которые создали будет обработанный.

2) Извлеките звук из режима обратного вызова. Это позволяет графическому интерфейсу работать как обычно, а затем, когда он не занят, будет вызван ваш обратный вызов, и вы можете сыграть следующий буфер.

3) Управляйте аудио-контуром в отдельном потоке. Это позволит графическому интерфейсу работать как обычно на основном потоке, и звук будет просто воспроизводиться. Это несет в себе все стандартные опасности программирования с резьбой

4) Portaudio имеет асинхронную модель с обратным вызовом. Используйте это, и ваш обратный вызов будет вызван, когда Portaudio потребуется больше данных. Это также довольно сложно, потому что вы не должны делать доступ к файлам или распределения памяти в этом обратном вызове. Более подробная информация находится здесь: Portaudio callback documentation.

Чтобы быть честным, звуковое программирование на этом базовом уровне является сложным, и я бы рекомендовал использовать фреймворк вроде (например) GStreamer, который уже разработал все эти сложности.

+0

спасибо, Иэн! собираюсь проверить GStreamer. – Cecil

 Смежные вопросы

  • Нет связанных вопросов^_^