comparison src/crossfade/crossfade.c @ 3059:2e241e90494a

Import work in progress xmms-crossfade rewrite.
author William Pitcock <nenolod@atheme.org>
date Fri, 24 Apr 2009 05:57:35 -0500
parents
children 43a336a7791b
comparison
equal deleted inserted replaced
3058:2e649bf16ebc 3059:2e241e90494a
1 /*
2 * XMMS Crossfade Plugin
3 * Copyright (C) 2000-2007 Peter Eisenlohr <peter@eisenlohr.org>
4 *
5 * based on the original OSS Output Plugin
6 * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 * USA.
22 */
23 /* indent -i8 -ts8 -hnl -bli0 -l128 -npcs -cli8 */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include "crossfade.h"
30 #include "cfgutil.h"
31 #include "format.h"
32 #include "convert.h"
33 #include "timing.h"
34
35 #include "configure.h"
36 #include "monitor.h"
37
38 #include "interface-2.0.h"
39 #include "support-2.0.h"
40
41 #ifdef HAVE_LIBFFTW
42 # include "fft.h"
43 #endif
44
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <ctype.h>
49
50 #ifdef HAVE_DLFCN_H
51 # include <dlfcn.h>
52 #endif
53 #include <unistd.h>
54 #include <signal.h>
55 #include <sys/time.h>
56 #include <sys/types.h>
57 #include <sys/ioctl.h>
58
59 #undef DEBUG_HARDCORE
60
61 /* output plugin callback prototypes */
62 static void xfade_init();
63 static void xfade_cleanup(); /* audacious and patched only */
64 static void xfade_set_volume(int l, int r);
65 static void xfade_get_volume(int *l, int *r);
66 static gint xfade_open_audio(AFormat fmt, int rate, int nch);
67 static void xfade_write_audio(void *ptr, int length);
68 static void xfade_close_audio();
69 static void xfade_flush(int time);
70 static void xfade_pause(short paused);
71 static gint xfade_buffer_free();
72 static gint xfade_buffer_playing();
73 static gint xfade_written_time();
74 static gint xfade_output_time();
75
76 /* output plugin callback table (extended, needs patched player) */
77 static struct
78 {
79 OutputPlugin xfade_op;
80 void (*cleanup) (void);
81 }
82 xfade_op_private =
83 {
84 {
85 .description = "Crossfade Plugin",
86 .init = xfade_init,
87 .cleanup = xfade_cleanup,
88 .get_volume = xfade_get_volume,
89 .set_volume = xfade_set_volume,
90 .open_audio = xfade_open_audio,
91 .write_audio = xfade_write_audio,
92 .close_audio = xfade_close_audio,
93 .flush = xfade_flush,
94 .pause = xfade_pause,
95 .buffer_free = xfade_buffer_free,
96 .buffer_playing = xfade_buffer_playing,
97 .output_time = xfade_output_time,
98 .written_time = xfade_written_time,
99 .about = xfade_about,
100 .configure = xfade_configure,
101 .probe_priority = 2,
102 },
103 NULL
104 };
105
106 static OutputPlugin *xfade_op = &xfade_op_private.xfade_op;
107
108 static OutputPlugin *xfade_oplist[] = { &xfade_op_private.xfade_op, NULL };
109 DECLARE_PLUGIN(crossfade, NULL, NULL, NULL, xfade_oplist, NULL, NULL, NULL);
110
111 /* internal prototypes */
112 static void load_symbols();
113 static void output_list_hack();
114 static gint open_output();
115 static void buffer_reset(buffer_t *buf, config_t *cfg);
116 static void *buffer_thread_f(void *arg);
117 static void sync_output();
118
119 /* special XMMS symbols (dynamically looked up, see xfade_init) */
120 static gboolean *xmms_playlist_get_info_going = NULL; /* XMMS */
121 static gboolean *xmms_is_quitting = NULL; /* XMMS */
122 static gboolean *input_stopped_for_restart = NULL; /* XMMS */
123 static char * (*playlist_get_fadeinfo)(int) = NULL; /* XMMS patch */
124
125 static void (*xmms_input_get_song_info)(gchar *, gchar **, gint *); /* XMMS */
126 static gchar **xmms_gentitle_format = NULL; /* XMMS private cfg */
127
128 /* This function has been stolen from libxmms/util.c. */
129 void xfade_usleep(gint usec)
130 {
131 #if defined(HAVE_G_USLEEP)
132 g_usleep(usec);
133 #elif defined(HAVE_NANOSLEEP)
134 struct timespec req;
135
136 req.tv_sec = usec / 1000000;
137 usec -= req.tv_sec * 1000000;
138 req.tv_nsec = usec * 1000;
139
140 nanosleep(&req, NULL);
141 #else
142 struct timeval tv;
143
144 tv.tv_sec = usec / 1000000;
145 usec -= tv.tv_sec * 1000000;
146 tv.tv_usec = usec;
147 select(0, NULL, NULL, NULL, &tv);
148 #endif
149 }
150
151
152 /* local variables */
153 static gboolean realtime;
154 static gboolean is_http;
155
156 static gint64 streampos; /* position within current song (input bps) */
157 static gboolean playing;
158 gboolean opened; /* TRUE between open_audio() and close_audio() */
159 static gboolean paused; /* TRUE: no playback (but still filling buffer) */
160 static gboolean stopped; /* TRUE: stop buffer thread ASAP */
161 static gboolean eop; /* TRUE: wait until buffer is empty then sync() */
162
163 #ifdef HAVE_OSS /* avoid 'defined but not used' compiler warning */
164 static plugin_config_t default_op_config = DEFAULT_OP_CONFIG;
165 #endif
166 static plugin_config_t the_op_config = DEFAULT_OP_CONFIG;
167 OutputPlugin *the_op = NULL;
168 gint the_rate = 44100;
169
170 static gboolean input_playing = FALSE;
171
172 gboolean output_opened = FALSE;
173 gboolean output_restart = FALSE; /* used by XMMS 'songchange' patch */
174 static gint output_flush_time = 0;
175 gint output_offset = 0;
176 static gint64 output_written = 0;
177 gint64 output_streampos = 0;
178
179 static gchar zero_4k[4096];
180
181 #ifdef TIMING_COMMENTS
182 typedef struct
183 {
184 gboolean enable;
185 gint len_ms, volume, skip_ms, ofs_ms;
186 }
187 timing_half_config_t;
188
189 typedef struct
190 {
191 timing_half_config_t in;
192 timing_half_config_t out;
193 }
194 timing_config_t;
195
196 static timing_config_t last_timing, current_timing;
197 #endif
198
199 /*
200 * Available fade configs:
201 *
202 * fc_start: First song, only in_len and in_level are used
203 * fc_xfade: Automatic crossfade at end of song
204 * fc_album: Like xfade but for consecutive songs of the same album
205 * fc_manual: Manual crossfade (triggered by Next or Prev)
206 * fc_stop: Last song, only out_len and out_level are used
207 * fc_eop: Last song, only out_len and out_level are used
208 *
209 * NOTE: As of version 0.2 of xmms-crossfade,
210 * only xfade and manual are implemented.
211 *
212 * With version 0.2.3, fc_album has been added.
213 *
214 * With 0.2.4, all configs are implemented:
215 *
216 * Available parameters:
217 *
218 * | start | xfade | manual | album | stop | eop
219 * ------------+-------+-------+--------+-------+------+------
220 * in_len | yes | yes | yes | no | no | no
221 * in_volume | yes | yes | yes | no | no | no
222 * offset | no | yes | yes | no | +yes | +yes
223 * out_len | no | yes | yes | no | yes | yes
224 * out_volume | no | yes | yes | no | yes | yes
225 * flush (*) | no | no | yes | no | yes | no
226 * ------------+-------+-------+--------+-------+------+------
227 *
228 * Parameters marked with (*) are not configureable by the user
229 *
230 * The offset parameters for 'stop' and 'eop' is used to store the
231 * length of the additional silence to be added. It may be >= 0 only.
232 *
233 */
234
235 static struct timeval last_close;
236 static struct timeval last_write;
237
238 static gchar *last_filename = NULL;
239
240 static format_t in_format;
241 static format_t out_format;
242
243 static buffer_t the_buffer;
244 buffer_t *buffer = &the_buffer;
245
246 static THREAD buffer_thread;
247 MUTEX buffer_mutex = MUTEX_INITIALIZER;
248
249 static convert_context_t convert_context;
250 #ifdef HAVE_LIBFFTW
251 static fft_context_t fft_context;
252 #endif
253
254 static config_t the_config;
255 config_t *config = &the_config;
256 config_t config_default = CONFIG_DEFAULT;
257
258 static fade_config_t *fade_config = NULL;
259
260
261 /* this is the entry point for XMMS */
262 OutputPlugin *
263 get_oplugin_info()
264 {
265 return xfade_op;
266 }
267
268 OutputPlugin *
269 get_crossfade_oplugin_info()
270 {
271 return xfade_op;
272 }
273
274 static gboolean
275 open_output_f(gpointer data)
276 {
277 DEBUG(("[crossfade] open_output_f: pid=%d\n", getpid()));
278 open_output();
279 return FALSE; /* FALSE = 'do not call me again' */
280 }
281
282 void
283 xfade_realize_config() /* also called by xfade_init() */
284 {
285 /* 0.3.0: keep device opened */
286 if (config->output_keep_opened && !output_opened)
287 {
288 DEBUG(("[crossfade] realize_config: keeping output opened...\n"));
289
290 /* 0.3.1: HACK: this will make sure that we start playing silence after startup */
291 gettimeofday(&last_close, NULL);
292
293 /* 0.3.1: HACK: Somehow, if we open output here at XMMS startup, there
294 will be leftover filedescriptors later when closing output again.
295 Opening output in a timeout function seems to work around this... */
296 DEBUG(("[crossfade] realize_config: adding timeout (pid=%d)\n", (int) getpid()));
297 g_timeout_add(0, open_output_f, NULL);
298 }
299 }
300
301 static gint
302 output_list_f(gconstpointer a, gconstpointer b)
303 {
304 OutputPlugin *op = (OutputPlugin *) a;
305 gchar *name = (gchar *) b;
306
307 return strcmp(g_basename(op->filename), name);
308 }
309
310 static OutputPlugin *
311 find_output()
312 {
313 GList *list, *element;
314 OutputPlugin *op = NULL;
315
316 /* find output plugin */
317 {
318 if (config->op_name && (list = xfplayer_get_output_list()))
319 if ((element = g_list_find_custom(list, config->op_name, output_list_f)))
320 op = element->data;
321
322 if (op == xfade_op)
323 {
324 DEBUG(("[crossfade] find_output: can't use myself as output plugin!\n"));
325 op = NULL;
326 }
327 else if (!op)
328 {
329 DEBUG(("[crossfade] find_output: could not find output plugin \"%s\"\n",
330 config->op_name ? config->op_name : "#NULL#"));
331 }
332 else /* ok, we have a plugin. last, get its compatibility options */
333 xfade_load_plugin_config(config->op_config_string, config->op_name, &the_op_config);
334 }
335
336 return op;
337 }
338
339 static gint
340 open_output()
341 {
342 /* sanity check */
343 if (output_opened)
344 DEBUG(("[crossfade] open_output: WARNING: output_opened=TRUE!\n"));
345
346 /* reset output_* */
347 output_opened = FALSE;
348 output_flush_time = 0;
349 output_offset = 0;
350 output_written = 0;
351 output_streampos = 0;
352
353 /* get output plugin (this will also init the_op_config) */
354 if (!(the_op = find_output()))
355 {
356 DEBUG(("[crossfade] open_output: could not find any output!\n"));
357 return -1;
358 }
359
360 /* print output plugin info */
361 DEBUG(("[crossfade] open_output: using \"%s\" for output", the_op->description ? the_op->description : "#NULL#"));
362
363 if (realtime)
364 DEBUG((" (RT)"));
365
366 if (the_op_config.throttle_enable)
367 DEBUG((realtime ? " (throttled (disabled with RT))" : " (throttled)"));
368
369 if (the_op_config.max_write_enable)
370 DEBUG((" (max_write=%d)", the_op_config.max_write_len));
371
372 DEBUG(("\n"));
373
374 /* setup sample rate (note that OUTPUT_RATE is #defined as the_rate) */
375 the_rate = config->output_rate;
376
377 /* setup out_format. use host byte order for easy math */
378 setup_format(FMT_S16_NE, OUTPUT_RATE, OUTPUT_NCH, &out_format);
379
380 /* open plugin */
381 if (!the_op->open_audio(out_format.fmt, out_format.rate, out_format.nch))
382 {
383 DEBUG(("[crossfade] open_output: open_audio() failed!\n"));
384 the_op = NULL;
385 return -1;
386 }
387
388 /* clear buffer struct */
389 memset(buffer, 0, sizeof(*buffer));
390
391 /* calculate buffer size */
392 buffer->mix_size = MS2B(xfade_mix_size_ms(config)) & -4;
393 buffer->sync_size = MS2B(config->sync_size_ms) & -4;
394 buffer->preload_size = MS2B(config->preload_size_ms) & -4;
395
396 buffer->size = (buffer->mix_size + /* mixing area */
397 buffer->sync_size + /* additional sync */
398 buffer->preload_size); /* preload */
399
400 DEBUG(("[crossfade] open_output: buffer: size=%d (%d+%d+%d=%d ms) (%d Hz)\n",
401 buffer->size,
402 B2MS(buffer->mix_size),
403 B2MS(buffer->preload_size),
404 B2MS(buffer->sync_size),
405 B2MS(buffer->size),
406 the_rate));
407
408 /* allocate buffer */
409 if (!(buffer->data = g_malloc0(buffer->size)))
410 {
411 DEBUG(("[crossfade] open_output: error allocating buffer!\n"));
412 the_op->close_audio();
413 the_op = NULL;
414 return -1;
415 }
416
417 /* reset buffer */
418 buffer_reset(buffer, config);
419
420 /* make sure stopped is TRUE -- otherwise the buffer thread would
421 * stop again immediatelly after it has been started. */
422 stopped = FALSE;
423
424 /* create and run buffer thread */
425 if (THREAD_CREATE(buffer_thread, buffer_thread_f))
426 {
427 PERROR("[crossfade] open_output: thread_create()");
428 g_free(buffer->data);
429 the_op->close_audio();
430 the_op = NULL;
431 return -1;
432 }
433 SCHED_YIELD;
434
435 /* start updating monitor */
436 xfade_start_monitor();
437
438 /* done */
439 output_opened = TRUE;
440 return 0;
441 }
442
443 static void
444 xfade_init()
445 {
446 /* load config */
447 memset(config, 0, sizeof(*config));
448 *config = config_default;
449 xfade_load_config();
450
451 /* set default strings if there is no existing config */
452 if (!config->oss_alt_audio_device) config->oss_alt_audio_device = g_strdup(DEFAULT_OSS_ALT_AUDIO_DEVICE);
453 if (!config->oss_alt_mixer_device) config->oss_alt_mixer_device = g_strdup(DEFAULT_OSS_ALT_MIXER_DEVICE);
454 if (!config->op_config_string) config->op_config_string = g_strdup(DEFAULT_OP_CONFIG_STRING);
455 if (!config->op_name) config->op_name = g_strdup(DEFAULT_OP_NAME);
456
457 /* check for realtime priority, it needs some special attention */
458 realtime = xfplayer_check_realtime_priority();
459
460 /* show monitor win if enabled in config */
461 xfade_check_monitor_win();
462
463 /* init contexts */
464 convert_init(&convert_context);
465 #ifdef HAVE_LIBFFTW
466 fft_init(&fft_context);
467 #endif
468
469 /* reset */
470 stopped = FALSE;
471
472 /* find current output plugin early so that volume control works
473 * even if playback has not started yet. */
474 if (!(the_op = find_output()))
475 DEBUG(("[crossfade] init: could not find any output!\n"));
476
477 /* load any dynamic linked symbols */
478 load_symbols();
479
480 /* HACK: make sure we are at the beginning of XMMS' output plugin list */
481 output_list_hack();
482
483 /* realize config -- will also setup the pre-mixing effect plugin */
484 xfade_realize_config();
485 }
486
487 static void
488 load_symbols()
489 {
490 #ifdef HAVE_DLFCN_H
491 void *handle;
492 char *error;
493 gchar **xmms_cfg;
494 gchar * (*get_gentitle_format)();
495
496 /* open ourselves (that is, the XMMS binary) */
497 handle = dlopen(NULL, RTLD_NOW);
498 if (!handle)
499 {
500 DEBUG(("[crossfade] init: dlopen(NULL) failed!\n"));
501 return;
502 }
503
504 /* check for XMMS patches */
505 DEBUG(("[crossfade] load_symbols: input_stopped_for_restart:"));
506 input_stopped_for_restart = dlsym(handle, "input_stopped_for_restart");
507 DEBUG((!(error = dlerror())? " found\n" : " missing\n"));
508
509 DEBUG(("[crossfade] load_symbols: is_quitting:"));
510 xmms_is_quitting = dlsym(handle, "is_quitting");
511 DEBUG((!(error = dlerror())? " found\n" : " missing\n"));
512
513 DEBUG(("[crossfade] load_symbols: playlist_get_fadeinfo:"));
514 playlist_get_fadeinfo = dlsym(handle, "playlist_get_fadeinfo");
515 DEBUG((!(error = dlerror())? " found\n" : " missing\n"));
516
517 /* check for some XMMS functions */
518 xmms_playlist_get_info_going = dlsym(handle, "playlist_get_info_going");
519 xmms_input_get_song_info = dlsym(handle, "input_get_song_info");
520
521 /* HACK: direct access to XMMS' config 'gentitle_format' */
522 xmms_cfg = dlsym(handle, "cfg");
523 get_gentitle_format = dlsym(handle, "xmms_get_gentitle_format");
524 if (xmms_cfg && get_gentitle_format)
525 {
526 gchar *format = get_gentitle_format();
527
528 int i = 128;
529 gchar **p = (gchar **)xmms_cfg;
530 for (i = 128; i > 0 && *p != format; i--, p++);
531 if (*p == format)
532 xmms_gentitle_format = p;
533 }
534
535 dlclose(handle);
536 #endif
537 }
538
539 /*
540 HACK: Try to move ourselves to the beginning of XMMS output plugin list,
541 so that we will be freed first when XMMS is quitting. This way, we
542 avoid the segfault when using ALSA as the output plugin.
543 */
544 static void
545 output_list_hack()
546 {
547 GList *output_list = xfplayer_get_output_list();
548 if (!output_list)
549 return;
550
551 int i0 = g_list_index(output_list, xfade_op), i1;
552
553 GList *first = g_list_first(output_list);
554 GList *xfade = g_list_find(output_list, xfade_op);
555 xfade->data = first->data;
556 first->data = xfade_op;
557
558 i1 = g_list_index(output_list, xfade_op);
559 if (i0 != i1)
560 DEBUG(("[crossfade] output_list_hack: crossfade moved from index %d to %d\n", i0, i1));
561 }
562
563 void
564 xfade_get_volume(int *l, int *r)
565 {
566 if (config->mixer_software)
567 {
568 *l = config->mixer_reverse
569 ? config->mixer_vol_right
570 : config->mixer_vol_left;
571 *r = config->mixer_reverse
572 ? config->mixer_vol_left
573 : config->mixer_vol_right;
574 }
575 else
576 {
577 if (the_op && the_op->get_volume)
578 {
579 if (config->mixer_reverse)
580 the_op->get_volume(r, l);
581 else
582 the_op->get_volume(l, r);
583 }
584 }
585
586 /* DEBUG(("[crossfade] xfade_get_volume: l=%d r=%d\n", *l, *r)); */
587 }
588
589 void
590 xfade_set_volume(int l, int r)
591 {
592 /* DEBUG(("[crossfade] xfade_set_volume: l=%d r=%d\n", l, r)); */
593
594 if (!config->enable_mixer)
595 return;
596
597 if (the_op && the_op->set_volume)
598 {
599 if (config->mixer_reverse)
600 the_op->set_volume(r, l);
601 else
602 the_op->set_volume(l, r);
603 }
604 }
605
606 /*** buffer stuff ***********************************************************/
607
608 static void
609 buffer_mfg_reset(buffer_t *buf, config_t *cfg)
610 {
611 buf->mix = 0;
612 buf->fade = 0;
613 buf->gap = (cfg->gap_lead_enable ? MS2B(cfg->gap_lead_len_ms) & -4 : 0);
614 buf->gap_len = buf->gap;
615 buf->gap_level = cfg->gap_lead_level;
616 buf->gap_killed = 0;
617 buf->skip = 0;
618 buf->skip_len = 0;
619 }
620
621 static void
622 buffer_reset(buffer_t *buf, config_t *cfg)
623 {
624 buffer_mfg_reset(buf, cfg);
625
626 buf->rd_index = 0;
627 buf->used = 0;
628 buf->preload = buf->preload_size;
629
630 buf->silence = 0;
631 buf->silence_len = 0;
632 buf->reopen = -1;
633 buf->pause = -1;
634 }
635
636 /****************************************************************************/
637
638 static void
639 xfade_apply_fade_config(fade_config_t *fc)
640 {
641 gint out_skip, in_skip;
642 gint avail, out_len, in_len, offset, preload;
643 gint index, length, fade, n;
644 gfloat out_scale, in_scale;
645 gboolean out_skip_clipped = FALSE;
646 gboolean out_len_clipped = FALSE;
647 gboolean offset_clipped = FALSE;
648
649 /* Overwrites mix and fade; may add silence */
650
651 /*
652 * Example 1: offset < 0 --> mix streams together
653 * Example 2: offset > 0 --> insert pause between streams
654 *
655 * |----- out_len -----| * |out_len|
656 * | | * | |
657 * ~~~~~-_ /T~~~~~~~T~~ * ~~~~~\ | /T~~
658 * ~-_ / | | * \ | / |
659 * ~-_/ | | * \ | / |
660 * /~-_| | * \ | / |
661 * / T-_ | * \ | / |
662 * / | ~-_ | * \ | / |
663 * _________/______|_____~-|__ * ___________\__________/______|__
664 * |in_len| | * | |in_len|
665 * |<-- offset ---| * |offset-->|
666 *
667 * a) avail: max(0, used - preload)
668 * b) out_len: 0 .. avail
669 * c) in_len: 0 .. #
670 * d) offset: -avail .. buffer->mix_size - out_size
671 * e) skip: min(used, preload)
672 *
673 */
674
675 out_scale = 1.0f - (gfloat) xfade_cfg_fadeout_volume(fc) / 100.0f;
676 in_scale = 1.0f - (gfloat) xfade_cfg_fadein_volume (fc) / 100.0f;
677
678 /* rules (see above) */
679 /* a: leave preload untouched */
680 avail = buffer->used - buffer->preload_size;
681 if (avail < 0)
682 avail = 0;
683
684 /* skip end of song */
685 out_skip = MS2B(xfade_cfg_out_skip(fc)) & -4;
686 if (out_skip > avail)
687 {
688 DEBUG(("[crossfade] apply_fade_config: WARNING: clipping out_skip (%d -> %d)!\n", B2MS(out_skip), B2MS(avail)));
689 out_skip = avail;
690 out_skip_clipped = TRUE;
691 }
692
693 if (out_skip > 0)
694 {
695 buffer->used -= out_skip;
696 avail -= out_skip;
697 }
698
699 /* b: fadeout */
700 out_len = MS2B(xfade_cfg_fadeout_len(fc)) & -4;
701 if (out_len > avail)
702 {
703 DEBUG(("[crossfade] apply_fade_config: WARNING: clipping out_len (%d -> %d)!\n", B2MS(out_len), B2MS(avail)));
704 out_len = avail;
705 out_len_clipped = TRUE;
706 }
707 else if (out_len < 0)
708 out_len = 0;
709
710 /* skip beginning of song */
711 in_skip = MS2B(xfade_cfg_in_skip(fc)) & -4;
712 if (in_skip < 0)
713 in_skip = 0;
714
715 /* c: fadein */
716 in_len = MS2B(xfade_cfg_fadein_len(fc)) & -4;
717 if (in_len < 0)
718 in_len = 0;
719
720 /* d: offset (mixing point) */
721 offset = MS2B(xfade_cfg_offset(fc)) & -4;
722 if (offset < -avail)
723 {
724 DEBUG(("[crossfade] apply_fade_config: WARNING: clipping offset (%d -> %d)!\n", B2MS(offset), -B2MS(avail)));
725 offset = -avail;
726 offset_clipped = TRUE;
727 }
728 if (offset > (buffer->mix_size - out_len))
729 offset = buffer->mix_size - out_len;
730
731 /* e */
732 preload = buffer->preload_size;
733 if (preload > buffer->used)
734 preload = buffer->used;
735
736 /* cut off rest of stream (decreases latency on manual songchange) */
737 if (fc->flush)
738 {
739 gint cutoff = avail - MAX(out_len, -offset); /* MAX() -> glib.h */
740 if (cutoff > 0)
741 {
742 DEBUG(("[crossfade] apply_fade_config: %d ms flushed\n", B2MS(cutoff)));
743 buffer->used -= cutoff;
744 avail -= cutoff;
745 }
746
747 /* make sure there is no pending silence */
748 buffer->silence = 0;
749 buffer->silence_len = 0;
750 }
751
752 /* begin modifying buffer at index */
753 index = (buffer->rd_index + buffer->used - out_len) % buffer->size;
754
755 /* fade out (modifies buffer directly) */
756 fade = 0;
757 length = out_len;
758 while (length > 0)
759 {
760 gint16 *p = buffer->data + index;
761 gint blen = buffer->size - index;
762 if (blen > length) blen = length;
763
764 for (n = blen / 4; n > 0; n--)
765 {
766 gfloat factor = 1.0f - (((gfloat) fade / out_len) * out_scale);
767 *p = (gfloat)*p * factor; p++;
768 *p = (gfloat)*p * factor; p++;
769 fade += 4;
770 }
771
772 index = (index + blen) % buffer->size;
773 length -= blen;
774 }
775
776 /* Initialize fadein. Note that the actual fading / mixing will be done
777 * on-the-fly when audio data is received by xfade_write_audio() */
778
779 /* start skipping */
780 if (in_skip > 0)
781 {
782 buffer->skip = in_skip;
783 buffer->skip_len = in_skip;
784 }
785 else
786 buffer->skip = 0;
787
788 /* start fading in */
789 if (in_len > 0)
790 {
791 buffer->fade = in_len;
792 buffer->fade_len = in_len;
793 buffer->fade_scale = in_scale;
794 }
795 else
796 buffer->fade = 0;
797
798 /* start mixing */
799 if (offset < 0)
800 {
801 length = -offset;
802 buffer->mix = length;
803 buffer->used -= length;
804 }
805 else
806 buffer->mix = 0;
807
808 /* start silence if applicable (will be applied in buffer_thread_f) */
809 if (offset > 0)
810 {
811 if ((buffer->silence > 0) || (buffer->silence_len > 0))
812 DEBUG(("[crossfade] apply_config: WARNING: silence in progress (%d/%d ms)\n",
813 B2MS(buffer->silence), B2MS(buffer->silence_len)));
814
815 buffer->silence = buffer->used;
816 buffer->silence_len = offset;
817 }
818
819 /* done */
820 if (in_skip || out_skip)
821 DEBUG(("[crossfade] apply_fade_config: out_skip=%d in_skip=%d\n", B2MS(out_skip), B2MS(in_skip)));
822 DEBUG(("[crossfade] apply_fade_config: avail=%d out=%d in=%d offset=%d preload=%d\n",
823 B2MS(avail), B2MS(out_len), B2MS(in_len), B2MS(offset), B2MS(preload)));
824 }
825
826 static gint
827 extract_track(const gchar *name)
828 {
829 #if 1
830 /* skip non-digits at beginning */
831 while (*name && !isdigit(*name))
832 name++;
833
834 return atoi(name);
835 #else
836 /* Remove all but numbers.
837 * Will not work if a filename has number in the title, like "track-03-U2.mp3"
838 * Ideally, should look into id3 track entry and fallback to filename
839 * */
840 gchar temp[8];
841 int t = 0;
842
843 memset(temp, 0, sizeof(temp));
844 while (*name != '\0' && t < sizeof(temp))
845 {
846 if (strcmp(name, "mp3") == 0)
847 break;
848
849 if (isdigit(*name))
850 temp[t++] = *name;
851
852 name++;
853 }
854 return atoi(temp);
855 #endif
856 }
857
858 static gint
859 album_match(gchar *old, gchar *new)
860 {
861 gchar *old_dir, *new_dir;
862 gboolean same_dir;
863 gint old_track = 0, new_track = 0;
864
865 if (!old || !new)
866 return 0;
867
868 old_dir = g_dirname(old);
869 new_dir = g_dirname(new);
870 same_dir = !strcmp(old_dir, new_dir);
871 g_free(old_dir);
872 g_free(new_dir);
873
874 if (!same_dir)
875 {
876 DEBUG(("[crossfade] album_match: no match (different dirs)\n"));
877 return 0;
878 }
879
880 old_track = extract_track(g_basename(old));
881 new_track = extract_track(g_basename(new));
882
883 if (new_track <= 0)
884 {
885 DEBUG(("[crossfade] album_match: can't parse track number:\n"));
886 DEBUG(("[crossfade] album_match: ... \"%s\"\n", g_basename(new)));
887 return 0;
888 }
889
890 if ((old_track < 0) || (old_track + 1 != new_track))
891 {
892 DEBUG(("[crossfade] album_match: no match (same dir, but non-successive (%d, %d))\n", old_track, new_track));
893 return 0;
894 }
895
896 DEBUG(("[crossfade] album_match: match detected (same dir, successive tracks (%d, %d))\n", old_track, new_track));
897
898 return old_track;
899 }
900
901 static gint
902 xfade_open_audio(AFormat fmt, int rate, int nch)
903 {
904 gint pos;
905 gchar *file, *title, *comment;
906 #if defined(HAVE_ID3LIB)
907 id3_t id3;
908 #endif
909
910 struct timeval tv;
911 glong dt;
912
913 DEBUG(("[crossfade]\n"));
914 DEBUG(("[crossfade] open_audio: pid=%d\n", (int) getpid()));
915
916 /* sanity... don't do anything about it */
917 if (opened)
918 DEBUG(("[crossfade] open_audio: WARNING: already opened!\n"));
919
920 /* get filename */
921 pos = xfplaylist_get_position ();
922 file = xfplaylist_get_filename (pos);
923 title = xfplaylist_get_songtitle(pos);
924 comment = playlist_get_fadeinfo ? playlist_get_fadeinfo(pos) : NULL;
925
926 if (!file)
927 file = g_strdup(title);
928
929 DEBUG(("[crossfade] open_audio: bname=\"%s\"\n", g_basename(file)));
930 DEBUG(("[crossfade] open_audio: title=\"%s\"\n", title));
931
932 #if 0
933 /* HACK: try to get comment and track number from xmms by sneaking in a custom title format */
934 if (xmms_gentitle_format)
935 {
936 gchar *old_gentitle_format = *xmms_gentitle_format;
937
938 gchar *temp_title = NULL;
939 gint temp_length = 0;
940
941 xmms_input_get_song_info(file, &temp_title, &temp_length);
942 DEBUG(("[crossfade] open_audio: TITLE: %s\n", temp_title));
943 g_free(temp_title);
944
945 *xmms_gentitle_format = "%n/%c";
946
947 xmms_input_get_song_info(file, &temp_title, &temp_length);
948 DEBUG(("[crossfade] open_audio: TRACK/COMMENT: %s\n", temp_title));
949 g_free(temp_title);
950
951 *xmms_gentitle_format = old_gentitle_format;
952 }
953 #endif
954
955 /* try to read comment from ID3 tag */
956 #if defined(HAVE_ID3LIB)
957 if (!comment && get_id3(file, &id3))
958 comment = g_strdup(id3.comment);
959 #endif
960
961 if (comment)
962 DEBUG(("[crossfade] open_audio: comment=\"%s\"\n", comment))
963 else
964 DEBUG(("[crossfade] open_audio: comment=NULL\n"));
965
966 /* is this an automatic crossfade? */
967 if (last_filename && (fade_config == &config->fc[FADE_CONFIG_XFADE]))
968 {
969 /* check if next song is the same as the current one */
970 if (config->no_xfade_if_same_file && !strcmp(last_filename, file))
971 {
972 DEBUG(("[crossfade] open_audio: same file, disabling crossfade\n"));
973 fade_config = &config->fc[FADE_CONFIG_ALBUM];
974 }
975
976 /* check if next song is the next song from the same album */
977 else if (config->album_detection && album_match(last_filename, file))
978 {
979 gboolean use_fc_album = FALSE;
980
981 if (xfade_cfg_gap_trail_enable(config))
982 {
983 DEBUG(("[crossfade] album_match: "
984 "trailing gap: length=%d/%d ms\n", B2MS(buffer->gap_killed), B2MS(buffer->gap_len)));
985
986 if (buffer->gap_killed < buffer->gap_len)
987 {
988 DEBUG(("[crossfade] album_match: "
989 "trailing gap: -> no silence, probably pre-faded\n"));
990 use_fc_album = TRUE;
991 }
992 else
993 {
994 DEBUG(("[crossfade] album_match: " "trailing gap: -> silence, sticking to XFADE\n"));
995 }
996 }
997 else
998 {
999 DEBUG(("[crossfade] album_match: " "trailing gap killer disabled\n"));
1000 use_fc_album = TRUE;
1001 }
1002
1003 if (use_fc_album)
1004 {
1005 DEBUG(("[crossfade] album_match: " "-> using FADE_CONFIG_ALBUM\n"));
1006 fade_config = &config->fc[FADE_CONFIG_ALBUM];
1007 }
1008 }
1009 }
1010 g_free(last_filename);
1011 last_filename = g_strdup(file);
1012
1013 #if 0
1014 /* FIXME: finish this */
1015 /* Check if this is a short song. */
1016 if (fade_config == &config->fc[FADE_CONFIG_XFADE])
1017 {
1018 DEBUG(("*** XFADE:\n"));
1019 int current_length = playlist_get_current_length();
1020 DEBUG(("*** length=%d\n", current_length));
1021 if (current_length < 30 * 1000)
1022 fade_config = &config->fc[FADE_CONFIG_ALBUM];
1023 }
1024 #endif
1025
1026 #ifdef TIMING_COMMENTS
1027 last_timing = current_timing;
1028 current_timing. in.enable = FALSE;
1029 current_timing.out.enable = FALSE;
1030 if (comment)
1031 {
1032 gchar *str;
1033 if ((str = strstr(comment, "fadein=")))
1034 {
1035 current_timing.in.enable =
1036 (3 == sscanf(str + 7, "%d,%d,%d",
1037 &current_timing.in.len_ms,
1038 &current_timing.in.volume,
1039 &current_timing.in.skip_ms));
1040 current_timing.in.ofs_ms = 0; /* not used */
1041 }
1042
1043 if ((str = strstr(comment, "fadeout=")))
1044 {
1045 current_timing.out.enable =
1046 (4 == sscanf(str + 8, "%d,%d,%d,%d",
1047 &current_timing.out.len_ms,
1048 &current_timing.out.volume,
1049 &current_timing.out.skip_ms,
1050 &current_timing.out.ofs_ms));
1051 }
1052 }
1053
1054 #if 0
1055 //
1056 // use the fade info only on a regular, non-manual songchange
1057 //
1058 if (fade_config && !((fade_config->config == FADE_CONFIG_XFADE) ||
1059 (fade_config->config == FADE_CONFIG_ALBUM)))
1060 last_timing.out.enable = FALSE;
1061 #endif
1062
1063 #if 1
1064 if (last_timing.out.enable || current_timing.in.enable)
1065 #else
1066 if ((last_timing.out.enable || current_timing.in.enable) &&
1067 (!fade_config ||
1068 (fade_config->config == FADE_CONFIG_XFADE) ||
1069 (fade_config->config == FADE_CONFIG_ALBUM)))
1070 #endif
1071 {
1072 config->fc[FADE_CONFIG_TIMING].out_len_ms = xfade_cfg_fadeout_len (fade_config);
1073 config->fc[FADE_CONFIG_TIMING].out_volume = xfade_cfg_fadeout_volume(fade_config);
1074 config->fc[FADE_CONFIG_TIMING].out_skip_ms = 0;
1075 config->fc[FADE_CONFIG_TIMING].ofs_custom_ms = xfade_cfg_offset (fade_config);
1076 config->fc[FADE_CONFIG_TIMING].in_skip_ms = 0;
1077 config->fc[FADE_CONFIG_TIMING].in_len_ms = xfade_cfg_fadein_len (fade_config);
1078 config->fc[FADE_CONFIG_TIMING].in_volume = xfade_cfg_fadein_volume (fade_config);
1079 config->fc[FADE_CONFIG_TIMING].flush = fade_config && fade_config->flush;
1080
1081 if (last_timing.out.enable && current_timing.in.enable)
1082 config->fc[FADE_CONFIG_TIMING].ofs_custom_ms = 0;
1083
1084 if (last_timing.out.enable)
1085 {
1086 DEBUG(("[crossfade] open_audio: TIMING: out: enable=%d len=%d volume=%d skip=%d ofs=%d\n",
1087 last_timing.out.enable,
1088 last_timing.out.len_ms,
1089 last_timing.out.volume,
1090 last_timing.out.skip_ms,
1091 last_timing.out.ofs_ms));
1092
1093 config->fc[FADE_CONFIG_TIMING].out_len_ms = last_timing.out.len_ms;
1094 config->fc[FADE_CONFIG_TIMING].out_volume = last_timing.out.volume;
1095 config->fc[FADE_CONFIG_TIMING].out_skip_ms = last_timing.out.skip_ms;
1096 config->fc[FADE_CONFIG_TIMING].ofs_custom_ms += last_timing.out.ofs_ms;
1097 }
1098 if (current_timing.in.enable)
1099 {
1100 DEBUG(("[crossfade] open_audio: TIMING: in: enable=%d len=%d volume=%d skip=%d\n",
1101 current_timing.in.enable,
1102 current_timing.in.len_ms,
1103 current_timing.in.volume,
1104 current_timing.in.skip_ms));
1105
1106 config->fc[FADE_CONFIG_TIMING].in_skip_ms = current_timing.in.skip_ms;
1107 config->fc[FADE_CONFIG_TIMING].in_len_ms = current_timing.in.len_ms;
1108 config->fc[FADE_CONFIG_TIMING].in_volume = current_timing.in.volume;
1109 config->fc[FADE_CONFIG_TIMING].ofs_custom_ms -= current_timing.in.ofs_ms;
1110 /* NOTE: in.ofs_ms is currently not used always 0 */
1111 }
1112
1113 fade_config = &config->fc[FADE_CONFIG_TIMING];
1114 }
1115 #endif
1116
1117 /* cleanup */
1118 g_free(file); file = NULL;
1119 g_free(title); title = NULL;
1120 g_free(comment); comment = NULL;
1121
1122 /* check for HTTP streaming */
1123 if (config->enable_http_workaround && (0 == strncasecmp(file, "http://", 7)))
1124 {
1125 DEBUG(("[crossfade] open_audio: HTTP underrun workaround enabled.\n"));
1126 is_http = TRUE;
1127 }
1128 else
1129 is_http = FALSE;
1130
1131 /* lock buffer */
1132 MUTEX_LOCK(&buffer_mutex);
1133
1134 /* reset writer timeout */
1135 gettimeofday(&last_write, NULL);
1136
1137 /* calculate time since last close() (don't care about overflows at 24h) */
1138 if (output_opened)
1139 {
1140 gettimeofday(&tv, NULL);
1141 dt = (tv.tv_sec - last_close.tv_sec) * 1000 + (tv.tv_usec - last_close.tv_usec) / 1000;
1142 }
1143 else
1144 dt = 0;
1145
1146 DEBUG(("[crossfade] open_audio: fmt=%s rate=%d nch=%d dt=%ld ms\n", format_name(fmt), rate, nch, dt));
1147
1148 /* check format */
1149 if (setup_format(fmt, rate, nch, &in_format) < 0)
1150 {
1151 DEBUG(("[crossfade] open_audio: format not supported!\n"));
1152 return 0;
1153 }
1154
1155 /* (re)open the device if necessary */
1156 if (!output_opened)
1157 {
1158 if (open_output())
1159 {
1160 DEBUG(("[crossfade] open_audio: error opening/configuring output!\n"));
1161 MUTEX_UNLOCK(&buffer_mutex);
1162 return 0;
1163 }
1164 fade_config = &config->fc[FADE_CONFIG_START];
1165 }
1166
1167 /* reset */
1168 streampos = 0;
1169 playing = TRUE;
1170 opened = TRUE;
1171 paused = FALSE;
1172
1173 /* reset mix/fade/gap */
1174 buffer_mfg_reset(buffer, config);
1175
1176 /* enable gap killer / zero crossing only for automatic/album songchange */
1177 switch (fade_config->config)
1178 {
1179 case FADE_CONFIG_XFADE:
1180 case FADE_CONFIG_ALBUM:
1181 break;
1182
1183 default:
1184 buffer->gap = GAP_SKIPPING_DONE;
1185 }
1186
1187 /* restart realtime throttling */
1188 output_written = 0;
1189
1190 /* start mixing */
1191 switch (fade_config ? fade_config->type : -1)
1192 {
1193 case FADE_TYPE_FLUSH:
1194 DEBUG(("[crossfade] open_audio: FLUSH:\n"));
1195
1196 /* flush output plugin */
1197 the_op->flush(0);
1198 output_streampos = 0;
1199
1200 /* flush buffer */
1201 buffer_reset(buffer, config);
1202
1203 /* apply fade config (pause/fadein after flush) */
1204 xfade_apply_fade_config(fade_config);
1205
1206 /* also repopen device (if configured so in the plugin compat. options) */
1207 if (the_op_config.force_reopen)
1208 {
1209 buffer->reopen = 0;
1210 buffer->reopen_sync = FALSE;
1211 }
1212 break;
1213
1214 case FADE_TYPE_REOPEN:
1215 DEBUG(("[crossfade] open_audio: REOPEN:\n"));
1216
1217 /* flush buffer if applicable */
1218 if (fade_config->flush)
1219 buffer_reset(buffer, config);
1220
1221 if (buffer->reopen >= 0)
1222 DEBUG(("[crossfade] open_audio: REOPEN: WARNING: reopen in progress (%d ms)\n",
1223 B2MS(buffer->reopen)));
1224
1225 /* start reopen countdown (will be executed in buffer_thread_f) */
1226 buffer->reopen = buffer->used; /* may be 0 */
1227 buffer->reopen_sync = FALSE;
1228 break;
1229
1230 case FADE_TYPE_NONE:
1231 case FADE_TYPE_PAUSE:
1232 case FADE_TYPE_SIMPLE_XF:
1233 case FADE_TYPE_ADVANCED_XF:
1234 case FADE_TYPE_FADEIN:
1235 case FADE_TYPE_FADEOUT:
1236 DEBUG(("[crossfade] open_audio: XFADE:\n"));
1237
1238 /* apply fade config (do fadeout, init mix/fade/gap, add silence) */
1239 xfade_apply_fade_config(fade_config);
1240
1241 /* set reopen countdown. after buffer_thread_f has written
1242 * buffer->reopen bytes, it will close/reopen the output plugin. */
1243 if (the_op_config.force_reopen && !(fade_config->config == FADE_CONFIG_START))
1244 {
1245 if (buffer->reopen >= 0)
1246 DEBUG(("[crossfade] open_audio: XFADE: WARNING: reopen in progress (%d ms)\n",
1247 B2MS(buffer->reopen)));
1248 buffer->reopen = buffer->used;
1249 buffer->reopen_sync = TRUE;
1250 }
1251 break;
1252 }
1253
1254 /* calculate offset of the output plugin */
1255 output_offset = the_op->written_time() + B2MS(buffer->used) + B2MS(buffer->silence_len);
1256
1257 /* unlock buffer */
1258 MUTEX_UNLOCK(&buffer_mutex);
1259
1260 /* done */
1261 return 1;
1262 }
1263
1264 void
1265 xfade_write_audio(void *ptr, int length)
1266 {
1267 gint free;
1268 gint ofs = 0;
1269 format_t format;
1270
1271 #ifdef DEBUG_HARDCORE
1272 DEBUG(("[crossfade] write_audio: ptr=0x%08lx, length=%d\n", (long) ptr, length));
1273 #endif
1274
1275 /* sanity */
1276 if (length <= 0)
1277 return;
1278
1279 if (length & 3)
1280 {
1281 DEBUG(("[crossfade] write_audio: truncating %d bytes!\n", length & 3));
1282 length &= -4;
1283 }
1284
1285 /* update input accumulator (using input format size) */
1286 streampos += length;
1287
1288 /* convert sample format (signed-16bit-ne 44100hz stereo) */
1289 format_copy(&format, &in_format);
1290 length = convert_flow(&convert_context, (gpointer *) &ptr, length, &format);
1291
1292 /* lock buffer */
1293 MUTEX_LOCK(&buffer_mutex);
1294
1295 /* check if device has been closed, reopen if necessary */
1296 if (!output_opened)
1297 {
1298 if (open_output())
1299 {
1300 DEBUG(("[crossfade] write_audio: reopening failed!\n"));
1301 MUTEX_UNLOCK(&buffer_mutex);
1302 return;
1303 }
1304 }
1305
1306 /* reset timeout */
1307 gettimeofday(&last_write, NULL);
1308
1309 /* calculate free buffer space, check for overflow (should never happen :) */
1310 free = buffer->size - buffer->used;
1311 if (length > free)
1312 {
1313 DEBUG(("[crossfade] write_audio: %d bytes truncated!\n", length - free));
1314 length = free;
1315 }
1316
1317 /* skip beginning of song */
1318 if ((length > 0) && (buffer->skip > 0))
1319 {
1320 gint blen = MIN(length, buffer->skip);
1321
1322 buffer->skip -= blen;
1323 length -= blen;
1324 ptr += blen;
1325 }
1326
1327 /* kill leading gap */
1328 if ((length > 0) && (buffer->gap > 0))
1329 {
1330 gint blen = MIN(length, buffer->gap);
1331 gint16 *p = ptr;
1332 gint index = 0;
1333
1334 gint16 left, right;
1335 while (index < blen)
1336 {
1337 left = *p++, right = *p++;
1338 if (ABS(left) >= buffer->gap_level) break;
1339 if (ABS(right) >= buffer->gap_level) break;
1340 index += 4;
1341 }
1342
1343 buffer->gap -= index;
1344 length -= index;
1345 ptr += index;
1346
1347 if ((index < blen) || (buffer->gap <= 0))
1348 {
1349 buffer->gap_killed = buffer->gap_len - buffer->gap;
1350 buffer->gap = 0;
1351
1352 DEBUG(("[crossfade] write_audio: leading gap size: %d/%d ms\n",
1353 B2MS(buffer->gap_killed), B2MS(buffer->gap_len)));
1354
1355 /* fix streampos */
1356 streampos -= (gint64) buffer->gap_killed * in_format.bps / out_format.bps;
1357 }
1358 }
1359
1360 /* start skipping to next crossing (if enabled) */
1361 if (buffer->gap == 0)
1362 {
1363 if (config->gap_crossing)
1364 {
1365 buffer->gap = GAP_SKIPPING_POSITIVE;
1366 buffer->gap_skipped = 0;
1367 }
1368 else
1369 buffer->gap = GAP_SKIPPING_DONE;
1370 }
1371
1372 /* skip until next zero crossing (pos -> neg) */
1373 if ((length > 0) && (buffer->gap == GAP_SKIPPING_POSITIVE))
1374 {
1375 gint16 *p = ptr;
1376 gint index = 0;
1377
1378 gint16 left;
1379 while (index < length)
1380 {
1381 left = *p++;
1382 p++;
1383 if (left < 0)
1384 break;
1385 index += 4;
1386 }
1387
1388 buffer->gap_skipped += index;
1389 length -= index;
1390 ptr += index;
1391
1392 if (index < length)
1393 buffer->gap = GAP_SKIPPING_NEGATIVE;
1394 }
1395
1396 /* skip until next zero crossing (neg -> pos) */
1397 if ((length > 0) && (buffer->gap == GAP_SKIPPING_NEGATIVE))
1398 {
1399 gint16 *p = ptr;
1400 gint index = 0;
1401
1402 gint16 left;
1403 while (index < length)
1404 {
1405 left = *p++;
1406 p++;
1407 if (left >= 0)
1408 break;
1409 index += 4;
1410 }
1411
1412 buffer->gap_skipped += index;
1413 length -= index;
1414 ptr += index;
1415
1416 if (index < length)
1417 {
1418 DEBUG(("[crossfade] write_audio: %d samples to next crossing\n", buffer->gap_skipped));
1419 buffer->gap = GAP_SKIPPING_DONE;
1420 }
1421 }
1422
1423 /* update preload. the buffer thread will not write any
1424 * data to the device before preload is decreased below 1. */
1425 if ((length > 0) && (buffer->preload > 0))
1426 buffer->preload -= length;
1427
1428 /* fadein -- FIXME: is modifying the input/effect buffer safe? */
1429 if ((length > 0) && (buffer->fade > 0))
1430 {
1431 gint16 *p = ptr;
1432 gint blen = MIN(length, buffer->fade);
1433 gint n;
1434
1435 for (n = blen / 4; n > 0; n--)
1436 {
1437 gfloat factor = 1.0f - (((gfloat) buffer->fade / buffer->fade_len) * buffer->fade_scale);
1438 *p = (gfloat)*p * factor; p++;
1439 *p = (gfloat)*p * factor; p++;
1440 buffer->fade -= 4;
1441 }
1442 }
1443
1444 /* mix */
1445 while ((length > 0) && (buffer->mix > 0))
1446 {
1447 gint wr_index = (buffer->rd_index + buffer->used) % buffer->size;
1448 gint blen = buffer->size - wr_index;
1449 gint16 *p1 = buffer->data + wr_index;
1450 gint16 *p2 = ptr + ofs;
1451 gint n;
1452
1453 if (blen > length) blen = length;
1454 if (blen > buffer->mix) blen = buffer->mix;
1455
1456 for (n = blen / 2; n > 0; n--)
1457 {
1458 gint out = (gint)*p1 + *p2++; /* add */
1459 if (out > 32767) /* clamp */
1460 *p1++ = 32767;
1461 else if (out < -32768)
1462 *p1++ = -32768;
1463 else
1464 *p1++ = out;
1465 }
1466
1467 buffer->used += blen;
1468 buffer->mix -= blen;
1469 length -= blen;
1470 ofs += blen;
1471 }
1472
1473 /* normal write */
1474 while (length > 0)
1475 {
1476 gint wr_index = (buffer->rd_index + buffer->used) % buffer->size;
1477 gint blen = buffer->size - wr_index;
1478
1479 if (blen > length)
1480 blen = length;
1481
1482 memcpy(buffer->data + wr_index, ptr + ofs, blen);
1483
1484 buffer->used += blen;
1485 length -= blen;
1486 ofs += blen;
1487 }
1488
1489 /* unlock buffer */
1490 MUTEX_UNLOCK(&buffer_mutex);
1491 #ifdef DEBUG_HARDCORE
1492 DEBUG(("[crossfade] write_audio: done.\n"));
1493 #endif
1494 }
1495
1496 /* sync_output: wait for output plugin to finish playback */
1497 /* is only called from within buffer_thread_f */
1498 static void
1499 sync_output()
1500 {
1501 glong dt, total;
1502 gint opt, opt_last;
1503 struct timeval tv, tv_start, tv_last_change;
1504 gboolean was_closed = !opened;
1505
1506 if (!the_op->buffer_playing || !the_op->buffer_playing())
1507 {
1508 DEBUG(("[crossfade] sync_output: nothing to do\n"));
1509 return;
1510 }
1511
1512 DEBUG(("[crossfade] sync_output: waiting for plugin...\n"));
1513
1514 dt = 0;
1515 opt_last = 0;
1516 gettimeofday(&tv_start, NULL);
1517 gettimeofday(&tv_last_change, NULL);
1518
1519 while ((dt < SYNC_OUTPUT_TIMEOUT)
1520 && !stopped && output_opened && !(was_closed && opened) && the_op && the_op->buffer_playing())
1521 {
1522
1523 /* use output_time() to check if the output plugin is still active */
1524 if (the_op->output_time)
1525 {
1526 opt = the_op->output_time();
1527 if (opt != opt_last)
1528 {
1529 /* output_time has changed */
1530 opt_last = opt;
1531 gettimeofday(&tv_last_change, NULL);
1532 }
1533 else
1534 {
1535 /* calculate time since last change of the_op->output_time() */
1536 gettimeofday(&tv, NULL);
1537 dt = (tv.tv_sec - tv_last_change.tv_sec) * 1000 + (tv.tv_usec - tv_last_change.tv_usec) / 1000;
1538 }
1539 }
1540
1541 /* yield */
1542 MUTEX_UNLOCK(&buffer_mutex);
1543 xfade_usleep(10000);
1544 MUTEX_LOCK(&buffer_mutex);
1545 }
1546
1547 /* calculate total time we spent in here */
1548 gettimeofday(&tv, NULL);
1549 total = (tv.tv_sec - tv_start.tv_sec) * 1000 + (tv.tv_usec - tv_start.tv_usec) / 1000;
1550
1551 /* print some debug info */
1552 /* *INDENT-OFF* */
1553 if (stopped)
1554 DEBUG(("[crossfade] sync_output: ... stopped\n"))
1555 else if (was_closed && opened)
1556 DEBUG(("[crossfade] sync_output: ... reopened\n"))
1557 else if (dt >= SYNC_OUTPUT_TIMEOUT)
1558 DEBUG(("[crossfade] sync_output: ... TIMEOUT! (%ld ms)\n", total))
1559 else
1560 DEBUG(("[crossfade] sync_output: ... done (%ld ms)\n", total));
1561 /* *INDENT-ON* */
1562 }
1563
1564 void *
1565 buffer_thread_f(void *arg)
1566 {
1567 gpointer data;
1568 gint sync;
1569 gint op_free;
1570 gint length_bak, length, blen;
1571 glong timeout, dt;
1572 gboolean stopping;
1573
1574 struct timeval tv;
1575 struct timeval mark;
1576
1577 DEBUG(("[crossfade] buffer_thread_f: thread started (pid=%d)\n", (int) getpid()));
1578
1579 /* lock buffer */
1580 MUTEX_LOCK(&buffer_mutex);
1581
1582 while (!stopped)
1583 {
1584 /* yield */
1585 #ifdef DEBUG_HARDCORE
1586 DEBUG(("[crossfade] buffer_thread_f: yielding...\n"));
1587 #endif
1588 MUTEX_UNLOCK(&buffer_mutex);
1589 xfade_usleep(10000);
1590 MUTEX_LOCK(&buffer_mutex);
1591
1592 /* --------------------------------------------------------------------- */
1593
1594 stopping = FALSE;
1595
1596 /* V0.3.0: New timeout detection */
1597 if (!opened)
1598 {
1599 gboolean current = xfplayer_input_playing();
1600
1601 /* also see fini() */
1602 if (last_close.tv_sec || last_close.tv_usec)
1603 {
1604 gettimeofday(&tv, NULL);
1605 timeout = (tv.tv_sec - last_close.tv_sec) * 1000
1606 + (tv.tv_usec - last_close.tv_usec) / 1000;
1607 }
1608 else
1609 timeout = -1;
1610
1611 if (current != input_playing)
1612 {
1613 input_playing = current;
1614
1615 if (current)
1616 DEBUG(("[crossfade] buffer_thread_f: input restarted after %ld ms\n", timeout))
1617 else
1618 DEBUG(("[crossfade] buffer_thread_f: input stopped after + %ld ms\n", timeout));
1619 }
1620
1621 /* 0.3.0: HACK: output_keep_opened: play silence during prebuffering */
1622 if (input_playing && config->output_keep_opened && (buffer->used == 0))
1623 {
1624 buffer->silence = 0;
1625 buffer->silence_len = MS2B(100);
1626 }
1627
1628 /* 0.3.9: Check for timeout only if we have not been stopped for restart */
1629 /* 0.3.11: When using the songchange hack, depend on it's output_restart
1630 * flag. Without the hack, use the configuration's dialog songchange
1631 * timeout setting instead of a fixed timeout value. */
1632 if (input_stopped_for_restart && !output_restart)
1633 {
1634 if (playing)
1635 DEBUG(("[crossfade] buffer_thread_f: timeout:"
1636 " stopping after %ld ms (songchange patch)\n", timeout));
1637 stopping = TRUE;
1638 }
1639 else if (((timeout < 0) || (timeout >= config->songchange_timeout && !output_restart)) && !input_playing)
1640 {
1641 if (playing)
1642 DEBUG(("[crossfade] buffer_thread_f: timeout:"
1643 " input did not restart after %ld ms\n", timeout));
1644 stopping = TRUE;
1645 }
1646 }
1647
1648 /* V0.2.4: Moved the timeout checks in front of the buffer_free() check
1649 * below. Before, buffer_thread_f could (theoretically) loop
1650 * endlessly if buffer_free() returned 0 all the time. */
1651
1652 /* calculate time since last write to the buffer (ignore overflows) */
1653 gettimeofday(&tv, NULL);
1654 timeout = (tv.tv_sec - last_write.tv_sec) * 1000
1655 + (tv.tv_usec - last_write.tv_usec) / 1000;
1656
1657 /* check for timeout/eop (note this is the only way out of this loop) */
1658 if (stopping)
1659 {
1660 if (playing)
1661 {
1662 DEBUG(("[crossfade] buffer_thread_f: timeout: manual stop\n"));
1663
1664 /* if CONFIG_STOP is of TYPE_NONE, immediatelly close the device... */
1665 if ((config->fc[FADE_CONFIG_STOP].type == FADE_TYPE_NONE) && !config->output_keep_opened)
1666 break;
1667
1668 /* special handling for pause */
1669 if (paused)
1670 {
1671 DEBUG(("[crossfade] buffer_thread_f: timeout: paused, closing now...\n"));
1672 paused = FALSE;
1673 if (config->output_keep_opened)
1674 the_op->pause(0);
1675 else
1676 break;
1677 }
1678 else if (buffer->pause >= 0)
1679 {
1680 DEBUG(("[crossfade] buffer_thread_f: timeout: cancelling pause countdown\n"));
1681 buffer->pause = -1;
1682 }
1683
1684 /* ...otherwise, do the fadeout first */
1685 xfade_apply_fade_config(&config->fc[FADE_CONFIG_STOP]);
1686
1687 /* force CONFIG_START in case the user restarts playback during fadeout */
1688 fade_config = &config->fc[FADE_CONFIG_START];
1689 playing = FALSE;
1690 eop = TRUE;
1691 }
1692 else
1693 {
1694 if (!eop)
1695 {
1696 DEBUG(("[crossfade] buffer_thread_f: timeout: end of playback\n"));
1697
1698 /* 0.3.3: undo trailing gap killer at end of playlist */
1699 if (buffer->gap_killed)
1700 {
1701 buffer->used += buffer->gap_killed;
1702 DEBUG(("[crossfade] buffer_thread_f: timeout:"
1703 " undoing trailing gap (%d ms)\n", B2MS(buffer->gap_killed)));
1704 }
1705
1706 /* do the fadeout if applicable */
1707 if (config->fc[FADE_CONFIG_EOP].type != FADE_TYPE_NONE)
1708 xfade_apply_fade_config(&config->fc[FADE_CONFIG_EOP]);
1709
1710 fade_config = &config->fc[FADE_CONFIG_START]; /* see above */
1711 eop = TRUE;
1712 }
1713
1714 if (buffer->used == 0)
1715 {
1716 if (config->output_keep_opened)
1717 {
1718 /* 0.3.0: play silence while keeping the output opened */
1719 buffer->silence = 0;
1720 buffer->silence_len = MS2B(100);
1721 }
1722 else if (buffer->silence_len <= 0)
1723 {
1724 sync_output();
1725 if (opened)
1726 {
1727 DEBUG(("[crossfade] buffer_thread_f: timeout, eop: device has been reopened\n"));
1728 DEBUG(("[crossfade] buffer_thread_f: timeout, eop: -> continuing playback\n"));
1729 eop = FALSE;
1730 }
1731 else
1732 {
1733 DEBUG(("[crossfade] buffer_thread_f: timeout, eop: closing output...\n"));
1734 break;
1735 }
1736 }
1737 }
1738 }
1739 }
1740 else
1741 eop = FALSE;
1742
1743 /* --------------------------------------------------------------------- */
1744
1745 /* get free space in device output buffer
1746 * NOTE: disk_writer always returns <big int> here */
1747 op_free = the_op->buffer_free() & -4;
1748
1749 /* continue waiting if there is no room in the device buffer */
1750 if (op_free == 0)
1751 continue;
1752
1753 /* --- Limit OP buffer use (decreases latency) ------------------------- */
1754
1755 /* HACK: limit output plugin buffer usage to decrease latency */
1756 if (config->enable_op_max_used)
1757 {
1758 gint output_time = the_op->output_time();
1759 gint output_used = the_op->written_time() - output_time;
1760 gint output_limit = MS2B(config->op_max_used_ms - MIN(output_used, config->op_max_used_ms));
1761
1762 if (output_flush_time != output_time)
1763 {
1764 /* slow down output, but always write _some_ data */
1765 if (output_limit < in_format.bps / 100 / 2)
1766 output_limit = in_format.bps / 100 / 2;
1767
1768 if (op_free > output_limit)
1769 op_free = output_limit;
1770 }
1771 }
1772
1773 /* --- write silence --------------------------------------------------- */
1774
1775 if (!paused && (buffer->silence <= 0) && (buffer->silence_len >= 4))
1776 {
1777 /* write as much silence as a) there is left and b) the device can take */
1778 length = buffer->silence_len;
1779 if (length > op_free)
1780 length = op_free;
1781
1782 /* make sure we always operate on stereo sample boundary */
1783 length &= -4;
1784
1785 /* HACK: don't stay in here too long when in realtime mode (see below) */
1786 if (realtime)
1787 gettimeofday(&mark, NULL);
1788
1789 /* write length bytes to the device */
1790 length_bak = length;
1791 while (length > 0)
1792 {
1793 data = zero_4k;
1794 blen = sizeof(zero_4k);
1795 if (blen > length)
1796 blen = length;
1797
1798 /* make sure zero_4k is cleared. The effect plugin within
1799 * the output plugin may have modified this buffer! (0.2.8) */
1800 memset(zero_4k, 0, blen);
1801
1802 /* HACK: the original OSS plugin hangs when writing large
1803 * blocks (greater than device buffer size) in realtime mode */
1804 if (the_op_config.max_write_enable && (blen > the_op_config.max_write_len))
1805 blen = the_op_config.max_write_len;
1806
1807 /* finally, write data */
1808 the_op->write_audio(data, blen);
1809 length -= blen;
1810
1811 /* HACK: don't stay in here too long (force yielding every 10 ms) */
1812 if (realtime)
1813 {
1814 gettimeofday(&tv, NULL);
1815 dt = (tv.tv_sec - mark.tv_sec) * 1000
1816 + (tv.tv_usec - mark.tv_usec) / 1000;
1817 if (dt >= 10)
1818 break;
1819 }
1820 }
1821
1822 /* calculate how many bytes actually have been written */
1823 length = length_bak - length;
1824 }
1825
1826 /* --- write data ------------------------------------------------- */
1827
1828 else if (!paused && (buffer->preload <= 0) && (buffer->used >= 4))
1829 {
1830 /* write as much data as a) is available and b) the device can take */
1831 length = buffer->used;
1832 if (length > op_free)
1833 length = op_free;
1834
1835 /* HACK: throttle output (used with fast output plugins) */
1836 if (the_op_config.throttle_enable && !realtime && opened)
1837 {
1838 sync = buffer->sync_size - (buffer->size - buffer->used);
1839 if (sync < 0) length = 0;
1840 else if (sync < length) length = sync;
1841 }
1842
1843 /* clip length to silence countdown (if applicable) */
1844 if ((buffer->silence >= 4) && (length > buffer->silence))
1845 length = buffer->silence;
1846
1847 /* clip length to reopen countdown (if applicable) */
1848 if ((buffer->reopen >= 0) && (length > buffer->reopen))
1849 length = buffer->reopen;
1850
1851 /* clip length to pause countdown (if applicable) */
1852 if ((buffer->pause >= 0) && (length > buffer->pause))
1853 length = buffer->pause;
1854
1855 /* make sure we always operate on stereo sample boundary */
1856 length &= -4;
1857
1858 /* HACK: don't stay in here too long when in realtime mode (see below) */
1859 if (realtime)
1860 gettimeofday(&mark, NULL);
1861
1862 /* write length bytes to the device */
1863 length_bak = length;
1864 while (length > 0)
1865 {
1866 data = buffer->data + buffer->rd_index;
1867 blen = buffer->size - buffer->rd_index;
1868 if (blen > length)
1869 blen = length;
1870
1871 /* HACK: the original OSS plugin hangs when writing large
1872 * blocks (greater than device buffer size) in realtime mode */
1873 if (the_op_config.max_write_enable && (blen > the_op_config.max_write_len))
1874 blen = the_op_config.max_write_len;
1875
1876 #ifdef HAVE_LIBFFTW
1877 /* fft playground */
1878 fft_flow(&fft_context, (gpointer) data, blen);
1879 #endif
1880 /* finally, write data */
1881 the_op->write_audio(data, blen);
1882
1883 buffer->rd_index = (buffer->rd_index + blen) % buffer->size;
1884 buffer->used -= blen;
1885 length -= blen;
1886
1887 /* HACK: don't stay in here too long (force yielding every 10 ms) */
1888 if (realtime)
1889 {
1890 gettimeofday(&tv, NULL);
1891 dt = (tv.tv_sec - mark.tv_sec) * 1000 + (tv.tv_usec - mark.tv_usec) / 1000;
1892 if (dt >= 10)
1893 break;
1894 }
1895 }
1896
1897 /* calculate how many bytes actually have been written */
1898 length = length_bak - length;
1899 }
1900 else
1901 length = 0;
1902
1903 /* update realtime throttling */
1904 output_written += length;
1905 output_streampos += length;
1906
1907 /* --- check countdowns ------------------------------------------------ */
1908
1909 if (buffer->silence > 0)
1910 {
1911 buffer->silence -= length;
1912 if (buffer->silence < 0)
1913 DEBUG(("[crossfade] buffer_thread_f: WARNING: silence overrun: %d\n", buffer->silence));
1914 }
1915 else if (buffer->silence_len > 0)
1916 {
1917 buffer->silence_len -= length;
1918 if (buffer->silence_len <= 0)
1919 {
1920 if (buffer->silence_len < 0)
1921 DEBUG(("[crossfade] buffer_thread_f: WARNING: silence_len overrun: %d\n",
1922 buffer->silence_len));
1923 }
1924 }
1925
1926 if ((buffer->reopen >= 0) && !((buffer->silence <= 0) && (buffer->silence_len > 0)))
1927 {
1928 buffer->reopen -= length;
1929 if (buffer->reopen <= 0)
1930 {
1931 if (buffer->reopen < 0)
1932 DEBUG(("[crossfade] buffer_thread_f: WARNING: reopen overrun: %d\n", buffer->reopen));
1933
1934 DEBUG(("[crossfade] buffer_thread_f: closing/reopening device\n"));
1935 if (buffer->reopen_sync)
1936 sync_output();
1937
1938 if (the_op->close_audio)
1939 the_op->close_audio();
1940
1941 if (!the_op->open_audio(out_format.fmt, out_format.rate, out_format.nch))
1942 {
1943 DEBUG(("[crossfade] buffer_thread_f: reopening output plugin failed!\n"));
1944 g_free(buffer->data);
1945 output_opened = FALSE;
1946 MUTEX_UNLOCK(&buffer_mutex);
1947 THREAD_EXIT(0);
1948 return NULL;
1949 }
1950
1951 output_flush_time = 0;
1952 output_written = 0;
1953 output_streampos = 0;
1954
1955 /* We need to take the leading gap killer into account here:
1956 * It will fix streampos only after gapkilling has finished.
1957 * So, if gapkilling is still in progress at this point, we
1958 * have to fix it ourselves. */
1959 output_offset = buffer->used;
1960 if ((buffer->gap_len > 0) && (buffer->gap > 0))
1961 output_offset += buffer->gap_len - buffer->gap;
1962 output_offset = B2MS(output_offset) - xfade_written_time();
1963
1964 /* make sure reopen is not 0 */
1965 buffer->reopen = -1;
1966 }
1967 }
1968
1969 if (buffer->pause >= 0)
1970 {
1971 buffer->pause -= length;
1972 if (buffer->pause <= 0)
1973 {
1974 if (buffer->pause < 0)
1975 DEBUG(("[crossfade] buffer_thread_f: WARNING: pause overrun: %d\n", buffer->pause));
1976
1977 DEBUG(("[crossfade] buffer_thread_f: pausing output\n"));
1978
1979 paused = TRUE;
1980 sync_output();
1981
1982 if (paused)
1983 the_op->pause(1);
1984 else
1985 DEBUG(("[crossfade] buffer_thread_f: unpause during sync\n")) buffer->pause = -1;
1986 }
1987 }
1988 }
1989
1990 /* ----------------------------------------------------------------------- */
1991
1992 /* cleanup: close output */
1993 if (output_opened)
1994 {
1995 xfade_stop_monitor();
1996
1997 DEBUG(("[crossfade] buffer_thread_f: closing output...\n"));
1998
1999 if (the_op->close_audio)
2000 the_op->close_audio();
2001
2002 DEBUG(("[crossfade] buffer_thread_f: closing output... done\n"));
2003
2004 g_free(buffer->data);
2005 output_opened = FALSE;
2006 }
2007 else
2008 DEBUG(("[crossfade] buffer_thread_f: output already closed!\n"));
2009
2010 /* ----------------------------------------------------------------------- */
2011
2012 /* unlock buffer */
2013 MUTEX_UNLOCK(&buffer_mutex);
2014
2015 /* done */
2016 DEBUG(("[crossfade] buffer_thread_f: thread finished\n"));
2017 THREAD_EXIT(0);
2018 return NULL;
2019 }
2020
2021 void
2022 xfade_close_audio()
2023 {
2024 DEBUG(("[crossfade] close:\n"));
2025 DEBUG(("[crossfade] close: playing=%d filename=%s\n",
2026 xfplayer_input_playing(), xfplaylist_get_filename(xfplaylist_get_position())));
2027
2028 /* lock buffer */
2029 MUTEX_LOCK(&buffer_mutex);
2030
2031 /* sanity... the vorbis plugin likes to call close_audio() twice */
2032 if (!opened)
2033 {
2034 DEBUG(("[crossfade] close: WARNING: not opened!\n"));
2035 MUTEX_UNLOCK(&buffer_mutex);
2036 return;
2037 }
2038
2039 #if defined(COMPILE_FOR_AUDACIOUS) && AUDACIOUS_ABI_VERSION >= 2
2040 /* HACK: to distinguish between STOP and EOP, check Audacious'
2041 input_playing() variable. It seems to be TRUE at this point
2042 only when the end of the playlist is reached.
2043
2044 Normally, 'playing' is constantly being updated in the
2045 xfade_buffer_playing() callback, but Audacious does not seem
2046 to use it. Therefore, we can set 'playing' to FALSE here,
2047 which later 'buffer_thread' will interpret as EOP (see above).
2048 */
2049 if (xfplayer_input_playing())
2050 playing = FALSE;
2051 #else
2052 /* HACK: use patched XMMS 'input_stopped_for_restart' */
2053 if (input_stopped_for_restart && *input_stopped_for_restart)
2054 {
2055 DEBUG(("[crossfade] close: playback will restart soon\n"));
2056 output_restart = TRUE;
2057 }
2058 else
2059 output_restart = FALSE;
2060 #endif
2061
2062 if (playing)
2063 {
2064 /* immediatelly close output when paused */
2065 if (paused)
2066 {
2067 buffer->pause = -1;
2068 paused = FALSE;
2069 if (config->output_keep_opened)
2070 {
2071 buffer->used = 0;
2072 the_op->flush(0);
2073 the_op->pause(0);
2074 }
2075 else
2076 stopped = TRUE;
2077 }
2078
2079 /* HACK: If playlist_get_info_going is not true here,
2080 * XMMS is about to exit. In this case, we stop
2081 * the buffer thread before returning from this
2082 * function. Otherwise, SEGFAULT may occur when
2083 * XMMS tries to cleanup an output plugin which
2084 * we are still using.
2085 *
2086 * NOTE: This hack has become obsolete as of 0.3.5.
2087 * See output_list_hack().
2088 *
2089 * NOTE: Not quite. There still are some problems when
2090 * XMMS is exitting while a song is playing. So
2091 * this HACK has been enabled again.
2092 *
2093 * NOTE: Another thing: If output_keep_opened is enabled,
2094 * close_audio() is never called, so that the patch
2095 * can not work.
2096 */
2097 #if 1
2098 if ((xmms_is_quitting && *xmms_is_quitting)
2099 || (xmms_playlist_get_info_going && !*xmms_playlist_get_info_going))
2100 {
2101 DEBUG(("[crossfade] close: stop (about to quit)\n"))
2102
2103 /* wait for buffer thread to clean up and terminate */
2104 stopped = TRUE;
2105 #if 1
2106 MUTEX_UNLOCK(&buffer_mutex);
2107 if (THREAD_JOIN(buffer_thread))
2108 PERROR("[crossfade] close: phtread_join()");
2109 MUTEX_LOCK(&buffer_mutex);
2110 #else
2111 while (output_opened)
2112 {
2113 MUTEX_UNLOCK(&buffer_mutex);
2114 xfade_usleep(10000);
2115 MUTEX_LOCK(&buffer_mutex);
2116 }
2117 #endif
2118 }
2119 else
2120 #endif
2121 DEBUG(("[crossfade] close: stop\n"));
2122
2123 fade_config = &config->fc[FADE_CONFIG_MANUAL];
2124 }
2125 else
2126 {
2127 /* gint x = *((gint *)0); */ /* force SEGFAULT for debugging */
2128 DEBUG(("[crossfade] close: songchange/eop\n"));
2129
2130 /* kill trailing gap (does not use buffer->gap_*) */
2131 if (output_opened && xfade_cfg_gap_trail_enable(config))
2132 {
2133 gint gap_len = MS2B(xfade_cfg_gap_trail_len(config)) & -4;
2134 gint gap_level = xfade_cfg_gap_trail_level(config);
2135 gint length = MIN(gap_len, buffer->used);
2136
2137 /* DEBUG(("[crossfade] close: len=%d level=%d length=%d\n", gap_len, gap_level, length)); */
2138
2139 buffer->gap_killed = 0;
2140 while (length > 0)
2141 {
2142 gint wr_xedni = (buffer->rd_index + buffer->used - 1) % buffer->size + 1;
2143 gint blen = MIN(length, wr_xedni);
2144 gint16 *p = buffer->data + wr_xedni, left, right;
2145 gint index = 0;
2146
2147 while (index < blen)
2148 {
2149 right = *--p;
2150 left = *--p;
2151 if (ABS(left) >= gap_level) break;
2152 if (ABS(right) >= gap_level) break;
2153 index += 4;
2154 }
2155
2156 buffer->used -= index;
2157 buffer->gap_killed += index;
2158
2159 if (index < blen)
2160 break;
2161 length -= blen;
2162 }
2163
2164 DEBUG(("[crossfade] close: trailing gap size: %d/%d ms\n", B2MS(buffer->gap_killed), B2MS(gap_len)));
2165 }
2166
2167 /* skip to previous zero crossing */
2168 if (output_opened && config->gap_crossing)
2169 {
2170 int crossing;
2171
2172 buffer->gap_skipped = 0;
2173 for (crossing = 0; crossing < 4; crossing++)
2174 {
2175 while (buffer->used > 0)
2176 {
2177 gint wr_xedni = (buffer->rd_index + buffer->used - 1) % buffer->size + 1;
2178 gint blen = MIN(buffer->used, wr_xedni);
2179 gint16 *p = buffer->data + wr_xedni, left;
2180 gint index = 0;
2181
2182 while (index < blen)
2183 {
2184 left = (--p, *--p);
2185 if ((crossing & 1) ^ (left > 0))
2186 break;
2187 index += 4;
2188 }
2189
2190 buffer->used -= index;
2191 buffer->gap_skipped += index;
2192
2193 if (index < blen)
2194 break;
2195 }
2196 }
2197 DEBUG(("[crossfade] close: skipped %d bytes to previous zero crossing\n", buffer->gap_skipped));
2198
2199 /* update gap_killed (for undoing gap_killer in case of EOP) */
2200 buffer->gap_killed += buffer->gap_skipped;
2201 }
2202
2203 fade_config = &config->fc[FADE_CONFIG_XFADE];
2204 }
2205
2206 /* XMMS has left the building */
2207 opened = FALSE;
2208
2209 /* update last_close */
2210 gettimeofday(&last_close, NULL);
2211 input_playing = FALSE;
2212
2213 /* unlock buffer */
2214 MUTEX_UNLOCK(&buffer_mutex);
2215 }
2216
2217 void
2218 xfade_flush(gint time)
2219 {
2220 gint pos;
2221 gchar *file;
2222
2223 DEBUG(("[crossfade] flush: time=%d\n", time));
2224
2225 /* get filename */
2226 pos = xfplaylist_get_position();
2227 file = xfplaylist_get_filename(pos);
2228
2229 if (!file)
2230 file = g_strdup(xfplaylist_get_songtitle(pos));
2231
2232 #if defined(COMPILE_FOR_AUDACIOUS)
2233 /* HACK: special handling for audacious, which just calls flush(0) on a songchange */
2234 if (file && last_filename && strcmp(file, last_filename) != 0)
2235 {
2236 DEBUG(("[crossfade] flush: filename changed, forcing close/reopen...\n"));
2237 xfade_close_audio();
2238 /* 0.3.14: xfade_close_audio sets fade_config to FADE_CONFIG_MANUAL,
2239 * but this is an automatic songchange */
2240 fade_config = &config->fc[FADE_CONFIG_XFADE];
2241 xfade_open_audio(in_format.fmt, in_format.rate, in_format.nch);
2242 DEBUG(("[crossfade] flush: filename changed, forcing close/reopen... done\n"));
2243 return;
2244 }
2245 #endif
2246
2247 /* lock buffer */
2248 MUTEX_LOCK(&buffer_mutex);
2249
2250 /* update streampos with new stream position (input format size) */
2251 streampos = ((gint64) time * in_format.bps / 1000) & -4;
2252
2253 /* flush output device / apply seek crossfade */
2254 if (config->fc[FADE_CONFIG_SEEK].type == FADE_TYPE_FLUSH)
2255 {
2256 /* flush output plugin */
2257 the_op->flush(time);
2258 output_flush_time = time;
2259 output_streampos = MS2B(time);
2260
2261 /* flush buffer, disable leading gap killing */
2262 buffer_reset(buffer, config);
2263 }
2264 else if (paused)
2265 {
2266 fade_config_t fc;
2267
2268 /* clear buffer */
2269 buffer->used = 0;
2270
2271 /* apply only the fade_in part of FADE_CONFIG_PAUSE */
2272 memcpy(&fc, &config->fc[FADE_CONFIG_PAUSE], sizeof(fc));
2273 fc.out_len_ms = 0;
2274 fc.ofs_custom_ms = 0;
2275 xfade_apply_fade_config(&fc);
2276 }
2277 else
2278 xfade_apply_fade_config(&config->fc[FADE_CONFIG_SEEK]);
2279
2280 /* restart realtime throttling (should find another name for that var) */
2281 output_written = 0;
2282
2283 /* make sure that the gapkiller is disabled */
2284 buffer->gap = 0;
2285
2286 /* update output offset */
2287 output_offset = the_op->written_time() - time + B2MS(buffer->used) + B2MS(buffer->silence_len);
2288
2289 /* unlock buffer */
2290 MUTEX_UNLOCK(&buffer_mutex);
2291
2292 #ifdef DEBUG_HARDCORE
2293 DEBUG(("[crossfade] flush: time=%d: done.\n", time));
2294 #endif
2295 }
2296
2297 void
2298 xfade_pause(short p)
2299 {
2300 /* lock buffer */
2301 MUTEX_LOCK(&buffer_mutex);
2302
2303 if (p)
2304 {
2305 fade_config_t *fc = &config->fc[FADE_CONFIG_PAUSE];
2306 if (fc->type == FADE_TYPE_PAUSE_ADV)
2307 {
2308 int fade, length, n;
2309 int index = buffer->rd_index;
2310 int out_len = MS2B(xfade_cfg_fadeout_len(fc)) & -4;
2311 int in_len = MS2B(xfade_cfg_fadein_len(fc)) & -4;
2312 int silence_len = MS2B(xfade_cfg_offset(fc)) & -4;
2313
2314 /* limit fadeout/fadein len to available data in buffer */
2315 if ((out_len + in_len) > buffer->used)
2316 {
2317 out_len = (buffer->used / 2) & -4;
2318 in_len = out_len;
2319 }
2320
2321 DEBUG(("[crossfade] pause: paused=1 out=%d in=%d silence=%d\n",
2322 B2MS(out_len), B2MS(in_len), B2MS(silence_len)));
2323
2324 /* fade out (modifies buffer directly) */
2325 fade = 0;
2326 length = out_len;
2327 while (length > 0)
2328 {
2329 gint16 *p = buffer->data + index;
2330 gint blen = buffer->size - index;
2331 if (blen > length)
2332 blen = length;
2333
2334 for (n = blen / 4; n > 0; n--)
2335 {
2336 gfloat factor = 1.0f - ((gfloat) fade / out_len);
2337 *p = (gfloat)*p * factor; p++;
2338 *p = (gfloat)*p * factor; p++;
2339 fade += 4;
2340 }
2341
2342 index = (index + blen) % buffer->size;
2343 length -= blen;
2344 }
2345
2346 /* fade in (modifies buffer directly) */
2347 fade = 0;
2348 length = in_len;
2349 while (length > 0)
2350 {
2351 gint16 *p = buffer->data + index;
2352 gint blen = buffer->size - index;
2353 if (blen > length)
2354 blen = length;
2355
2356 for (n = blen / 4; n > 0; n--)
2357 {
2358 gfloat factor = (gfloat) fade / in_len;
2359 *p = (gfloat)*p * factor; p++;
2360 *p = (gfloat)*p * factor; p++;
2361 fade += 4;
2362 }
2363
2364 index = (index + blen) % buffer->size;
2365 length -= blen;
2366 }
2367
2368 /* start silence and pause countdowns */
2369 buffer->silence = out_len;
2370 buffer->silence_len = silence_len;
2371 buffer->pause = out_len + silence_len;
2372 paused = FALSE; /* (!) will be set to TRUE in buffer_thread_f */
2373 }
2374 else
2375 {
2376 the_op->pause(1);
2377 paused = TRUE;
2378 DEBUG(("[crossfade] pause: paused=1\n"));
2379 }
2380 }
2381 else
2382 {
2383 the_op->pause(0);
2384 buffer->pause = -1;
2385 paused = FALSE;
2386 DEBUG(("[crossfade] pause: paused=0\n"));
2387 }
2388
2389 /* unlock buffer */
2390 MUTEX_UNLOCK(&buffer_mutex);
2391 }
2392
2393 gint
2394 xfade_buffer_free()
2395 {
2396 gint size, free;
2397
2398 #ifdef DEBUG_HARDCORE
2399 DEBUG(("[crossfade] buffer_free:\n"));
2400 #endif
2401
2402 /* sanity check */
2403 if (!output_opened)
2404 {
2405 DEBUG(("[crossfade] buffer_free: WARNING: output closed!\n"));
2406 return buffer->sync_size;
2407 }
2408
2409 /* lock buffer */
2410 MUTEX_LOCK(&buffer_mutex);
2411
2412 size = buffer->size;
2413
2414 /* When running in realtime mode, we need to take special care here:
2415 * While XMMS is writing data to the output plugin, it will not yield
2416 * ANY processing time to the buffer thread. It will only stop when
2417 * xfade_buffer_free() no longer reports free buffer space. */
2418 if (realtime)
2419 {
2420 gint64 wanted = output_written + buffer->preload_size;
2421
2422 /* Fix for XMMS misbehaviour (possibly a bug): If the free space as
2423 * returned by xfade_buffer_free() is below a certain minimum block size
2424 * (tests showed 2304 bytes), XMMS will not send more data until there
2425 * is enough room for one of those blocks.
2426 *
2427 * This breaks preloading in realtime mode. To make sure that the pre-
2428 * load buffer gets filled we request additional sync_size bytes. */
2429 wanted += buffer->sync_size;
2430
2431 if (wanted <= size)
2432 size = wanted;
2433 }
2434
2435 free = size - buffer->used;
2436 if (free < 0)
2437 free = 0;
2438
2439 /* unlock buffer */
2440 MUTEX_UNLOCK(&buffer_mutex);
2441
2442 /* Convert to input format size. For input rates > output rate this will
2443 * return less free space than actually is available, but we don't care. */
2444 free /= (out_format.rate / (in_format.rate + 1)) + 1;
2445 if (in_format.is_8bit)
2446 free /= 2;
2447 if (in_format.nch == 1)
2448 free /= 2;
2449
2450 #ifdef DEBUG_HARDCORE
2451 DEBUG(("[crossfade] buffer_free: %d\n", free));
2452 #endif
2453 return free;
2454 }
2455
2456 gint
2457 xfade_buffer_playing()
2458 {
2459 /* always return FALSE here (if not in pause) so XMMS immediatelly
2460 * starts playback of the next song */
2461
2462 /*
2463 * NOTE: this causes trouble when playing HTTP audio streams.
2464 *
2465 * mpg123.lib will start prebuffering (and thus stalling output) when both
2466 * 1) it's internal buffer is emptied (does happen all the time)
2467 * 2) the output plugin's buffer_playing() (this function) returns FALSE
2468 */
2469
2470 if (paused)
2471 playing = TRUE;
2472 else
2473 playing =
2474 (is_http && (buffer->used > 0) && the_op->buffer_playing())
2475 || (buffer->reopen >= 0)
2476 || (buffer->silence > 0)
2477 || (buffer->silence_len > 0);
2478
2479 #ifdef DEBUG_HARDCORE
2480 DEBUG(("[crossfade] buffer_playing: %d\n", playing));
2481 #endif
2482 return playing;
2483 }
2484
2485 gint
2486 xfade_written_time()
2487 {
2488 if (!output_opened)
2489 return 0;
2490 return (gint) (streampos * 1000 / in_format.bps);
2491 }
2492
2493 gint
2494 xfade_output_time()
2495 {
2496 gint time;
2497
2498 #ifdef DEBUG_HARDCORE
2499 DEBUG(("[crossfade] output_time:\n"));
2500 #endif
2501
2502 /* sanity check (note: this one _does_ happen all the time) */
2503 if (!output_opened)
2504 return 0;
2505
2506 /* lock buffer */
2507 MUTEX_LOCK(&buffer_mutex);
2508
2509 time = the_op->output_time() - output_offset;
2510 if (time < 0)
2511 time = 0;
2512
2513 /* unlock buffer */
2514 MUTEX_UNLOCK(&buffer_mutex);
2515
2516 #ifdef DEBUG_HARDCORE
2517 DEBUG(("[crossfade] output_time: time=%d\n", time));
2518 #endif
2519 return time;
2520 }
2521
2522 void
2523 xfade_cleanup()
2524 {
2525 DEBUG(("[crossfade] cleanup:\n"));
2526
2527 /* lock buffer */
2528 MUTEX_LOCK(&buffer_mutex);
2529
2530 /* check if buffer thread is still running */
2531 if (output_opened)
2532 {
2533 DEBUG(("[crossfade] cleanup: closing output\n"));
2534
2535 stopped = TRUE;
2536
2537 /* wait for buffer thread to clean up and terminate */
2538 MUTEX_UNLOCK(&buffer_mutex);
2539 if (THREAD_JOIN(buffer_thread))
2540 PERROR("[crossfade] close: thread_join()");
2541 MUTEX_LOCK(&buffer_mutex);
2542 }
2543
2544 /* unlock buffer */
2545 MUTEX_UNLOCK(&buffer_mutex);
2546
2547 DEBUG(("[crossfade] cleanup: done\n"));
2548 }