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         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 (gfloat * * data, gint * samples)
00105 {
00106     g_static_mutex_lock (& mutex);
00107 
00108     EffectProcessState state = {data, samples};
00109     g_list_foreach (running_effects, (GFunc) effect_process_cb, & state);
00110 
00111     g_static_mutex_unlock (& mutex);
00112 }
00113 
00114 void effect_flush (void)
00115 {
00116     g_static_mutex_lock (& mutex);
00117 
00118     for (GList * node = running_effects; node != NULL; node = node->next)
00119         ((RunningEffect *) node->data)->header->flush ();
00120 
00121     g_static_mutex_unlock (& mutex);
00122 }
00123 
00124 void effect_finish (gfloat * * data, gint * samples)
00125 {
00126     g_static_mutex_lock (& mutex);
00127 
00128     for (GList * node = running_effects; node != NULL; node = node->next)
00129         ((RunningEffect *) node->data)->header->finish (data, samples);
00130 
00131     g_static_mutex_unlock (& mutex);
00132 }
00133 
00134 gint effect_decoder_to_output_time (gint time)
00135 {
00136     g_static_mutex_lock (& mutex);
00137 
00138     for (GList * node = running_effects; node != NULL; node = node->next)
00139         time = ((RunningEffect *) node->data)->header->decoder_to_output_time
00140          (time);
00141 
00142     g_static_mutex_unlock (& mutex);
00143     return time;
00144 }
00145 
00146 gint effect_output_to_decoder_time (gint time)
00147 {
00148     g_static_mutex_lock (& mutex);
00149 
00150     for (GList * node = g_list_last (running_effects); node != NULL; node =
00151      node->prev)
00152         time = ((RunningEffect *) node->data)->header->output_to_decoder_time
00153          (time);
00154 
00155     g_static_mutex_unlock (& mutex);
00156     return time;
00157 }
00158 
00159 static gint effect_find_cb (RunningEffect * effect, PluginHandle * plugin)
00160 {
00161     return (effect->plugin == plugin) ? 0 : -1;
00162 }
00163 
00164 static gint effect_compare (RunningEffect * a, RunningEffect * b)
00165 {
00166     return plugin_compare (a->plugin, b->plugin);
00167 }
00168 
00169 static void effect_insert (PluginHandle * plugin, EffectPlugin * header)
00170 {
00171     if (g_list_find_custom (running_effects, plugin, (GCompareFunc)
00172      effect_find_cb) != NULL)
00173         return;
00174 
00175     AUDDBG ("Adding %s without reset.\n", plugin_get_name (plugin));
00176     RunningEffect * effect = g_malloc (sizeof (RunningEffect));
00177     effect->plugin = plugin;
00178     effect->header = header;
00179     effect->remove_flag = FALSE;
00180 
00181     running_effects = g_list_insert_sorted (running_effects, effect,
00182      (GCompareFunc) effect_compare);
00183     GList * node = g_list_find (running_effects, effect);
00184 
00185     gint channels, rate;
00186     if (node->prev != NULL)
00187     {
00188         RunningEffect * prev = node->prev->data;
00189         AUDDBG ("Added %s after %s.\n", plugin_get_name (plugin),
00190          plugin_get_name (prev->plugin));
00191         channels = prev->channels_returned;
00192         rate = prev->rate_returned;
00193     }
00194     else
00195     {
00196         AUDDBG ("Added %s as first effect.\n", plugin_get_name (plugin));
00197         channels = input_channels;
00198         rate = input_rate;
00199     }
00200 
00201     AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
00202      channels, rate);
00203     header->start (& channels, & rate);
00204     effect->channels_returned = channels;
00205     effect->rate_returned = rate;
00206 }
00207 
00208 static void effect_remove (PluginHandle * plugin)
00209 {
00210     GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc)
00211      effect_find_cb);
00212     if (node == NULL)
00213         return;
00214 
00215     AUDDBG ("Removing %s without reset.\n", plugin_get_name (plugin));
00216     ((RunningEffect *) node->data)->remove_flag = TRUE;
00217 }
00218 
00219 static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, gboolean
00220  enable)
00221 {
00222     if (ep->preserves_format)
00223     {
00224         g_static_mutex_lock (& mutex);
00225 
00226         if (enable)
00227             effect_insert (plugin, ep);
00228         else
00229             effect_remove (plugin);
00230 
00231         g_static_mutex_unlock (& mutex);
00232     }
00233     else
00234     {
00235         AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
00236         gint time = playback_get_time ();
00237         gboolean paused = playback_get_paused ();
00238         playback_stop ();
00239         playback_play (time, paused);
00240     }
00241 }
00242 
00243 gboolean effect_plugin_start (PluginHandle * plugin)
00244 {
00245     if (playback_get_playing ())
00246     {
00247         EffectPlugin * ep = plugin_get_header (plugin);
00248         g_return_val_if_fail (ep != NULL, FALSE);
00249         effect_enable (plugin, ep, TRUE);
00250     }
00251 
00252     return TRUE;
00253 }
00254 
00255 void effect_plugin_stop (PluginHandle * plugin)
00256 {
00257     if (playback_get_playing ())
00258     {
00259         EffectPlugin * ep = plugin_get_header (plugin);
00260         g_return_if_fail (ep != NULL);
00261         effect_enable (plugin, ep, FALSE);
00262     }
00263 }