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 "output.h"
00027 #include "playback.h"
00028 #include "plugin.h"
00029 #include "plugins.h"
00030 
00031 typedef struct {
00032     PluginHandle * plugin;
00033     EffectPlugin * header;
00034     gint channels_returned, rate_returned;
00035     gboolean remove_flag;
00036 } RunningEffect;
00037 
00038 static GList * running_effects = NULL;
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     AUDDBG ("Starting effects.\n");
00067     g_list_foreach (running_effects, (GFunc) g_free, NULL);
00068     g_list_free (running_effects);
00069     running_effects = NULL;
00070 
00071     input_channels = * channels;
00072     input_rate = * rate;
00073 
00074     EffectStartState state = {channels, rate};
00075     plugin_for_enabled (PLUGIN_TYPE_EFFECT, (PluginForEachFunc) effect_start_cb,
00076      & state);
00077     running_effects = g_list_reverse (running_effects);
00078 }
00079 
00080 typedef struct
00081 {
00082     gfloat * * data;
00083     gint * samples;
00084 } EffectProcessState;
00085 
00086 static void effect_process_cb (RunningEffect * effect, EffectProcessState *
00087  state)
00088 {
00089     if (effect->remove_flag)
00090     {
00091         effect->header->finish (state->data, state->samples);
00092         effect->header->finish (state->data, state->samples);
00093 
00094         running_effects = g_list_remove (running_effects, effect);
00095         g_free (effect);
00096     }
00097     else
00098         effect->header->process (state->data, state->samples);
00099 }
00100 
00101 void effect_process (gfloat * * data, gint * samples)
00102 {
00103     EffectProcessState state = {data, samples};
00104     g_list_foreach (running_effects, (GFunc) effect_process_cb, & state);
00105 }
00106 
00107 void effect_flush (void)
00108 {
00109     for (GList * node = running_effects; node != NULL; node = node->next)
00110         ((RunningEffect *) node->data)->header->flush ();
00111 }
00112 
00113 void effect_finish (gfloat * * data, gint * samples)
00114 {
00115     for (GList * node = running_effects; node != NULL; node = node->next)
00116         ((RunningEffect *) node->data)->header->finish (data, samples);
00117 }
00118 
00119 gint effect_decoder_to_output_time (gint time)
00120 {
00121     for (GList * node = running_effects; node != NULL; node = node->next)
00122         time = ((RunningEffect *) node->data)->header->decoder_to_output_time
00123          (time);
00124     return time;
00125 }
00126 
00127 gint effect_output_to_decoder_time (gint time)
00128 {
00129     for (GList * node = g_list_last (running_effects); node != NULL; node =
00130      node->prev)
00131         time = ((RunningEffect *) node->data)->header->output_to_decoder_time
00132          (time);
00133     return time;
00134 }
00135 
00136 static gint effect_find_cb (RunningEffect * effect, PluginHandle * plugin)
00137 {
00138     return (effect->plugin == plugin) ? 0 : -1;
00139 }
00140 
00141 static gint effect_compare (RunningEffect * a, RunningEffect * b)
00142 {
00143     return plugin_compare (a->plugin, b->plugin);
00144 }
00145 
00146 static void effect_insert (PluginHandle * plugin, EffectPlugin * header)
00147 {
00148     if (g_list_find_custom (running_effects, plugin, (GCompareFunc)
00149      effect_find_cb) != NULL)
00150         return;
00151 
00152     AUDDBG ("Adding %s without reset.\n", plugin_get_name (plugin));
00153     RunningEffect * effect = g_malloc (sizeof (RunningEffect));
00154     effect->plugin = plugin;
00155     effect->header = header;
00156     effect->remove_flag = FALSE;
00157 
00158     running_effects = g_list_insert_sorted (running_effects, effect,
00159      (GCompareFunc) effect_compare);
00160     GList * node = g_list_find (running_effects, effect);
00161 
00162     gint channels, rate;
00163     if (node->prev != NULL)
00164     {
00165         RunningEffect * prev = node->prev->data;
00166         AUDDBG ("Added %s after %s.\n", plugin_get_name (plugin),
00167          plugin_get_name (prev->plugin));
00168         channels = prev->channels_returned;
00169         rate = prev->rate_returned;
00170     }
00171     else
00172     {
00173         AUDDBG ("Added %s as first effect.\n", plugin_get_name (plugin));
00174         channels = input_channels;
00175         rate = input_rate;
00176     }
00177 
00178     AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin),
00179      channels, rate);
00180     header->start (& channels, & rate);
00181     effect->channels_returned = channels;
00182     effect->rate_returned = rate;
00183 }
00184 
00185 static void effect_remove (PluginHandle * plugin)
00186 {
00187     GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc)
00188      effect_find_cb);
00189     if (node == NULL)
00190         return;
00191 
00192     AUDDBG ("Removing %s without reset.\n", plugin_get_name (plugin));
00193     ((RunningEffect *) node->data)->remove_flag = TRUE;
00194 }
00195 
00196 void effect_plugin_enable (PluginHandle * plugin, gboolean enable)
00197 {
00198     plugin_set_enabled (plugin, enable);
00199 
00200     if (playback_get_playing ())
00201     {
00202         EffectPlugin * header = plugin_get_header (plugin);
00203         g_return_if_fail (header != NULL);
00204 
00205         if (header->preserves_format)
00206         {
00207             if (enable)
00208                 effect_insert (plugin, header);
00209             else
00210                 effect_remove (plugin);
00211         }
00212         else
00213         {
00214             AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
00215             set_current_output_plugin (current_output_plugin);
00216         }
00217     }
00218 }