Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
effect.c
Go to the documentation of this file.
00001 /*
00002  * effect.c
00003  * Copyright 2010 John Lindgren
00004  *
00005  * This file is part of Audacious.
00006  *
00007  * Audacious is free software: you can redistribute it and/or modify it under
00008  * the terms of the GNU General Public License as published by the Free Software
00009  * Foundation, version 2 or version 3 of the License.
00010  *
00011  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
00012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00013  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along with
00016  * Audacious. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The Audacious team does not consider modular code linking to Audacious or
00019  * using our public API to be a derived work.
00020  */
00021 
00022 #include <glib.h>
00023 #include <pthread.h>
00024 
00025 #include "debug.h"
00026 #include "effect.h"
00027 #include "playback.h"
00028 #include "plugin.h"
00029 #include "plugins.h"
00030 
00031 typedef struct {
00032     PluginHandle * plugin;
00033     EffectPlugin * header;
00034     int channels_returned, rate_returned;
00035     bool_t remove_flag;
00036 } RunningEffect;
00037 
00038 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
00039 static GList * running_effects = NULL; /* (RunningEffect *) */
00040 static int input_channels, input_rate;
00041 
00042 typedef struct {
00043     int * channels, * rate;
00044 } EffectStartState;
00045 
00046 static bool_t effect_start_cb (PluginHandle * plugin, EffectStartState * state)
00047 {
00048     AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
00049      * state->channels, * state->rate);
00050     EffectPlugin * header = plugin_get_header (plugin);
00051     g_return_val_if_fail (header != NULL, TRUE);
00052     header->start (state->channels, state->rate);
00053 
00054     RunningEffect * effect = g_malloc (sizeof (RunningEffect));
00055     effect->plugin = plugin;
00056     effect->header = header;
00057     effect->channels_returned = * state->channels;
00058     effect->rate_returned = * state->rate;
00059     effect->remove_flag = FALSE;
00060 
00061     running_effects = g_list_prepend (running_effects, effect);
00062     return TRUE;
00063 }
00064 
00065 void effect_start (int * channels, int * rate)
00066 {
00067     pthread_mutex_lock (& mutex);
00068 
00069     AUDDBG ("Starting effects.\n");
00070     g_list_foreach (running_effects, (GFunc) g_free, NULL);
00071     g_list_free (running_effects);
00072     running_effects = NULL;
00073 
00074     input_channels = * channels;
00075     input_rate = * rate;
00076 
00077     EffectStartState state = {channels, rate};
00078     plugin_for_enabled (PLUGIN_TYPE_EFFECT, (PluginForEachFunc) effect_start_cb,
00079      & state);
00080     running_effects = g_list_reverse (running_effects);
00081 
00082     pthread_mutex_unlock (& mutex);
00083 }
00084 
00085 typedef struct {
00086     float * * data;
00087     int * samples;
00088 } EffectProcessState;
00089 
00090 static void effect_process_cb (RunningEffect * effect, EffectProcessState *
00091  state)
00092 {
00093     if (effect->remove_flag)
00094     {
00095         effect->header->finish (state->data, state->samples);
00096 
00097         running_effects = g_list_remove (running_effects, effect);
00098         g_free (effect);
00099     }
00100     else
00101         effect->header->process (state->data, state->samples);
00102 }
00103 
00104 void effect_process (float * * data, int * samples)
00105 {
00106     pthread_mutex_lock (& mutex);
00107 
00108     EffectProcessState state = {data, samples};
00109     g_list_foreach (running_effects, (GFunc) effect_process_cb, & state);
00110 
00111     pthread_mutex_unlock (& mutex);
00112 }
00113 
00114 void effect_flush (void)
00115 {
00116     pthread_mutex_lock (& mutex);
00117 
00118     for (GList * node = running_effects; node != NULL; node = node->next)
00119     {
00120         if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, flush))
00121             ((RunningEffect *) node->data)->header->flush ();
00122     }
00123 
00124     pthread_mutex_unlock (& mutex);
00125 }
00126 
00127 void effect_finish (float * * data, int * samples)
00128 {
00129     pthread_mutex_lock (& mutex);
00130 
00131     for (GList * node = running_effects; node != NULL; node = node->next)
00132         ((RunningEffect *) node->data)->header->finish (data, samples);
00133 
00134     pthread_mutex_unlock (& mutex);
00135 }
00136 
00137 int effect_decoder_to_output_time (int time)
00138 {
00139     pthread_mutex_lock (& mutex);
00140 
00141     for (GList * node = running_effects; node != NULL; node = node->next)
00142     {
00143         if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, decoder_to_output_time))
00144             time = ((RunningEffect *) node->data)->header->decoder_to_output_time (time);
00145     }
00146 
00147     pthread_mutex_unlock (& mutex);
00148     return time;
00149 }
00150 
00151 int effect_output_to_decoder_time (int time)
00152 {
00153     pthread_mutex_lock (& mutex);
00154 
00155     for (GList * node = g_list_last (running_effects); node != NULL; node = node->prev)
00156     {
00157         if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, output_to_decoder_time))
00158             time = ((RunningEffect *) node->data)->header->output_to_decoder_time (time);
00159     }
00160 
00161     pthread_mutex_unlock (& mutex);
00162     return time;
00163 }
00164 
00165 static int effect_find_cb (RunningEffect * effect, PluginHandle * plugin)
00166 {
00167     return (effect->plugin == plugin) ? 0 : -1;
00168 }
00169 
00170 static int effect_compare (RunningEffect * a, RunningEffect * b)
00171 {
00172     return plugin_compare (a->plugin, b->plugin);
00173 }
00174 
00175 static void effect_insert (PluginHandle * plugin, EffectPlugin * header)
00176 {
00177     if (g_list_find_custom (running_effects, plugin, (GCompareFunc)
00178      effect_find_cb) != NULL)
00179         return;
00180 
00181     AUDDBG ("Adding %s without reset.\n", plugin_get_name (plugin));
00182     RunningEffect * effect = g_malloc (sizeof (RunningEffect));
00183     effect->plugin = plugin;
00184     effect->header = header;
00185     effect->remove_flag = FALSE;
00186 
00187     running_effects = g_list_insert_sorted (running_effects, effect,
00188      (GCompareFunc) effect_compare);
00189     GList * node = g_list_find (running_effects, effect);
00190 
00191     int channels, rate;
00192     if (node->prev != NULL)
00193     {
00194         RunningEffect * prev = node->prev->data;
00195         AUDDBG ("Added %s after %s.\n", plugin_get_name (plugin),
00196          plugin_get_name (prev->plugin));
00197         channels = prev->channels_returned;
00198         rate = prev->rate_returned;
00199     }
00200     else
00201     {
00202         AUDDBG ("Added %s as first effect.\n", plugin_get_name (plugin));
00203         channels = input_channels;
00204         rate = input_rate;
00205     }
00206 
00207     AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
00208      channels, rate);
00209     header->start (& channels, & rate);
00210     effect->channels_returned = channels;
00211     effect->rate_returned = rate;
00212 }
00213 
00214 static void effect_remove (PluginHandle * plugin)
00215 {
00216     GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc)
00217      effect_find_cb);
00218     if (node == NULL)
00219         return;
00220 
00221     AUDDBG ("Removing %s without reset.\n", plugin_get_name (plugin));
00222     ((RunningEffect *) node->data)->remove_flag = TRUE;
00223 }
00224 
00225 static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, bool_t
00226  enable)
00227 {
00228     if (ep->preserves_format)
00229     {
00230         pthread_mutex_lock (& mutex);
00231 
00232         if (enable)
00233             effect_insert (plugin, ep);
00234         else
00235             effect_remove (plugin);
00236 
00237         pthread_mutex_unlock (& mutex);
00238     }
00239     else
00240     {
00241         AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
00242         int time = playback_get_time ();
00243         bool_t paused = playback_get_paused ();
00244         playback_stop ();
00245         playback_play (time, paused);
00246     }
00247 }
00248 
00249 bool_t effect_plugin_start (PluginHandle * plugin)
00250 {
00251     if (playback_get_playing ())
00252     {
00253         EffectPlugin * ep = plugin_get_header (plugin);
00254         g_return_val_if_fail (ep != NULL, FALSE);
00255         effect_enable (plugin, ep, TRUE);
00256     }
00257 
00258     return TRUE;
00259 }
00260 
00261 void effect_plugin_stop (PluginHandle * plugin)
00262 {
00263     if (playback_get_playing ())
00264     {
00265         EffectPlugin * ep = plugin_get_header (plugin);
00266         g_return_if_fail (ep != NULL);
00267         effect_enable (plugin, ep, FALSE);
00268     }
00269 }