changeset 890:ed26947bbf57 trunk

[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.)
author nenolod
date Mon, 27 Mar 2006 13:05:09 -0800
parents 21e0ef28e318
children 08b940c25a9a
files audacious/input.c audacious/input.h audacious/mainwin.c audacious/output.c audacious/output.h audacious/playback.c
diffstat 6 files changed, 157 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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
 };
 
--- 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;
 };
 
--- 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
--- 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                */
 }
--- 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);
--- 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;