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 
00024 #include "debug.h"
00025 #include "effect.h"
00026 #include "playback.h"
00027 #include "plugin.h"
00028 #include "plugins.h"
00029 
00030 typedef struct {
00031     PluginHandle * plugin;
00032     EffectPlugin * header;
00033     gint channels_returned, rate_returned;
00034     gboolean remove_flag;
00035 } RunningEffect;
00036 
00037 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
00038 static GList * running_effects = NULL; /* (RunningEffect *) */
00039 static gint input_channels, input_rate;
00040 
00041 typedef struct {
00042     gint * channels, * rate;
00043 } EffectStartState;
00044 
00045 static gboolean effect_start_cb (PluginHandle * plugin, EffectStartState * state)
00046 {
00047     AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
00048      * state->channels, * state->rate);
00049     EffectPlugin * header = plugin_get_header (plugin);
00050     g_return_val_if_fail (header != NULL, TRUE);
00051     header->start (state->channels, state->rate);
00052 
00053     RunningEffect * effect = g_malloc (sizeof (RunningEffect));
00054     effect->plugin = plugin;
00055     effect->header = header;
00056     effect->channels_returned = * state->channels;
00057     effect->rate_returned = * state->rate;
00058     effect->remove_flag = FALSE;
00059 
00060     running_effects = g_list_prepend (running_effects, effect);
00061     return TRUE;
00062 }
00063 
00064 void effect_start (gint * channels, gint * rate)
00065 {
00066     g_static_mutex_lock (& mutex);
00067 
00068     AUDDBG ("Starting effects.\n");
00069     g_list_foreach (running_effects, (GFunc) g_free, NULL);
00070     g_list_free (running_effects);
00071     running_effects = NULL;
00072 
00073     input_channels = * channels;
00074     input_rate = * rate;
00075 
00076     EffectStartState state = {channels, rate};
00077     plugin_for_enabled (PLUGIN_TYPE_EFFECT, (PluginForEachFunc) effect_start_cb,
00078      & state);
00079     running_effects = g_list_reverse (running_effects);
00080 
00081     g_static_mutex_unlock (& mutex);
00082 }
00083 
00084 typedef struct {
00085     gfloat * * data;
00086     gint * samples;
00087 } EffectProcessState;
00088 
00089 static void effect_process_cb (RunningEffect * effect, EffectProcessState *
00090  state)
00091 {
00092     if (effect->remove_flag)
00093     {
00094         effect->header->finish (state->data, state->samples);
00095 
00096         running_effects = g_list_remove (running_effects, effect);
00097         g_free (effect);
00098     }
00099     else
00100         effect->header->process (state->data, state->samples);
00101 }
00102 
00103 void effect_process (gfloat * * data, gint * samples)
00104 {
00105     g_static_mutex_lock (& mutex);
00106 
00107     EffectProcessState state = {data, samples};
00108     g_list_foreach (running_effects, (GFunc) effect_process_cb, & state);
00109 
00110     g_static_mutex_unlock (& mutex);
00111 }
00112 
00113 void effect_flush (void)
00114 {
00115     g_static_mutex_lock (& mutex);
00116 
00117     for (GList * node = running_effects; node != NULL; node = node->next)
00118         ((RunningEffect *) node->data)->header->flush ();
00119 
00120     g_static_mutex_unlock (& mutex);
00121 }
00122 
00123 void effect_finish (gfloat * * data, gint * samples)
00124 {
00125     g_static_mutex_lock (& mutex);
00126 
00127     for (GList * node = running_effects; node != NULL; node = node->next)
00128         ((RunningEffect *) node->data)->header->finish (data, samples);
00129 
00130     g_static_mutex_unlock (& mutex);
00131 }
00132 
00133 gint effect_decoder_to_output_time (gint time)
00134 {
00135     g_static_mutex_lock (& mutex);
00136 
00137     for (GList * node = running_effects; node != NULL; node = node->next)
00138         time = ((RunningEffect *) node->data)->header->decoder_to_output_time
00139          (time);
00140 
00141     g_static_mutex_unlock (& mutex);
00142     return time;
00143 }
00144 
00145 gint effect_output_to_decoder_time (gint time)
00146 {
00147     g_static_mutex_lock (& mutex);
00148 
00149     for (GList * node = g_list_last (running_effects); node != NULL; node =
00150      node->prev)
00151         time = ((RunningEffect *) node->data)->header->output_to_decoder_time
00152          (time);
00153 
00154     g_static_mutex_unlock (& mutex);
00155     return time;
00156 }
00157 
00158 static gint effect_find_cb (RunningEffect * effect, PluginHandle * plugin)
00159 {
00160     return (effect->plugin == plugin) ? 0 : -1;
00161 }
00162 
00163 static gint effect_compare (RunningEffect * a, RunningEffect * b)
00164 {
00165     return plugin_compare (a->plugin, b->plugin);
00166 }
00167 
00168 static void effect_insert (PluginHandle * plugin, EffectPlugin * header)
00169 {
00170     if (g_list_find_custom (running_effects, plugin, (GCompareFunc)
00171      effect_find_cb) != NULL)
00172         return;
00173 
00174     AUDDBG ("Adding %s without reset.\n", plugin_get_name (plugin));
00175     RunningEffect * effect = g_malloc (sizeof (RunningEffect));
00176     effect->plugin = plugin;
00177     effect->header = header;
00178     effect->remove_flag = FALSE;
00179 
00180     running_effects = g_list_insert_sorted (running_effects, effect,
00181      (GCompareFunc) effect_compare);
00182     GList * node = g_list_find (running_effects, effect);
00183 
00184     gint channels, rate;
00185     if (node->prev != NULL)
00186     {
00187         RunningEffect * prev = node->prev->data;
00188         AUDDBG ("Added %s after %s.\n", plugin_get_name (plugin),
00189          plugin_get_name (prev->plugin));
00190         channels = prev->channels_returned;
00191         rate = prev->rate_returned;
00192     }
00193     else
00194     {
00195         AUDDBG ("Added %s as first effect.\n", plugin_get_name (plugin));
00196         channels = input_channels;
00197         rate = input_rate;
00198     }
00199 
00200     AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
00201      channels, rate);
00202     header->start (& channels, & rate);
00203     effect->channels_returned = channels;
00204     effect->rate_returned = rate;
00205 }
00206 
00207 static void effect_remove (PluginHandle * plugin)
00208 {
00209     GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc)
00210      effect_find_cb);
00211     if (node == NULL)
00212         return;
00213 
00214     AUDDBG ("Removing %s without reset.\n", plugin_get_name (plugin));
00215     ((RunningEffect *) node->data)->remove_flag = TRUE;
00216 }
00217 
00218 static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, gboolean
00219  enable)
00220 {
00221     if (ep->preserves_format)
00222     {
00223         g_static_mutex_lock (& mutex);
00224 
00225         if (enable)
00226             effect_insert (plugin, ep);
00227         else
00228             effect_remove (plugin);
00229 
00230         g_static_mutex_unlock (& mutex);
00231     }
00232     else
00233     {
00234         AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
00235         gint time = playback_get_time ();
00236         gboolean paused = playback_get_paused ();
00237         playback_stop ();
00238         playback_play (time, paused);
00239     }
00240 }
00241 
00242 gboolean effect_plugin_start (PluginHandle * plugin)
00243 {
00244     if (playback_get_playing ())
00245     {
00246         EffectPlugin * ep = plugin_get_header (plugin);
00247         g_return_val_if_fail (ep != NULL, FALSE);
00248         effect_enable (plugin, ep, TRUE);
00249     }
00250 
00251     return TRUE;
00252 }
00253 
00254 void effect_plugin_stop (PluginHandle * plugin)
00255 {
00256     if (playback_get_playing ())
00257     {
00258         EffectPlugin * ep = plugin_get_header (plugin);
00259         g_return_if_fail (ep != NULL);
00260         effect_enable (plugin, ep, FALSE);
00261     }
00262 }