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  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <glib.h>
21 #include <gtk/gtk.h>
22 #include <string.h>
23 
24 #include "debug.h"
25 #include "fft.h"
26 #include "interface.h"
27 #include "misc.h"
28 #include "plugin.h"
29 #include "plugins.h"
30 #include "ui_preferences.h"
31 #include "visualization.h"
32 #include "vis_runner.h"
33 
34 static GList * vis_funcs[AUD_VIS_TYPES];
35 
36 typedef struct {
38  VisPlugin * header;
39  GtkWidget * widget;
40 } LoadedVis;
41 
42 static int running = FALSE;
43 static GList * loaded_vis_plugins = NULL;
44 
45 void vis_func_add (int type, GCallback func)
46 {
47  g_return_if_fail (type >= 0 && type < AUD_VIS_TYPES);
48  vis_funcs[type] = g_list_prepend (vis_funcs[type], (void *) func);
49 
51 }
52 
53 void vis_func_remove (GCallback func)
54 {
55  bool_t disable = TRUE;
56 
57  for (int i = 0; i < AUD_VIS_TYPES; i ++)
58  {
59  vis_funcs[i] = g_list_remove_all (vis_funcs[i], (void *) func);
60  if (vis_funcs[i])
61  disable = FALSE;
62  }
63 
64  if (disable)
66 }
67 
68 void vis_send_clear (void)
69 {
70  for (GList * node = vis_funcs[AUD_VIS_TYPE_CLEAR]; node; node = node->next)
71  {
72  void (* func) (void) = (void (*) (void)) node->data;
73  func ();
74  }
75 }
76 
77 static void pcm_to_mono (const float * data, float * mono, int channels)
78 {
79  if (channels == 1)
80  memcpy (mono, data, sizeof (float) * 512);
81  else
82  {
83  float * set = mono;
84  while (set < & mono[512])
85  {
86  * set ++ = (data[0] + data[1]) / 2;
87  data += channels;
88  }
89  }
90 }
91 
92 void vis_send_audio (const float * data, int channels)
93 {
94  float mono[512];
95  float freq[256];
96 
98  pcm_to_mono (data, mono, channels);
99  if (vis_funcs[AUD_VIS_TYPE_FREQ])
100  calc_freq (mono, freq);
101 
102  for (GList * node = vis_funcs[AUD_VIS_TYPE_MONO_PCM]; node; node = node->next)
103  {
104  void (* func) (const float *) = (void (*) (const float *)) node->data;
105  func (mono);
106  }
107 
108  for (GList * node = vis_funcs[AUD_VIS_TYPE_MULTI_PCM]; node; node = node->next)
109  {
110  void (* func) (const float *, int) = (void (*) (const float *, int)) node->data;
111  func (data, channels);
112  }
113 
114  for (GList * node = vis_funcs[AUD_VIS_TYPE_FREQ]; node; node = node->next)
115  {
116  void (* func) (const float *) = (void (*) (const float *)) node->data;
117  func (freq);
118  }
119 }
120 
122 {
123  return (vis->plugin == plugin) ? 0 : -1;
124 }
125 
126 static void vis_load (PluginHandle * plugin)
127 {
128  GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
129  (GCompareFunc) vis_find_cb);
130  if (node != NULL)
131  return;
132 
133  AUDDBG ("Loading %s.\n", plugin_get_name (plugin));
134  VisPlugin * header = plugin_get_header (plugin);
135  g_return_if_fail (header != NULL);
136 
137  LoadedVis * vis = g_slice_new (LoadedVis);
138  vis->plugin = plugin;
139  vis->header = header;
140  vis->widget = NULL;
141 
142  if (header->get_widget != NULL)
143  vis->widget = header->get_widget ();
144 
145  if (vis->widget != NULL)
146  {
147  AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin));
148  g_signal_connect (vis->widget, "destroy", (GCallback)
149  gtk_widget_destroyed, & vis->widget);
150  interface_add_plugin_widget (plugin, vis->widget);
151  }
152 
153  if (PLUGIN_HAS_FUNC (header, clear))
154  vis_func_add (AUD_VIS_TYPE_CLEAR, (GCallback) header->clear);
155  if (PLUGIN_HAS_FUNC (header, render_mono_pcm))
156  vis_func_add (AUD_VIS_TYPE_MONO_PCM, (GCallback) header->render_mono_pcm);
157  if (PLUGIN_HAS_FUNC (header, render_multi_pcm))
158  vis_func_add (AUD_VIS_TYPE_MULTI_PCM, (GCallback) header->render_multi_pcm);
159  if (PLUGIN_HAS_FUNC (header, render_freq))
160  vis_func_add (AUD_VIS_TYPE_FREQ, (GCallback) header->render_freq);
161 
162  loaded_vis_plugins = g_list_prepend (loaded_vis_plugins, vis);
163 }
164 
166 {
167  GList * node = g_list_find_custom (loaded_vis_plugins, plugin,
168  (GCompareFunc) vis_find_cb);
169  if (node == NULL)
170  return;
171 
172  AUDDBG ("Unloading %s.\n", plugin_get_name (plugin));
173  LoadedVis * vis = node->data;
174  loaded_vis_plugins = g_list_delete_link (loaded_vis_plugins, node);
175 
176  VisPlugin * header = vis->header;
177  if (PLUGIN_HAS_FUNC (header, clear))
178  vis_func_remove ((GCallback) header->clear);
179  if (PLUGIN_HAS_FUNC (header, render_mono_pcm))
180  vis_func_remove ((GCallback) header->render_mono_pcm);
181  if (PLUGIN_HAS_FUNC (header, render_multi_pcm))
182  vis_func_remove ((GCallback) header->render_multi_pcm);
183  if (PLUGIN_HAS_FUNC (header, render_freq))
184  vis_func_remove ((GCallback) header->render_freq);
185 
186  if (vis->widget != NULL)
187  {
188  AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin));
189  interface_remove_plugin_widget (plugin, vis->widget);
190  g_return_if_fail (vis->widget == NULL); /* not destroyed? */
191  }
192 
193  g_slice_free (LoadedVis, vis);
194 }
195 
197 {
198  vis_load (plugin);
199  return TRUE;
200 }
201 
202 void vis_init (void)
203 {
204  g_return_if_fail (! running);
205  running = TRUE;
206 
208 }
209 
210 static void vis_cleanup_cb (LoadedVis * vis)
211 {
212  vis_unload (vis->plugin);
213 }
214 
215 void vis_cleanup (void)
216 {
217  g_return_if_fail (running);
218  running = FALSE;
219 
220  g_list_foreach (loaded_vis_plugins, (GFunc) vis_cleanup_cb, NULL);
221 }
222 
224 {
225  VisPlugin * vp = plugin_get_header (plugin);
226  g_return_val_if_fail (vp != NULL, FALSE);
227 
228  if (vp->init != NULL && ! vp->init ())
229  return FALSE;
230 
231  if (running)
232  vis_load (plugin);
233 
234  return TRUE;
235 }
236 
238 {
239  VisPlugin * vp = plugin_get_header (plugin);
240  g_return_if_fail (vp != NULL);
241 
242  if (running)
243  vis_unload (plugin);
244 
245  if (vp->cleanup != NULL)
246  vp->cleanup ();
247 }
248 
249 PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget)
250 {
251  g_return_val_if_fail (widget, NULL);
252 
253  for (GList * node = loaded_vis_plugins; node; node = node->next)
254  {
255  LoadedVis * vis = node->data;
256  if (vis->widget == widget)
257  return vis->plugin;
258  }
259 
260  return NULL;
261 }