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) {
607
for (t = p; n > 0; n -= fs) {
608
int32_t factor = linear_get_int(e, v);
612
for (c = 0; c < e->sample_spec.channels; c++, t++)
613
*t = (uint8_t) (((factor * ((int16_t) *t - 0x80)) / 0x10000) + 0x80);
619
case PA_SAMPLE_ULAW: {
622
for (t = p; n > 0; n -= fs) {
623
int32_t factor = linear_get_int(e, v);
627
for (c = 0; c < e->sample_spec.channels; c++, t++) {
628
int16_t k = st_ulaw2linear16(*t);
629
*t = (uint8_t) st_14linear2ulaw((int16_t) (((factor * k) / 0x10000) >> 2));
636
case PA_SAMPLE_ALAW: {
639
for (t = p; n > 0; n -= fs) {
640
int32_t factor = linear_get_int(e, v);
644
for (c = 0; c < e->sample_spec.channels; c++, t++) {
645
int16_t k = st_alaw2linear16(*t);
646
*t = (uint8_t) st_13linear2alaw((int16_t) (((factor * k) / 0x10000) >> 3));
653
case PA_SAMPLE_S16NE: {
656
for (t = p; n > 0; n -= fs) {
657
int32_t factor = linear_get_int(e, v);
661
for (c = 0; c < e->sample_spec.channels; c++, t++)
662
*t = (int16_t) ((factor * *t) / 0x10000);
668
case PA_SAMPLE_S16RE: {
671
for (t = p; n > 0; n -= fs) {
672
int32_t factor = linear_get_int(e, v);
676
for (c = 0; c < e->sample_spec.channels; c++, t++) {
677
int16_t r = (int16_t) ((factor * PA_INT16_SWAP(*t)) / 0x10000);
678
*t = PA_INT16_SWAP(r);
685
case PA_SAMPLE_S32NE: {
688
for (t = p; n > 0; n -= fs) {
689
int32_t factor = linear_get_int(e, v);
693
for (c = 0; c < e->sample_spec.channels; c++, t++)
694
*t = (int32_t) (((int64_t) factor * (int64_t) *t) / 0x10000);
700
case PA_SAMPLE_S32RE: {
703
for (t = p; n > 0; n -= fs) {
704
int32_t factor = linear_get_int(e, v);
708
for (c = 0; c < e->sample_spec.channels; c++, t++) {
709
int32_t r = (int32_t) (((int64_t) factor * (int64_t) PA_INT32_SWAP(*t)) / 0x10000);
710
*t = PA_INT32_SWAP(r);
717
case PA_SAMPLE_FLOAT32NE: {
720
for (t = p; n > 0; n -= fs) {
721
float factor = linear_get_float(e, v);
725
for (c = 0; c < e->sample_spec.channels; c++, t++)
732
case PA_SAMPLE_FLOAT32RE: {
735
for (t = p; n > 0; n -= fs) {
736
float factor = linear_get_float(e, v);
740
for (c = 0; c < e->sample_spec.channels; c++, t++) {
741
float r = PA_FLOAT32_SWAP(*t) * factor;
742
*t = PA_FLOAT32_SWAP(r);
750
case PA_SAMPLE_INVALID:
751
pa_assert_not_reached();
754
pa_memblock_release(chunk->memblock);
756
e->x += chunk->length;
758
/* When we have no envelope to apply we reset our origin */
762
envelope_commit_read(e, v);
765
void pa_envelope_rewind(pa_envelope *e, size_t n_bytes) {
770
envelope_begin_read(e, &v);
777
e->points[v].n_current = 0;
778
e->points[v].cached_valid = FALSE;
780
envelope_commit_read(e, v);