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