Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
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 }