Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
effect.c
Go to the documentation of this file.
1 /*
2  * effect.c
3  * Copyright 2010 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 <pthread.h>
24 
25 #include "debug.h"
26 #include "effect.h"
27 #include "playback.h"
28 #include "plugin.h"
29 #include "plugins.h"
30 
31 typedef struct {
33  EffectPlugin * header;
34  int channels_returned, rate_returned;
37 
38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39 static GList * running_effects = NULL; /* (RunningEffect *) */
41 
42 typedef struct {
43  int * channels, * rate;
45 
47 {
48  AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
49  * state->channels, * state->rate);
50  EffectPlugin * header = plugin_get_header (plugin);
51  g_return_val_if_fail (header != NULL, TRUE);
52  header->start (state->channels, state->rate);
53 
54  RunningEffect * effect = g_malloc (sizeof (RunningEffect));
55  effect->plugin = plugin;
56  effect->header = header;
57  effect->channels_returned = * state->channels;
58  effect->rate_returned = * state->rate;
59  effect->remove_flag = FALSE;
60 
61  running_effects = g_list_prepend (running_effects, effect);
62  return TRUE;
63 }
64 
65 void effect_start (int * channels, int * rate)
66 {
67  pthread_mutex_lock (& mutex);
68 
69  AUDDBG ("Starting effects.\n");
70  g_list_foreach (running_effects, (GFunc) g_free, NULL);
71  g_list_free (running_effects);
73 
75  input_rate = * rate;
76 
77  EffectStartState state = {channels, rate};
79  & state);
80  running_effects = g_list_reverse (running_effects);
81 
82  pthread_mutex_unlock (& mutex);
83 }
84 
85 typedef struct {
86  float * * data;
87  int * samples;
89 
91  state)
92 {
93  if (effect->remove_flag)
94  {
95  effect->header->finish (state->data, state->samples);
96 
97  running_effects = g_list_remove (running_effects, effect);
98  g_free (effect);
99  }
100  else
101  effect->header->process (state->data, state->samples);
102 }
103 
104 void effect_process (float * * data, int * samples)
105 {
106  pthread_mutex_lock (& mutex);
107 
108  EffectProcessState state = {data, samples};
109  g_list_foreach (running_effects, (GFunc) effect_process_cb, & state);
110 
111  pthread_mutex_unlock (& mutex);
112 }
113 
114 void effect_flush (void)
115 {
116  pthread_mutex_lock (& mutex);
117 
118  for (GList * node = running_effects; node != NULL; node = node->next)
119  {
120  if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, flush))
121  ((RunningEffect *) node->data)->header->flush ();
122  }
123 
124  pthread_mutex_unlock (& mutex);
125 }
126 
127 void effect_finish (float * * data, int * samples)
128 {
129  pthread_mutex_lock (& mutex);
130 
131  for (GList * node = running_effects; node != NULL; node = node->next)
132  ((RunningEffect *) node->data)->header->finish (data, samples);
133 
134  pthread_mutex_unlock (& mutex);
135 }
136 
138 {
139  pthread_mutex_lock (& mutex);
140 
141  for (GList * node = running_effects; node != NULL; node = node->next)
142  {
143  if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, decoder_to_output_time))
144  time = ((RunningEffect *) node->data)->header->decoder_to_output_time (time);
145  }
146 
147  pthread_mutex_unlock (& mutex);
148  return time;
149 }
150 
152 {
153  pthread_mutex_lock (& mutex);
154 
155  for (GList * node = g_list_last (running_effects); node != NULL; node = node->prev)
156  {
157  if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, output_to_decoder_time))
158  time = ((RunningEffect *) node->data)->header->output_to_decoder_time (time);
159  }
160 
161  pthread_mutex_unlock (& mutex);
162  return time;
163 }
164 
166 {
167  return (effect->plugin == plugin) ? 0 : -1;
168 }
169 
171 {
172  return plugin_compare (a->plugin, b->plugin);
173 }
174 
175 static void effect_insert (PluginHandle * plugin, EffectPlugin * header)
176 {
177  if (g_list_find_custom (running_effects, plugin, (GCompareFunc)
178  effect_find_cb) != NULL)
179  return;
180 
181  AUDDBG ("Adding %s without reset.\n", plugin_get_name (plugin));
182  RunningEffect * effect = g_malloc (sizeof (RunningEffect));
183  effect->plugin = plugin;
184  effect->header = header;
185  effect->remove_flag = FALSE;
186 
187  running_effects = g_list_insert_sorted (running_effects, effect,
188  (GCompareFunc) effect_compare);
189  GList * node = g_list_find (running_effects, effect);
190 
191  int channels, rate;
192  if (node->prev != NULL)
193  {
194  RunningEffect * prev = node->prev->data;
195  AUDDBG ("Added %s after %s.\n", plugin_get_name (plugin),
196  plugin_get_name (prev->plugin));
197  channels = prev->channels_returned;
198  rate = prev->rate_returned;
199  }
200  else
201  {
202  AUDDBG ("Added %s as first effect.\n", plugin_get_name (plugin));
203  channels = input_channels;
204  rate = input_rate;
205  }
206 
207  AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
208  channels, rate);
209  header->start (& channels, & rate);
210  effect->channels_returned = channels;
211  effect->rate_returned = rate;
212 }
213 
215 {
216  GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc)
218  if (node == NULL)
219  return;
220 
221  AUDDBG ("Removing %s without reset.\n", plugin_get_name (plugin));
222  ((RunningEffect *) node->data)->remove_flag = TRUE;
223 }
224 
225 static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, bool_t
226  enable)
227 {
228  if (ep->preserves_format)
229  {
230  pthread_mutex_lock (& mutex);
231 
232  if (enable)
233  effect_insert (plugin, ep);
234  else
235  effect_remove (plugin);
236 
237  pthread_mutex_unlock (& mutex);
238  }
239  else
240  {
241  AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
242  int time = playback_get_time ();
244  playback_stop ();
245  playback_play (time, paused);
246  }
247 }
248 
250 {
251  if (playback_get_playing ())
252  {
253  EffectPlugin * ep = plugin_get_header (plugin);
254  g_return_val_if_fail (ep != NULL, FALSE);
255  effect_enable (plugin, ep, TRUE);
256  }
257 
258  return TRUE;
259 }
260 
262 {
263  if (playback_get_playing ())
264  {
265  EffectPlugin * ep = plugin_get_header (plugin);
266  g_return_if_fail (ep != NULL);
267  effect_enable (plugin, ep, FALSE);
268  }
269 }