1 /* $NetBSD: aurateconv.c,v 1.17 2006/11/16 01:32:44 christos Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: aurateconv.c,v 1.17 2006/11/16 01:32:44 christos Exp $");
35 #include <sys/systm.h>
36 #include <sys/types.h>
37 #include <sys/device.h>
38 #include <sys/errno.h>
39 #include <sys/malloc.h>
40 #include <sys/select.h>
41 #include <sys/audioio.h>
43 #include <dev/audio_if.h>
44 #include <dev/audiovar.h>
45 #include <dev/auconv.h>
52 /* #define AURATECONV_DEBUG */
53 #ifdef AURATECONV_DEBUG
54 #define DPRINTF(x) printf x
59 typedef struct aurateconv
{
64 int32_t prev
[AUDIO_MAX_CHANNELS
];
65 int32_t next
[AUDIO_MAX_CHANNELS
];
68 static int aurateconv_fetch_to(stream_fetcher_t
*, audio_stream_t
*, int);
69 static void aurateconv_dtor(stream_filter_t
*);
70 static int aurateconv_slinear16_LE(aurateconv_t
*, audio_stream_t
*,
72 static int aurateconv_slinear24_LE(aurateconv_t
*, audio_stream_t
*,
74 static int aurateconv_slinear32_LE(aurateconv_t
*, audio_stream_t
*,
76 static int aurateconv_slinear16_BE(aurateconv_t
*, audio_stream_t
*,
78 static int aurateconv_slinear24_BE(aurateconv_t
*, audio_stream_t
*,
80 static int aurateconv_slinear32_BE(aurateconv_t
*, audio_stream_t
*,
83 static int32_t int32_mask
[33] = {
84 0x0, 0x80000000, 0xc0000000, 0xe0000000,
85 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
86 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
87 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
88 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000,
89 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
90 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0,
91 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe,
96 aurateconv(struct audio_softc
*sc
, const audio_params_t
*from
,
97 const audio_params_t
*to
)
101 DPRINTF(("Construct '%s' filter: rate=%u:%u chan=%u:%u prec=%u/%u:%u/"
102 "%u enc=%u:%u\n", __func__
, from
->sample_rate
,
103 to
->sample_rate
, from
->channels
, to
->channels
,
104 from
->validbits
, from
->precision
, to
->validbits
,
105 to
->precision
, from
->encoding
, to
->encoding
));
108 if (from
->channels
== to
->channels
109 && from
->sample_rate
== to
->sample_rate
)
110 printf("%s: no conversion\n", __func__
); /* No conversion */
112 if (from
->encoding
!= to
->encoding
113 || from
->precision
!= to
->precision
114 || from
->validbits
!= to
->validbits
) {
115 printf("%s: encoding/precision must not be changed\n", __func__
);
118 if ((from
->encoding
!= AUDIO_ENCODING_SLINEAR_LE
119 && from
->encoding
!= AUDIO_ENCODING_SLINEAR_BE
)
120 || (from
->precision
!= 16 && from
->precision
!= 24 && from
->precision
!= 32)) {
121 printf("%s: encoding/precision must be SLINEAR_LE 16/24/32bit, "
122 "or SLINEAR_BE 16/24/32bit", __func__
);
126 if (from
->channels
> AUDIO_MAX_CHANNELS
|| from
->channels
<= 0
127 || to
->channels
> AUDIO_MAX_CHANNELS
|| to
->channels
<= 0) {
128 printf("%s: invalid channels: from=%u to=%u\n",
129 __func__
, from
->channels
, to
->channels
);
133 if (from
->sample_rate
<= 0 || to
->sample_rate
<= 0) {
134 printf("%s: invalid sampling rate: from=%u to=%u\n",
135 __func__
, from
->sample_rate
, to
->sample_rate
);
140 /* initialize context */
141 this = malloc(sizeof(aurateconv_t
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
142 this->count
= from
->sample_rate
< to
->sample_rate
143 ? to
->sample_rate
+ from
->sample_rate
: 0;
147 /* initialize vtbl */
148 this->base
.base
.fetch_to
= aurateconv_fetch_to
;
149 this->base
.dtor
= aurateconv_dtor
;
150 this->base
.set_fetcher
= stream_filter_set_fetcher
;
151 this->base
.set_inputbuffer
= stream_filter_set_inputbuffer
;
156 aurateconv_dtor(struct stream_filter
*this)
159 free(this, M_DEVBUF
);
163 aurateconv_fetch_to(stream_fetcher_t
*self
, audio_stream_t
*dst
, int max_used
)
166 int m
, err
, frame_dst
, frame_src
;
168 this = (aurateconv_t
*)self
;
169 frame_dst
= (this->to
.precision
/ 8) * this->to
.channels
;
170 frame_src
= (this->from
.precision
/ 8) * this->from
.channels
;
171 max_used
= max_used
/ frame_dst
* frame_dst
;
173 max_used
= frame_dst
;
174 /* calculate required input size for output max_used bytes */
175 m
= max_used
/ frame_dst
;
176 m
*= this->from
.sample_rate
;
177 m
/= this->to
.sample_rate
;
182 if ((err
= this->base
.prev
->fetch_to(this->base
.prev
, this->base
.src
, m
)))
184 m
= (dst
->end
- dst
->start
) / frame_dst
* frame_dst
;
185 m
= min(m
, max_used
);
187 switch (this->from
.encoding
) {
188 case AUDIO_ENCODING_SLINEAR_LE
:
189 switch (this->from
.precision
) {
191 return aurateconv_slinear16_LE(this, dst
, m
,
192 frame_src
, frame_dst
);
194 return aurateconv_slinear24_LE(this, dst
, m
,
195 frame_src
, frame_dst
);
197 return aurateconv_slinear32_LE(this, dst
, m
,
198 frame_src
, frame_dst
);
201 case AUDIO_ENCODING_SLINEAR_BE
:
202 switch (this->from
.precision
) {
204 return aurateconv_slinear16_BE(this, dst
, m
,
205 frame_src
, frame_dst
);
207 return aurateconv_slinear24_BE(this, dst
, m
,
208 frame_src
, frame_dst
);
210 return aurateconv_slinear32_BE(this, dst
, m
,
211 frame_src
, frame_dst
);
215 printf("%s: internal error: unsupported encoding: enc=%u prec=%u\n",
216 __func__
, this->from
.encoding
, this->from
.precision
);
221 #define READ_S8LE(P) *(const int8_t*)(P)
222 #define WRITE_S8LE(P, V) *(int8_t*)(P) = V
223 #define READ_S8BE(P) *(const int8_t*)(P)
224 #define WRITE_S8BE(P, V) *(int8_t*)(P) = V
225 #if BYTE_ORDER == LITTLE_ENDIAN
226 # define READ_S16LE(P) *(const int16_t*)(P)
227 # define WRITE_S16LE(P, V) *(int16_t*)(P) = V
228 # define READ_S16BE(P) (int16_t)((P)[0] | ((P)[1]<<8))
229 # define WRITE_S16BE(P, V) \
234 } while (/*CONSTCOND*/ 0)
235 # define READ_S32LE(P) *(const int32_t*)(P)
236 # define WRITE_S32LE(P, V) *(int32_t*)(P) = V
237 # define READ_S32BE(P) (int32_t)((P)[3] | ((P)[2]<<8) | ((P)[1]<<16) | (((int8_t)((P)[0]))<<24))
238 # define WRITE_S32BE(P, V) \
241 (P)[0] = vvv >> 24; \
242 (P)[1] = vvv >> 16; \
245 } while (/*CONSTCOND*/ 0)
246 #else /* !LITTLE_ENDIAN */
247 # define READ_S16LE(P) (int16_t)((P)[0] | ((P)[1]<<8))
248 # define WRITE_S16LE(P, V) \
253 } while (/*CONSTCOND*/ 0)
254 # define READ_S16BE(P) *(const int16_t*)(P)
255 # define WRITE_S16BE(P, V) *(int16_t*)(P) = V
256 # define READ_S32LE(P) (int32_t)((P)[0] | ((P)[1]<<8) | ((P)[2]<<16) | (((int8_t)((P)[3]))<<24))
257 # define WRITE_S32LE(P, V) \
262 (P)[2] = vvv >> 16; \
263 (P)[3] = vvv >> 24; \
264 } while (/*CONSTCOND*/ 0)
265 # define READ_S32BE(P) *(const int32_t*)(P)
266 # define WRITE_S32BE(P, V) *(int32_t*)(P) = V
267 #endif /* !LITTLE_ENDIAN */
268 #define READ_S24LE(P) (int32_t)((P)[0] | ((P)[1]<<8) | (((int8_t)((P)[2]))<<16))
269 #define WRITE_S24LE(P, V) \
274 (P)[2] = vvv >> 16; \
275 } while (/*CONSTCOND*/ 0)
276 #define READ_S24BE(P) (int32_t)((P)[2] | ((P)[1]<<8) | (((int8_t)((P)[0]))<<16))
277 #define WRITE_S24BE(P, V) \
280 (P)[0] = vvv >> 16; \
283 } while (/*CONSTCOND*/ 0)
285 #define READ_Sn(BITS, EN, V, STREAM, RP, PAR) \
288 for (j = 0; j < (PAR)->channels; j++) { \
289 (V)[j] = READ_S##BITS##EN(RP); \
290 RP = audio_stream_add_outp(STREAM, RP, (BITS) / NBBY); \
292 } while (/*CONSTCOND*/ 0)
293 #define WRITE_Sn(BITS, EN, V, STREAM, WP, FROM, TO) \
295 if ((FROM)->channels == 2 && (TO)->channels == 1) { \
296 WRITE_S##BITS##EN(WP, ((V)[0] + (V)[1]) / 2); \
297 WP = audio_stream_add_inp(STREAM, WP, (BITS) / NBBY); \
298 } else if (from->channels <= to->channels) { \
300 for (j = 0; j < (FROM)->channels; j++) { \
301 WRITE_S##BITS##EN(WP, (V)[j]); \
302 WP = audio_stream_add_inp(STREAM, WP, (BITS) / NBBY); \
304 if (j == 1 && 1 < (TO)->channels) { \
305 WRITE_S##BITS##EN(WP, (V)[0]); \
306 WP = audio_stream_add_inp(STREAM, WP, (BITS) / NBBY); \
309 for (; j < (TO)->channels; j++) { \
310 WRITE_S##BITS##EN(WP, 0); \
311 WP = audio_stream_add_inp(STREAM, WP, (BITS) / NBBY); \
313 } else { /* from->channels < to->channels */ \
315 for (j = 0; j < (TO)->channels; j++) { \
316 WRITE_S##BITS##EN(WP, (V)[j]); \
317 WP = audio_stream_add_inp(STREAM, WP, (BITS) / NBBY); \
320 } while (/*CONSTCOND*/ 0)
325 * Don't use this for 32bit data because this linear interpolation overflows
328 #define AURATECONV_SLINEAR(BITS, EN) \
330 aurateconv_slinear##BITS##_##EN (aurateconv_t *this, audio_stream_t *dst, \
331 int m, int frame_src, int frame_dst) \
335 const audio_params_t *from, *to; \
336 audio_stream_t *src; \
337 int32_t v[AUDIO_MAX_CHANNELS]; \
338 int32_t *prev, *next, c256; \
339 int i, values_size; \
341 src = this->base.src; \
344 DPRINTF(("%s: ENTER w=%p r=%p dst->used=%d src->used=%d\n", \
345 __func__, w, r, dst->used, src->used)); \
346 from = &this->from; \
348 if (this->from.sample_rate == this->to.sample_rate) { \
349 while (dst->used < m && src->used >= frame_src) { \
350 READ_Sn(BITS, EN, v, src, r, from); \
351 WRITE_Sn(BITS, EN, v, dst, w, from, to); \
353 } else if (to->sample_rate < from->sample_rate) { \
354 while (dst->used < m && src->used >= frame_src) { \
355 READ_Sn(BITS, EN, v, src, r, from); \
356 this->count += to->sample_rate; \
357 if (this->count >= from->sample_rate) { \
358 this->count -= from->sample_rate; \
359 WRITE_Sn(BITS, EN, v, dst, w, from, to); \
363 /* Initial value of this->count >= to->sample_rate */ \
364 values_size = sizeof(int32_t) * from->channels; \
367 while (dst->used < m \
368 && ((this->count >= to->sample_rate && src->used >= frame_src) \
369 || this->count < to->sample_rate)) { \
370 if (this->count >= to->sample_rate) { \
371 this->count -= to->sample_rate; \
372 memcpy(prev, next, values_size); \
373 READ_Sn(BITS, EN, next, src, r, from); \
375 c256 = this->count * 256 / to->sample_rate; \
376 for (i = 0; i < from->channels; i++) \
377 v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \
378 WRITE_Sn(BITS, EN, v, dst, w, from, to); \
379 this->count += from->sample_rate; \
382 DPRINTF(("%s: LEAVE w=%p r=%p dst->used=%d src->used=%d\n", \
383 __func__, w, r, dst->used, src->used)); \
390 * Function template for 32bit container
392 #define AURATECONV_SLINEAR32(EN) \
394 aurateconv_slinear32_##EN (aurateconv_t *this, audio_stream_t *dst, \
395 int m, int frame_src, int frame_dst) \
399 const audio_params_t *from, *to; \
400 audio_stream_t *src; \
401 int32_t v[AUDIO_MAX_CHANNELS]; \
402 int32_t *prev, *next; \
403 int64_t c256, mask; \
404 int i, values_size, used_src, used_dst; \
406 src = this->base.src; \
409 used_dst = audio_stream_get_used(dst); \
410 used_src = audio_stream_get_used(src); \
411 from = &this->from; \
413 if (this->from.sample_rate == this->to.sample_rate) { \
414 while (used_dst < m && used_src >= frame_src) { \
415 READ_Sn(32, EN, v, src, r, from); \
416 used_src -= frame_src; \
417 WRITE_Sn(32, EN, v, dst, w, from, to); \
418 used_dst += frame_dst; \
420 } else if (to->sample_rate < from->sample_rate) { \
421 while (used_dst < m && used_src >= frame_src) { \
422 READ_Sn(32, EN, v, src, r, from); \
423 used_src -= frame_src; \
424 this->count += to->sample_rate; \
425 if (this->count >= from->sample_rate) { \
426 this->count -= from->sample_rate; \
427 WRITE_Sn(32, EN, v, dst, w, from, to); \
428 used_dst += frame_dst; \
432 /* Initial value of this->count >= to->sample_rate */ \
433 values_size = sizeof(int32_t) * from->channels; \
434 mask = int32_mask[to->validbits]; \
437 while (used_dst < m \
438 && ((this->count >= to->sample_rate && used_src >= frame_src) \
439 || this->count < to->sample_rate)) { \
440 if (this->count >= to->sample_rate) { \
441 this->count -= to->sample_rate; \
442 memcpy(prev, next, values_size); \
443 READ_Sn(32, EN, next, src, r, from); \
444 used_src -= frame_src; \
446 c256 = this->count * 256 / to->sample_rate; \
447 for (i = 0; i < from->channels; i++) \
448 v[i] = (int32_t)((c256 * next[i] + (INT64_C(256) - c256) * prev[i]) >> 8) & mask; \
449 WRITE_Sn(32, EN, v, dst, w, from, to); \
450 used_dst += frame_dst; \
451 this->count += from->sample_rate; \
459 AURATECONV_SLINEAR(16, LE
)
460 AURATECONV_SLINEAR(24, LE
)
461 AURATECONV_SLINEAR32(LE
)
462 AURATECONV_SLINEAR(16, BE
)
463 AURATECONV_SLINEAR(24, BE
)
464 AURATECONV_SLINEAR32(BE
)