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