00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <glib.h>
00027 #include <gtk/gtk.h>
00028 #include <math.h>
00029 #include <string.h>
00030
00031 #include <libaudcore/hook.h>
00032
00033 #include "debug.h"
00034 #include "fft.h"
00035 #include "interface.h"
00036 #include "misc.h"
00037 #include "playback.h"
00038 #include "plugin.h"
00039 #include "plugins.h"
00040 #include "ui_preferences.h"
00041 #include "visualization.h"
00042
00043 typedef struct {
00044 PluginHandle * plugin;
00045 VisPlugin * header;
00046 GtkWidget * widget;
00047 gboolean started;
00048 } LoadedVis;
00049
00050 static gint running = FALSE;
00051 static GList * loaded_vis_plugins = NULL;
00052
00053 void calc_stereo_pcm (VisPCMData dest, const VisPCMData src, gint nch)
00054 {
00055 memcpy(dest[0], src[0], 512 * sizeof(gint16));
00056 if (nch == 1)
00057 memcpy(dest[1], src[0], 512 * sizeof(gint16));
00058 else
00059 memcpy(dest[1], src[1], 512 * sizeof(gint16));
00060 }
00061
00062 void calc_mono_pcm (VisPCMData dest, const VisPCMData src, gint nch)
00063 {
00064 gint i;
00065 gint16 *d;
00066 const gint16 *sl, *sr;
00067
00068 if (nch == 1)
00069 memcpy(dest[0], src[0], 512 * sizeof(gint16));
00070 else {
00071 d = dest[0];
00072 sl = src[0];
00073 sr = src[1];
00074 for (i = 0; i < 512; i++) {
00075 *(d++) = (*(sl++) + *(sr++)) >> 1;
00076 }
00077 }
00078 }
00079
00080 static void calc_freq (gint16 * dest, const gint16 * src)
00081 {
00082 static fft_state *state = NULL;
00083 gfloat tmp_out[257];
00084 gint i;
00085
00086 if (!state)
00087 state = fft_init();
00088
00089 fft_perform(src, tmp_out, state);
00090
00091 for (i = 0; i < 256; i++)
00092 dest[i] = ((gint) sqrt(tmp_out[i + 1])) >> 8;
00093 }
00094
00095 void calc_mono_freq (VisFreqData dest, const VisPCMData src, gint nch)
00096 {
00097 gint i;
00098 gint16 *d, tmp[512];
00099 const gint16 *sl, *sr;
00100
00101 if (nch == 1)
00102 calc_freq(dest[0], src[0]);
00103 else {
00104 d = tmp;
00105 sl = src[0];
00106 sr = src[1];
00107 for (i = 0; i < 512; i++) {
00108 *(d++) = (*(sl++) + *(sr++)) >> 1;
00109 }
00110 calc_freq(dest[0], tmp);
00111 }
00112 }
00113
00114 void calc_stereo_freq (VisFreqData dest, const VisPCMData src, gint nch)
00115 {
00116 calc_freq(dest[0], src[0]);
00117
00118 if (nch == 2)
00119 calc_freq(dest[1], src[1]);
00120 else
00121 memcpy(dest[1], dest[0], 256 * sizeof(gint16));
00122 }
00123
00124 static void send_audio (const VisNode * vis_node)
00125 {
00126 gint16 mono_freq[2][256], stereo_freq[2][256];
00127 gboolean mono_freq_calced = FALSE, stereo_freq_calced = FALSE;
00128 gint16 mono_pcm[2][512], stereo_pcm[2][512];
00129 gboolean mono_pcm_calced = FALSE, stereo_pcm_calced = FALSE;
00130
00131 for (GList * node = loaded_vis_plugins; node != NULL; node = node->next)
00132 {
00133 VisPlugin * vp = ((LoadedVis *) node->data)->header;
00134
00135 if (vp->num_pcm_chs_wanted > 0 && vp->render_pcm) {
00136 if (vp->num_pcm_chs_wanted == 1) {
00137 if (!mono_pcm_calced) {
00138 calc_mono_pcm(mono_pcm, vis_node->data, vis_node->nch);
00139 mono_pcm_calced = TRUE;
00140 }
00141 vp->render_pcm(mono_pcm);
00142 }
00143 else {
00144 if (!stereo_pcm_calced) {
00145 calc_stereo_pcm(stereo_pcm, vis_node->data, vis_node->nch);
00146 stereo_pcm_calced = TRUE;
00147 }
00148 vp->render_pcm(stereo_pcm);
00149 }
00150 }
00151 if (vp->num_freq_chs_wanted > 0 && vp->render_freq) {
00152 if (vp->num_freq_chs_wanted == 1) {
00153 if (!mono_freq_calced) {
00154 calc_mono_freq(mono_freq, vis_node->data, vis_node->nch);
00155 mono_freq_calced = TRUE;
00156 }
00157 vp->render_freq(mono_freq);
00158 }
00159 else {
00160 if (!stereo_freq_calced) {
00161 calc_stereo_freq(stereo_freq, vis_node->data, vis_node->nch);
00162 stereo_freq_calced = TRUE;
00163 }
00164 vp->render_freq(stereo_freq);
00165 }
00166 }
00167 }
00168 }
00169
00170 static void vis_start (LoadedVis * vis)
00171 {
00172 if (vis->started)
00173 return;
00174 AUDDBG ("Starting %s.\n", plugin_get_name (vis->plugin));
00175 if (vis->header->playback_start != NULL)
00176 vis->header->playback_start ();
00177 vis->started = TRUE;
00178 }
00179
00180 static void vis_start_all (void)
00181 {
00182 g_list_foreach (loaded_vis_plugins, (GFunc) vis_start, NULL);
00183 }
00184
00185 static void vis_stop (LoadedVis * vis)
00186 {
00187 if (! vis->started)
00188 return;
00189 AUDDBG ("Stopping %s.\n", plugin_get_name (vis->plugin));
00190 if (vis->header->playback_stop != NULL)
00191 vis->header->playback_stop ();
00192 vis->started = FALSE;
00193 }
00194
00195 static void vis_stop_all (void)
00196 {
00197 g_list_foreach (loaded_vis_plugins, (GFunc) vis_stop, NULL);
00198 }
00199
00200 static gint vis_find_cb (LoadedVis * vis, PluginHandle * plugin)
00201 {
00202 return (vis->plugin == plugin) ? 0 : -1;
00203 }
00204
00205 static void vis_load (PluginHandle * plugin)
00206 {
00207 GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
00208 (GCompareFunc) vis_find_cb);
00209 if (node != NULL)
00210 return;
00211
00212 AUDDBG ("Loading %s.\n", plugin_get_name (plugin));
00213 VisPlugin * header = plugin_get_header (plugin);
00214 g_return_if_fail (header != NULL);
00215
00216 LoadedVis * vis = g_slice_new (LoadedVis);
00217 vis->plugin = plugin;
00218 vis->header = header;
00219 vis->widget = NULL;
00220 vis->started = FALSE;
00221
00222 if (header->get_widget != NULL)
00223 vis->widget = header->get_widget ();
00224
00225 if (vis->widget != NULL)
00226 {
00227 AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin));
00228 g_signal_connect (vis->widget, "destroy", (GCallback)
00229 gtk_widget_destroyed, & vis->widget);
00230 interface_add_plugin_widget (plugin, vis->widget);
00231 }
00232
00233 if (playback_get_playing ())
00234 vis_start (vis);
00235
00236 if (loaded_vis_plugins == NULL)
00237 vis_runner_add_hook ((VisHookFunc) send_audio, NULL);
00238
00239 loaded_vis_plugins = g_list_prepend (loaded_vis_plugins, vis);
00240 }
00241
00242 static void vis_unload (PluginHandle * plugin)
00243 {
00244 GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
00245 (GCompareFunc) vis_find_cb);
00246 if (node == NULL)
00247 return;
00248
00249 AUDDBG ("Unloading %s.\n", plugin_get_name (plugin));
00250 LoadedVis * vis = node->data;
00251 loaded_vis_plugins = g_list_delete_link (loaded_vis_plugins, node);
00252
00253 if (loaded_vis_plugins == NULL)
00254 vis_runner_remove_hook ((VisHookFunc) send_audio);
00255
00256 if (vis->widget != NULL)
00257 {
00258 AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin));
00259 interface_remove_plugin_widget (plugin, vis->widget);
00260 g_return_if_fail (vis->widget == NULL);
00261 }
00262
00263 g_slice_free (LoadedVis, vis);
00264 }
00265
00266 static gboolean vis_init_cb (PluginHandle * plugin)
00267 {
00268 vis_load (plugin);
00269 return TRUE;
00270 }
00271
00272 void vis_init (void)
00273 {
00274 g_return_if_fail (! running);
00275 running = TRUE;
00276
00277 plugin_for_enabled (PLUGIN_TYPE_VIS, (PluginForEachFunc) vis_init_cb, NULL);
00278
00279 hook_associate ("playback begin", (HookFunction) vis_start_all, NULL);
00280 hook_associate ("playback stop", (HookFunction) vis_stop_all, NULL);
00281 }
00282
00283 static void vis_cleanup_cb (LoadedVis * vis)
00284 {
00285 vis_unload (vis->plugin);
00286 }
00287
00288 void vis_cleanup (void)
00289 {
00290 g_return_if_fail (running);
00291 running = FALSE;
00292
00293 hook_dissociate ("playback begin", (HookFunction) vis_start_all);
00294 hook_dissociate ("playback stop", (HookFunction) vis_stop_all);
00295
00296 g_list_foreach (loaded_vis_plugins, (GFunc) vis_cleanup_cb, NULL);
00297 }
00298
00299 gboolean vis_plugin_start (PluginHandle * plugin)
00300 {
00301 VisPlugin * vp = plugin_get_header (plugin);
00302 g_return_val_if_fail (vp != NULL, FALSE);
00303
00304 if (vp->init != NULL && ! vp->init ())
00305 return FALSE;
00306
00307 if (running)
00308 vis_load (plugin);
00309
00310 return TRUE;
00311 }
00312
00313 void vis_plugin_stop (PluginHandle * plugin)
00314 {
00315 VisPlugin * vp = plugin_get_header (plugin);
00316 g_return_if_fail (vp != NULL);
00317
00318 if (running)
00319 vis_unload (plugin);
00320
00321 if (vp->settings != NULL)
00322 plugin_preferences_cleanup (vp->settings);
00323 if (vp->cleanup != NULL)
00324 vp->cleanup ();
00325 }
00326
00327 PluginHandle * vis_plugin_by_widget ( void * widget)
00328 {
00329 g_return_val_if_fail (widget, NULL);
00330
00331 for (GList * node = loaded_vis_plugins; node; node = node->next)
00332 {
00333 LoadedVis * vis = node->data;
00334 if (vis->widget == widget)
00335 return vis->plugin;
00336 }
00337
00338 return NULL;
00339 }