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 ((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 }