Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
output.c
Go to the documentation of this file.
1 /*
2  * output.c
3  * Copyright 2009-2012 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <math.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <glib.h> /* for g_usleep */
26 
27 #include <libaudcore/hook.h>
28 
29 #include "debug.h"
30 #include "effect.h"
31 #include "equalizer.h"
32 #include "misc.h"
33 #include "output.h"
34 #include "plugin.h"
35 #include "plugins.h"
36 #include "vis_runner.h"
37 
38 #define SW_VOLUME_RANGE 40 /* decibels */
39 
40 static pthread_mutex_t mutex_major = PTHREAD_MUTEX_INITIALIZER;
41 static pthread_mutex_t mutex_minor = PTHREAD_MUTEX_INITIALIZER;
42 
43 #define LOCK_MAJOR pthread_mutex_lock (& mutex_major)
44 #define UNLOCK_MAJOR pthread_mutex_unlock (& mutex_major)
45 #define LOCK_MINOR pthread_mutex_lock (& mutex_minor)
46 #define UNLOCK_MINOR pthread_mutex_unlock (& mutex_minor)
47 #define LOCK_ALL do { LOCK_MAJOR; LOCK_MINOR; } while (0)
48 #define UNLOCK_ALL do { UNLOCK_MINOR; UNLOCK_MAJOR; } while (0)
49 
50 /* State variables. State changes that are allowed between LOCK_MINOR and
51  * UNLOCK_MINOR (all others must take place between LOCK_ALL and UNLOCK_ALL):
52  * s_paused -> TRUE or FALSE, s_aborted -> TRUE, s_resetting -> TRUE */
53 
54 static bool_t s_input; /* input plugin connected */
55 static bool_t s_output; /* output plugin connected */
56 static bool_t s_gain; /* replay gain info set */
57 static bool_t s_paused; /* paused */
58 static bool_t s_aborted; /* writes aborted */
59 static bool_t s_resetting; /* resetting output system */
60 
61 static OutputPlugin * cop;
62 static int seek_time;
65 static int64_t in_frames, out_frames;
67 
69 static OutputPlugin * new_op;
70 
71 static inline int FR2MS (int64_t f, int r)
72  { return (f > 0) ? (f * 1000 + r / 2) / r : (f * 1000 - r / 2) / r; }
73 
74 static inline int get_format (void)
75 {
76  switch (get_int (NULL, "output_bit_depth"))
77  {
78  case 16: return FMT_S16_NE;
79  case 24: return FMT_S24_NE;
80  case 32: return FMT_S32_NE;
81  default: return FMT_FLOAT;
82  }
83 }
84 
85 /* assumes LOCK_ALL, s_output */
86 static void cleanup_output (void)
87 {
88  if (! (s_paused || s_aborted) && PLUGIN_HAS_FUNC (cop, drain))
89  {
91  cop->drain ();
92  LOCK_MINOR;
93  }
94 
95  s_output = FALSE;
96 
97  if (PLUGIN_HAS_FUNC (cop, close_audio))
98  cop->close_audio ();
99 
100  effect_flush ();
102 }
103 
104 /* assumes LOCK_ALL, s_output */
105 static void apply_pause (void)
106 {
107  if (PLUGIN_HAS_FUNC (cop, pause))
108  cop->pause (s_paused);
109 
111 }
112 
113 /* assumes LOCK_ALL, s_input */
114 static void setup_output (void)
115 {
116  int format = get_format ();
117  int channels = in_channels;
118  int rate = in_rate;
119 
120  effect_start (& channels, & rate);
121  eq_set_format (channels, rate);
122 
123  if (s_output && format == out_format && channels == out_channels && rate ==
124  out_rate && ! PLUGIN_HAS_FUNC (cop, force_reopen))
125  return;
126 
127  if (s_output)
128  cleanup_output ();
129 
130  if (! cop || ! PLUGIN_HAS_FUNC (cop, open_audio) || ! cop->open_audio (format, rate, channels))
131  return;
132 
133  s_output = TRUE;
134 
135  out_format = format;
137  out_rate = rate;
138  out_frames = 0;
139 
140  apply_pause ();
141 }
142 
143 /* assumes LOCK_MINOR, s_output */
144 static void flush_output (void)
145 {
146  if (PLUGIN_HAS_FUNC (cop, flush))
147  {
148  cop->flush (0);
149  out_frames = 0;
150  }
151 
152  effect_flush ();
153  vis_runner_flush ();
154 }
155 
156 static void apply_replay_gain (float * data, int samples)
157 {
158  if (! get_bool (NULL, "enable_replay_gain"))
159  return;
160 
161  float factor = powf (10, get_double (NULL, "replay_gain_preamp") / 20);
162 
163  if (s_gain)
164  {
165  float peak;
166 
167  if (get_bool (NULL, "replay_gain_album"))
168  {
169  factor *= powf (10, gain_info.album_gain / 20);
170  peak = gain_info.album_peak;
171  }
172  else
173  {
174  factor *= powf (10, gain_info.track_gain / 20);
175  peak = gain_info.track_peak;
176  }
177 
178  if (get_bool (NULL, "enable_clipping_prevention") && peak * factor > 1)
179  factor = 1 / peak;
180  }
181  else
182  factor *= powf (10, get_double (NULL, "default_gain") / 20);
183 
184  if (factor < 0.99 || factor > 1.01)
185  audio_amplify (data, 1, samples, & factor);
186 }
187 
188 static void apply_software_volume (float * data, int channels, int samples)
189 {
190  if (! get_bool (NULL, "software_volume_control"))
191  return;
192 
193  int l = get_int (NULL, "sw_volume_left");
194  int r = get_int (NULL, "sw_volume_right");
195 
196  if (l == 100 && r == 100)
197  return;
198 
199  float lfactor = (l == 0) ? 0 : powf (10, (float) SW_VOLUME_RANGE * (l - 100) / 100 / 20);
200  float rfactor = (r == 0) ? 0 : powf (10, (float) SW_VOLUME_RANGE * (r - 100) / 100 / 20);
201  float factors[channels];
202 
203  if (channels == 2)
204  {
205  factors[0] = lfactor;
206  factors[1] = rfactor;
207  }
208  else
209  {
210  for (int c = 0; c < channels; c ++)
211  factors[c] = MAX (lfactor, rfactor);
212  }
213 
214  audio_amplify (data, channels, samples / channels, factors);
215 }
216 
217 /* assumes LOCK_ALL, s_output */
218 static void write_output_raw (void * data, int samples)
219 {
220  void * buffer = NULL;
221 
222  vis_runner_pass_audio (FR2MS (out_frames, out_rate), data, samples,
224  out_frames += samples / out_channels;
225 
226  eq_filter (data, samples);
227  apply_software_volume (data, out_channels, samples);
228 
229  if (get_bool (NULL, "soft_clipping"))
230  audio_soft_clip (data, samples);
231 
232  if (out_format != FMT_FLOAT)
233  {
234  buffer = malloc (FMT_SIZEOF (out_format) * samples);
235  audio_to_int (data, buffer, out_format, samples);
236  data = buffer;
237  }
238 
239  while (! (s_aborted || s_resetting))
240  {
241  bool_t blocking = ! PLUGIN_HAS_FUNC (cop, buffer_free);
242  int ready;
243 
244  if (blocking)
245  ready = out_channels * (out_rate / 50);
246  else
247  ready = cop->buffer_free () / FMT_SIZEOF (out_format);
248 
249  ready = MIN (ready, samples);
250 
251  if (PLUGIN_HAS_FUNC (cop, write_audio))
252  {
253  cop->write_audio (data, FMT_SIZEOF (out_format) * ready);
254  data = (char *) data + FMT_SIZEOF (out_format) * ready;
255  samples -= ready;
256  }
257 
258  if (samples == 0)
259  break;
260 
261  UNLOCK_MINOR;
262 
263  if (! blocking)
264  {
265  if (PLUGIN_HAS_FUNC (cop, period_wait))
266  cop->period_wait ();
267  else
268  g_usleep (20000);
269  }
270 
271  LOCK_MINOR;
272  }
273 
274  free (buffer);
275 }
276 
277 /* assumes LOCK_ALL, s_input, s_output */
278 static void write_output (void * data, int size)
279 {
280  void * buffer = NULL;
281 
282  int samples = size / FMT_SIZEOF (in_format);
283  in_frames += samples / in_channels;
284 
285  if (s_aborted)
286  return;
287 
288  if (in_format != FMT_FLOAT)
289  {
290  buffer = malloc (sizeof (float) * samples);
291  audio_from_int (data, in_format, buffer, samples);
292  data = buffer;
293  }
294 
295  float * fdata = data;
296  apply_replay_gain (fdata, samples);
297  effect_process (& fdata, & samples);
298  write_output_raw (fdata, samples);
299 
300  free (buffer);
301 }
302 
303 /* assumes LOCK_ALL, s_output */
304 static void finish_effects (void)
305 {
306  float * data = NULL;
307  int samples = 0;
308 
309  effect_finish (& data, & samples);
310  write_output_raw (data, samples);
311 }
312 
314 {
315  /* prevent division by zero */
316  if (rate < 1 || channels < 1)
317  return FALSE;
318 
319  LOCK_ALL;
320 
321  if (s_output && s_paused)
322  {
323  flush_output ();
324  s_paused = FALSE;
325  apply_pause ();
326  }
327 
328  s_input = TRUE;
330  seek_time = 0;
331 
332  in_format = format;
334  in_rate = rate;
335  in_frames = 0;
336 
337  setup_output ();
338 
339  UNLOCK_ALL;
340  return TRUE;
341 }
342 
344 {
345  LOCK_ALL;
346 
347  if (s_input)
348  {
349  memcpy (& gain_info, info, sizeof (ReplayGainInfo));
350  s_gain = TRUE;
351 
352  AUDDBG ("Replay Gain info:\n");
353  AUDDBG (" album gain: %f dB\n", info->album_gain);
354  AUDDBG (" album peak: %f\n", info->album_peak);
355  AUDDBG (" track gain: %f dB\n", info->track_gain);
356  AUDDBG (" track peak: %f\n", info->track_peak);
357  }
358 
359  UNLOCK_ALL;
360 }
361 
362 void output_write_audio (void * data, int size)
363 {
364  LOCK_ALL;
365 
366  if (s_input)
367  {
368  while ((! s_output || s_resetting) && ! s_aborted)
369  {
370  UNLOCK_ALL;
371  g_usleep (20000);
372  LOCK_ALL;
373  }
374 
375  write_output (data, size);
376  }
377 
378  UNLOCK_ALL;
379 }
380 
382 {
383  LOCK_MINOR;
384 
385  if (s_input)
386  {
387  s_aborted = TRUE;
388 
389  if (s_output)
390  flush_output ();
391  }
392 
393  UNLOCK_MINOR;
394 }
395 
397 {
398  LOCK_MINOR;
399 
400  if (s_input)
401  {
402  s_paused = pause;
403 
404  if (s_output)
405  apply_pause ();
406  }
407 
408  UNLOCK_MINOR;
409 }
410 
412 {
413  LOCK_MINOR;
414  int time = 0;
415 
416  if (s_input)
417  time = seek_time + FR2MS (in_frames, in_rate);
418 
419  UNLOCK_MINOR;
420  return time;
421 }
422 
423 void output_set_time (int time)
424 {
425  LOCK_ALL;
426 
427  if (s_input)
428  {
429  s_aborted = FALSE;
430  seek_time = time;
431  in_frames = 0;
432  }
433 
434  UNLOCK_ALL;
435 
436  /* See comment in playback_seek(). */
437  event_queue ("playback seek", NULL);
438 }
439 
441 {
442  LOCK_MINOR;
443  bool_t is_open = s_input;
444  UNLOCK_MINOR;
445  return is_open;
446 }
447 
448 int output_get_time (void)
449 {
450  LOCK_MINOR;
451  int time = 0, delay = 0;
452 
453  if (s_input)
454  {
455  if (s_output && PLUGIN_HAS_FUNC (cop, output_time))
456  delay = FR2MS (out_frames, out_rate) - cop->output_time ();
457 
458  delay = effect_adjust_delay (delay);
459  time = FR2MS (in_frames, in_rate);
460  time = seek_time + MAX (time - delay, 0);
461  }
462 
463  UNLOCK_MINOR;
464  return time;
465 }
466 
468 {
469  LOCK_MINOR;
470  int time = 0;
471 
472  if (s_output && PLUGIN_HAS_FUNC (cop, output_time))
473  time = cop->output_time ();
474 
475  UNLOCK_MINOR;
476  return time;
477 }
478 
480 {
481  LOCK_ALL;
482 
483  if (s_input)
484  {
485  s_input = FALSE;
486 
487  if (s_output && ! (s_paused || s_aborted || s_resetting))
488  finish_effects (); /* first time for end of song */
489  }
490 
491  UNLOCK_ALL;
492 }
493 
494 void output_drain (void)
495 {
496  LOCK_ALL;
497 
498  if (! s_input && s_output)
499  {
500  finish_effects (); /* second time for end of playlist */
501  cleanup_output ();
502  }
503 
504  UNLOCK_ALL;
505 }
506 
507 void output_reset (int type)
508 {
509  LOCK_MINOR;
510 
511  s_resetting = TRUE;
512 
513  if (s_output)
514  flush_output ();
515 
516  UNLOCK_MINOR;
517  LOCK_ALL;
518 
519  if (s_output && type != OUTPUT_RESET_EFFECTS_ONLY)
520  cleanup_output ();
521 
522  if (type == OUTPUT_RESET_HARD)
523  {
524  if (cop && PLUGIN_HAS_FUNC (cop, cleanup))
525  cop->cleanup ();
526 
527  if (change_op)
528  cop = new_op;
529 
530  if (cop && PLUGIN_HAS_FUNC (cop, init) && ! cop->init ())
531  cop = NULL;
532  }
533 
534  if (s_input)
535  setup_output ();
536 
537  s_resetting = FALSE;
538 
539  UNLOCK_ALL;
540 }
541 
542 void output_get_volume (int * left, int * right)
543 {
544  LOCK_MINOR;
545 
546  * left = * right = 0;
547 
548  if (get_bool (NULL, "software_volume_control"))
549  {
550  * left = get_int (NULL, "sw_volume_left");
551  * right = get_int (NULL, "sw_volume_right");
552  }
553  else if (cop && PLUGIN_HAS_FUNC (cop, get_volume))
554  cop->get_volume (left, right);
555 
556  UNLOCK_MINOR;
557 }
558 
559 void output_set_volume (int left, int right)
560 {
561  LOCK_MINOR;
562 
563  if (get_bool (NULL, "software_volume_control"))
564  {
565  set_int (NULL, "sw_volume_left", left);
566  set_int (NULL, "sw_volume_right", right);
567  }
568  else if (cop && PLUGIN_HAS_FUNC (cop, set_volume))
569  cop->set_volume (left, right);
570 
571  UNLOCK_MINOR;
572 }
573 
575 {
576  OutputPlugin * op = plugin_get_header (p);
577 
578  if (! op || (PLUGIN_HAS_FUNC (op, init) && ! op->init ()))
579  return TRUE; /* keep searching */
580 
581  if (PLUGIN_HAS_FUNC (op, cleanup))
582  op->cleanup ();
583 
584  * pp = p;
585  return FALSE; /* stop searching */
586 }
587 
589 {
590  PluginHandle * p = NULL;
592  return p;
593 }
594 
596 {
597  return cop ? plugin_by_header (cop) : NULL;
598 }
599 
601 {
602  change_op = TRUE;
603  new_op = plugin ? plugin_get_header (plugin) : NULL;
605 
606  bool_t success = (cop == new_op);
607  change_op = FALSE;
608  new_op = NULL;
609 
610  return success;
611 }