virtual: minor simplifications for the virtual sink
[pulseaudio-mirror.git] / src / pulsecore / envelope.c
blob75e189cb5915450d63894755ae0a57c3e308c851
1 /***
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
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdio.h>
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>
38 #include "envelope.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
44 applied.
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
54 used.
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;
62 pa_usec_t start_x;
63 union {
64 int32_t i;
65 float f;
66 } start_y;
67 unsigned j;
70 enum envelope_state {
71 STATE_VALID0,
72 STATE_VALID1,
73 STATE_READ0,
74 STATE_READ1,
75 STATE_WAIT0,
76 STATE_WAIT1,
77 STATE_WRITE0,
78 STATE_WRITE1
81 struct pa_envelope {
82 pa_sample_spec sample_spec;
84 PA_LLIST_HEAD(pa_envelope_item, items);
86 pa_atomic_t state;
88 size_t x;
90 struct {
91 unsigned n_points, n_allocated, n_current;
93 size_t *x;
94 union {
95 int32_t *i;
96 float *f;
97 } y;
99 size_t cached_dx;
100 int32_t cached_dy_i;
101 float cached_dy_dx;
102 pa_bool_t cached_valid;
103 } points[2];
105 pa_bool_t is_float;
107 pa_semaphore *semaphore;
110 pa_envelope *pa_envelope_new(const pa_sample_spec *ss) {
111 pa_envelope *e;
112 pa_assert(ss);
114 e = pa_xnew(pa_envelope, 1);
116 e->sample_spec = *ss;
117 PA_LLIST_HEAD_INIT(pa_envelope_item, e->items);
119 e->x = 0;
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);
130 e->is_float =
131 ss->format == PA_SAMPLE_FLOAT32LE ||
132 ss->format == PA_SAMPLE_FLOAT32BE;
134 e->semaphore = pa_semaphore_new(0);
136 return e;
139 void pa_envelope_free(pa_envelope *e) {
140 pa_assert(e);
142 while (e->items)
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);
152 pa_xfree(e);
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) {
164 pa_assert(i);
166 if (x <= i->start_x)
167 return i->start_y.i;
169 x -= i->start_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];
178 pa_assert(i->j > 0);
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) {
187 pa_assert(i);
189 if (x <= i->start_x)
190 return i->start_y.f;
192 x -= i->start_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];
201 pa_assert(i->j > 0);
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;
211 pa_bool_t wait_sem;
213 pa_assert(e);
214 pa_assert(v);
216 for (;;) {
217 do {
218 wait_sem = FALSE;
219 old_state = pa_atomic_load(&e->state);
221 switch (old_state) {
222 case STATE_VALID0:
223 *v = 1;
224 new_state = STATE_WRITE0;
225 break;
226 case STATE_VALID1:
227 *v = 0;
228 new_state = STATE_WRITE1;
229 break;
230 case STATE_READ0:
231 new_state = STATE_WAIT0;
232 wait_sem = TRUE;
233 break;
234 case STATE_READ1:
235 new_state = STATE_WAIT1;
236 wait_sem = TRUE;
237 break;
238 default:
239 pa_assert_not_reached();
241 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
243 if (!wait_sem)
244 break;
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;
253 pa_assert(e);
255 do {
256 old_state = pa_atomic_load(&e->state);
258 switch (old_state) {
259 case STATE_WRITE0:
260 pa_assert(v == 1);
261 new_state = STATE_VALID1;
262 break;
263 case STATE_WRITE1:
264 pa_assert(v == 0);
265 new_state = STATE_VALID0;
266 break;
267 case STATE_VALID0:
268 case STATE_VALID1:
269 case STATE_READ0:
270 case STATE_READ1:
271 return FALSE;
272 default:
273 pa_assert_not_reached();
275 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
277 return TRUE;
280 static void envelope_begin_read(pa_envelope *e, int *v) {
281 enum envelope_state new_state, old_state;
282 pa_assert(e);
283 pa_assert(v);
285 do {
286 old_state = pa_atomic_load(&e->state);
288 switch (old_state) {
289 case STATE_VALID0:
290 case STATE_WRITE0:
291 *v = 0;
292 new_state = STATE_READ0;
293 break;
294 case STATE_VALID1:
295 case STATE_WRITE1:
296 *v = 1;
297 new_state = STATE_READ1;
298 break;
299 default:
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;
307 pa_bool_t post_sem;
309 pa_assert(e);
311 do {
312 post_sem = FALSE;
313 old_state = pa_atomic_load(&e->state);
315 switch (old_state) {
316 case STATE_READ0:
317 pa_assert(v == 0);
318 new_state = STATE_VALID0;
319 break;
320 case STATE_READ1:
321 pa_assert(v == 1);
322 new_state = STATE_VALID1;
323 break;
324 case STATE_WAIT0:
325 pa_assert(v == 0);
326 new_state = STATE_VALID0;
327 post_sem = TRUE;
328 break;
329 case STATE_WAIT1:
330 pa_assert(v == 1);
331 new_state = STATE_VALID1;
332 post_sem = TRUE;
333 break;
334 default:
335 pa_assert_not_reached();
337 } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
339 if (post_sem)
340 pa_semaphore_post(e->semaphore);
343 static void envelope_merge(pa_envelope *e, int v) {
345 e->points[v].n_points = 0;
347 if (e->items) {
348 pa_envelope_item *i;
349 pa_usec_t x = (pa_usec_t) -1;
351 for (i = e->items; i; i = i->next)
352 i->j = 0;
354 for (;;) {
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) {
361 for (;;) {
363 if (i->j >= i->def->n_points)
364 break;
366 if ((x != (pa_usec_t) -1) && i->start_x + i->def->points_x[i->j] <= x) {
367 i->j++;
368 continue;
371 if (!s || (i->start_x + i->def->points_x[i->j] < s->start_x + s->def->points_x[s->j]))
372 s = i;
374 break;
378 if (!s)
379 break;
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);
391 min_is_set = FALSE;
393 /* Now let's find the lowest value */
394 if (e->is_float) {
395 float min_f;
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) {
400 min_f = f;
401 min_is_set = TRUE;
405 e->points[v].y.f[e->points[v].n_points] = min_f;
406 } else {
407 int32_t min_k;
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) {
412 min_k = k;
413 min_is_set = TRUE;
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) {
430 pa_envelope_item *i;
431 int v;
433 pa_assert(e);
434 pa_assert(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);
440 i->def = def;
442 if (e->is_float)
443 i->start_y.f = def->points_y.f[0];
444 else
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);
451 do {
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));
458 return i;
461 pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const pa_envelope_def *def) {
462 pa_usec_t x;
463 int v;
465 pa_assert(e);
466 pa_assert(i);
467 pa_assert(def->n_points > 0);
469 envelope_begin_write(e, &v);
471 for (;;) {
472 float saved_f;
473 int32_t saved_i;
474 uint64_t saved_start_x;
475 const pa_envelope_def *saved_def;
477 x = pa_bytes_to_usec(e->x, &e->sample_spec);
479 if (e->is_float) {
480 saved_f = i->start_y.f;
481 i->start_y.f = item_get_float(i, x);
482 } else {
483 saved_i = i->start_y.i;
484 i->start_y.i = item_get_int(i, x);
487 saved_start_x = i->start_x;
488 saved_def = i->def;
490 i->start_x = x;
491 i->def = def;
493 envelope_merge(e, v);
495 if (envelope_commit_write(e, v))
496 break;
498 i->start_x = saved_start_x;
499 i->def = saved_def;
501 if (e->is_float)
502 i->start_y.f = saved_f;
503 else
504 i->start_y.i = saved_i;
507 return i;
510 void pa_envelope_remove(pa_envelope *e, pa_envelope_item *i) {
511 int v;
513 pa_assert(e);
514 pa_assert(i);
516 PA_LLIST_REMOVE(pa_envelope_item, e->items, i);
518 if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
519 pa_xfree(i);
521 envelope_begin_write(e, &v);
522 do {
523 envelope_merge(e, v);
524 } while (!envelope_commit_write(e, v));
527 static int32_t linear_get_int(pa_envelope *e, int v) {
528 pa_assert(e);
530 /* The repeated division could be replaced by Bresenham, as an
531 * optimization */
533 if (e->x < e->points[v].x[0])
534 return e->points[v].y.i[0];
536 for (;;) {
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])
541 break;
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] + ((float)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) {
557 pa_assert(e);
559 if (e->x < e->points[v].x[0])
560 return e->points[v].y.f[0];
562 for (;;) {
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])
567 break;
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) {
584 int v;
586 pa_assert(e);
587 pa_assert(chunk);
589 envelope_begin_read(e, &v);
591 if (e->points[v].n_points > 0) {
592 void *p;
593 size_t fs, n;
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);
598 n = chunk->length;
600 pa_log_debug("Envelop position %zu applying factor %d=%f, sample spec is %d, chunk's length is %zu, fs is %zu\n", e->x, linear_get_int(e, v), ((float) linear_get_int(e,v))/0x10000, e->sample_spec.format, n, fs);
602 switch (e->sample_spec.format) {
604 case PA_SAMPLE_U8: {
605 uint8_t *d, *s;
606 unsigned channel;
607 int32_t factor = linear_get_int(e, v);
609 s = (uint8_t*) p + n;
611 for (channel = 0, d = p; d < s; d++) {
612 int32_t t, hi, lo;
614 hi = factor >> 16;
615 lo = factor & 0xFFFF;
617 t = (int32_t) *d - 0x80;
618 t = ((t * lo) >> 16) + (t * hi);
619 t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
620 *d = (uint8_t) (t + 0x80);
622 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
623 channel = 0;
624 e->x += fs;
625 factor = linear_get_int(e, v);
629 break;
632 case PA_SAMPLE_ULAW: {
633 uint8_t *d, *s;
634 unsigned channel;
635 int32_t factor = linear_get_int(e, v);
637 s = (uint8_t*) p + n;
639 for (channel = 0, d = p; d < s; d++) {
640 int32_t t, hi, lo;
642 hi = factor >> 16;
643 lo = factor & 0xFFFF;
645 t = (int32_t) st_ulaw2linear16(*d);
646 t = ((t * lo) >> 16) + (t * hi);
647 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
648 *d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2);
650 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
651 channel = 0;
652 e->x += fs;
653 factor = linear_get_int(e, v);
657 break;
660 case PA_SAMPLE_ALAW: {
661 uint8_t *d, *s;
662 unsigned channel;
663 int32_t factor = linear_get_int(e, v);
665 s = (uint8_t*) p + n;
667 for (channel = 0, d = p; d < s; d++) {
668 int32_t t, hi, lo;
670 hi = factor >> 16;
671 lo = factor & 0xFFFF;
673 t = (int32_t) st_alaw2linear16(*d);
674 t = ((t * lo) >> 16) + (t * hi);
675 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
676 *d = (uint8_t) st_13linear2alaw((int16_t) t >> 3);
678 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
679 channel = 0;
680 e->x += fs;
681 factor = linear_get_int(e, v);
685 break;
688 case PA_SAMPLE_S16NE: {
689 int16_t *d, *s;
690 unsigned channel;
691 int32_t factor = linear_get_int(e, v);
693 s = (int16_t*) p + n/sizeof(int16_t);
695 for (channel = 0, d = p; d < s; d++) {
696 int32_t t, hi, lo;
698 hi = factor >> 16;
699 lo = factor & 0xFFFF;
701 t = (int32_t)(*d);
702 t = ((t * lo) >> 16) + (t * hi);
703 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
704 *d = (int16_t) t;
706 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
707 channel = 0;
708 e->x += fs;
709 factor = linear_get_int(e, v);
713 break;
716 case PA_SAMPLE_S16RE: {
717 int16_t *d, *s;
718 unsigned channel;
719 int32_t factor = linear_get_int(e, v);
721 s = (int16_t*) p + n/sizeof(int16_t);
723 for (channel = 0, d = p; d < s; d++) {
724 int32_t t, hi, lo;
726 hi = factor >> 16;
727 lo = factor & 0xFFFF;
729 t = (int32_t) PA_INT16_SWAP(*d);
730 t = ((t * lo) >> 16) + (t * hi);
731 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
732 *d = PA_INT16_SWAP((int16_t) t);
734 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
735 channel = 0;
736 e->x += fs;
737 factor = linear_get_int(e, v);
741 break;
744 case PA_SAMPLE_S32NE: {
745 int32_t *d, *s;
746 unsigned channel;
747 int32_t factor = linear_get_int(e, v);
749 s = (int32_t*) p + n/sizeof(int32_t);
751 for (channel = 0, d = p; d < s; d++) {
752 int64_t t;
754 t = (int64_t)(*d);
755 t = (t * factor) >> 16;
756 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
757 *d = (int32_t) t;
759 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
760 channel = 0;
761 e->x += fs;
762 factor = linear_get_int(e, v);
766 break;
769 case PA_SAMPLE_S32RE: {
770 int32_t *d, *s;
771 unsigned channel;
772 int32_t factor = linear_get_int(e, v);
774 s = (int32_t*) p + n/sizeof(int32_t);
776 for (channel = 0, d = p; d < s; d++) {
777 int64_t t;
779 t = (int64_t) PA_INT32_SWAP(*d);
780 t = (t * factor) >> 16;
781 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
782 *d = PA_INT32_SWAP((int32_t) t);
784 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
785 channel = 0;
786 e->x += fs;
787 factor = linear_get_int(e, v);
791 break;
794 case PA_SAMPLE_FLOAT32NE: {
795 /*Seems the FLOAT32NE part of pa_volume_memchunk not right, do not reuse here*/
796 float *t;
798 for (t = p; n > 0; n -= fs) {
799 float factor = linear_get_float(e, v);
800 unsigned c;
801 e->x += fs;
803 for (c = 0; c < e->sample_spec.channels; c++, t++)
804 *t = *t * factor;
807 break;
810 case PA_SAMPLE_FLOAT32RE: {
811 /*Seems the FLOAT32RE part of pa_volume_memchunk not right, do not reuse here*/
812 float *t;
814 for (t = p; n > 0; n -= fs) {
815 float factor = linear_get_float(e, v);
816 unsigned c;
817 e->x += fs;
819 for (c = 0; c < e->sample_spec.channels; c++, t++) {
820 float r = PA_FLOAT32_SWAP(*t) * factor;
821 *t = PA_FLOAT32_SWAP(r);
825 break;
828 case PA_SAMPLE_S24NE: {
829 uint8_t *d, *s;
830 unsigned channel;
831 int32_t factor = linear_get_int(e, v);
833 s = (uint8_t*) p + n/3;
835 for (channel = 0, d = p; d < s; d++) {
836 int64_t t;
838 t = (int64_t)((int32_t) (PA_READ24NE(d) << 8));
839 t = (t * factor) >> 16;
840 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
841 PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8);
843 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
844 channel = 0;
845 e->x += fs;
846 factor = linear_get_int(e, v);
850 break;
852 case PA_SAMPLE_S24RE: {
853 uint8_t *d, *s;
854 unsigned channel;
855 int32_t factor = linear_get_int(e, v);
857 s = (uint8_t*) p + n/3;
859 for (channel = 0, d = p; d < s; d++) {
860 int64_t t;
862 t = (int64_t)((int32_t) (PA_READ24RE(d) << 8));
863 t = (t * factor) >> 16;
864 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
865 PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8);
867 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
868 channel = 0;
869 e->x += fs;
870 factor = linear_get_int(e, v);
874 break;
876 case PA_SAMPLE_S24_32NE: {
877 uint32_t *d, *s;
878 unsigned channel;
879 int32_t factor = linear_get_int(e, v);
881 s = (uint32_t*) p + n/sizeof(uint32_t);
883 for (channel = 0, d = p; d < s; d++) {
884 int64_t t;
886 t = (int64_t) ((int32_t) (*d << 8));
887 t = (t * factor) >> 16;
888 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
889 *d = ((uint32_t) ((int32_t) t)) >> 8;
891 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
892 channel = 0;
893 e->x += fs;
894 factor = linear_get_int(e, v);
898 break;
900 case PA_SAMPLE_S24_32RE: {
901 uint32_t *d, *s;
902 unsigned channel;
903 int32_t factor = linear_get_int(e, v);
905 s = (uint32_t*) p + n/sizeof(uint32_t);
907 for (channel = 0, d = p; d < s; d++) {
908 int64_t t;
910 t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*d) << 8));
911 t = (t * factor) >> 16;
912 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
913 *d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8);
915 if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
916 channel = 0;
917 e->x += fs;
918 factor = linear_get_int(e, v);
921 break;
923 /* FIXME */
924 pa_assert_not_reached();
926 case PA_SAMPLE_MAX:
927 case PA_SAMPLE_INVALID:
928 pa_assert_not_reached();
931 pa_memblock_release(chunk->memblock);
932 } else {
933 /* When we have no envelope to apply we reset our origin */
934 e->x = 0;
937 envelope_commit_read(e, v);
940 void pa_envelope_rewind(pa_envelope *e, size_t n_bytes) {
941 int v;
943 pa_assert(e);
945 envelope_begin_read(e, &v);
947 if (e->x - n_bytes <= e->points[v].x[0])
948 e->x = e->points[v].x[0];
949 else
950 e->x -= n_bytes;
952 e->points[v].n_current = 0;
953 e->points[v].cached_valid = FALSE;
955 envelope_commit_read(e, v);
958 void pa_envelope_restart(pa_envelope* e) {
959 int v;
960 pa_assert(e);
962 envelope_begin_read(e, &v);
963 e->x = e->points[v].x[0];
964 envelope_commit_read(e, v);
967 pa_bool_t pa_envelope_is_finished(pa_envelope* e) {
968 int v;
969 pa_bool_t finished;
971 pa_assert(e);
972 envelope_begin_read(e, &v);
973 finished = (e->x >= e->points[v].x[e->points[v].n_points-1]);
974 envelope_commit_read(e, v);
976 return finished;
979 int32_t pa_envelope_length(pa_envelope *e) {
980 int v;
981 size_t size;
983 pa_assert(e);
984 envelope_begin_read(e, &v);
985 size = e->points[v].x[e->points[v].n_points-1] - e->points[v].x[0];
986 envelope_commit_read(e, v);
988 return size;