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