2 This file is part of PulseAudio.
4 Copyright 2007 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 #include <pulse/sample.h>
29 #include <pulse/xmalloc.h>
31 #include <pulsecore/endianmacros.h>
32 #include <pulsecore/memchunk.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/flist.h>
35 #include <pulsecore/semaphore.h>
36 #include <pulsecore/g711.h>
41 Envelope subsystem for applying linear interpolated volume
42 envelopes on audio data. If multiple enevelopes shall be applied
43 at the same time, the "minimum" envelope is determined and
46 Envelopes are defined in a statically allocated constant structure
47 pa_envelope_def. It may be activated using pa_envelope_add(). And
48 already active envelope may be replaced with pa_envelope_replace()
49 and removed with pa_envelope_remove().The combined "minimum"
50 envelope can be applied to audio data with pa_envelope_apply().
52 _apply() on one hand and _add()/_replace()/_remove() on the other
53 can be executed in seperate threads, in which case no locking is
57 PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
59 struct pa_envelope_item {
60 PA_LLIST_FIELDS(pa_envelope_item);
61 const pa_envelope_def *def;
82 pa_sample_spec sample_spec;
84 PA_LLIST_HEAD(pa_envelope_item, items);
91 unsigned n_points, n_allocated, n_current;
102 pa_bool_t cached_valid;
107 pa_semaphore *semaphore;
110 pa_envelope *pa_envelope_new(const pa_sample_spec *ss) {
114 e = pa_xnew(pa_envelope, 1);
116 e->sample_spec = *ss;
117 PA_LLIST_HEAD_INIT(pa_envelope_item, e->items);
121 e->points[0].n_points = e->points[1].n_points = 0;
122 e->points[0].n_allocated = e->points[1].n_allocated = 0;
123 e->points[0].n_current = e->points[1].n_current = 0;
124 e->points[0].x = e->points[1].x = NULL;
125 e->points[0].y.i = e->points[1].y.i = NULL;
126 e->points[0].cached_valid = e->points[1].cached_valid = FALSE;
128 pa_atomic_store(&e->state, STATE_VALID0);
131 ss->format == PA_SAMPLE_FLOAT32LE ||
132 ss->format == PA_SAMPLE_FLOAT32BE;
134 e->semaphore = pa_semaphore_new(0);
139 void pa_envelope_free(pa_envelope *e) {
143 pa_envelope_remove(e, e->items);
145 pa_xfree(e->points[0].x);
146 pa_xfree(e->points[1].x);
147 pa_xfree(e->points[0].y.i);
148 pa_xfree(e->points[1].y.i);
150 pa_semaphore_free(e->semaphore);
155 static int32_t linear_interpolate_int(pa_usec_t x1, int32_t _y1, pa_usec_t x2, int32_t y2, pa_usec_t x3) {
156 return (int32_t) ((double) _y1 + (double) (x3 - x1) * (double) (y2 - _y1) / (double) (x2 - x1));
159 static float linear_interpolate_float(pa_usec_t x1, float _y1, pa_usec_t x2, float y2, pa_usec_t x3) {
160 return _y1 + ((float) x3 - (float) x1) * (y2 - _y1) / ((float) x2 - (float) x1);
163 static int32_t item_get_int(pa_envelope_item *i, pa_usec_t x) {
171 if (x <= i->def->points_x[0])
172 return linear_interpolate_int(0, i->start_y.i,
173 i->def->points_x[0], i->def->points_y.i[0], x);
175 if (x >= i->def->points_x[i->def->n_points-1])
176 return i->def->points_y.i[i->def->n_points-1];
179 pa_assert(i->def->points_x[i->j-1] <= x);
180 pa_assert(x < i->def->points_x[i->j]);
182 return linear_interpolate_int(i->def->points_x[i->j-1], i->def->points_y.i[i->j-1],
183 i->def->points_x[i->j], i->def->points_y.i[i->j], x);
186 static float item_get_float(pa_envelope_item *i, pa_usec_t x) {
194 if (x <= i->def->points_x[0])
195 return linear_interpolate_float(0, i->start_y.f,
196 i->def->points_x[0], i->def->points_y.f[0], x);
198 if (x >= i->def->points_x[i->def->n_points-1])
199 return i->def->points_y.f[i->def->n_points-1];
202 pa_assert(i->def->points_x[i->j-1] <= x);
203 pa_assert(x < i->def->points_x[i->j]);
205 return linear_interpolate_float(i->def->points_x[i->j-1], i->def->points_y.f[i->j-1],
206 i->def->points_x[i->j], i->def->points_y.f[i->j], x);
209 static void envelope_begin_write(pa_envelope *e, int *v) {
210 enum envelope_state new_state, old_state;
219 old_state = pa_atomic_load(&e->state);
224 new_state = STATE_WRITE0;
228 new_state = STATE_WRITE1;
231 new_state = STATE_WAIT0;
235 new_state = STATE_WAIT1;
239 pa_assert_not_reached();
241 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
246 pa_semaphore_wait(e->semaphore);
250 static pa_bool_t envelope_commit_write(pa_envelope *e, int v) {
251 enum envelope_state new_state, old_state;
256 old_state = pa_atomic_load(&e->state);
261 new_state = STATE_VALID1;
265 new_state = STATE_VALID0;
273 pa_assert_not_reached();
275 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
280 static void envelope_begin_read(pa_envelope *e, int *v) {
281 enum envelope_state new_state, old_state;
286 old_state = pa_atomic_load(&e->state);
292 new_state = STATE_READ0;
297 new_state = STATE_READ1;
300 pa_assert_not_reached();
302 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
305 static void envelope_commit_read(pa_envelope *e, int v) {
306 enum envelope_state new_state, old_state;
313 old_state = pa_atomic_load(&e->state);
318 new_state = STATE_VALID0;
322 new_state = STATE_VALID1;
326 new_state = STATE_VALID0;
331 new_state = STATE_VALID1;
335 pa_assert_not_reached();
337 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
340 pa_semaphore_post(e->semaphore);
343 static void envelope_merge(pa_envelope *e, int v) {
345 e->points[v].n_points = 0;
349 pa_usec_t x = (pa_usec_t) -1;
351 for (i = e->items; i; i = i->next)
355 pa_bool_t min_is_set;
356 pa_envelope_item *s = NULL;
358 /* Let's find the next spot on the X axis to analyze */
359 for (i = e->items; i; i = i->next) {
363 if (i->j >= i->def->n_points)
366 if ((x != (pa_usec_t) -1) && i->start_x + i->def->points_x[i->j] <= x) {
371 if (!s || (i->start_x + i->def->points_x[i->j] < s->start_x + s->def->points_x[s->j]))
381 if (e->points[v].n_points >= e->points[v].n_allocated) {
382 e->points[v].n_allocated = PA_MAX(e->points[v].n_points*2, PA_ENVELOPE_POINTS_MAX);
384 e->points[v].x = pa_xrealloc(e->points[v].x, sizeof(size_t) * e->points[v].n_allocated);
385 e->points[v].y.i = pa_xrealloc(e->points[v].y.i, sizeof(int32_t) * e->points[v].n_allocated);
388 x = s->start_x + s->def->points_x[s->j];
389 e->points[v].x[e->points[v].n_points] = pa_usec_to_bytes(x, &e->sample_spec);
393 /* Now let's find the lowest value */
397 for (i = e->items; i; i = i->next) {
398 float f = item_get_float(i, x);
399 if (!min_is_set || f < min_f) {
405 e->points[v].y.f[e->points[v].n_points] = min_f;
409 for (i = e->items; i; i = i->next) {
410 int32_t k = item_get_int(i, x);
411 if (!min_is_set || k < min_k) {
417 e->points[v].y.i[e->points[v].n_points] = min_k;
420 pa_assert_se(min_is_set);
421 e->points[v].n_points++;
425 e->points[v].n_current = 0;
426 e->points[v].cached_valid = FALSE;
429 pa_envelope_item *pa_envelope_add(pa_envelope *e, const pa_envelope_def *def) {
435 pa_assert(def->n_points > 0);
437 if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
438 i = pa_xnew(pa_envelope_item, 1);
443 i->start_y.f = def->points_y.f[0];
445 i->start_y.i = def->points_y.i[0];
447 PA_LLIST_PREPEND(pa_envelope_item, e->items, i);
449 envelope_begin_write(e, &v);
453 i->start_x = pa_bytes_to_usec(e->x, &e->sample_spec);
454 envelope_merge(e, v);
456 } while (!envelope_commit_write(e, v));
461 pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const pa_envelope_def *def) {
467 pa_assert(def->n_points > 0);
469 envelope_begin_write(e, &v);
474 uint64_t saved_start_x;
475 const pa_envelope_def *saved_def;
477 x = pa_bytes_to_usec(e->x, &e->sample_spec);
480 saved_f = i->start_y.f;
481 i->start_y.f = item_get_float(i, x);
483 saved_i = i->start_y.i;
484 i->start_y.i = item_get_int(i, x);
487 saved_start_x = i->start_x;
493 envelope_merge(e, v);
495 if (envelope_commit_write(e, v))
498 i->start_x = saved_start_x;
502 i->start_y.f = saved_f;
504 i->start_y.i = saved_i;
510 void pa_envelope_remove(pa_envelope *e, pa_envelope_item *i) {
516 PA_LLIST_REMOVE(pa_envelope_item, e->items, i);
518 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
521 envelope_begin_write(e, &v);
523 envelope_merge(e, v);
524 } while (!envelope_commit_write(e, v));
527 static int32_t linear_get_int(pa_envelope *e, int v) {
530 /* The repeated division could be replaced by Bresenham, as an
533 if (e->x < e->points[v].x[0])
534 return e->points[v].y.i[0];
537 if (e->points[v].n_current+1 >= e->points[v].n_points)
538 return e->points[v].y.i[e->points[v].n_points-1];
540 if (e->x < e->points[v].x[e->points[v].n_current+1])
543 e->points[v].n_current++;
544 e->points[v].cached_valid = FALSE;
547 if (!e->points[v].cached_valid) {
548 e->points[v].cached_dx = e->points[v].x[e->points[v].n_current+1] - e->points[v].x[e->points[v].n_current];
549 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];
550 e->points[v].cached_valid = TRUE;
553 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;
556 static float linear_get_float(pa_envelope *e, int v) {
559 if (e->x < e->points[v].x[0])
560 return e->points[v].y.f[0];
563 if (e->points[v].n_current+1 >= e->points[v].n_points)
564 return e->points[v].y.f[e->points[v].n_points-1];
566 if (e->x < e->points[v].x[e->points[v].n_current+1])
569 e->points[v].n_current++;
570 e->points[v].cached_valid = FALSE;
573 if (!e->points[v].cached_valid) {
574 e->points[v].cached_dy_dx =
575 (e->points[v].y.f[e->points[v].n_current+1] - e->points[v].y.f[e->points[v].n_current]) /
576 ((float) e->points[v].x[e->points[v].n_current+1] - (float) e->points[v].x[e->points[v].n_current]);
577 e->points[v].cached_valid = TRUE;
580 return e->points[v].y.f[e->points[v].n_current] + (float) (e->x - e->points[v].x[e->points[v].n_current]) * e->points[v].cached_dy_dx;
583 void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) {
589 envelope_begin_read(e, &v);
591 if (e->points[v].n_points > 0) {
595 pa_memchunk_make_writable(chunk, 0);
596 p = (uint8_t*) pa_memblock_acquire(chunk->memblock) + chunk->index;
597 fs = pa_frame_size(&e->sample_spec);
600 switch (e->sample_spec.format) {
605 for (t = p; n > 0; n -= fs) {
606 int32_t factor = linear_get_int(e, v);
610 for (c = 0; c < e->sample_spec.channels; c++, t++)
611 *t = (uint8_t) (((factor * ((int16_t) *t - 0x80)) / 0x10000) + 0x80);
617 case PA_SAMPLE_ULAW: {
620 for (t = p; n > 0; n -= fs) {
621 int32_t factor = linear_get_int(e, v);
625 for (c = 0; c < e->sample_spec.channels; c++, t++) {
626 int16_t k = st_ulaw2linear16(*t);
627 *t = (uint8_t) st_14linear2ulaw((int16_t) (((factor * k) / 0x10000) >> 2));
634 case PA_SAMPLE_ALAW: {
637 for (t = p; n > 0; n -= fs) {
638 int32_t factor = linear_get_int(e, v);
642 for (c = 0; c < e->sample_spec.channels; c++, t++) {
643 int16_t k = st_alaw2linear16(*t);
644 *t = (uint8_t) st_13linear2alaw((int16_t) (((factor * k) / 0x10000) >> 3));
651 case PA_SAMPLE_S16NE: {
654 for (t = p; n > 0; n -= fs) {
655 int32_t factor = linear_get_int(e, v);
659 for (c = 0; c < e->sample_spec.channels; c++, t++)
660 *t = (int16_t) ((factor * *t) / 0x10000);
666 case PA_SAMPLE_S16RE: {
669 for (t = p; n > 0; n -= fs) {
670 int32_t factor = linear_get_int(e, v);
674 for (c = 0; c < e->sample_spec.channels; c++, t++) {
675 int16_t r = (int16_t) ((factor * PA_INT16_SWAP(*t)) / 0x10000);
676 *t = PA_INT16_SWAP(r);
683 case PA_SAMPLE_S32NE: {
686 for (t = p; n > 0; n -= fs) {
687 int32_t factor = linear_get_int(e, v);
691 for (c = 0; c < e->sample_spec.channels; c++, t++)
692 *t = (int32_t) (((int64_t) factor * (int64_t) *t) / 0x10000);
698 case PA_SAMPLE_S32RE: {
701 for (t = p; n > 0; n -= fs) {
702 int32_t factor = linear_get_int(e, v);
706 for (c = 0; c < e->sample_spec.channels; c++, t++) {
707 int32_t r = (int32_t) (((int64_t) factor * (int64_t) PA_INT32_SWAP(*t)) / 0x10000);
708 *t = PA_INT32_SWAP(r);
715 case PA_SAMPLE_FLOAT32NE: {
718 for (t = p; n > 0; n -= fs) {
719 float factor = linear_get_float(e, v);
723 for (c = 0; c < e->sample_spec.channels; c++, t++)
730 case PA_SAMPLE_FLOAT32RE: {
733 for (t = p; n > 0; n -= fs) {
734 float factor = linear_get_float(e, v);
738 for (c = 0; c < e->sample_spec.channels; c++, t++) {
739 float r = PA_FLOAT32_SWAP(*t) * factor;
740 *t = PA_FLOAT32_SWAP(r);
747 case PA_SAMPLE_S24LE:
748 case PA_SAMPLE_S24BE:
749 case PA_SAMPLE_S24_32LE:
750 case PA_SAMPLE_S24_32BE:
752 pa_assert_not_reached();
755 case PA_SAMPLE_INVALID:
756 pa_assert_not_reached();
759 pa_memblock_release(chunk->memblock);
761 e->x += chunk->length;
763 /* When we have no envelope to apply we reset our origin */
767 envelope_commit_read(e, v);
770 void pa_envelope_rewind(pa_envelope *e, size_t n_bytes) {
775 envelope_begin_read(e, &v);
782 e->points[v].n_current = 0;
783 e->points[v].cached_valid = FALSE;
785 envelope_commit_read(e, v);