4 This file is part of PulseAudio.
6 Copyright 2007 Lennart Poettering
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <pulse/sample.h>
31 #include <pulse/xmalloc.h>
33 #include <pulsecore/endianmacros.h>
34 #include <pulsecore/memchunk.h>
35 #include <pulsecore/macro.h>
36 #include <pulsecore/flist.h>
37 #include <pulsecore/semaphore.h>
38 #include <pulsecore/g711.h>
43 Envelope subsystem for applying linear interpolated volume
44 envelopes on audio data. If multiple enevelopes shall be applied
45 at the same time, the "minimum" envelope is determined and
48 Envelopes are defined in a statically allocated constant structure
49 pa_envelope_def. It may be activated using pa_envelope_add(). And
50 already active envelope may be replaced with pa_envelope_replace()
51 and removed with pa_envelope_remove().The combined "minimum"
52 envelope can be applied to audio data with pa_envelope_apply().
54 _apply() on one hand and _add()/_replace()/_remove() on the other
55 can be executed in seperate threads, in which case no locking is
59 PA_STATIC_FLIST_DECLARE(items
, 0, pa_xfree
);
61 struct pa_envelope_item
{
62 PA_LLIST_FIELDS(pa_envelope_item
);
63 const pa_envelope_def
*def
;
84 pa_sample_spec sample_spec
;
86 PA_LLIST_HEAD(pa_envelope_item
, items
);
93 unsigned n_points
, n_allocated
, n_current
;
104 pa_bool_t cached_valid
;
109 pa_semaphore
*semaphore
;
112 pa_envelope
*pa_envelope_new(const pa_sample_spec
*ss
) {
116 e
= pa_xnew(pa_envelope
, 1);
118 e
->sample_spec
= *ss
;
119 PA_LLIST_HEAD_INIT(pa_envelope_item
, e
->items
);
123 e
->points
[0].n_points
= e
->points
[1].n_points
= 0;
124 e
->points
[0].n_allocated
= e
->points
[1].n_allocated
= 0;
125 e
->points
[0].n_current
= e
->points
[1].n_current
= 0;
126 e
->points
[0].x
= e
->points
[1].x
= NULL
;
127 e
->points
[0].y
.i
= e
->points
[1].y
.i
= NULL
;
128 e
->points
[0].cached_valid
= e
->points
[1].cached_valid
= FALSE
;
130 pa_atomic_store(&e
->state
, STATE_VALID0
);
133 ss
->format
== PA_SAMPLE_FLOAT32LE
||
134 ss
->format
== PA_SAMPLE_FLOAT32BE
;
136 e
->semaphore
= pa_semaphore_new(0);
141 void pa_envelope_free(pa_envelope
*e
) {
145 pa_envelope_remove(e
, e
->items
);
147 pa_xfree(e
->points
[0].x
);
148 pa_xfree(e
->points
[1].x
);
149 pa_xfree(e
->points
[0].y
.i
);
150 pa_xfree(e
->points
[1].y
.i
);
152 pa_semaphore_free(e
->semaphore
);
157 static int32_t linear_interpolate_int(pa_usec_t x1
, int32_t _y1
, pa_usec_t x2
, int32_t y2
, pa_usec_t x3
) {
158 return (int32_t) (_y1
+ (x3
- x1
) * (float) (y2
- _y1
) / (float) (x2
- x1
));
161 static float linear_interpolate_float(pa_usec_t x1
, float _y1
, pa_usec_t x2
, float y2
, pa_usec_t x3
) {
162 return _y1
+ (x3
- x1
) * (y2
- _y1
) / (x2
- x1
);
165 static int32_t item_get_int(pa_envelope_item
*i
, pa_usec_t x
) {
173 if (x
<= i
->def
->points_x
[0])
174 return linear_interpolate_int(0, i
->start_y
.i
,
175 i
->def
->points_x
[0], i
->def
->points_y
.i
[0], x
);
177 if (x
>= i
->def
->points_x
[i
->def
->n_points
-1])
178 return i
->def
->points_y
.i
[i
->def
->n_points
-1];
181 pa_assert(i
->def
->points_x
[i
->j
-1] <= x
);
182 pa_assert(x
< i
->def
->points_x
[i
->j
]);
184 return linear_interpolate_int(i
->def
->points_x
[i
->j
-1], i
->def
->points_y
.i
[i
->j
-1],
185 i
->def
->points_x
[i
->j
], i
->def
->points_y
.i
[i
->j
], x
);
188 static float item_get_float(pa_envelope_item
*i
, pa_usec_t x
) {
196 if (x
<= i
->def
->points_x
[0])
197 return linear_interpolate_float(0, i
->start_y
.f
,
198 i
->def
->points_x
[0], i
->def
->points_y
.f
[0], x
);
200 if (x
>= i
->def
->points_x
[i
->def
->n_points
-1])
201 return i
->def
->points_y
.f
[i
->def
->n_points
-1];
204 pa_assert(i
->def
->points_x
[i
->j
-1] <= x
);
205 pa_assert(x
< i
->def
->points_x
[i
->j
]);
207 return linear_interpolate_float(i
->def
->points_x
[i
->j
-1], i
->def
->points_y
.f
[i
->j
-1],
208 i
->def
->points_x
[i
->j
], i
->def
->points_y
.f
[i
->j
], x
);
211 static void envelope_begin_write(pa_envelope
*e
, int *v
) {
212 enum envelope_state new_state
, old_state
;
221 old_state
= pa_atomic_load(&e
->state
);
226 new_state
= STATE_WRITE0
;
230 new_state
= STATE_WRITE1
;
233 new_state
= STATE_WAIT0
;
237 new_state
= STATE_WAIT1
;
241 pa_assert_not_reached();
243 } while (!pa_atomic_cmpxchg(&e
->state
, old_state
, new_state
));
248 pa_semaphore_wait(e
->semaphore
);
252 static pa_bool_t
envelope_commit_write(pa_envelope
*e
, int v
) {
253 enum envelope_state new_state
, old_state
;
258 old_state
= pa_atomic_load(&e
->state
);
263 new_state
= STATE_VALID1
;
267 new_state
= STATE_VALID0
;
275 pa_assert_not_reached();
277 } while (!pa_atomic_cmpxchg(&e
->state
, old_state
, new_state
));
282 static void envelope_begin_read(pa_envelope
*e
, int *v
) {
283 enum envelope_state new_state
, old_state
;
288 old_state
= pa_atomic_load(&e
->state
);
294 new_state
= STATE_READ0
;
299 new_state
= STATE_READ1
;
302 pa_assert_not_reached();
304 } while (!pa_atomic_cmpxchg(&e
->state
, old_state
, new_state
));
307 static void envelope_commit_read(pa_envelope
*e
, int v
) {
308 enum envelope_state new_state
, old_state
;
315 old_state
= pa_atomic_load(&e
->state
);
320 new_state
= STATE_VALID0
;
324 new_state
= STATE_VALID1
;
328 new_state
= STATE_VALID0
;
333 new_state
= STATE_VALID1
;
337 pa_assert_not_reached();
339 } while (!pa_atomic_cmpxchg(&e
->state
, old_state
, new_state
));
342 pa_semaphore_post(e
->semaphore
);
345 static void envelope_merge(pa_envelope
*e
, int v
) {
347 e
->points
[v
].n_points
= 0;
351 pa_usec_t x
= (pa_usec_t
) -1;
353 for (i
= e
->items
; i
; i
= i
->next
)
357 pa_bool_t min_is_set
;
358 pa_envelope_item
*s
= NULL
;
360 /* Let's find the next spot on the X axis to analyze */
361 for (i
= e
->items
; i
; i
= i
->next
) {
365 if (i
->j
>= i
->def
->n_points
)
368 if ((x
!= (pa_usec_t
) -1) && i
->start_x
+ i
->def
->points_x
[i
->j
] <= x
) {
373 if (!s
|| (i
->start_x
+ i
->def
->points_x
[i
->j
] < s
->start_x
+ s
->def
->points_x
[s
->j
]))
383 if (e
->points
[v
].n_points
>= e
->points
[v
].n_allocated
) {
384 e
->points
[v
].n_allocated
= PA_MAX(e
->points
[v
].n_points
*2, PA_ENVELOPE_POINTS_MAX
);
386 e
->points
[v
].x
= pa_xrealloc(e
->points
[v
].x
, sizeof(size_t) * e
->points
[v
].n_allocated
);
387 e
->points
[v
].y
.i
= pa_xrealloc(e
->points
[v
].y
.i
, sizeof(int32_t) * e
->points
[v
].n_allocated
);
390 x
= s
->start_x
+ s
->def
->points_x
[s
->j
];
391 e
->points
[v
].x
[e
->points
[v
].n_points
] = pa_usec_to_bytes(x
, &e
->sample_spec
);
395 /* Now let's find the lowest value */
399 for (i
= e
->items
; i
; i
= i
->next
) {
400 float f
= item_get_float(i
, x
);
401 if (!min_is_set
|| f
< min_f
) {
407 e
->points
[v
].y
.f
[e
->points
[v
].n_points
] = min_f
;
411 for (i
= e
->items
; i
; i
= i
->next
) {
412 int32_t k
= item_get_int(i
, x
);
413 if (!min_is_set
|| k
< min_k
) {
419 e
->points
[v
].y
.i
[e
->points
[v
].n_points
] = min_k
;
422 pa_assert_se(min_is_set
);
423 e
->points
[v
].n_points
++;
427 e
->points
[v
].n_current
= 0;
428 e
->points
[v
].cached_valid
= FALSE
;
431 pa_envelope_item
*pa_envelope_add(pa_envelope
*e
, const pa_envelope_def
*def
) {
437 pa_assert(def
->n_points
> 0);
439 if (!(i
= pa_flist_pop(PA_STATIC_FLIST_GET(items
))))
440 i
= pa_xnew(pa_envelope_item
, 1);
445 i
->start_y
.f
= def
->points_y
.f
[0];
447 i
->start_y
.i
= def
->points_y
.i
[0];
449 PA_LLIST_PREPEND(pa_envelope_item
, e
->items
, i
);
451 envelope_begin_write(e
, &v
);
455 i
->start_x
= pa_bytes_to_usec(e
->x
, &e
->sample_spec
);
456 envelope_merge(e
, v
);
458 } while (!envelope_commit_write(e
, v
));
463 pa_envelope_item
*pa_envelope_replace(pa_envelope
*e
, pa_envelope_item
*i
, const pa_envelope_def
*def
) {
469 pa_assert(def
->n_points
> 0);
471 envelope_begin_write(e
, &v
);
476 uint64_t saved_start_x
;
477 const pa_envelope_def
*saved_def
;
479 x
= pa_bytes_to_usec(e
->x
, &e
->sample_spec
);
482 saved_f
= i
->start_y
.f
;
483 i
->start_y
.f
= item_get_float(i
, x
);
485 saved_i
= i
->start_y
.i
;
486 i
->start_y
.i
= item_get_int(i
, x
);
489 saved_start_x
= i
->start_x
;
495 envelope_merge(e
, v
);
497 if (envelope_commit_write(e
, v
))
500 i
->start_x
= saved_start_x
;
504 i
->start_y
.f
= saved_f
;
506 i
->start_y
.i
= saved_i
;
512 void pa_envelope_remove(pa_envelope
*e
, pa_envelope_item
*i
) {
518 PA_LLIST_REMOVE(pa_envelope_item
, e
->items
, i
);
520 if (pa_flist_push(PA_STATIC_FLIST_GET(items
), i
) < 0)
523 envelope_begin_write(e
, &v
);
525 envelope_merge(e
, v
);
526 } while (!envelope_commit_write(e
, v
));
529 static int32_t linear_get_int(pa_envelope
*e
, int v
) {
532 /* The repeated division could be replaced by Bresenham, as an
535 if (e
->x
< e
->points
[v
].x
[0])
536 return e
->points
[v
].y
.i
[0];
539 if (e
->points
[v
].n_current
+1 >= e
->points
[v
].n_points
)
540 return e
->points
[v
].y
.i
[e
->points
[v
].n_points
-1];
542 if (e
->x
< e
->points
[v
].x
[e
->points
[v
].n_current
+1])
545 e
->points
[v
].n_current
++;
546 e
->points
[v
].cached_valid
= FALSE
;
549 if (!e
->points
[v
].cached_valid
) {
550 e
->points
[v
].cached_dx
= e
->points
[v
].x
[e
->points
[v
].n_current
+1] - e
->points
[v
].x
[e
->points
[v
].n_current
];
551 e
->points
[v
].cached_dy_i
= e
->points
[v
].y
.i
[e
->points
[v
].n_current
+1] - e
->points
[v
].y
.i
[e
->points
[v
].n_current
];
552 e
->points
[v
].cached_valid
= TRUE
;
555 return e
->points
[v
].y
.i
[e
->points
[v
].n_current
] + (e
->points
[v
].cached_dy_i
* (int32_t) (e
->x
- e
->points
[v
].x
[e
->points
[v
].n_current
])) / (int32_t) e
->points
[v
].cached_dx
;
558 static float linear_get_float(pa_envelope
*e
, int v
) {
561 if (e
->x
< e
->points
[v
].x
[0])
562 return e
->points
[v
].y
.f
[0];
565 if (e
->points
[v
].n_current
+1 >= e
->points
[v
].n_points
)
566 return e
->points
[v
].y
.f
[e
->points
[v
].n_points
-1];
568 if (e
->x
< e
->points
[v
].x
[e
->points
[v
].n_current
+1])
571 e
->points
[v
].n_current
++;
572 e
->points
[v
].cached_valid
= FALSE
;
575 if (!e
->points
[v
].cached_valid
) {
576 e
->points
[v
].cached_dy_dx
=
577 (e
->points
[v
].y
.f
[e
->points
[v
].n_current
+1] - e
->points
[v
].y
.f
[e
->points
[v
].n_current
]) /
578 (e
->points
[v
].x
[e
->points
[v
].n_current
+1] - e
->points
[v
].x
[e
->points
[v
].n_current
]);
579 e
->points
[v
].cached_valid
= TRUE
;
582 return e
->points
[v
].y
.f
[e
->points
[v
].n_current
] + (e
->x
- e
->points
[v
].x
[e
->points
[v
].n_current
]) * e
->points
[v
].cached_dy_dx
;
585 void pa_envelope_apply(pa_envelope
*e
, pa_memchunk
*chunk
) {
591 envelope_begin_read(e
, &v
);
593 if (e
->points
[v
].n_points
> 0) {
597 pa_memchunk_make_writable(chunk
, 0);
598 p
= (uint8_t*) pa_memblock_acquire(chunk
->memblock
) + chunk
->index
;
599 fs
= pa_frame_size(&e
->sample_spec
);
602 switch (e
->sample_spec
.format
) {
609 for (t
= p
; n
> 0; n
-= fs
) {
610 int16_t factor
= linear_get_int(e
, v
);
614 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++)
615 *t
= (uint8_t) (((factor
* ((int16_t) *t
- 0x80)) / 0x10000) + 0x80);
621 case PA_SAMPLE_ULAW
: {
624 for (t
= p
; n
> 0; n
-= fs
) {
625 int16_t factor
= linear_get_int(e
, v
);
629 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++) {
630 int16_t k
= st_ulaw2linear16(*t
);
631 *t
= (uint8_t) st_14linear2ulaw(((factor
* k
) / 0x10000) >> 2);
638 case PA_SAMPLE_ALAW
: {
641 for (t
= p
; n
> 0; n
-= fs
) {
642 int16_t factor
= linear_get_int(e
, v
);
646 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++) {
647 int16_t k
= st_alaw2linear16(*t
);
648 *t
= (uint8_t) st_13linear2alaw(((factor
* k
) / 0x10000) >> 3);
655 case PA_SAMPLE_S16NE
: {
658 for (t
= p
; n
> 0; n
-= fs
) {
659 int32_t factor
= linear_get_int(e
, v
);
663 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++)
664 *t
= (factor
* *t
) / 0x10000;
670 case PA_SAMPLE_S16RE
: {
673 for (t
= p
; n
> 0; n
-= fs
) {
674 int32_t factor
= linear_get_int(e
, v
);
678 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++) {
679 int16_t r
= (factor
* PA_INT16_SWAP(*t
)) / 0x10000;
680 *t
= PA_INT16_SWAP(r
);
687 case PA_SAMPLE_S32NE
: {
690 for (t
= p
; n
> 0; n
-= fs
) {
691 int32_t factor
= linear_get_int(e
, v
);
695 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++)
696 *t
= (int32_t) (((int64_t) factor
* (int64_t) *t
) / 0x10000);
702 case PA_SAMPLE_S32RE
: {
705 for (t
= p
; n
> 0; n
-= fs
) {
706 int32_t factor
= linear_get_int(e
, v
);
710 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++) {
711 int32_t r
= (int32_t) (((int64_t) factor
* (int64_t) PA_INT32_SWAP(*t
)) / 0x10000);
712 *t
= PA_INT32_SWAP(r
);
719 case PA_SAMPLE_FLOAT32NE
: {
722 for (t
= p
; n
> 0; n
-= fs
) {
723 float factor
= linear_get_float(e
, v
);
727 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++)
734 case PA_SAMPLE_FLOAT32RE
: {
737 for (t
= p
; n
> 0; n
-= fs
) {
738 float factor
= linear_get_float(e
, v
);
742 for (c
= 0; c
< e
->sample_spec
.channels
; c
++, t
++) {
743 float r
= PA_FLOAT32_SWAP(*t
) * factor
;
744 *t
= PA_FLOAT32_SWAP(r
);
752 case PA_SAMPLE_INVALID
:
753 pa_assert_not_reached();
756 pa_memblock_release(chunk
->memblock
);
758 e
->x
+= chunk
->length
;
760 /* When we have no envelope to apply we reset our origin */
764 envelope_commit_read(e
, v
);
767 void pa_envelope_rewind(pa_envelope
*e
, size_t n_bytes
) {
772 envelope_begin_read(e
, &v
);
779 e
->points
[v
].n_current
= 0;
780 e
->points
[v
].cached_valid
= FALSE
;
782 envelope_commit_read(e
, v
);