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 
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 }
void output_close_audio(void)
Definition: output.c:479
static int channels
Definition: equalizer.c:54
#define SW_VOLUME_RANGE
Definition: output.c:38
static void write_output_raw(void *data, int samples)
Definition: output.c:218
static int64_t in_frames
Definition: output.c:65
static bool_t s_input
Definition: output.c:54
#define LOCK_MINOR
Definition: output.c:45
bool_t(* open_audio)(int format, int rate, int chans)
Definition: plugin.h:178
float album_peak
Definition: types.h:58
#define FMT_SIZEOF(f)
Definition: audio.h:47
static int get_format(void)
Definition: output.c:74
#define MIN(a, b)
Definition: core.h:40
void output_set_replaygain_info(const ReplayGainInfo *info)
Definition: output.c:343
static int FR2MS(int64_t f, int r)
Definition: output.c:71
int effect_adjust_delay(int delay)
Definition: effect.c:138
static int seek_time
Definition: output.c:62
static bool_t s_resetting
Definition: output.c:59
void(* write_audio)(void *data, int size)
Definition: plugin.h:194
float track_peak
Definition: types.h:56
#define FMT_S16_NE
Definition: audio.h:32
static void setup_output(void)
Definition: output.c:114
static bool_t change_op
Definition: output.c:68
EXPORT void audio_from_int(const void *in, int format, float *out, int samples)
Definition: audio.c:172
PluginHandle * output_plugin_get_current(void)
Definition: output.c:595
static void write_output(void *data, int size)
Definition: output.c:278
void(* flush)(int time)
Definition: plugin.h:209
static int out_rate
Definition: output.c:64
double get_double(const char *section, const char *name)
Definition: config.c:327
int output_get_time(void)
Definition: output.c:448
void eq_filter(float *data, int samples)
Definition: equalizer.c:109
bool_t pause
Definition: main.c:58
int format
Definition: audio.c:132
void(* drain)(void)
Definition: plugin.h:197
#define LOCK_ALL
Definition: output.c:47
#define PLUGIN_HAS_FUNC(p, func)
Definition: plugin.h:515
static void flush(void)
Definition: vis_runner.c:104
static int out_channels
Definition: output.c:64
void effect_process(float **data, int *samples)
Definition: effect.c:105
static OutputPlugin * cop
Definition: output.c:61
type
Definition: plugins-api.h:41
static bool_t s_aborted
Definition: output.c:58
void effect_finish(float **data, int *samples)
Definition: effect.c:128
#define FMT_S24_NE
Definition: audio.h:34
static void finish_effects(void)
Definition: output.c:304
static bool_t s_paused
Definition: output.c:57
#define FALSE
Definition: core.h:35
void(* set_volume)(int l, int r)
Definition: plugin.h:173
static ReplayGainInfo gain_info
Definition: output.c:66
static bool_t s_gain
Definition: output.c:56
Index Index bool_t
Definition: playlist-api.h:122
void output_abort_write(void)
Definition: output.c:381
#define AUDDBG(...)
Definition: debug.h:30
void(* period_wait)(void)
Definition: plugin.h:191
static void apply_pause(void)
Definition: output.c:105
const void * plugin_get_header(PluginHandle *plugin)
static void flush_output(void)
Definition: output.c:144
EXPORT void audio_soft_clip(float *data, int samples)
Definition: audio.c:217
void vis_runner_start_stop(bool_t new_playing, bool_t new_paused)
Definition: vis_runner.c:150
#define NULL
Definition: core.h:27
void output_set_volume(int left, int right)
Definition: output.c:559
void vis_runner_pass_audio(int time, float *data, int samples, int channels, int rate)
Definition: vis_runner.c:157
void effect_flush(void)
Definition: effect.c:115
void set_int(const char *section, const char *name, int value)
Definition: config.c:302
static bool_t probe_cb(PluginHandle *p, PluginHandle **pp)
Definition: output.c:574
static int64_t out_frames
Definition: output.c:65
int output_get_raw_time(void)
Definition: output.c:467
static bool_t s_output
Definition: output.c:55
void(* get_volume)(int *l, int *r)
Definition: plugin.h:170
bool_t(* PluginForEachFunc)(PluginHandle *plugin, void *data)
Definition: plugins.h:27
void effect_start(int *channels, int *rate)
Definition: effect.c:64
#define TRUE
Definition: core.h:37
bool_t get_bool(const char *section, const char *name)
Definition: config.c:294
static int out_format
Definition: output.c:64
float album_gain
Definition: types.h:57
bool_t output_open_audio(int format, int rate, int channels)
Definition: output.c:313
int output_written_time(void)
Definition: output.c:411
int(* output_time)(void)
Definition: plugin.h:201
void vis_runner_flush(void)
Definition: vis_runner.c:119
static void apply_replay_gain(float *data, int samples)
Definition: output.c:156
float track_gain
Definition: types.h:55
static OutputPlugin * new_op
Definition: output.c:69
bool_t output_plugin_set_current(PluginHandle *plugin)
Definition: output.c:600
static int rate
Definition: equalizer.c:54
static void apply_software_volume(float *data, int channels, int samples)
Definition: output.c:188
static int in_format
Definition: output.c:63
#define event_queue(n, d)
Definition: hook.h:44
static pthread_mutex_t mutex_major
Definition: output.c:40
int(* buffer_free)(void)
Definition: plugin.h:185
#define UNLOCK_MINOR
Definition: output.c:46
EXPORT void audio_amplify(float *data, int channels, int frames, float *factors)
Definition: audio.c:200
void output_reset(int type)
Definition: output.c:507
void output_get_volume(int *left, int *right)
Definition: output.c:542
static void cleanup_output(void)
Definition: output.c:86
int get_int(const char *section, const char *name)
Definition: config.c:310
void output_write_audio(void *data, int size)
Definition: output.c:362
#define MAX(a, b)
Definition: core.h:42
bool_t output_is_open(void)
Definition: output.c:440
static pthread_mutex_t mutex_minor
Definition: output.c:41
#define FMT_S32_NE
Definition: audio.h:36
void output_drain(void)
Definition: output.c:494
void data PluginHandle plugin
Definition: plugins-api.h:54
void(* pause)(bool_t p)
Definition: plugin.h:205
static int in_rate
Definition: output.c:63
EXPORT void audio_to_int(const float *in, void *out, int format, int samples)
Definition: audio.c:186
void plugin_for_each(int type, PluginForEachFunc func, void *data)
PluginHandle * plugin_by_header(const void *header)
PluginHandle * output_plugin_probe(void)
Definition: output.c:588
void(* close_audio)(void)
Definition: plugin.h:181
void output_set_time(int time)
Definition: output.c:423
static int in_channels
Definition: output.c:63
void eq_set_format(int new_channels, int new_rate)
Definition: equalizer.c:73
void output_pause(bool_t pause)
Definition: output.c:396
#define UNLOCK_ALL
Definition: output.c:48