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