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 "debug.h"
00026 #include "effect.h"
00027 #include "equalizer.h"
00028 #include "misc.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 (get_bool (NULL, "software_volume_control"))
00041 {
00042 * l = get_int (NULL, "sw_volume_left");
00043 * r = get_int (NULL, "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 (get_bool (NULL, "software_volume_control"))
00057 {
00058 set_int (NULL, "sw_volume_left", l);
00059 set_int (NULL, "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 gint depth = get_int (NULL, "output_bit_depth");
00139 output_format = (depth == 32) ? FMT_S32_NE : (depth == 24) ? FMT_S24_NE
00140 : (depth == 16) ? 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 if (! get_bool (NULL, "enable_replay_gain"))
00196 return;
00197
00198 gfloat factor = powf (10, get_double (NULL, "replay_gain_preamp") / 20);
00199
00200 if (have_replay_gain)
00201 {
00202 if (get_bool (NULL, "replay_gain_album"))
00203 {
00204 factor *= powf (10, replay_gain_info.album_gain / 20);
00205
00206 if (get_bool (NULL, "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 (get_bool (NULL, "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, get_double (NULL, "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 (! get_bool (NULL, "software_volume_control"))
00233 return;
00234
00235 gint l = get_int (NULL, "sw_volume_left");
00236 gint r = get_int (NULL, "sw_volume_right");
00237 if (l == 100 && r == 100)
00238 return;
00239
00240 left_factor = (l == 0) ? 0 : powf (10, (gfloat) SW_VOLUME_RANGE * (l - 100) / 100 / 20);
00241 right_factor = (r == 0) ? 0 : powf (10, (gfloat) SW_VOLUME_RANGE * (r - 100) / 100 / 20);
00242
00243 if (channels == 2)
00244 {
00245 factors[0] = left_factor;
00246 factors[1] = right_factor;
00247 }
00248 else
00249 {
00250 for (channel = 0; channel < channels; channel ++)
00251 factors[channel] = MAX (left_factor, right_factor);
00252 }
00253
00254 audio_amplify (data, channels, frames, factors);
00255 }
00256
00257 static void write_processed (void * data, gint samples)
00258 {
00259 LOCKED_VIS;
00260
00261 if (! samples)
00262 return;
00263
00264 vis_runner_pass_audio (cop->written_time (), data, samples, output_channels,
00265 output_rate);
00266 eq_filter (data, samples);
00267 apply_software_volume (data, output_channels, samples / output_channels);
00268
00269 void * allocated = NULL;
00270
00271 if (output_format != FMT_FLOAT)
00272 {
00273 void * new = g_malloc (FMT_SIZEOF (output_format) * samples);
00274 audio_to_int (data, new, output_format, samples);
00275 data = new;
00276 g_free (allocated);
00277 allocated = new;
00278 }
00279
00280 while (! aborted)
00281 {
00282 gint ready = (cop->buffer_free != NULL) ? cop->buffer_free () /
00283 FMT_SIZEOF (output_format) : output_channels * (output_rate / 50);
00284 ready = MIN (ready, samples);
00285 cop->write_audio (data, FMT_SIZEOF (output_format) * ready);
00286 data = (char *) data + FMT_SIZEOF (output_format) * ready;
00287 samples -= ready;
00288
00289 if (! samples)
00290 break;
00291
00292 waiting = TRUE;
00293 UNLOCK_VIS;
00294
00295 if (cop->period_wait != NULL)
00296 cop->period_wait ();
00297 else if (cop->buffer_free != NULL)
00298 g_usleep (20000);
00299
00300 LOCK_VIS;
00301 waiting = FALSE;
00302 }
00303
00304 g_free (allocated);
00305 }
00306
00307 static void write_audio (void * data, gint size)
00308 {
00309 LOCKED;
00310 g_return_if_fail (opened && ! waiting);
00311
00312 gint samples = size / FMT_SIZEOF (decoder_format);
00313 frames_written += samples / decoder_channels;
00314
00315 void * allocated = NULL;
00316
00317 if (decoder_format != FMT_FLOAT)
00318 {
00319 gfloat * new = g_malloc (sizeof (gfloat) * samples);
00320 audio_from_int (data, decoder_format, new, samples);
00321 data = new;
00322 g_free (allocated);
00323 allocated = new;
00324 }
00325
00326 apply_replay_gain (data, samples);
00327 gfloat * fdata = data;
00328 effect_process (& fdata, & samples);
00329 data = fdata;
00330
00331 if (data != allocated)
00332 {
00333 g_free (allocated);
00334 allocated = NULL;
00335 }
00336
00337 write_processed (data, samples);
00338 g_free (allocated);
00339 }
00340
00341 static void output_write_audio (void * data, gint size)
00342 {
00343 g_return_if_fail (cop != NULL);
00344 LOCK_VIS;
00345 write_audio (data, size);
00346 UNLOCK_VIS;
00347 }
00348
00349 static void close_audio (void)
00350 {
00351 LOCKED;
00352 g_return_if_fail (opened && ! waiting);
00353 opened = FALSE;
00354
00355 if (! leave_open)
00356 {
00357 effect_flush ();
00358 real_close ();
00359 }
00360 }
00361
00362 static void output_close_audio (void)
00363 {
00364 g_return_if_fail (cop != NULL);
00365 LOCK_VIS;
00366 close_audio ();
00367 UNLOCK_VIS;
00368 }
00369
00370 static void do_pause (gboolean p)
00371 {
00372 LOCKED_VIS;
00373 g_return_if_fail (opened);
00374 cop->pause (p);
00375 vis_runner_start_stop (TRUE, p);
00376 paused = p;
00377 }
00378
00379 static void output_pause (gboolean p)
00380 {
00381 g_return_if_fail (cop != NULL);
00382 LOCK_VIS;
00383 do_pause (p);
00384 UNLOCK_VIS;
00385 }
00386
00387 static void flush (gint time)
00388 {
00389 LOCKED_VIS;
00390 g_return_if_fail (opened);
00391
00392 aborted = FALSE;
00393
00394
00395
00396
00397
00398 if (! frames_written)
00399 {
00400 g_return_if_fail (cop->set_written_time != NULL);
00401 vis_runner_time_offset (time - cop->written_time ());
00402 cop->set_written_time (time);
00403 }
00404 else
00405 {
00406 vis_runner_flush ();
00407 effect_flush ();
00408 cop->flush (effect_decoder_to_output_time (time));
00409 }
00410
00411 frames_written = time * (gint64) decoder_rate / 1000;
00412 }
00413
00414 static void output_flush (gint time)
00415 {
00416 g_return_if_fail (cop != NULL);
00417 LOCK_VIS;
00418 flush (time);
00419 UNLOCK_VIS;
00420 }
00421
00422 static gint written_time (void)
00423 {
00424 LOCKED_RET (0);
00425 g_return_val_if_fail (opened && ! waiting, 0);
00426 return frames_written * (gint64) 1000 / decoder_rate;
00427 }
00428
00429 static gint output_written_time (void)
00430 {
00431 g_return_val_if_fail (cop != NULL, 0);
00432 LOCK;
00433 gint time = written_time ();
00434 UNLOCK;
00435 return time;
00436 }
00437
00438 static void write_buffers (void)
00439 {
00440 LOCKED;
00441 gfloat * data = NULL;
00442 gint samples = 0;
00443 effect_finish (& data, & samples);
00444 write_processed (data, samples);
00445 }
00446
00447 static void set_leave_open (void)
00448 {
00449 LOCKED;
00450 g_return_if_fail (opened && ! waiting);
00451
00452 if (! paused)
00453 {
00454 write_buffers ();
00455 leave_open = TRUE;
00456 }
00457 }
00458
00459 static gboolean output_buffer_playing (void)
00460 {
00461 g_return_val_if_fail (cop != NULL, FALSE);
00462 LOCK_VIS;
00463 set_leave_open ();
00464 UNLOCK_VIS;
00465 return FALSE;
00466 }
00467
00468 static void abort_write (void)
00469 {
00470 LOCKED;
00471 g_return_if_fail (opened);
00472 aborted = TRUE;
00473 cop->flush (cop->output_time ());
00474 }
00475
00476 static void output_abort_write (void)
00477 {
00478 g_return_if_fail (cop != NULL);
00479 LOCK;
00480 abort_write ();
00481 UNLOCK;
00482 }
00483
00484 const struct OutputAPI output_api =
00485 {
00486 .open_audio = output_open_audio,
00487 .set_replaygain_info = output_set_replaygain_info,
00488 .write_audio = output_write_audio,
00489 .close_audio = output_close_audio,
00490
00491 .pause = output_pause,
00492 .flush = output_flush,
00493 .written_time = output_written_time,
00494 .buffer_playing = output_buffer_playing,
00495 .abort_write = output_abort_write,
00496 };
00497
00498 static gint output_time (void)
00499 {
00500 LOCKED_RET (0);
00501 g_return_val_if_fail (opened || leave_open, 0);
00502 return cop->output_time ();
00503 }
00504
00505 gint get_output_time (void)
00506 {
00507 g_return_val_if_fail (cop != NULL, 0);
00508 LOCK;
00509
00510 gint time = 0;
00511 if (opened)
00512 {
00513 time = effect_output_to_decoder_time (output_time ());
00514 time = MAX (0, time);
00515 }
00516
00517 UNLOCK;
00518 return time;
00519 }
00520
00521 gint get_raw_output_time (void)
00522 {
00523 g_return_val_if_fail (cop != NULL, 0);
00524 LOCK;
00525 gint time = output_time ();
00526 UNLOCK;
00527 return time;
00528 }
00529
00530 void output_drain (void)
00531 {
00532 g_return_if_fail (cop != NULL);
00533 LOCK_VIS;
00534
00535 if (leave_open)
00536 {
00537 write_buffers ();
00538 drain ();
00539 real_close ();
00540 }
00541
00542 UNLOCK_VIS;
00543 }
00544
00545 static gboolean probe_cb (PluginHandle * p, PluginHandle * * pp)
00546 {
00547 OutputPlugin * op = plugin_get_header (p);
00548 g_return_val_if_fail (op != NULL && op->init != NULL, TRUE);
00549
00550 if (! op->init ())
00551 return TRUE;
00552
00553 if (op->cleanup != NULL)
00554 op->cleanup ();
00555
00556 * pp = p;
00557 return FALSE;
00558 }
00559
00560 PluginHandle * output_plugin_probe (void)
00561 {
00562 PluginHandle * p = NULL;
00563 plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) probe_cb, & p);
00564 return p;
00565 }
00566
00567 PluginHandle * output_plugin_get_current (void)
00568 {
00569 return (cop != NULL) ? plugin_by_header (cop) : NULL;
00570 }
00571
00572 gboolean output_plugin_set_current (PluginHandle * plugin)
00573 {
00574 if (cop != NULL)
00575 {
00576 if (playback_get_playing ())
00577 playback_stop ();
00578
00579 if (cop->cleanup != NULL)
00580 cop->cleanup ();
00581
00582 cop = NULL;
00583 }
00584
00585 if (plugin != NULL)
00586 {
00587 OutputPlugin * op = plugin_get_header (plugin);
00588 g_return_val_if_fail (op != NULL && op->init != NULL, FALSE);
00589
00590 if (! op->init ())
00591 return FALSE;
00592
00593 cop = op;
00594 }
00595
00596 return TRUE;
00597 }