Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
visualization.c
Go to the documentation of this file.
00001 /*
00002  * visualization.c
00003  * Copyright 2010-2011 John Lindgren
00004  *
00005  * This file is part of Audacious.
00006  *
00007  * Audacious is free software: you can redistribute it and/or modify it under
00008  * the terms of the GNU General Public License as published by the Free Software
00009  * Foundation, version 2 or version 3 of the License.
00010  *
00011  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
00012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00013  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along with
00016  * Audacious. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The Audacious team does not consider modular code linking to Audacious or
00019  * using our public API to be a derived work.
00020  */
00021 
00022 #include <glib.h>
00023 #include <gtk/gtk.h>
00024 #include <string.h>
00025 
00026 #include "debug.h"
00027 #include "fft.h"
00028 #include "interface.h"
00029 #include "misc.h"
00030 #include "plugin.h"
00031 #include "plugins.h"
00032 #include "ui_preferences.h"
00033 #include "visualization.h"
00034 #include "vis_runner.h"
00035 
00036 static GList * vis_funcs[AUD_VIS_TYPES];
00037 
00038 typedef struct {
00039     PluginHandle * plugin;
00040     VisPlugin * header;
00041     GtkWidget * widget;
00042 } LoadedVis;
00043 
00044 static int running = FALSE;
00045 static GList * loaded_vis_plugins = NULL;
00046 
00047 void vis_func_add (int type, GCallback func)
00048 {
00049     g_return_if_fail (type >= 0 && type < AUD_VIS_TYPES);
00050     vis_funcs[type] = g_list_prepend (vis_funcs[type], (void *) func);
00051 
00052     vis_runner_enable (TRUE);
00053 }
00054 
00055 void vis_func_remove (GCallback func)
00056 {
00057     bool_t disable = TRUE;
00058 
00059     for (int i = 0; i < AUD_VIS_TYPES; i ++)
00060     {
00061         vis_funcs[i] = g_list_remove_all (vis_funcs[i], (void *) func);
00062         if (vis_funcs[i])
00063             disable = FALSE;
00064     }
00065 
00066     if (disable)
00067         vis_runner_enable (FALSE);
00068 }
00069 
00070 void vis_send_clear (void)
00071 {
00072     for (GList * node = vis_funcs[AUD_VIS_TYPE_CLEAR]; node; node = node->next)
00073     {
00074         void (* func) (void) = (void (*) (void)) node->data;
00075         func ();
00076     }
00077 }
00078 
00079 static void pcm_to_mono (const float * data, float * mono, int channels)
00080 {
00081     if (channels == 1)
00082         memcpy (mono, data, sizeof (float) * 512);
00083     else
00084     {
00085         float * set = mono;
00086         while (set < & mono[512])
00087         {
00088             * set ++ = (data[0] + data[1]) / 2;
00089             data += channels;
00090         }
00091     }
00092 }
00093 
00094 void vis_send_audio (const float * data, int channels)
00095 {
00096     float mono[512];
00097     float freq[256];
00098 
00099     if (vis_funcs[AUD_VIS_TYPE_MONO_PCM] || vis_funcs[AUD_VIS_TYPE_FREQ])
00100         pcm_to_mono (data, mono, channels);
00101     if (vis_funcs[AUD_VIS_TYPE_FREQ])
00102         calc_freq (mono, freq);
00103 
00104     for (GList * node = vis_funcs[AUD_VIS_TYPE_MONO_PCM]; node; node = node->next)
00105     {
00106         void (* func) (const float *) = (void (*) (const float *)) node->data;
00107         func (mono);
00108     }
00109 
00110     for (GList * node = vis_funcs[AUD_VIS_TYPE_MULTI_PCM]; node; node = node->next)
00111     {
00112         void (* func) (const float *, int) = (void (*) (const float *, int)) node->data;
00113         func (data, channels);
00114     }
00115 
00116     for (GList * node = vis_funcs[AUD_VIS_TYPE_FREQ]; node; node = node->next)
00117     {
00118         void (* func) (const float *) = (void (*) (const float *)) node->data;
00119         func (freq);
00120     }
00121 }
00122 
00123 static int vis_find_cb (LoadedVis * vis, PluginHandle * plugin)
00124 {
00125     return (vis->plugin == plugin) ? 0 : -1;
00126 }
00127 
00128 static void vis_load (PluginHandle * plugin)
00129 {
00130     GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
00131      (GCompareFunc) vis_find_cb);
00132     if (node != NULL)
00133         return;
00134 
00135     AUDDBG ("Loading %s.\n", plugin_get_name (plugin));
00136     VisPlugin * header = plugin_get_header (plugin);
00137     g_return_if_fail (header != NULL);
00138 
00139     LoadedVis * vis = g_slice_new (LoadedVis);
00140     vis->plugin = plugin;
00141     vis->header = header;
00142     vis->widget = NULL;
00143 
00144     if (header->get_widget != NULL)
00145         vis->widget = header->get_widget ();
00146 
00147     if (vis->widget != NULL)
00148     {
00149         AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin));
00150         g_signal_connect (vis->widget, "destroy", (GCallback)
00151          gtk_widget_destroyed, & vis->widget);
00152         interface_add_plugin_widget (plugin, vis->widget);
00153     }
00154 
00155     if (PLUGIN_HAS_FUNC (header, clear))
00156         vis_func_add (AUD_VIS_TYPE_CLEAR, (GCallback) header->clear);
00157     if (PLUGIN_HAS_FUNC (header, render_mono_pcm))
00158         vis_func_add (AUD_VIS_TYPE_MONO_PCM, (GCallback) header->render_mono_pcm);
00159     if (PLUGIN_HAS_FUNC (header, render_multi_pcm))
00160         vis_func_add (AUD_VIS_TYPE_MULTI_PCM, (GCallback) header->render_multi_pcm);
00161     if (PLUGIN_HAS_FUNC (header, render_freq))
00162         vis_func_add (AUD_VIS_TYPE_FREQ, (GCallback) header->render_freq);
00163 
00164     loaded_vis_plugins = g_list_prepend (loaded_vis_plugins, vis);
00165 }
00166 
00167 static void vis_unload (PluginHandle * plugin)
00168 {
00169     GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
00170      (GCompareFunc) vis_find_cb);
00171     if (node == NULL)
00172         return;
00173 
00174     AUDDBG ("Unloading %s.\n", plugin_get_name (plugin));
00175     LoadedVis * vis = node->data;
00176     loaded_vis_plugins = g_list_delete_link (loaded_vis_plugins, node);
00177 
00178     VisPlugin * header = vis->header;
00179     if (PLUGIN_HAS_FUNC (header, clear))
00180         vis_func_remove ((GCallback) header->clear);
00181     if (PLUGIN_HAS_FUNC (header, render_mono_pcm))
00182         vis_func_remove ((GCallback) header->render_mono_pcm);
00183     if (PLUGIN_HAS_FUNC (header, render_multi_pcm))
00184         vis_func_remove ((GCallback) header->render_multi_pcm);
00185     if (PLUGIN_HAS_FUNC (header, render_freq))
00186         vis_func_remove ((GCallback) header->render_freq);
00187 
00188     if (vis->widget != NULL)
00189     {
00190         AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin));
00191         interface_remove_plugin_widget (plugin, vis->widget);
00192         g_return_if_fail (vis->widget == NULL); /* not destroyed? */
00193     }
00194 
00195     g_slice_free (LoadedVis, vis);
00196 }
00197 
00198 static bool_t vis_init_cb (PluginHandle * plugin)
00199 {
00200     vis_load (plugin);
00201     return TRUE;
00202 }
00203 
00204 void vis_init (void)
00205 {
00206     g_return_if_fail (! running);
00207     running = TRUE;
00208 
00209     plugin_for_enabled (PLUGIN_TYPE_VIS, (PluginForEachFunc) vis_init_cb, NULL);
00210 }
00211 
00212 static void vis_cleanup_cb (LoadedVis * vis)
00213 {
00214     vis_unload (vis->plugin);
00215 }
00216 
00217 void vis_cleanup (void)
00218 {
00219     g_return_if_fail (running);
00220     running = FALSE;
00221 
00222     g_list_foreach (loaded_vis_plugins, (GFunc) vis_cleanup_cb, NULL);
00223 }
00224 
00225 bool_t vis_plugin_start (PluginHandle * plugin)
00226 {
00227     VisPlugin * vp = plugin_get_header (plugin);
00228     g_return_val_if_fail (vp != NULL, FALSE);
00229 
00230     if (vp->init != NULL && ! vp->init ())
00231         return FALSE;
00232 
00233     if (running)
00234         vis_load (plugin);
00235 
00236     return TRUE;
00237 }
00238 
00239 void vis_plugin_stop (PluginHandle * plugin)
00240 {
00241     VisPlugin * vp = plugin_get_header (plugin);
00242     g_return_if_fail (vp != NULL);
00243 
00244     if (running)
00245         vis_unload (plugin);
00246 
00247     if (vp->settings != NULL)
00248         plugin_preferences_cleanup (vp->settings);
00249     if (vp->cleanup != NULL)
00250         vp->cleanup ();
00251 }
00252 
00253 PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget)
00254 {
00255     g_return_val_if_fail (widget, NULL);
00256 
00257     for (GList * node = loaded_vis_plugins; node; node = node->next)
00258     {
00259         LoadedVis * vis = node->data;
00260         if (vis->widget == widget)
00261             return vis->plugin;
00262     }
00263 
00264     return NULL;
00265 }