00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <math.h>
00023
00024 #include <libaudcore/audio.h>
00025
00026 #include "audconfig.h"
00027 #include "debug.h"
00028 #include "effect.h"
00029 #include "equalizer.h"
00030 #include "output.h"
00031 #include "playback.h"
00032 #include "plugins.h"
00033 #include "vis_runner.h"
00034
00035 #define SW_VOLUME_RANGE 40
00036
00037 OutputPlugin * current_output_plugin = NULL;
00038 #define COP current_output_plugin
00039
00040 static gboolean plugin_list_func (PluginHandle * plugin, GList * * list)
00041 {
00042 OutputPlugin * op = plugin_get_header (plugin);
00043 g_return_val_if_fail (op != NULL, TRUE);
00044 * list = g_list_prepend (* list, op);
00045 return TRUE;
00046 }
00047
00048 GList * get_output_list (void)
00049 {
00050 static GList * list = NULL;
00051
00052 if (list == NULL)
00053 {
00054 plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc)
00055 plugin_list_func, & list);
00056 list = g_list_reverse (list);
00057 }
00058
00059 return list;
00060 }
00061
00062 void output_get_volume (gint * l, gint * r)
00063 {
00064 if (cfg.software_volume_control)
00065 {
00066 * l = cfg.sw_volume_left;
00067 * r = cfg.sw_volume_right;
00068 }
00069 else if (COP != NULL && COP->get_volume != NULL)
00070 COP->get_volume (l, r);
00071 else
00072 {
00073 * l = 0;
00074 * r = 0;
00075 }
00076 }
00077
00078 void output_set_volume (gint l, gint r)
00079 {
00080 if (cfg.software_volume_control)
00081 {
00082 cfg.sw_volume_left = l;
00083 cfg.sw_volume_right = r;
00084 }
00085 else if (COP != NULL && COP->set_volume != NULL)
00086 COP->set_volume (l, r);
00087 }
00088
00089 static GMutex * output_mutex;
00090 static gboolean output_opened, output_aborted, output_leave_open, output_paused;
00091
00092 static gint decoder_format, output_format;
00093 static gint decoder_channels, decoder_rate, effect_channels, effect_rate,
00094 output_channels, output_rate;
00095 static gint64 frames_written;
00096 static gboolean have_replay_gain;
00097 static ReplayGainInfo replay_gain_info;
00098
00099 #define REMOVE_SOURCE(s) \
00100 do { \
00101 if (s != 0) { \
00102 g_source_remove (s); \
00103 s = 0; \
00104 } \
00105 } while (0)
00106
00107 #define LOCK g_mutex_lock (output_mutex)
00108 #define UNLOCK g_mutex_unlock (output_mutex)
00109
00110 static void write_buffers (void);
00111 static void drain (void);
00112
00113
00114 static void real_close (void)
00115 {
00116 vis_runner_start_stop (FALSE, FALSE);
00117 COP->close_audio ();
00118 output_opened = FALSE;
00119 output_leave_open = FALSE;
00120 }
00121
00122 void output_init (void)
00123 {
00124 output_mutex = g_mutex_new ();
00125 output_opened = FALSE;
00126 output_leave_open = FALSE;
00127 }
00128
00129 void output_cleanup (void)
00130 {
00131 LOCK;
00132
00133 if (output_leave_open)
00134 real_close ();
00135
00136 UNLOCK;
00137
00138 g_mutex_free (output_mutex);
00139 }
00140
00141 static gboolean output_open_audio (gint format, gint rate, gint channels)
00142 {
00143 if (COP == NULL)
00144 {
00145 fprintf (stderr, "No output plugin selected.\n");
00146 return FALSE;
00147 }
00148
00149 LOCK;
00150
00151 if (output_leave_open && COP->set_written_time != NULL)
00152 {
00153 vis_runner_time_offset (- COP->written_time ());
00154 COP->set_written_time (0);
00155 }
00156
00157 decoder_format = format;
00158 decoder_channels = channels;
00159 decoder_rate = rate;
00160 frames_written = 0;
00161
00162 effect_channels = channels;
00163 effect_rate = rate;
00164 effect_start (& effect_channels, & effect_rate);
00165 eq_set_format (effect_channels, effect_rate);
00166
00167 if (output_leave_open && COP->set_written_time != NULL && effect_channels ==
00168 output_channels && effect_rate == output_rate)
00169 output_opened = TRUE;
00170 else
00171 {
00172 if (output_leave_open)
00173 {
00174 UNLOCK;
00175 drain ();
00176 LOCK;
00177 real_close ();
00178 }
00179
00180 output_format = cfg.output_bit_depth == 32 ? FMT_S32_NE :
00181 cfg.output_bit_depth == 24 ? FMT_S24_NE : cfg.output_bit_depth == 16 ?
00182 FMT_S16_NE : FMT_FLOAT;
00183 output_channels = effect_channels;
00184 output_rate = effect_rate;
00185
00186 if (COP->open_audio (output_format, output_rate, output_channels) > 0)
00187 {
00188 vis_runner_start_stop (TRUE, FALSE);
00189 output_opened = TRUE;
00190 }
00191 }
00192
00193 output_aborted = FALSE;
00194 output_leave_open = FALSE;
00195 output_paused = FALSE;
00196
00197 UNLOCK;
00198 return output_opened;
00199 }
00200
00201 static void output_close_audio (void)
00202 {
00203 LOCK;
00204
00205 output_opened = FALSE;
00206
00207 if (! output_leave_open)
00208 {
00209 effect_flush ();
00210 real_close ();
00211 }
00212
00213 UNLOCK;
00214 }
00215
00216 static void output_flush (gint time)
00217 {
00218 LOCK;
00219
00220 frames_written = time * (gint64) decoder_rate / 1000;
00221 output_aborted = FALSE;
00222
00223 vis_runner_flush ();
00224 effect_flush ();
00225 COP->flush (effect_decoder_to_output_time (time));
00226
00227 UNLOCK;
00228 }
00229
00230 static void output_pause (gboolean pause)
00231 {
00232 LOCK;
00233 COP->pause (pause);
00234 vis_runner_start_stop (TRUE, pause);
00235 output_paused = pause;
00236 UNLOCK;
00237 }
00238
00239 static gint get_written_time (void)
00240 {
00241 gint time = 0;
00242
00243 LOCK;
00244
00245 if (output_opened)
00246 time = frames_written * (gint64) 1000 / decoder_rate;
00247
00248 UNLOCK;
00249 return time;
00250 }
00251
00252 static gboolean output_buffer_playing (void)
00253 {
00254 LOCK;
00255
00256 if (! output_paused)
00257 {
00258 UNLOCK;
00259 write_buffers ();
00260 LOCK;
00261 output_leave_open = TRUE;
00262 }
00263
00264 UNLOCK;
00265 return FALSE;
00266 }
00267
00268 static void output_set_replaygain_info (ReplayGainInfo * info)
00269 {
00270 AUDDBG ("Replay Gain info:\n");
00271 AUDDBG (" album gain: %f dB\n", info->album_gain);
00272 AUDDBG (" album peak: %f\n", info->album_peak);
00273 AUDDBG (" track gain: %f dB\n", info->track_gain);
00274 AUDDBG (" track peak: %f\n", info->track_peak);
00275
00276 have_replay_gain = TRUE;
00277 memcpy (& replay_gain_info, info, sizeof (ReplayGainInfo));
00278 }
00279
00280 static void apply_replay_gain (gfloat * data, gint samples)
00281 {
00282 gfloat factor = powf (10, (gfloat) cfg.replay_gain_preamp / 20);
00283
00284 if (! cfg.enable_replay_gain)
00285 return;
00286
00287 if (have_replay_gain)
00288 {
00289 if (cfg.replay_gain_album)
00290 {
00291 factor *= powf (10, replay_gain_info.album_gain / 20);
00292
00293 if (cfg.enable_clipping_prevention &&
00294 replay_gain_info.album_peak * factor > 1)
00295 factor = 1 / replay_gain_info.album_peak;
00296 }
00297 else
00298 {
00299 factor *= powf (10, replay_gain_info.track_gain / 20);
00300
00301 if (cfg.enable_clipping_prevention &&
00302 replay_gain_info.track_peak * factor > 1)
00303 factor = 1 / replay_gain_info.track_peak;
00304 }
00305 }
00306 else
00307 factor *= powf (10, (gfloat) cfg.default_gain / 20);
00308
00309 if (factor < 0.99 || factor > 1.01)
00310 audio_amplify (data, 1, samples, & factor);
00311 }
00312
00313 static void apply_software_volume (gfloat * data, gint channels, gint frames)
00314 {
00315 gfloat left_factor, right_factor;
00316 gfloat factors[channels];
00317 gint channel;
00318
00319 if (! cfg.software_volume_control || (cfg.sw_volume_left == 100 &&
00320 cfg.sw_volume_right == 100))
00321 return;
00322
00323 left_factor = (cfg.sw_volume_left == 0) ? 0 : powf (10, (gfloat)
00324 SW_VOLUME_RANGE * (cfg.sw_volume_left - 100) / 100 / 20);
00325 right_factor = (cfg.sw_volume_right == 0) ? 0 : powf (10, (gfloat)
00326 SW_VOLUME_RANGE * (cfg.sw_volume_right - 100) / 100 / 20);
00327
00328 if (channels == 2)
00329 {
00330 factors[0] = left_factor;
00331 factors[1] = right_factor;
00332 }
00333 else
00334 {
00335 for (channel = 0; channel < channels; channel ++)
00336 factors[channel] = MAX (left_factor, right_factor);
00337 }
00338
00339 audio_amplify (data, channels, frames, factors);
00340 }
00341
00342 static void do_write (void * data, gint samples)
00343 {
00344 if (! samples)
00345 return;
00346
00347 void * allocated = NULL;
00348
00349 vis_runner_pass_audio (COP->written_time (), data, samples, output_channels,
00350 output_rate);
00351 eq_filter (data, samples);
00352 apply_software_volume (data, output_channels, samples / output_channels);
00353
00354 if (output_format != FMT_FLOAT)
00355 {
00356 void * new = g_malloc (FMT_SIZEOF (output_format) * samples);
00357
00358 audio_to_int (data, new, output_format, samples);
00359
00360 data = new;
00361 g_free (allocated);
00362 allocated = new;
00363 }
00364
00365 while (1)
00366 {
00367 gint ready;
00368
00369 if (COP->buffer_free)
00370 ready = COP->buffer_free () / FMT_SIZEOF (output_format);
00371 else
00372 ready = output_channels * (output_rate / 50);
00373
00374 LOCK;
00375
00376 if (output_aborted)
00377 {
00378 UNLOCK;
00379 break;
00380 }
00381
00382 UNLOCK;
00383
00384 ready = MIN (ready, samples);
00385 COP->write_audio (data, FMT_SIZEOF (output_format) * ready);
00386 data = (char *) data + FMT_SIZEOF (output_format) * ready;
00387 samples -= ready;
00388
00389 if (! samples)
00390 break;
00391
00392 if (COP->period_wait)
00393 COP->period_wait ();
00394 else if (COP->buffer_free)
00395 g_usleep (20000);
00396 }
00397
00398 g_free (allocated);
00399 }
00400
00401 static void output_write_audio (void * data, gint size)
00402 {
00403 gint samples = size / FMT_SIZEOF (decoder_format);
00404 void * allocated = NULL;
00405
00406 LOCK;
00407 frames_written += samples / decoder_channels;
00408 UNLOCK;
00409
00410 if (decoder_format != FMT_FLOAT)
00411 {
00412 gfloat * new = g_malloc (sizeof (gfloat) * samples);
00413
00414 audio_from_int (data, decoder_format, new, samples);
00415
00416 data = new;
00417 g_free (allocated);
00418 allocated = new;
00419 }
00420
00421 apply_replay_gain (data, samples);
00422 gfloat * fdata = data;
00423 effect_process (& fdata, & samples);
00424 data = fdata;
00425
00426 if (data != allocated)
00427 {
00428 g_free (allocated);
00429 allocated = NULL;
00430 }
00431
00432 do_write (data, samples);
00433 g_free (allocated);
00434 }
00435
00436 static void write_buffers (void)
00437 {
00438 gfloat * data = NULL;
00439 gint samples = 0;
00440
00441 effect_finish (& data, & samples);
00442 do_write (data, samples);
00443 }
00444
00445 static void abort_write (void)
00446 {
00447 LOCK;
00448 output_aborted = TRUE;
00449 COP->flush (COP->output_time ());
00450 UNLOCK;
00451 }
00452
00453 static void drain (void)
00454 {
00455 if (COP->buffer_playing != NULL)
00456 {
00457 while (COP->buffer_playing ())
00458 g_usleep (30000);
00459 }
00460 else
00461 COP->drain ();
00462 }
00463
00464 struct OutputAPI output_api =
00465 {
00466 .open_audio = output_open_audio,
00467 .set_replaygain_info = output_set_replaygain_info,
00468 .write_audio = output_write_audio,
00469 .close_audio = output_close_audio,
00470
00471 .pause = output_pause,
00472 .flush = output_flush,
00473 .written_time = get_written_time,
00474 .buffer_playing = output_buffer_playing,
00475 .abort_write = abort_write,
00476 };
00477
00478 gint get_output_time (void)
00479 {
00480 gint time = 0;
00481
00482 LOCK;
00483
00484 if (output_opened)
00485 {
00486 time = effect_output_to_decoder_time (COP->output_time ());
00487 time = MAX (0, time);
00488 }
00489
00490 UNLOCK;
00491 return time;
00492 }
00493
00494 void output_drain (void)
00495 {
00496 LOCK;
00497
00498 if (output_leave_open)
00499 {
00500 UNLOCK;
00501 write_buffers ();
00502 drain ();
00503 LOCK;
00504 real_close ();
00505 }
00506
00507 UNLOCK;
00508 }
00509
00510 void set_current_output_plugin (OutputPlugin * plugin)
00511 {
00512 OutputPlugin * old = COP;
00513 gboolean playing = playback_get_playing ();
00514 gboolean paused = FALSE;
00515 gint time = 0;
00516
00517 if (playing)
00518 {
00519 paused = playback_get_paused ();
00520 time = playback_get_time ();
00521 playback_stop ();
00522 }
00523
00524
00525
00526
00527 if (plugin != COP)
00528 {
00529 COP = NULL;
00530
00531 if (old != NULL && old->cleanup != NULL)
00532 old->cleanup ();
00533
00534 if (plugin->init () == OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
00535 COP = plugin;
00536 else
00537 {
00538 fprintf (stderr, "Output plugin failed to load: %s\n",
00539 plugin->description);
00540
00541 if (old == NULL || old->init () != OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
00542 return;
00543
00544 fprintf (stderr, "Falling back to: %s\n", old->description);
00545 COP = old;
00546 }
00547 }
00548
00549 if (playing)
00550 playback_play (time, paused);
00551 }