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