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 #include <unistd.h>
25 
26 #include <libaudcore/hook.h>
27 
28 #include "debug.h"
29 #include "effect.h"
30 #include "equalizer.h"
31 #include "misc.h"
32 #include "output.h"
33 #include "playback.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_input, 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_input, 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  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 (in_format != FMT_FLOAT)
286  {
287  buffer = malloc (sizeof (float) * samples);
288  audio_from_int (data, in_format, buffer, samples);
289  data = buffer;
290  }
291 
292  float * fdata = data;
293  apply_replay_gain (fdata, samples);
294  effect_process (& fdata, & samples);
295  write_output_raw (fdata, samples);
296 
297  free (buffer);
298 }
299 
300 /* assumes LOCK_ALL, s_output */
301 static void finish_effects (void)
302 {
303  float * data = NULL;
304  int samples = 0;
305 
306  effect_finish (& data, & samples);
307  write_output_raw (data, samples);
308 }
309 
311 {
312  /* prevent division by zero */
313  if (rate < 1 || channels < 1)
314  return FALSE;
315 
316  LOCK_ALL;
317 
318  s_input = TRUE;
320  seek_time = 0;
321 
322  in_format = format;
324  in_rate = rate;
325  in_frames = 0;
326 
327  setup_output ();
328 
329  UNLOCK_ALL;
330  return TRUE;
331 }
332 
334 {
335  LOCK_ALL;
336 
337  if (s_input)
338  {
339  memcpy (& gain_info, info, sizeof (ReplayGainInfo));
340  s_gain = TRUE;
341 
342  AUDDBG ("Replay Gain info:\n");
343  AUDDBG (" album gain: %f dB\n", info->album_gain);
344  AUDDBG (" album peak: %f\n", info->album_peak);
345  AUDDBG (" track gain: %f dB\n", info->track_gain);
346  AUDDBG (" track peak: %f\n", info->track_peak);
347  }
348 
349  UNLOCK_ALL;
350 }
351 
352 void output_write_audio (void * data, int size)
353 {
354  LOCK_ALL;
355 
356  if (s_input)
357  {
358  while ((! s_output || s_resetting) && ! s_aborted)
359  {
360  UNLOCK_ALL;
361  usleep (20000);
362  LOCK_ALL;
363  }
364 
365  if (! s_aborted)
366  write_output (data, size);
367  }
368 
369  UNLOCK_ALL;
370 }
371 
373 {
374  LOCK_MINOR;
375 
376  if (s_input)
377  {
378  s_aborted = TRUE;
379 
380  if (s_output)
381  flush_output ();
382  }
383 
384  UNLOCK_MINOR;
385 }
386 
388 {
389  LOCK_MINOR;
390 
391  if (s_input)
392  {
393  s_paused = pause;
394 
395  if (s_output)
396  apply_pause ();
397  }
398 
399  UNLOCK_MINOR;
400 }
401 
403 {
404  LOCK_MINOR;
405  int time = 0;
406 
407  if (s_input)
408  time = seek_time + FR2MS (in_frames, in_rate);
409 
410  UNLOCK_MINOR;
411  return time;
412 }
413 
414 void output_set_time (int time)
415 {
416  LOCK_ALL;
417 
418  if (s_input)
419  {
420  s_aborted = FALSE;
421  seek_time = time;
422  in_frames = 0;
423  }
424 
425  UNLOCK_ALL;
426 
427  /* See comment in playback_seek(). */
428  event_queue ("playback seek", NULL);
429 }
430 
432 {
433  LOCK_MINOR;
434  bool_t is_open = s_input;
435  UNLOCK_MINOR;
436  return is_open;
437 }
438 
439 int output_get_time (void)
440 {
441  LOCK_MINOR;
442  int time = 0, delay = 0;
443 
444  if (s_input)
445  {
446  if (s_output && PLUGIN_HAS_FUNC (cop, output_time))
447  delay = FR2MS (out_frames, out_rate) - cop->output_time ();
448 
449  delay = effect_adjust_delay (delay);
450  time = FR2MS (in_frames, in_rate);
451  time = seek_time + MAX (time - delay, 0);
452  }
453 
454  UNLOCK_MINOR;
455  return time;
456 }
457 
459 {
460  LOCK_MINOR;
461  int time = 0;
462 
463  if (s_output && PLUGIN_HAS_FUNC (cop, output_time))
464  time = cop->output_time ();
465 
466  UNLOCK_MINOR;
467  return time;
468 }
469 
471 {
472  LOCK_ALL;
473 
474  if (s_input)
475  {
476  s_input = FALSE;
477 
478  if (s_output && ! (s_paused || s_aborted || s_resetting))
479  finish_effects (); /* first time for end of song */
480  }
481 
482  UNLOCK_ALL;
483 }
484 
485 void output_drain (void)
486 {
487  LOCK_ALL;
488 
489  if (! s_input && s_output)
490  {
491  finish_effects (); /* second time for end of playlist */
492  cleanup_output ();
493  }
494 
495  UNLOCK_ALL;
496 }
497 
498 void output_reset (int type)
499 {
500  LOCK_MINOR;
501 
502  s_resetting = TRUE;
503 
504  if (s_output)
505  flush_output ();
506 
507  UNLOCK_MINOR;
508  LOCK_ALL;
509 
510  if (s_output && type != OUTPUT_RESET_EFFECTS_ONLY)
511  cleanup_output ();
512 
513  if (type == OUTPUT_RESET_HARD)
514  {
515  if (cop && PLUGIN_HAS_FUNC (cop, cleanup))
516  cop->cleanup ();
517 
518  if (change_op)
519  cop = new_op;
520 
521  if (cop && PLUGIN_HAS_FUNC (cop, init) && ! cop->init ())
522  cop = NULL;
523  }
524 
525  if (s_input)
526  setup_output ();
527 
528  s_resetting = FALSE;
529 
530  UNLOCK_ALL;
531 }
532 
533 void output_get_volume (int * left, int * right)
534 {
535  LOCK_MINOR;
536 
537  * left = * right = 0;
538 
539  if (get_bool (NULL, "software_volume_control"))
540  {
541  * left = get_int (NULL, "sw_volume_left");
542  * right = get_int (NULL, "sw_volume_right");
543  }
544  else if (cop && PLUGIN_HAS_FUNC (cop, get_volume))
545  cop->get_volume (left, right);
546 
547  UNLOCK_MINOR;
548 }
549 
550 void output_set_volume (int left, int right)
551 {
552  LOCK_MINOR;
553 
554  if (get_bool (NULL, "software_volume_control"))
555  {
556  set_int (NULL, "sw_volume_left", left);
557  set_int (NULL, "sw_volume_right", right);
558  }
559  else if (cop && PLUGIN_HAS_FUNC (cop, set_volume))
560  cop->set_volume (left, right);
561 
562  UNLOCK_MINOR;
563 }
564 
566 {
567  OutputPlugin * op = plugin_get_header (p);
568 
569  if (! op || (PLUGIN_HAS_FUNC (op, init) && ! op->init ()))
570  return TRUE; /* keep searching */
571 
572  if (PLUGIN_HAS_FUNC (op, cleanup))
573  op->cleanup ();
574 
575  * pp = p;
576  return FALSE; /* stop searching */
577 }
578 
580 {
581  PluginHandle * p = NULL;
583  return p;
584 }
585 
587 {
588  return cop ? plugin_by_header (cop) : NULL;
589 }
590 
592 {
593  change_op = TRUE;
594  new_op = plugin ? plugin_get_header (plugin) : NULL;
596 
597  bool_t success = (cop == new_op);
598  change_op = FALSE;
599  new_op = NULL;
600 
601  return success;
602 }