Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
visualization.c
Go to the documentation of this file.
1 /*
2  * visualization.c
3  * Copyright 2010-2011 John Lindgren
4  *
5  * This file is part of Audacious.
6  *
7  * Audacious is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, version 2 or version 3 of the License.
10  *
11  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Audacious. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * The Audacious team does not consider modular code linking to Audacious or
19  * using our public API to be a derived work.
20  */
21 
22 #include <glib.h>
23 #include <gtk/gtk.h>
24 #include <string.h>
25 
26 #include "debug.h"
27 #include "fft.h"
28 #include "interface.h"
29 #include "misc.h"
30 #include "plugin.h"
31 #include "plugins.h"
32 #include "ui_preferences.h"
33 #include "visualization.h"
34 #include "vis_runner.h"
35 
36 static GList * vis_funcs[AUD_VIS_TYPES];
37 
38 typedef struct {
40  VisPlugin * header;
41  GtkWidget * widget;
42 } LoadedVis;
43 
44 static int running = FALSE;
45 static GList * loaded_vis_plugins = NULL;
46 
47 void vis_func_add (int type, GCallback func)
48 {
49  g_return_if_fail (type >= 0 && type < AUD_VIS_TYPES);
50  vis_funcs[type] = g_list_prepend (vis_funcs[type], (void *) func);
51 
53 }
54 
55 void vis_func_remove (GCallback func)
56 {
57  bool_t disable = TRUE;
58 
59  for (int i = 0; i < AUD_VIS_TYPES; i ++)
60  {
61  vis_funcs[i] = g_list_remove_all (vis_funcs[i], (void *) func);
62  if (vis_funcs[i])
63  disable = FALSE;
64  }
65 
66  if (disable)
68 }
69 
70 void vis_send_clear (void)
71 {
72  for (GList * node = vis_funcs[AUD_VIS_TYPE_CLEAR]; node; node = node->next)
73  {
74  void (* func) (void) = (void (*) (void)) node->data;
75  func ();
76  }
77 }
78 
79 static void pcm_to_mono (const float * data, float * mono, int channels)
80 {
81  if (channels == 1)
82  memcpy (mono, data, sizeof (float) * 512);
83  else
84  {
85  float * set = mono;
86  while (set < & mono[512])
87  {
88  * set ++ = (data[0] + data[1]) / 2;
89  data += channels;
90  }
91  }
92 }
93 
94 void vis_send_audio (const float * data, int channels)
95 {
96  float mono[512];
97  float freq[256];
98 
100  pcm_to_mono (data, mono, channels);
101  if (vis_funcs[AUD_VIS_TYPE_FREQ])
102  calc_freq (mono, freq);
103 
104  for (GList * node = vis_funcs[AUD_VIS_TYPE_MONO_PCM]; node; node = node->next)
105  {
106  void (* func) (const float *) = (void (*) (const float *)) node->data;
107  func (mono);
108  }
109 
110  for (GList * node = vis_funcs[AUD_VIS_TYPE_MULTI_PCM]; node; node = node->next)
111  {
112  void (* func) (const float *, int) = (void (*) (const float *, int)) node->data;
113  func (data, channels);
114  }
115 
116  for (GList * node = vis_funcs[AUD_VIS_TYPE_FREQ]; node; node = node->next)
117  {
118  void (* func) (const float *) = (void (*) (const float *)) node->data;
119  func (freq);
120  }
121 }
122 
124 {
125  return (vis->plugin == plugin) ? 0 : -1;
126 }
127 
128 static void vis_load (PluginHandle * plugin)
129 {
130  GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
131  (GCompareFunc) vis_find_cb);
132  if (node != NULL)
133  return;
134 
135  AUDDBG ("Loading %s.\n", plugin_get_name (plugin));
136  VisPlugin * header = plugin_get_header (plugin);
137  g_return_if_fail (header != NULL);
138 
139  LoadedVis * vis = g_slice_new (LoadedVis);
140  vis->plugin = plugin;
141  vis->header = header;
142  vis->widget = NULL;
143 
144  if (header->get_widget != NULL)
145  vis->widget = header->get_widget ();
146 
147  if (vis->widget != NULL)
148  {
149  AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin));
150  g_signal_connect (vis->widget, "destroy", (GCallback)
151  gtk_widget_destroyed, & vis->widget);
152  interface_add_plugin_widget (plugin, vis->widget);
153  }
154 
155  if (PLUGIN_HAS_FUNC (header, clear))
156  vis_func_add (AUD_VIS_TYPE_CLEAR, (GCallback) header->clear);
157  if (PLUGIN_HAS_FUNC (header, render_mono_pcm))
158  vis_func_add (AUD_VIS_TYPE_MONO_PCM, (GCallback) header->render_mono_pcm);
159  if (PLUGIN_HAS_FUNC (header, render_multi_pcm))
160  vis_func_add (AUD_VIS_TYPE_MULTI_PCM, (GCallback) header->render_multi_pcm);
161  if (PLUGIN_HAS_FUNC (header, render_freq))
162  vis_func_add (AUD_VIS_TYPE_FREQ, (GCallback) header->render_freq);
163 
164  loaded_vis_plugins = g_list_prepend (loaded_vis_plugins, vis);
165 }
166 
168 {
169  GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
170  (GCompareFunc) vis_find_cb);
171  if (node == NULL)
172  return;
173 
174  AUDDBG ("Unloading %s.\n", plugin_get_name (plugin));
175  LoadedVis * vis = node->data;
176  loaded_vis_plugins = g_list_delete_link (loaded_vis_plugins, node);
177 
178  VisPlugin * header = vis->header;
179  if (PLUGIN_HAS_FUNC (header, clear))
180  vis_func_remove ((GCallback) header->clear);
181  if (PLUGIN_HAS_FUNC (header, render_mono_pcm))
182  vis_func_remove ((GCallback) header->render_mono_pcm);
183  if (PLUGIN_HAS_FUNC (header, render_multi_pcm))
184  vis_func_remove ((GCallback) header->render_multi_pcm);
185  if (PLUGIN_HAS_FUNC (header, render_freq))
186  vis_func_remove ((GCallback) header->render_freq);
187 
188  if (vis->widget != NULL)
189  {
190  AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin));
191  interface_remove_plugin_widget (plugin, vis->widget);
192  g_return_if_fail (vis->widget == NULL); /* not destroyed? */
193  }
194 
195  g_slice_free (LoadedVis, vis);
196 }
197 
199 {
200  vis_load (plugin);
201  return TRUE;
202 }
203 
204 void vis_init (void)
205 {
206  g_return_if_fail (! running);
207  running = TRUE;
208 
210 }
211 
212 static void vis_cleanup_cb (LoadedVis * vis)
213 {
214  vis_unload (vis->plugin);
215 }
216 
217 void vis_cleanup (void)
218 {
219  g_return_if_fail (running);
220  running = FALSE;
221 
222  g_list_foreach (loaded_vis_plugins, (GFunc) vis_cleanup_cb, NULL);
223 }
224 
226 {
227  VisPlugin * vp = plugin_get_header (plugin);
228  g_return_val_if_fail (vp != NULL, FALSE);
229 
230  if (vp->init != NULL && ! vp->init ())
231  return FALSE;
232 
233  if (running)
234  vis_load (plugin);
235 
236  return TRUE;
237 }
238 
240 {
241  VisPlugin * vp = plugin_get_header (plugin);
242  g_return_if_fail (vp != NULL);
243 
244  if (running)
245  vis_unload (plugin);
246 
247  if (vp->settings != NULL)
248  plugin_preferences_cleanup (vp->settings);
249  if (vp->cleanup != NULL)
250  vp->cleanup ();
251 }
252 
253 PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget)
254 {
255  g_return_val_if_fail (widget, NULL);
256 
257  for (GList * node = loaded_vis_plugins; node; node = node->next)
258  {
259  LoadedVis * vis = node->data;
260  if (vis->widget == widget)
261  return vis->plugin;
262  }
263 
264  return NULL;
265 }