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 "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); /* not destroyed? */ 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 }