00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 }