Audacious
$Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
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 }