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