00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <glib.h>
00023
00024 #include "output.h"
00025 #include "vis_runner.h"
00026 #include "visualization.h"
00027
00028 #define INTERVAL 30
00029
00030 typedef struct {
00031 gint time;
00032 gfloat * data;
00033 gint channels;
00034 } VisNode;
00035
00036 G_LOCK_DEFINE_STATIC (mutex);
00037 static gboolean enabled = FALSE;
00038 static gboolean playing = FALSE, paused = FALSE, active = FALSE;
00039 static VisNode * current_node = NULL;
00040 static gint current_frames;
00041 static GQueue vis_list = G_QUEUE_INIT;
00042 static gint send_source = 0, clear_source = 0;
00043
00044 static void vis_node_free (VisNode * node)
00045 {
00046 g_free (node->data);
00047 g_free (node);
00048 }
00049
00050 static gboolean send_audio (void * unused)
00051 {
00052 G_LOCK (mutex);
00053
00054 if (! send_source)
00055 {
00056 G_UNLOCK (mutex);
00057 return FALSE;
00058 }
00059
00060 gint outputted = get_raw_output_time ();
00061
00062 VisNode * vis_node = NULL;
00063 VisNode * next;
00064
00065 while ((next = g_queue_peek_head (& vis_list)))
00066 {
00067
00068
00069
00070
00071 if (next->time > outputted + (vis_node ? 0 : INTERVAL))
00072 break;
00073
00074 if (vis_node)
00075 vis_node_free (vis_node);
00076
00077 vis_node = g_queue_pop_head (& vis_list);
00078 }
00079
00080 G_UNLOCK (mutex);
00081
00082 if (! vis_node)
00083 return TRUE;
00084
00085 vis_send_audio (vis_node->data, vis_node->channels);
00086
00087 vis_node_free (vis_node);
00088 return TRUE;
00089 }
00090
00091 static gboolean send_clear (void * unused)
00092 {
00093 G_LOCK (mutex);
00094 clear_source = 0;
00095 G_UNLOCK (mutex);
00096
00097 vis_send_clear ();
00098
00099 return FALSE;
00100 }
00101
00102 static gboolean locked = FALSE;
00103
00104 void vis_runner_lock (void)
00105 {
00106 G_LOCK (mutex);
00107 locked = TRUE;
00108 }
00109
00110 void vis_runner_unlock (void)
00111 {
00112 locked = FALSE;
00113 G_UNLOCK (mutex);
00114 }
00115
00116 gboolean vis_runner_locked (void)
00117 {
00118 return locked;
00119 }
00120
00121 void vis_runner_flush (void)
00122 {
00123 if (current_node)
00124 {
00125 vis_node_free (current_node);
00126 current_node = NULL;
00127 }
00128
00129 g_queue_foreach (& vis_list, (GFunc) vis_node_free, NULL);
00130 g_queue_clear (& vis_list);
00131
00132 if (! clear_source)
00133 clear_source = g_timeout_add (0, send_clear, NULL);
00134 }
00135
00136 void vis_runner_start_stop (gboolean new_playing, gboolean new_paused)
00137 {
00138 playing = new_playing;
00139 paused = new_paused;
00140 active = playing && enabled;
00141
00142 if (send_source)
00143 {
00144 g_source_remove (send_source);
00145 send_source = 0;
00146 }
00147
00148 if (clear_source)
00149 {
00150 g_source_remove (clear_source);
00151 clear_source = 0;
00152 }
00153
00154 if (! active)
00155 vis_runner_flush ();
00156 else if (! paused)
00157 send_source = g_timeout_add (INTERVAL, send_audio, NULL);
00158 }
00159
00160 void vis_runner_pass_audio (gint time, gfloat * data, gint samples, gint
00161 channels, gint rate)
00162 {
00163 if (! active)
00164 return;
00165
00166
00167
00168
00169
00170 if (current_node && current_node->channels != channels)
00171 {
00172 vis_node_free (current_node);
00173 current_node = NULL;
00174 }
00175
00176 gint at = 0;
00177
00178 while (1)
00179 {
00180 if (! current_node)
00181 {
00182 gint node_time = time;
00183 VisNode * last;
00184
00185
00186
00187
00188
00189
00190
00191
00192 if ((last = g_queue_peek_tail (& vis_list)))
00193 node_time = last->time + INTERVAL;
00194
00195 at = channels * (gint) ((gint64) (node_time - time) * rate / 1000);
00196
00197 if (at < 0)
00198 at = 0;
00199 if (at >= samples)
00200 break;
00201
00202 current_node = g_malloc (sizeof (VisNode));
00203 current_node->time = node_time;
00204 current_node->data = g_malloc (sizeof (gfloat) * channels * 512);
00205 current_node->channels = channels;
00206 current_frames = 0;
00207 }
00208
00209
00210
00211
00212
00213
00214 gint copy = MIN (samples - at, channels * (512 - current_frames));
00215 memcpy (current_node->data + channels * current_frames, data + at, sizeof (gfloat) * copy);
00216 current_frames += copy / channels;
00217
00218 if (current_frames < 512)
00219 break;
00220
00221 g_queue_push_tail (& vis_list, current_node);
00222 current_node = NULL;
00223 }
00224 }
00225
00226 static void time_offset_cb (VisNode * vis_node, void * offset)
00227 {
00228 vis_node->time += GPOINTER_TO_INT (offset);
00229 }
00230
00231 void vis_runner_time_offset (gint offset)
00232 {
00233 if (current_node)
00234 current_node->time += offset;
00235
00236 g_queue_foreach (& vis_list, (GFunc) time_offset_cb, GINT_TO_POINTER (offset));
00237 }
00238
00239 void vis_runner_enable (gboolean enable)
00240 {
00241 G_LOCK (mutex);
00242 enabled = enable;
00243 vis_runner_start_stop (playing, paused);
00244 G_UNLOCK (mutex);
00245 }