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