2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "crossfade.h"
24 #include "audio_format.h"
33 #define G_LOG_DOMAIN "crossfade"
36 #define strtok_r(s,d,p) strtok(s,d)
39 static float mixramp_interpolate(char *ramp_list
, float required_db
)
41 float db
, secs
, last_db
= nan(""), last_secs
= 0;
42 char *ramp_str
, *save_str
= NULL
;
44 /* ramp_list is a string of pairs of dBs and seconds that describe the
45 * volume profile. Delimiters are semi-colons between pairs and spaces
46 * between the dB and seconds of a pair.
47 * The dB values must be monotonically increasing for this to work. */
50 /* Parse the dB tokens out of the input string. */
51 ramp_str
= strtok_r(ramp_list
, " ", &save_str
);
53 /* Tell strtok to continue next time round. */
56 /* Parse the dB value. */
57 if (NULL
== ramp_str
) {
60 db
= (float)atof(ramp_str
);
63 ramp_str
= strtok_r(NULL
, ";", &save_str
);
64 if (NULL
== ramp_str
) {
67 secs
= (float)atof(ramp_str
);
69 /* Check for exact match. */
70 if (db
== required_db
) {
74 /* Save if too quiet. */
75 if (db
< required_db
) {
81 /* If required db < any stored value, use the least. */
86 /* Finally, interpolate linearly. */
87 secs
= last_secs
+ (required_db
- last_db
) * (secs
- last_secs
) / (db
- last_db
);
92 unsigned cross_fade_calc(float duration
, float total_time
,
93 float mixramp_db
, float mixramp_delay
,
94 char *mixramp_start
, char *mixramp_prev_end
,
95 const struct audio_format
*af
,
96 const struct audio_format
*old_format
,
99 unsigned int chunks
= 0;
101 float mixramp_overlap
;
103 if (duration
< 0 || duration
>= total_time
||
104 /* we can't crossfade when the audio formats are different */
105 !audio_format_equals(af
, old_format
))
108 assert(duration
>= 0);
109 assert(audio_format_valid(af
));
111 chunks_f
= (float)audio_format_time_to_size(af
) / (float)CHUNK_SIZE
;
113 if (isnan(mixramp_delay
) || !(mixramp_start
) || !(mixramp_prev_end
)) {
114 chunks
= (chunks_f
* duration
+ 0.5);
116 /* Calculate mixramp overlap.
117 * FIXME factor in ReplayGain for both songs. */
118 mixramp_overlap
= mixramp_interpolate(mixramp_start
, mixramp_db
)
119 + mixramp_interpolate(mixramp_prev_end
, mixramp_db
);
120 if (!isnan(mixramp_overlap
) && (mixramp_delay
<= mixramp_overlap
)) {
121 chunks
= (chunks_f
* (mixramp_overlap
- mixramp_delay
));
122 g_debug("will overlap %d chunks, %fs", chunks
,
123 mixramp_overlap
- mixramp_delay
);
127 if (chunks
> max_chunks
) {
129 g_warning("audio_buffer_size too small for computed MixRamp overlap");
135 void cross_fade_apply(struct music_chunk
*a
, const struct music_chunk
*b
,
136 const struct audio_format
*format
,
143 assert(a
->length
== 0 || b
->length
== 0 ||
144 audio_format_equals(&a
->audio_format
, &b
->audio_format
));
146 if (a
->tag
== NULL
&& b
->tag
!= NULL
)
147 /* merge the tag into the destination chunk */
148 a
->tag
= tag_dup(b
->tag
);
150 size
= b
->length
> a
->length
160 if (b
->length
> a
->length
) {
161 /* the second buffer is larger than the first one:
162 there is unmixed rest at the end. Copy it over.
163 The output buffer API guarantees that there is
164 enough room in a->data. */
168 a
->audio_format
= b
->audio_format
;
171 memcpy(a
->data
+ a
->length
,
173 b
->length
- a
->length
);
174 a
->length
= b
->length
;