9cee6f5de4e71adaa99aeb54814c9d71bca149cc
[AGL/meta-agl.git] / meta-agl-profile-core / recipes-multimedia / pulseaudio / pulseaudio-10.0 / 0002-volume-ramp-additions-to-the-low-level-infra.patch
1 From 7757059ffc6e63ea20ba9013682d72d619e7aefc Mon Sep 17 00:00:00 2001
2 From: Sangchul Lee <sangchul1011@gmail.com>
3 Date: Sat, 27 Aug 2016 21:33:16 +0900
4 Subject: [PATCH 2/6] volume ramp: additions to the low level infra
5
6 The original patch is
7  - https://review.tizen.org/git/?p=platform/upstream/pulseaudio.git;a=commit;h=df1c4275ed79e0b708c75b92f9d247e0492bc1f0
8  - by Jaska Uimonen <jaska.uimonen <at> helsinki.fi>
9
10 Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
11 ---
12  src/map-file        |   4 +
13  src/pulse/def.h     |  13 ++-
14  src/pulse/volume.c  |  74 ++++++++++++-
15  src/pulse/volume.h  |  33 ++++++
16  src/pulsecore/mix.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++
17  src/pulsecore/mix.h |  27 +++++
18  6 files changed, 459 insertions(+), 2 deletions(-)
19
20 diff --git a/src/map-file b/src/map-file
21 index 93a62b8..ef9b57d 100644
22 --- a/src/map-file
23 +++ b/src/map-file
24 @@ -138,6 +138,10 @@ pa_cvolume_max_mask;
25  pa_cvolume_merge;
26  pa_cvolume_min;
27  pa_cvolume_min_mask;
28 +pa_cvolume_ramp_equal;
29 +pa_cvolume_ramp_init;
30 +pa_cvolume_ramp_set;
31 +pa_cvolume_ramp_channel_ramp_set;
32  pa_cvolume_remap;
33  pa_cvolume_scale;
34  pa_cvolume_scale_mask;
35 diff --git a/src/pulse/def.h b/src/pulse/def.h
36 index 680bdc9..bc3cedd 100644
37 --- a/src/pulse/def.h
38 +++ b/src/pulse/def.h
39 @@ -347,11 +347,15 @@ typedef enum pa_stream_flags {
40       * consider absolute when the sink is in flat volume mode,
41       * relative otherwise. \since 0.9.20 */
42  
43 -    PA_STREAM_PASSTHROUGH = 0x80000U
44 +    PA_STREAM_PASSTHROUGH = 0x80000U,
45      /**< Used to tag content that will be rendered by passthrough sinks.
46       * The data will be left as is and not reformatted, resampled.
47       * \since 1.0 */
48  
49 +    PA_STREAM_START_RAMP_MUTED = 0x100000U
50 +    /**< Used to tag content that the stream will be started ramp volume
51 +     * muted so that you can nicely fade it in */
52 +
53  } pa_stream_flags_t;
54  
55  /** \cond fulldocs */
56 @@ -380,6 +384,7 @@ typedef enum pa_stream_flags {
57  #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND
58  #define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME
59  #define PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH
60 +#define PA_STREAM_START_RAMP_MUTED PA_STREAM_START_RAMP_MUTED
61  
62  /** \endcond */
63  
64 @@ -1047,6 +1052,12 @@ typedef enum pa_port_available {
65  /** \endcond */
66  #endif
67  
68 +/** \cond fulldocs */
69 +#define PA_VOLUMER_RAMP_TYPE_LINEAR PA_VOLUMER_RAMP_TYPE_LINEAR
70 +#define PA_VOLUMER_RAMP_TYPE_LOGARITHMIC PA_VOLUMER_RAMP_TYPE_LOGARITHMIC
71 +#define PA_VOLUMER_RAMP_TYPE_CUBIC PA_VOLUMER_RAMP_TYPE_CUBIC
72 +/** \endcond */
73 +
74  PA_C_DECL_END
75  
76  #endif
77 diff --git a/src/pulse/volume.c b/src/pulse/volume.c
78 index 1667b94..85072c1 100644
79 --- a/src/pulse/volume.c
80 +++ b/src/pulse/volume.c
81 @@ -445,7 +445,10 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
82      unsigned c;
83      pa_assert(a);
84  
85 -    pa_return_val_if_fail(pa_cvolume_valid(a), 0);
86 +    if (pa_cvolume_valid(a) == 0)
87 +        abort();
88 +
89 +    /* pa_return_val_if_fail(pa_cvolume_valid(a), 0); */
90      pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0);
91  
92      for (c = 0; c < a->channels; c++)
93 @@ -977,3 +980,72 @@ pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) {
94  
95      return pa_cvolume_scale(v, m);
96  }
97 +
98 +int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) {
99 +    int i;
100 +    pa_assert(a);
101 +    pa_assert(b);
102 +
103 +    if (PA_UNLIKELY(a == b))
104 +        return 1;
105 +
106 +    if (a->channels != b->channels)
107 +        return 0;
108 +
109 +    for (i = 0; i < a->channels; i++) {
110 +        if (a->ramps[i].type != b->ramps[i].type ||
111 +            a->ramps[i].length != b->ramps[i].length ||
112 +            a->ramps[i].target != b->ramps[i].target)
113 +            return 0;
114 +    }
115 +
116 +    return 1;
117 +}
118 +
119 +pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp) {
120 +    unsigned c;
121 +
122 +    pa_assert(ramp);
123 +
124 +    ramp->channels = 0;
125 +
126 +    for (c = 0; c < PA_CHANNELS_MAX; c++) {
127 +        ramp->ramps[c].type = PA_VOLUME_RAMP_TYPE_LINEAR;
128 +        ramp->ramps[c].length = 0;
129 +        ramp->ramps[c].target = PA_VOLUME_INVALID;
130 +    }
131 +
132 +    return ramp;
133 +}
134 +
135 +pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, long time, pa_volume_t vol) {
136 +    int i;
137 +
138 +    pa_assert(ramp);
139 +    pa_assert(channels > 0);
140 +    pa_assert(time >= 0);
141 +    pa_assert(channels <= PA_CHANNELS_MAX);
142 +
143 +    ramp->channels = (uint8_t) channels;
144 +
145 +    for (i = 0; i < ramp->channels; i++) {
146 +        ramp->ramps[i].type = type;
147 +        ramp->ramps[i].length = time;
148 +        ramp->ramps[i].target = PA_CLAMP_VOLUME(vol);
149 +    }
150 +
151 +    return ramp;
152 +}
153 +
154 +pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol) {
155 +
156 +    pa_assert(ramp);
157 +    pa_assert(channel <= ramp->channels);
158 +    pa_assert(time >= 0);
159 +
160 +    ramp->ramps[channel].type = type;
161 +    ramp->ramps[channel].length = time;
162 +    ramp->ramps[channel].target = PA_CLAMP_VOLUME(vol);
163 +
164 +    return ramp;
165 +}
166 diff --git a/src/pulse/volume.h b/src/pulse/volume.h
167 index 8cf4fa4..2ae3451 100644
168 --- a/src/pulse/volume.h
169 +++ b/src/pulse/volume.h
170 @@ -431,6 +431,39 @@ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc);
171   * the channels are kept. \since 0.9.16 */
172  pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec);
173  
174 +/** Volume ramp type
175 +*/
176 +typedef enum pa_volume_ramp_type {
177 +    PA_VOLUME_RAMP_TYPE_LINEAR = 0,        /**< linear */
178 +    PA_VOLUME_RAMP_TYPE_LOGARITHMIC = 1,   /**< logarithmic */
179 +    PA_VOLUME_RAMP_TYPE_CUBIC = 2,
180 +} pa_volume_ramp_type_t;
181 +
182 +/** A structure encapsulating a volume ramp */
183 +typedef struct pa_volume_ramp_t {
184 +    pa_volume_ramp_type_t type;
185 +    long length;
186 +    pa_volume_t target;
187 +} pa_volume_ramp_t;
188 +
189 +/** A structure encapsulating a multichannel volume ramp */
190 +typedef struct pa_cvolume_ramp {
191 +    uint8_t channels;
192 +    pa_volume_ramp_t ramps[PA_CHANNELS_MAX];
193 +} pa_cvolume_ramp;
194 +
195 +/** Return non-zero when *a == *b */
196 +int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b);
197 +
198 +/** Init volume ramp struct */
199 +pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp);
200 +
201 +/** Set first n channels of ramp struct to certain value */
202 +pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol);
203 +
204 +/** Set individual channel in the channel struct */
205 +pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol);
206 +
207  PA_C_DECL_END
208  
209  #endif
210 diff --git a/src/pulsecore/mix.c b/src/pulsecore/mix.c
211 index 59622d7..1e4cc1e 100644
212 --- a/src/pulsecore/mix.c
213 +++ b/src/pulsecore/mix.c
214 @@ -724,3 +724,313 @@ void pa_volume_memchunk(
215  
216      pa_memblock_release(c->memblock);
217  }
218 +
219 +static void calc_linear_integer_volume_no_mapping(int32_t linear[], float volume[], unsigned nchannels) {
220 +    unsigned channel, padding;
221 +
222 +    pa_assert(linear);
223 +    pa_assert(volume);
224 +
225 +    for (channel = 0; channel < nchannels; channel++)
226 +        linear[channel] = (int32_t) lrint(volume[channel] * 0x10000U);
227 +
228 +    for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
229 +        linear[channel] = linear[padding];
230 +}
231 +
232 +static void calc_linear_float_volume_no_mapping(float linear[], float volume[], unsigned nchannels) {
233 +    unsigned channel, padding;
234 +
235 +    pa_assert(linear);
236 +    pa_assert(volume);
237 +
238 +    for (channel = 0; channel < nchannels; channel++)
239 +        linear[channel] = volume[channel];
240 +
241 +    for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
242 +        linear[channel] = linear[padding];
243 +}
244 +
245 +typedef void (*pa_calc_volume_no_mapping_func_t) (void *volumes, float *volume, int channels);
246 +
247 +static const pa_calc_volume_no_mapping_func_t calc_volume_table_no_mapping[] = {
248 +  [PA_SAMPLE_U8]        = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
249 +  [PA_SAMPLE_ALAW]      = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
250 +  [PA_SAMPLE_ULAW]      = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
251 +  [PA_SAMPLE_S16LE]     = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
252 +  [PA_SAMPLE_S16BE]     = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
253 +  [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping,
254 +  [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping,
255 +  [PA_SAMPLE_S32LE]     = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
256 +  [PA_SAMPLE_S32BE]     = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
257 +  [PA_SAMPLE_S24LE]     = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
258 +  [PA_SAMPLE_S24BE]     = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
259 +  [PA_SAMPLE_S24_32LE]  = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
260 +  [PA_SAMPLE_S24_32BE]  = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping
261 +};
262 +
263 +static const unsigned format_sample_size_table[] = {
264 +  [PA_SAMPLE_U8]        = 1,
265 +  [PA_SAMPLE_ALAW]      = 1,
266 +  [PA_SAMPLE_ULAW]      = 1,
267 +  [PA_SAMPLE_S16LE]     = 2,
268 +  [PA_SAMPLE_S16BE]     = 2,
269 +  [PA_SAMPLE_FLOAT32LE] = 4,
270 +  [PA_SAMPLE_FLOAT32BE] = 4,
271 +  [PA_SAMPLE_S32LE]     = 4,
272 +  [PA_SAMPLE_S32BE]     = 4,
273 +  [PA_SAMPLE_S24LE]     = 3,
274 +  [PA_SAMPLE_S24BE]     = 3,
275 +  [PA_SAMPLE_S24_32LE]  = 4,
276 +  [PA_SAMPLE_S24_32BE]  = 4
277 +};
278 +
279 +static float calc_volume_ramp_linear(pa_volume_ramp_int_t *ramp) {
280 +    pa_assert(ramp);
281 +    pa_assert(ramp->length > 0);
282 +
283 +    /* basic linear interpolation */
284 +    return ramp->start + (ramp->length - ramp->left) * (ramp->end - ramp->start) / (float) ramp->length;
285 +}
286 +
287 +static float calc_volume_ramp_logarithmic(pa_volume_ramp_int_t *ramp) {
288 +    float x_val, s, e;
289 +    long temp;
290 +
291 +    pa_assert(ramp);
292 +    pa_assert(ramp->length > 0);
293 +
294 +    if (ramp->end > ramp->start) {
295 +        temp = ramp->left;
296 +        s = ramp->end;
297 +        e = ramp->start;
298 +    } else {
299 +        temp = ramp->length - ramp->left;
300 +        s = ramp->start;
301 +        e = ramp->end;
302 +    }
303 +
304 +    x_val = temp == 0 ? 0.0 : powf(temp, 10);
305 +
306 +    /* base 10 logarithmic interpolation */
307 +    return s + x_val * (e - s) / powf(ramp->length, 10);
308 +}
309 +
310 +static float calc_volume_ramp_cubic(pa_volume_ramp_int_t *ramp) {
311 +    float x_val, s, e;
312 +    long temp;
313 +
314 +    pa_assert(ramp);
315 +    pa_assert(ramp->length > 0);
316 +
317 +    if (ramp->end > ramp->start) {
318 +        temp = ramp->left;
319 +        s = ramp->end;
320 +        e = ramp->start;
321 +    } else {
322 +        temp = ramp->length - ramp->left;
323 +        s = ramp->start;
324 +        e = ramp->end;
325 +    }
326 +
327 +    x_val = temp == 0 ? 0.0 : cbrtf(temp);
328 +
329 +    /* cubic interpolation */
330 +    return s + x_val * (e - s) / cbrtf(ramp->length);
331 +}
332 +
333 +typedef float (*pa_calc_volume_ramp_func_t) (pa_volume_ramp_int_t *);
334 +
335 +static const pa_calc_volume_ramp_func_t calc_volume_ramp_table[] = {
336 +    [PA_VOLUME_RAMP_TYPE_LINEAR] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_linear,
337 +    [PA_VOLUME_RAMP_TYPE_LOGARITHMIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_logarithmic,
338 +    [PA_VOLUME_RAMP_TYPE_CUBIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_cubic
339 +};
340 +
341 +static void calc_volume_ramps(pa_cvolume_ramp_int *ram, float *vol)
342 +{
343 +    int i;
344 +
345 +    for (i = 0; i < ram->channels; i++) {
346 +        if (ram->ramps[i].left <= 0) {
347 +            if (ram->ramps[i].target == PA_VOLUME_NORM) {
348 +                vol[i] = 1.0;
349 +            }
350 +        } else {
351 +            vol[i] = ram->ramps[i].curr = calc_volume_ramp_table[ram->ramps[i].type] (&ram->ramps[i]);
352 +            ram->ramps[i].left--;
353 +        }
354 +    }
355 +}
356 +
357 +void pa_volume_ramp_memchunk(
358 +        pa_memchunk *c,
359 +        const pa_sample_spec *spec,
360 +        pa_cvolume_ramp_int *ramp) {
361 +
362 +    void *ptr;
363 +    volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
364 +    float vol[PA_CHANNELS_MAX + VOLUME_PADDING];
365 +    pa_do_volume_func_t do_volume;
366 +    long length_in_frames;
367 +    int i;
368 +
369 +    pa_assert(c);
370 +    pa_assert(spec);
371 +    pa_assert(pa_frame_aligned(c->length, spec));
372 +    pa_assert(ramp);
373 +
374 +    length_in_frames = c->length / format_sample_size_table[spec->format] / spec->channels;
375 +
376 +    if (pa_memblock_is_silence(c->memblock)) {
377 +        for (i = 0; i < ramp->channels; i++) {
378 +            if (ramp->ramps[i].length > 0)
379 +                ramp->ramps[i].length -= length_in_frames;
380 +        }
381 +        return;
382 +    }
383 +
384 +    if (spec->format < 0 || spec->format >= PA_SAMPLE_MAX) {
385 +      pa_log_warn("Unable to change volume of format");
386 +      return;
387 +    }
388 +
389 +    do_volume = pa_get_volume_func(spec->format);
390 +    pa_assert(do_volume);
391 +
392 +    ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
393 +
394 +    for (i = 0; i < length_in_frames; i++) {
395 +        calc_volume_ramps(ramp, vol);
396 +        calc_volume_table_no_mapping[spec->format] ((void *)linear, vol, spec->channels);
397 +
398 +        /* we only process one frame per iteration */
399 +        do_volume (ptr, (void *)linear, spec->channels, format_sample_size_table[spec->format] * spec->channels);
400 +
401 +        /* pa_log_debug("1: %d  2: %d", linear[0], linear[1]); */
402 +
403 +        ptr = (uint8_t*)ptr + format_sample_size_table[spec->format] * spec->channels;
404 +    }
405 +
406 +    pa_memblock_release(c->memblock);
407 +}
408 +
409 +pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate) {
410 +
411 +    int i, j, channels, remaining_channels;
412 +    float temp;
413 +
414 +    if (dst->channels < src->channels) {
415 +        channels = dst->channels;
416 +        remaining_channels = 0;
417 +    }
418 +    else {
419 +        channels = src->channels;
420 +        remaining_channels = dst->channels;
421 +    }
422 +
423 +    for (i = 0; i < channels; i++) {
424 +        dst->ramps[i].type = src->ramps[i].type;
425 +        /* ms to samples */
426 +        dst->ramps[i].length = src->ramps[i].length * sample_rate / 1000;
427 +        dst->ramps[i].left = dst->ramps[i].length;
428 +        dst->ramps[i].start = dst->ramps[i].end;
429 +        dst->ramps[i].target = src->ramps[i].target;
430 +        /* scale to pulse internal mapping so that when ramp is over there's no glitch in volume */
431 +        temp = src->ramps[i].target / (float)0x10000U;
432 +        dst->ramps[i].end = temp * temp * temp;
433 +    }
434 +
435 +    j = i;
436 +
437 +    for (i--; j < remaining_channels; j++) {
438 +        dst->ramps[j].type = dst->ramps[i].type;
439 +        dst->ramps[j].length = dst->ramps[i].length;
440 +        dst->ramps[j].left = dst->ramps[i].left;
441 +        dst->ramps[j].start = dst->ramps[i].start;
442 +        dst->ramps[j].target = dst->ramps[i].target;
443 +        dst->ramps[j].end = dst->ramps[i].end;
444 +    }
445 +
446 +    return dst;
447 +}
448 +
449 +bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp) {
450 +    int i;
451 +
452 +    for (i = 0; i < ramp->channels; i++) {
453 +        if (ramp->ramps[i].left > 0)
454 +            return true;
455 +    }
456 +
457 +    return false;
458 +}
459 +
460 +bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp) {
461 +    int i;
462 +
463 +    for (i = 0; i < ramp->channels; i++) {
464 +        if (ramp->ramps[i].target != PA_VOLUME_NORM)
465 +            return true;
466 +    }
467 +
468 +    return false;
469 +}
470 +
471 +pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume) {
472 +    int i = 0;
473 +
474 +    volume->channels = ramp->channels;
475 +
476 +    for (i = 0; i < ramp->channels; i++)
477 +        volume->values[i] = ramp->ramps[i].target;
478 +
479 +    return volume;
480 +}
481 +
482 +pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst) {
483 +    int i;
484 +
485 +    for (i = 0; i < src->channels; i++) {
486 +        /* if new vols are invalid, copy old ramp i.e. no effect */
487 +        if (dst->ramps[i].target == PA_VOLUME_INVALID)
488 +            dst->ramps[i] = src->ramps[i];
489 +        /* if there's some old ramp still left */
490 +        else if (src->ramps[i].left > 0)
491 +            dst->ramps[i].start = src->ramps[i].curr;
492 +    }
493 +
494 +    return dst;
495 +}
496 +
497 +pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels) {
498 +    int i;
499 +    float temp;
500 +
501 +    src->channels = channels;
502 +
503 +    for (i = 0; i < channels; i++) {
504 +        src->ramps[i].type = PA_VOLUME_RAMP_TYPE_LINEAR;
505 +        src->ramps[i].length = 0;
506 +        src->ramps[i].left = 0;
507 +        if (vol == PA_VOLUME_NORM) {
508 +            src->ramps[i].start = 1.0;
509 +            src->ramps[i].end = 1.0;
510 +            src->ramps[i].curr = 1.0;
511 +        }
512 +        else if (vol == PA_VOLUME_MUTED) {
513 +            src->ramps[i].start = 0.0;
514 +            src->ramps[i].end = 0.0;
515 +            src->ramps[i].curr = 0.0;
516 +        }
517 +        else {
518 +            temp = vol / (float)0x10000U;
519 +            src->ramps[i].start = temp * temp * temp;
520 +            src->ramps[i].end = src->ramps[i].start;
521 +            src->ramps[i].curr = src->ramps[i].start;
522 +        }
523 +        src->ramps[i].target = vol;
524 +    }
525 +
526 +    return src;
527 +}
528 diff --git a/src/pulsecore/mix.h b/src/pulsecore/mix.h
529 index 8102bcd..0f86b6f 100644
530 --- a/src/pulsecore/mix.h
531 +++ b/src/pulsecore/mix.h
532 @@ -59,4 +59,31 @@ void pa_volume_memchunk(
533      const pa_sample_spec *spec,
534      const pa_cvolume *volume);
535  
536 +typedef struct pa_volume_ramp_int_t {
537 +    pa_volume_ramp_type_t type;
538 +    long length;
539 +    long left;
540 +    float start;
541 +    float end;
542 +    float curr;
543 +    pa_volume_t target;
544 +} pa_volume_ramp_int_t;
545 +
546 +typedef struct pa_cvolume_ramp_int {
547 +    uint8_t channels;
548 +    pa_volume_ramp_int_t ramps[PA_CHANNELS_MAX];
549 +} pa_cvolume_ramp_int;
550 +
551 +pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate);
552 +bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp);
553 +bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp);
554 +pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst);
555 +pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels);
556 +pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume);
557 +
558 +void pa_volume_ramp_memchunk(
559 +        pa_memchunk *c,
560 +        const pa_sample_spec *spec,
561 +        pa_cvolume_ramp_int *ramp);
562 +
563  #endif
564 -- 
565 1.9.1
566