Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* Audacious - Cross-platform multimedia player 00002 * Copyright (C) 2005-2010 Audacious development team 00003 * 00004 * Based on BMP: 00005 * Copyright (C) 2003-2004 BMP development team 00006 * 00007 * Based on XMMS: 00008 * Copyright (C) 1998-2003 XMMS development team 00009 * 00010 * This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; under version 3 of the License. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program. If not, see <http://www.gnu.org/licenses>. 00021 * 00022 * The Audacious team does not consider modular code linking to 00023 * Audacious or using our public API to be a derived work. 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); /* not destroyed? */ 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 (/* GtkWidget * */ 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 }