# HG changeset patch # User nenolod # Date 1143493509 28800 # Node ID ed26947bbf573c6b1bbef7f6697989081199586f # Parent 21e0ef28e318d7d008802b33cafa647e9d997193 [svn] Gapless support. This comes with a few caveats, that I will mention here: 1) It is not really gapless, it just removes any delays caused by resetting the output device. Mileage depends on source performance. However, this commit reduces any gaps I have to a period of time that is unnoticable to me. (Of course, I have a 15k RPM SATA drive too.) diff -r 21e0ef28e318 -r ed26947bbf57 audacious/input.c --- a/audacious/input.c Mon Mar 27 11:02:35 2006 -0800 +++ b/audacious/input.c Mon Mar 27 13:05:09 2006 -0800 @@ -60,6 +60,7 @@ NULL, FALSE, FALSE, + FALSE, NULL }; diff -r 21e0ef28e318 -r ed26947bbf57 audacious/input.h --- a/audacious/input.h Mon Mar 27 11:02:35 2006 -0800 +++ b/audacious/input.h Mon Mar 27 13:05:09 2006 -0800 @@ -31,6 +31,7 @@ InputPlugin *current_input_plugin; gboolean playing; gboolean paused; + gboolean stop; GMutex *playback_mutex; }; diff -r 21e0ef28e318 -r ed26947bbf57 audacious/mainwin.c --- a/audacious/mainwin.c Mon Mar 27 11:02:35 2006 -0800 +++ b/audacious/mainwin.c Mon Mar 27 13:05:09 2006 -0800 @@ -2088,8 +2088,10 @@ void mainwin_stop_pushed(void) { + ip_data.stop = TRUE; mainwin_clear_song_info(); bmp_playback_stop(); + ip_data.stop = FALSE; } void diff -r 21e0ef28e318 -r ed26947bbf57 audacious/output.c --- a/audacious/output.c Mon Mar 27 11:02:35 2006 -0800 +++ b/audacious/output.c Mon Mar 27 13:05:09 2006 -0800 @@ -36,6 +36,12 @@ NULL }; +OutputPluginState op_state = { + 0, + 0, + 0 +}; + OutputPlugin psuedo_output_plugin = { NULL, NULL, @@ -46,17 +52,16 @@ NULL, output_get_volume, output_set_volume, - NULL, /* XXX we need noop code for this */ - NULL, - NULL, + output_open_audio, + output_write_audio, + output_close_audio, - NULL, - NULL, - NULL, - NULL, + output_flush, + output_pause, + output_buffer_free, + output_buffer_playing, get_output_time, get_written_time, - NULL }; @@ -215,6 +220,127 @@ return op->output_time(); } +gint +output_open_audio(AFormat fmt, gint rate, gint nch) +{ + gint ret; + OutputPlugin *op; + + op = get_current_output_plugin(); + + if (op == NULL) + return -1; + + /* Is our output port already open? */ + if ((op_state.rate != 0 && op_state.nch != 0) && + (op_state.rate == rate && op_state.nch == nch)) + { + /* Yes, and it's the correct sampling rate. Reset the counter and go. */ + op->flush(0); + return 1; + } + else if (op_state.rate != 0 && op_state.nch != 0) + op->close_audio(); + + ret = op->open_audio(fmt, rate, nch); + + if (ret == 1) /* Success? */ + { + op_state.fmt = fmt; + op_state.rate = rate; + op_state.nch = nch; + } + + return ret; +} + +void +output_write_audio(gpointer ptr, gint length) +{ + OutputPlugin *op = get_current_output_plugin(); + + /* Sanity check. */ + if (op == NULL) + return; + + op->write_audio(ptr, length); +} + +void +output_close_audio(void) +{ + OutputPlugin *op = get_current_output_plugin(); + + /* Do not close if there are still songs to play and the user has + * not requested a stop. --nenolod + */ + if (ip_data.stop == FALSE && + (playlist_get_position_nolock() < playlist_get_length_nolock() - 1)) + return; + + /* Sanity check. */ + if (op == NULL) + return; + +#if 0 + g_print("Requirements to close audio output have been met:\n" + "ip_data.stop = %d\n" + "playlist_get_position_nolock() = %d\n" + "playlist_get_length_nolock() - 1 = %d\n", + ip_data.stop, playlist_get_position_nolock(), + playlist_get_length_nolock() - 1); +#endif + + op->close_audio(); + + /* Reset the op_state. */ + op_state.fmt = op_state.rate = op_state.nch = 0; +} + +void +output_flush(gint time) +{ + OutputPlugin *op = get_current_output_plugin(); + + if (op == NULL) + return; + + op->flush(time); +} + +void +output_pause(gshort paused) +{ + OutputPlugin *op = get_current_output_plugin(); + + if (op == NULL) + return; + + op->pause(paused); +} + +gint +output_buffer_free(void) +{ + OutputPlugin *op = get_current_output_plugin(); + + if (op == NULL) + return 0; + + return op->buffer_free(); +} + +gint +output_buffer_playing(void) +{ + OutputPlugin *op = get_current_output_plugin(); + + if (op == NULL) + return 0; + + return op->buffer_playing(); +} + /* called by input plugin when data is ready */ void produce_audio(gint time, /* position */ @@ -261,5 +387,5 @@ g_usleep(10000); /* else sleep for retry */ } - op->write_audio(ptr, length); /* do output */ + op->write_audio(ptr, length); /* do output */ } diff -r 21e0ef28e318 -r ed26947bbf57 audacious/output.h --- a/audacious/output.h Mon Mar 27 11:02:35 2006 -0800 +++ b/audacious/output.h Mon Mar 27 13:05:09 2006 -0800 @@ -33,6 +33,14 @@ OutputPlugin *current_output_plugin; }; +typedef struct _OutputPluginState OutputPluginState; + +struct _OutputPluginState { + AFormat fmt; + gint rate; + gint nch; +}; + GList *get_output_list(void); OutputPlugin *get_current_output_plugin(void); void set_current_output_plugin(gint i); @@ -41,6 +49,15 @@ void output_get_volume(gint * l, gint * r); void output_set_volume(gint l, gint r); void output_set_eq(gboolean, gfloat, gfloat *); +gint output_open_audio(AFormat, gint, gint); +void output_write_audio(gpointer ptr, gint length); +void output_close_audio(void); + +void output_flush(gint); +void output_pause(gshort); +gint output_buffer_free(void); +gint output_buffer_playing(void); + void produce_audio(gint, AFormat, gint, gint, gpointer, int *); gint get_written_time(void); diff -r 21e0ef28e318 -r ed26947bbf57 audacious/playback.c --- a/audacious/playback.c Mon Mar 27 11:02:35 2006 -0800 +++ b/audacious/playback.c Mon Mar 27 13:05:09 2006 -0800 @@ -231,7 +231,7 @@ } set_current_input_plugin(entry->decoder); - entry->decoder->output = get_current_output_plugin(); + entry->decoder->output = &psuedo_output_plugin; entry->decoder->play_file(entry->filename); ip_data.playing = TRUE;