Audacious
$Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* 00002 * output.c 00003 * Copyright 2009-2010 John Lindgren 00004 * 00005 * This file is part of Audacious. 00006 * 00007 * Audacious is free software: you can redistribute it and/or modify it under 00008 * the terms of the GNU General Public License as published by the Free Software 00009 * Foundation, version 2 or version 3 of the License. 00010 * 00011 * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY 00012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00013 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along with 00016 * Audacious. If not, see <http://www.gnu.org/licenses/>. 00017 * 00018 * The Audacious team does not consider modular code linking to Audacious or 00019 * using our public API to be a derived work. 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 /* decibels */ 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 /* output_mutex must be locked */ 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 ()); /* signal wait to return immediately */ 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 (); /* tell effect plugins this is the last song */ 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 /* This function is also used to restart playback (for example, when 00525 resampling is switched on or off), in which case we don't need to do an 00526 init cycle. -jlindgren */ 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 }