diff --git a/sys/dev/auconv.c b/sys/dev/auconv.c index 0fdf7aba6fcc..3aa5c63e2bd7 100644 --- a/sys/dev/auconv.c +++ b/sys/dev/auconv.c @@ -1,4 +1,4 @@ -/* $NetBSD: auconv.c,v 1.8 2002/03/07 14:37:02 kent Exp $ */ +/* $NetBSD: auconv.c,v 1.9 2002/03/09 20:30:42 kent Exp $ */ /* * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -35,41 +35,13 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.8 2002/03/07 14:37:02 kent Exp $"); +__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.9 2002/03/09 20:30:42 kent Exp $"); -#include #include -#include #include -#include "audio_if.h" #include "auconv.h" -#ifdef AUCONV_DEBUG -#define DPRINTF(x) printf x -#else -#define DPRINTF(x) -#endif - -static int auconv_play_slinear16_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); -static int auconv_play_slinear16_channels_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); -static int auconv_play_slinear24_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); -static int auconv_play_slinear24_channels_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); - -static int auconv_record_slinear16_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); -static int auconv_record_slinear16_channels_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); -static int auconv_record_slinear24_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); -static int auconv_record_slinear24_channels_le(struct auconv_context *, - const struct audio_params *, uint8_t *, const uint8_t *, int); - - void change_sign8(void *v, u_char *p, int cc) { @@ -247,615 +219,3 @@ slinear16_to_ulinear8_be(void *v, u_char *p, int cc) p += 2; } } - -int -auconv_check_params(const struct audio_params *params) -{ - DPRINTF(("auconv_check_params: rate=%ld:%ld chan=%d:%d prec=%d:%d " - "enc=%d:%d\n", params->sample_rate, params->hw_sample_rate, - params->channels, params->hw_channels, params->precision, - params->hw_precision, params->encoding, params->hw_encoding)); - if (params->hw_channels == params->channels - && params->hw_sample_rate == params->sample_rate) - return 0; /* No conversion */ - - if (params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE - || (params->hw_precision != 16 && params->hw_precision != 24)) - return (EINVAL); - - /* Only 1:2 or 2:1 */ - if (params->hw_channels != params->channels) - if (!((params->hw_channels == 1 && params->channels == 2) - || (params->hw_channels == 2 && params->channels == 1))) - return (EINVAL); - - if (params->hw_sample_rate != params->sample_rate) - if (params->hw_sample_rate <= 0 || params->sample_rate <= 0) - return (EINVAL); - return 0; -} - -void -auconv_init_context(struct auconv_context *context, long src_rate, - long dst_rate, uint8_t *start, uint8_t *end) -{ - int i; - - context->ring_start = start; - context->ring_end = end; - if (dst_rate > src_rate) { - context->count = src_rate; - } else { - context->count = 0; - } - for (i = 0; i < AUDIO_MAX_CHANNELS; i++) - context->prev[i] = 0; -} - -/* - * src is a ring buffer. - */ -int -auconv_record(struct auconv_context *context, - const struct audio_params *params, uint8_t *dest, - const uint8_t *src, int srcsize) -{ - if (params->hw_sample_rate == params->sample_rate - && params->hw_channels == params->channels) { - int n; - - n = context->ring_end - src; - if (srcsize <= n) - memcpy(dest, src, srcsize); - else { - memcpy(dest, src, n); - memcpy(dest + n, context->ring_start, srcsize - n); - } - return srcsize; - } - - if (params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE) { - /* This should be rejected in auconv_check_params() */ - printf("auconv_record: unimplemented encoding: %d\n", - params->hw_encoding); - return 0; - } - switch (params->hw_precision) { - case 16: - if (params->hw_channels != params->channels) - return auconv_record_slinear16_channels_le(context, - params, dest, src, srcsize); - else - return auconv_record_slinear16_le(context, - params, dest, src, srcsize); - case 24: - if (params->hw_channels != params->channels) - return auconv_record_slinear24_channels_le(context, - params, dest, src, srcsize); - else - return auconv_record_slinear24_le(context, - params, dest, src, srcsize); - } - printf("auconv_record: unimplemented precision: %d\n", - params->hw_precision); - return 0; -} - -/* - * dest is a ring buffer. - */ -int -auconv_play(struct auconv_context *context, const struct audio_params *params, - uint8_t *dest, const uint8_t *src, int srcsize) -{ - int n; - - if (params->hw_sample_rate == params->sample_rate - && params->hw_channels == params->channels) { - n = context->ring_end - dest; - if (srcsize <= n) { - memcpy(dest, src, srcsize); - } else { - memcpy(dest, src, n); - memcpy(context->ring_start, src + n, srcsize - n); - } - return srcsize; - } - - if (params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE) { - /* This should be rejected in auconv_check_params() */ - printf("auconv_play: unimplemented encoding: %d\n", - params->hw_encoding); - return 0; - } - switch (params->hw_precision) { - case 16: - if (params->hw_channels != params->channels) - return auconv_play_slinear16_channels_le(context, - params, dest, src, srcsize); - else - return auconv_play_slinear16_le(context, - params, dest, src, srcsize); - case 24: - if (params->hw_channels != params->channels) - return auconv_play_slinear24_channels_le(context, - params, dest, src, srcsize); - else - return auconv_play_slinear24_le(context, - params, dest, src, srcsize); - } - printf("auconv_play: unimplemented precision: %d\n", - params->hw_precision); - return 0; -} - - -#define RING_CHECK(C, V) \ - do { \ - if (V >= (C)->ring_end) \ - V = (C)->ring_start; \ - } while (0) - -#if BYTE_ORDER == LITTLE_ENDIAN -# define READ_S16LE(P) *(int16_t*)(P) -# define WRITE_S16LE(P, V) *(int16_t*)(P) = V -#else -# define READ_S16LE(P) (int16_t)((P)[0] | ((P)[1]<<8)) -# define WRITE_S16LE(P, V) \ - do { \ - int vv = V; \ - (P)[0] = vv; \ - (P)[1] = vv >> 8; \ - } while (0) -#endif -#define READ_S24LE(P) (int32_t)((P)[0] | ((P)[1]<<8) | (((int8_t)((P)[2]))<<16)) -#define WRITE_S24LE(P, V) \ - do { \ - int vvv = V; \ - (P)[0] = vvv; \ - (P)[1] = vvv >> 8; \ - (P)[2] = vvv >> 16; \ - } while (0) - -#define P_READ_LR_S16LE(LV, RV, RP, PAR) \ - do { \ - LV = READ_S16LE(RP); \ - RP += sizeof(int16_t); \ - if ((PAR)->channels == 1) \ - RV = LV; \ - else { \ - RV = READ_S16LE(RP); \ - RP += sizeof(int16_t); \ - } \ - } while (0) -#define P_WRITE_LR_S16LE(LV, RV, WP, PAR, CON, WC) \ - do { \ - if ((PAR)->hw_channels == 1) { \ - WRITE_S16LE(WP, (LV + RV) / 2); \ - WP += sizeof(int16_t); \ - WC += sizeof(int16_t); \ - } else { \ - WRITE_S16LE(WP, LV); \ - WP += sizeof(int16_t); \ - RING_CHECK(CON, WP); \ - WRITE_S16LE(WP, RV); \ - WP += sizeof(int16_t); \ - WC += sizeof(int16_t) * 2; \ - } \ - RING_CHECK(CON, WP); \ - } while (0) -#define P_READ_N_S16LE(V, RP, PAR) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - (V)[i] = READ_S16LE(RP); \ - RP += sizeof(int16_t); \ - } \ - } while (0) -#define P_WRITE_N_S16LE(V, WP, PAR, CON, WC) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - WRITE_S16LE(WP, (V)[i]); \ - WP += sizeof(int16_t); \ - RING_CHECK(CON, WP); \ - } \ - WC += sizeof(int16_t) * i; \ - } while (0) -#define P_READ_LR_S24LE(LV, RV, RP, PAR) \ - do { \ - LV = READ_S24LE(RP); \ - RP += 3; \ - if ((PAR)->channels == 1) \ - RV = LV; \ - else { \ - RV = READ_S24LE(RP); \ - RP += 3; \ - } \ - } while (0) -#define P_WRITE_LR_S24LE(LV, RV, WP, PAR, CON, WC) \ - do { \ - if ((PAR)->hw_channels == 1) { \ - WRITE_S24LE(WP, (LV + RV) / 2); \ - WP += 3; \ - WC += 3; \ - } else { \ - WRITE_S24LE(WP, LV); \ - WP += 3; \ - RING_CHECK(CON, WP); \ - WRITE_S24LE(WP, RV); \ - WP += 3; \ - WC += 3 * 2; \ - } \ - RING_CHECK(CON, WP); \ - } while (0) -#define P_READ_N_S24LE(V, RP, PAR) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - (V)[i] = READ_S24LE(RP); \ - RP += 3; \ - } \ - } while (0) -#define P_WRITE_N_S24LE(V, WP, PAR, CON, WC) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - WRITE_S24LE(WP, (V)[i]); \ - WP += 3; \ - RING_CHECK(CON, WP); \ - } \ - WC += 3 * i; \ - } while (0) - -#define R_READ_LR_S16LE(LV, RV, RP, PAR, CON, RC) \ - do { \ - LV = READ_S16LE(RP); \ - RP += sizeof(int16_t); \ - RING_CHECK(CON, RP); \ - RC += sizeof(int16_t); \ - if ((PAR)->hw_channels == 1) \ - RV = LV; \ - else { \ - RV = READ_S16LE(RP); \ - RP += sizeof(int16_t); \ - RING_CHECK(CON, RP); \ - RC += sizeof(int16_t); \ - } \ - } while (0) -#define R_WRITE_LR_S16LE(LV, RV, WP, PAR, WC) \ - do { \ - if ((PAR)->channels == 1) { \ - WRITE_S16LE(WP, (LV + RV) / 2); \ - WP += sizeof(int16_t); \ - WC += sizeof(int16_t); \ - } else { \ - WRITE_S16LE(WP, LV); \ - WP += sizeof(int16_t); \ - WRITE_S16LE(WP, RV); \ - WP += sizeof(int16_t); \ - WC += sizeof(int16_t) * 2; \ - } \ - } while (0) -#define R_READ_N_S16LE(V, RP, PAR, CON, RC) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - (V)[i] = READ_S16LE(RP); \ - RP += sizeof(int16_t); \ - RING_CHECK(CON, RP); \ - RC += sizeof(int16_t); \ - } \ - } while (0) -#define R_WRITE_N_S16LE(V, WP, PAR, WC) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - WRITE_S16LE(WP, (V)[i]); \ - WP += sizeof(int16_t); \ - } \ - WC += sizeof(int16_t) * i; \ - } while (0) -#define R_READ_LR_S24LE(LV, RV, RP, PAR, CON, RC) \ - do { \ - LV = READ_S24LE(RP); \ - RP += 3; \ - RING_CHECK(CON, RP); \ - RC += 3; \ - if ((PAR)->hw_channels == 1) \ - RV = LV; \ - else { \ - RV = READ_S24LE(RP); \ - RP += 3; \ - RING_CHECK(CON, RP); \ - RC += 3; \ - } \ - } while (0) -#define R_WRITE_LR_S24LE(LV, RV, WP, PAR, WC) \ - do { \ - if ((PAR)->channels == 1) { \ - WRITE_S24LE(WP, (LV + RV) / 2); \ - WP += 3; \ - WC += 3; \ - } else { \ - WRITE_S24LE(WP, LV); \ - WP += 3; \ - WRITE_S24LE(WP, RV); \ - WP += 3; \ - WC += 3 * 2; \ - } \ - } while (0) -#define R_READ_N_S24LE(V, RP, PAR, CON, RC) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - (V)[i] = READ_S24LE(RP); \ - RP += 3; \ - RING_CHECK(CON, RP); \ - RC += 3; \ - } \ - } while (0) -#define R_WRITE_N_S24LE(V, WP, PAR, WC) \ - do { \ - int i; \ - for (i = 0; i < (PAR)->channels; i++) { \ - WRITE_S24LE(WP, (V)[i]); \ - WP += 3; \ - } \ - WC += 3 * i; \ - } while (0) - -/* - * Function templates - * - * Source may be 1 sample. Destination buffer must have space for converted - * source. - * Don't use them for 32bit data because this linear interpolation overflows - * for 32bit data. - */ -#define AUCONV_PLAY_SLINEAR_CHANNELS_LE(BITS) \ -static int \ -auconv_play_slinear##BITS##_channels_le(struct auconv_context *context, \ - const struct audio_params *params, \ - uint8_t *dest, const uint8_t *src, \ - int srcsize) \ -{ \ - int wrote; \ - uint8_t *w; \ - const uint8_t *r; \ - const uint8_t *src_end; \ - register int32_t lv, rv; \ - int32_t prev_l, prev_r, next_l, next_r, c256; \ - \ - wrote = 0; \ - w = dest; \ - r = src; \ - src_end = src + srcsize; \ - if (params->sample_rate == params->hw_sample_rate) { \ - while (r < src_end) { \ - P_READ_LR_S##BITS##LE(lv, rv, r, params); \ - P_WRITE_LR_S##BITS##LE(lv, rv, w, params, context, wrote); \ - } \ - } else if (params->hw_sample_rate < params->sample_rate) { \ - for (;;) { \ - do { \ - if (r >= src_end) \ - return wrote; \ - P_READ_LR_S##BITS##LE(lv, rv, r, params); \ - context->count += params->hw_sample_rate; \ - } while (context->count < params->sample_rate); \ - context->count -= params->sample_rate; \ - P_WRITE_LR_S##BITS##LE(lv, rv, w, params, context, wrote); \ - } \ - } else { \ - /* Initial value of context->count is params->sample_rate */ \ - prev_l = context->prev[0]; \ - prev_r = context->prev[1]; \ - P_READ_LR_S##BITS##LE(next_l, next_r, r, params); \ - for (;;) { \ - c256 = context->count * 256 / params->hw_sample_rate; \ - lv = (c256 * next_l + (256 - c256) * prev_l) >> 8; \ - rv = (c256 * next_r + (256 - c256) * prev_r) >> 8; \ - P_WRITE_LR_S##BITS##LE(lv, rv, w, params, context, wrote); \ - context->count += params->sample_rate; \ - if (context->count >= params->hw_sample_rate) { \ - context->count -= params->hw_sample_rate; \ - prev_l = next_l; \ - prev_r = next_r; \ - if (r >= src_end) \ - break; \ - P_READ_LR_S##BITS##LE(next_l, next_r, r, params); \ - } \ - } \ - context->prev[0] = next_l; \ - context->prev[1] = next_r; \ - } \ - return wrote; \ -} - -#define AUCONV_PLAY_SLINEAR_LE(BITS) \ -static int \ -auconv_play_slinear##BITS##_le(struct auconv_context *context, \ - const struct audio_params *params, \ - uint8_t *dest, const uint8_t *src, \ - int srcsize) \ -{ \ - int wrote; \ - uint8_t *w; \ - const uint8_t *r; \ - const uint8_t *src_end; \ - int32_t v[AUDIO_MAX_CHANNELS]; \ - int32_t prev[AUDIO_MAX_CHANNELS], next[AUDIO_MAX_CHANNELS], c256; \ - int i, values_size; \ - \ - wrote = 0; \ - w = dest; \ - r = src; \ - src_end = src + srcsize; \ - if (params->sample_rate == params->hw_sample_rate) { \ - while (r < src_end) { \ - P_READ_N_S##BITS##LE(v, r, params); \ - P_WRITE_N_S##BITS##LE(v, w, params, context, wrote); \ - } \ - } else if (params->hw_sample_rate < params->sample_rate) { \ - for (;;) { \ - do { \ - if (r >= src_end) \ - return wrote; \ - P_READ_N_S##BITS##LE(v, r, params); \ - context->count += params->hw_sample_rate; \ - } while (context->count < params->sample_rate); \ - context->count -= params->sample_rate; \ - P_WRITE_N_S##BITS##LE(v, w, params, context, wrote); \ - } \ - } else { \ - /* Initial value of context->count is params->sample_rate */ \ - values_size = sizeof(int32_t) * params->channels; \ - memcpy(prev, context->prev, values_size); \ - P_READ_N_S##BITS##LE(next, r, params); \ - for (;;) { \ - c256 = context->count * 256 / params->hw_sample_rate; \ - for (i = 0; i < params->channels; i++) \ - v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \ - P_WRITE_N_S##BITS##LE(v, w, params, context, wrote); \ - context->count += params->sample_rate; \ - if (context->count >= params->hw_sample_rate) { \ - context->count -= params->hw_sample_rate; \ - memcpy(prev, next, values_size); \ - if (r >= src_end) \ - break; \ - P_READ_N_S##BITS##LE(next, r, params); \ - } \ - } \ - memcpy(context->prev, next, values_size); \ - } \ - return wrote; \ -} - -#define AUCONV_RECORD_SLINEAR_CHANNELS_LE(BITS) \ -static int \ -auconv_record_slinear##BITS##_channels_le(struct auconv_context *context, \ - const struct audio_params *params, \ - uint8_t *dest, const uint8_t *src, \ - int srcsize) \ -{ \ - int wrote, rsize; \ - uint8_t *w; \ - const uint8_t *r; \ - register int32_t lv, rv; \ - int32_t prev_l, prev_r, next_l, next_r, c256; \ - \ - wrote = 0; \ - rsize = 0; \ - w = dest; \ - r = src; \ - if (params->sample_rate == params->hw_sample_rate) { \ - while (rsize < srcsize) { \ - R_READ_LR_S##BITS##LE(lv, rv, r, params, context, rsize); \ - R_WRITE_LR_S##BITS##LE(lv, rv, w, params, wrote); \ - } \ - } else if (params->sample_rate < params->hw_sample_rate) { \ - for (;;) { \ - do { \ - if (rsize >= srcsize) \ - return wrote; \ - R_READ_LR_S##BITS##LE(lv, rv, r, params, \ - context, rsize); \ - context->count += params->sample_rate; \ - } while (context->count < params->hw_sample_rate); \ - context->count -= params->hw_sample_rate; \ - R_WRITE_LR_S##BITS##LE(lv, rv, w, params, wrote); \ - } \ - } else { \ - /* Initial value of context->count is params->hw_sample_rate */ \ - prev_l = context->prev[0]; \ - prev_r = context->prev[1]; \ - R_READ_LR_S##BITS##LE(next_l, next_r, r, params, context, rsize); \ - for (;;) { \ - c256 = context->count * 256 / params->sample_rate; \ - lv = (c256 * next_l + (256 - c256) * prev_l) >> 8; \ - rv = (c256 * next_r + (256 - c256) * prev_r) >> 8; \ - R_WRITE_LR_S##BITS##LE(lv, rv, w, params, wrote); \ - context->count += params->hw_sample_rate; \ - if (context->count >= params->sample_rate) { \ - context->count -= params->sample_rate; \ - prev_l = next_l; \ - prev_r = next_r; \ - if (rsize >= srcsize) \ - break; \ - R_READ_LR_S##BITS##LE(next_l, next_r, r, \ - params, context, rsize); \ - } \ - } \ - context->prev[0] = next_l; \ - context->prev[1] = next_r; \ - } \ - return wrote; \ -} - -#define AUCONV_RECORD_SLINEAR_LE(BITS) \ -static int \ -auconv_record_slinear##BITS##_le(struct auconv_context *context, \ - const struct audio_params *params, \ - uint8_t *dest, const uint8_t *src, \ - int srcsize) \ -{ \ - int wrote, rsize; \ - uint8_t *w; \ - const uint8_t *r; \ - int32_t v[AUDIO_MAX_CHANNELS]; \ - int32_t prev[AUDIO_MAX_CHANNELS], next[AUDIO_MAX_CHANNELS], c256; \ - int i, values_size; \ - \ - wrote = 0; \ - rsize = 0; \ - w = dest; \ - r = src; \ - if (params->sample_rate == params->hw_sample_rate) { \ - while (rsize < srcsize) { \ - R_READ_N_S##BITS##LE(v, r, params, context, rsize); \ - R_WRITE_N_S##BITS##LE(v, w, params, wrote); \ - } \ - } else if (params->sample_rate < params->hw_sample_rate) { \ - for (;;) { \ - do { \ - if (rsize >= srcsize) \ - return wrote; \ - R_READ_N_S##BITS##LE(v, r, params, context, rsize); \ - context->count += params->sample_rate; \ - } while (context->count < params->hw_sample_rate); \ - context->count -= params->hw_sample_rate; \ - R_WRITE_N_S##BITS##LE(v, w, params, wrote); \ - } \ - } else { \ - /* Initial value of context->count is params->hw_sample_rate */ \ - values_size = sizeof(int32_t) * params->channels; \ - memcpy(prev, context->prev, values_size); \ - R_READ_N_S##BITS##LE(next, r, params, context, rsize); \ - for (;;) { \ - c256 = context->count * 256 / params->sample_rate; \ - for (i = 0; i < params->channels; i++) \ - v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \ - R_WRITE_N_S##BITS##LE(v, w, params, wrote); \ - context->count += params->hw_sample_rate; \ - if (context->count >= params->sample_rate) { \ - context->count -= params->sample_rate; \ - memcpy(prev, next, values_size); \ - if (rsize >= srcsize) \ - break; \ - R_READ_N_S##BITS##LE(next, r, params, context, rsize); \ - } \ - } \ - memcpy(context->prev, next, values_size); \ - } \ - return wrote; \ -} - -AUCONV_PLAY_SLINEAR_LE(16) -AUCONV_PLAY_SLINEAR_LE(24) -AUCONV_PLAY_SLINEAR_CHANNELS_LE(16) -AUCONV_PLAY_SLINEAR_CHANNELS_LE(24) -AUCONV_RECORD_SLINEAR_LE(16) -AUCONV_RECORD_SLINEAR_LE(24) -AUCONV_RECORD_SLINEAR_CHANNELS_LE(16) -AUCONV_RECORD_SLINEAR_CHANNELS_LE(24) diff --git a/sys/dev/audio.c b/sys/dev/audio.c index bc423ea7e731..c310c7ea1ee0 100644 --- a/sys/dev/audio.c +++ b/sys/dev/audio.c @@ -1,4 +1,4 @@ -/* $NetBSD: audio.c,v 1.148 2002/03/09 07:25:41 toshii Exp $ */ +/* $NetBSD: audio.c,v 1.149 2002/03/09 20:30:43 kent Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.148 2002/03/09 07:25:41 toshii Exp $"); +__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.149 2002/03/09 20:30:43 kent Exp $"); #include "audio.h" #if NAUDIO > 0 @@ -776,9 +776,11 @@ audio_initbufs(struct audio_softc *sc) DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_mode)); audio_init_ringbuffer(&sc->sc_rr); +#if NAURATECONV > 0 auconv_init_context(&sc->sc_rconv, sc->sc_rparams.hw_sample_rate, sc->sc_rparams.sample_rate, sc->sc_rr.start, sc->sc_rr.end); +#endif sc->sc_rconvbuffer_begin = 0; sc->sc_rconvbuffer_end = 0; if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) { @@ -789,9 +791,11 @@ audio_initbufs(struct audio_softc *sc) } audio_init_ringbuffer(&sc->sc_pr); +#if NAURATECONV > 0 auconv_init_context(&sc->sc_pconv, sc->sc_pparams.sample_rate, sc->sc_pparams.hw_sample_rate, sc->sc_pr.start, sc->sc_pr.end); +#endif sc->sc_sil_count = 0; if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) { error = hw->init_output(sc->hw_hdl, sc->sc_pr.start, @@ -1235,9 +1239,21 @@ audio_read(struct audio_softc *sc, struct uio *uio, int ioflag) * The format of data in the ring buffer is * [hw_sample_rate, hw_encoding, hw_precision, hw_channels] */ +#if NAURATECONV > 0 sc->sc_rconvbuffer_end = auconv_record(&sc->sc_rconv, params, sc->sc_rconvbuffer, outp, cc); +#else + n = cb->end - outp; + if (cc <= n) { + memcpy(sc->sc_rconvbuffer, outp, cc); + } else { + memcpy(sc->sc_rconvbuffer, outp, n); + memcpy(sc->sc_rconvbuffer + n, cb->start, + cc - n); + } + sc->sc_rconvbuffer_end = cc; +#endif /* !NAURATECONV */ /* * The format of data in sc_rconvbuffer is * [sample_rate, hw_encoding, hw_precision, channels] @@ -1627,8 +1643,18 @@ audio_write(struct audio_softc *sc, struct uio *uio, int ioflag) * The format of data in sc_pconvbuffer is: * [sample_rate, hw_encoding, hw_precision, channels] */ +#if NAURATECONV > 0 cc = auconv_play(&sc->sc_pconv, params, inp, sc->sc_pconvbuffer, cc); +#else + n = cb->end - inp; + if (cc <= n) { + memcpy(inp, sc->sc_pconvbuffer, cc); + } else { + memcpy(inp, sc->sc_pconvbuffer, n); + memcpy(cb->start, sc->sc_pconvbuffer + n, cc - n); + } +#endif /* !NAURATECONV */ /* * The format of data in inp is: * [hw_sample_rate, hw_encoding, hw_precision, hw_channels] @@ -2564,6 +2590,18 @@ au_get_port(struct audio_softc *sc, struct au_mixer_ports *ports) return aumask; } +#if NAURATECONV <= 0 +/* dummy function for the case that aurateconv is not linked */ +int +auconv_check_params(const struct audio_params *params) +{ + if (params->hw_channels == params->channels + && params->hw_sample_rate == params->sample_rate) + return 0; /* No conversion */ + return (EINVAL); +} +#endif /* !NAURATECONV */ + int audiosetinfo(struct audio_softc *sc, struct audio_info *ai) { diff --git a/sys/dev/audiovar.h b/sys/dev/audiovar.h index 85084275cc7d..41ae94ec25de 100644 --- a/sys/dev/audiovar.h +++ b/sys/dev/audiovar.h @@ -1,4 +1,4 @@ -/* $NetBSD: audiovar.h,v 1.21 2002/03/07 14:37:02 kent Exp $ */ +/* $NetBSD: audiovar.h,v 1.22 2002/03/09 20:30:43 kent Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -35,7 +35,7 @@ * From: Header: audiovar.h,v 1.3 93/07/18 14:07:25 mccanne Exp (LBL) */ -#include "auconv.h" /* for AUDIO_MAX_CHANNELS */ +#include "aurateconvproto.h" /* for AUDIO_MAX_CHANNELS */ /* * Initial/default block duration is both configurable and patchable. @@ -119,13 +119,17 @@ struct audio_softc { u_char sc_input_fragment[MAX_SAMPLE_SIZE]; int sc_pconvbuffer_size; u_char *sc_pconvbuffer; +#if NAURATECONV > 0 struct auconv_context sc_pconv; +#endif int sc_rconvbuffer_size; int sc_rconvbuffer_begin; int sc_rconvbuffer_end; u_char *sc_rconvbuffer; +#if NAURATECONV > 0 struct auconv_context sc_rconv; +#endif u_char sc_blkset; /* Blocksize has been set */ diff --git a/sys/dev/aurateconv.c b/sys/dev/aurateconv.c new file mode 100644 index 000000000000..0c6eba2f8fc4 --- /dev/null +++ b/sys/dev/aurateconv.c @@ -0,0 +1,684 @@ +/* $NetBSD: aurateconv.c,v 1.1 2002/03/09 20:30:43 kent Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by TAMURA Kent + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: aurateconv.c,v 1.1 2002/03/09 20:30:43 kent Exp $"); + +#include +#include +#include +#include + +#include "audio_if.h" +#include "aurateconvproto.h" + +#ifdef AURATECONV_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) +#endif + +static int auconv_play_slinear16_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); +static int auconv_play_slinear16_channels_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); +static int auconv_play_slinear24_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); +static int auconv_play_slinear24_channels_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); + +static int auconv_record_slinear16_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); +static int auconv_record_slinear16_channels_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); +static int auconv_record_slinear24_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); +static int auconv_record_slinear24_channels_le(struct auconv_context *, + const struct audio_params *, uint8_t *, const uint8_t *, int); + +int +auconv_check_params(const struct audio_params *params) +{ + DPRINTF(("auconv_check_params: rate=%ld:%ld chan=%d:%d prec=%d:%d " + "enc=%d:%d\n", params->sample_rate, params->hw_sample_rate, + params->channels, params->hw_channels, params->precision, + params->hw_precision, params->encoding, params->hw_encoding)); + if (params->hw_channels == params->channels + && params->hw_sample_rate == params->sample_rate) + return 0; /* No conversion */ + + if (params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE + || (params->hw_precision != 16 && params->hw_precision != 24)) + return (EINVAL); + + /* Only 1:2 or 2:1 */ + if (params->hw_channels != params->channels) + if (!((params->hw_channels == 1 && params->channels == 2) + || (params->hw_channels == 2 && params->channels == 1))) + return (EINVAL); + + if (params->hw_sample_rate != params->sample_rate) + if (params->hw_sample_rate <= 0 || params->sample_rate <= 0) + return (EINVAL); + return 0; +} + +void +auconv_init_context(struct auconv_context *context, long src_rate, + long dst_rate, uint8_t *start, uint8_t *end) +{ + int i; + + context->ring_start = start; + context->ring_end = end; + if (dst_rate > src_rate) { + context->count = src_rate; + } else { + context->count = 0; + } + for (i = 0; i < AUDIO_MAX_CHANNELS; i++) + context->prev[i] = 0; +} + +/* + * src is a ring buffer. + */ +int +auconv_record(struct auconv_context *context, + const struct audio_params *params, uint8_t *dest, + const uint8_t *src, int srcsize) +{ + if (params->hw_sample_rate == params->sample_rate + && params->hw_channels == params->channels) { + int n; + + n = context->ring_end - src; + if (srcsize <= n) + memcpy(dest, src, srcsize); + else { + memcpy(dest, src, n); + memcpy(dest + n, context->ring_start, srcsize - n); + } + return srcsize; + } + + if (params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE) { + /* This should be rejected in auconv_check_params() */ + printf("auconv_record: unimplemented encoding: %d\n", + params->hw_encoding); + return 0; + } + switch (params->hw_precision) { + case 16: + if (params->hw_channels != params->channels) + return auconv_record_slinear16_channels_le(context, + params, dest, src, srcsize); + else + return auconv_record_slinear16_le(context, + params, dest, src, srcsize); + case 24: + if (params->hw_channels != params->channels) + return auconv_record_slinear24_channels_le(context, + params, dest, src, srcsize); + else + return auconv_record_slinear24_le(context, + params, dest, src, srcsize); + } + printf("auconv_record: unimplemented precision: %d\n", + params->hw_precision); + return 0; +} + +/* + * dest is a ring buffer. + */ +int +auconv_play(struct auconv_context *context, const struct audio_params *params, + uint8_t *dest, const uint8_t *src, int srcsize) +{ + int n; + + if (params->hw_sample_rate == params->sample_rate + && params->hw_channels == params->channels) { + n = context->ring_end - dest; + if (srcsize <= n) { + memcpy(dest, src, srcsize); + } else { + memcpy(dest, src, n); + memcpy(context->ring_start, src + n, srcsize - n); + } + return srcsize; + } + + if (params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE) { + /* This should be rejected in auconv_check_params() */ + printf("auconv_play: unimplemented encoding: %d\n", + params->hw_encoding); + return 0; + } + switch (params->hw_precision) { + case 16: + if (params->hw_channels != params->channels) + return auconv_play_slinear16_channels_le(context, + params, dest, src, srcsize); + else + return auconv_play_slinear16_le(context, + params, dest, src, srcsize); + case 24: + if (params->hw_channels != params->channels) + return auconv_play_slinear24_channels_le(context, + params, dest, src, srcsize); + else + return auconv_play_slinear24_le(context, + params, dest, src, srcsize); + } + printf("auconv_play: unimplemented precision: %d\n", + params->hw_precision); + return 0; +} + + +#define RING_CHECK(C, V) \ + do { \ + if (V >= (C)->ring_end) \ + V = (C)->ring_start; \ + } while (0) + +#if BYTE_ORDER == LITTLE_ENDIAN +# define READ_S16LE(P) *(int16_t*)(P) +# define WRITE_S16LE(P, V) *(int16_t*)(P) = V +#else +# define READ_S16LE(P) (int16_t)((P)[0] | ((P)[1]<<8)) +# define WRITE_S16LE(P, V) \ + do { \ + int vv = V; \ + (P)[0] = vv; \ + (P)[1] = vv >> 8; \ + } while (0) +#endif +#define READ_S24LE(P) (int32_t)((P)[0] | ((P)[1]<<8) | (((int8_t)((P)[2]))<<16)) +#define WRITE_S24LE(P, V) \ + do { \ + int vvv = V; \ + (P)[0] = vvv; \ + (P)[1] = vvv >> 8; \ + (P)[2] = vvv >> 16; \ + } while (0) + +#define P_READ_LR_S16LE(LV, RV, RP, PAR) \ + do { \ + LV = READ_S16LE(RP); \ + RP += sizeof(int16_t); \ + if ((PAR)->channels == 1) \ + RV = LV; \ + else { \ + RV = READ_S16LE(RP); \ + RP += sizeof(int16_t); \ + } \ + } while (0) +#define P_WRITE_LR_S16LE(LV, RV, WP, PAR, CON, WC) \ + do { \ + if ((PAR)->hw_channels == 1) { \ + WRITE_S16LE(WP, (LV + RV) / 2); \ + WP += sizeof(int16_t); \ + WC += sizeof(int16_t); \ + } else { \ + WRITE_S16LE(WP, LV); \ + WP += sizeof(int16_t); \ + RING_CHECK(CON, WP); \ + WRITE_S16LE(WP, RV); \ + WP += sizeof(int16_t); \ + WC += sizeof(int16_t) * 2; \ + } \ + RING_CHECK(CON, WP); \ + } while (0) +#define P_READ_N_S16LE(V, RP, PAR) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + (V)[i] = READ_S16LE(RP); \ + RP += sizeof(int16_t); \ + } \ + } while (0) +#define P_WRITE_N_S16LE(V, WP, PAR, CON, WC) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + WRITE_S16LE(WP, (V)[i]); \ + WP += sizeof(int16_t); \ + RING_CHECK(CON, WP); \ + } \ + WC += sizeof(int16_t) * i; \ + } while (0) +#define P_READ_LR_S24LE(LV, RV, RP, PAR) \ + do { \ + LV = READ_S24LE(RP); \ + RP += 3; \ + if ((PAR)->channels == 1) \ + RV = LV; \ + else { \ + RV = READ_S24LE(RP); \ + RP += 3; \ + } \ + } while (0) +#define P_WRITE_LR_S24LE(LV, RV, WP, PAR, CON, WC) \ + do { \ + if ((PAR)->hw_channels == 1) { \ + WRITE_S24LE(WP, (LV + RV) / 2); \ + WP += 3; \ + WC += 3; \ + } else { \ + WRITE_S24LE(WP, LV); \ + WP += 3; \ + RING_CHECK(CON, WP); \ + WRITE_S24LE(WP, RV); \ + WP += 3; \ + WC += 3 * 2; \ + } \ + RING_CHECK(CON, WP); \ + } while (0) +#define P_READ_N_S24LE(V, RP, PAR) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + (V)[i] = READ_S24LE(RP); \ + RP += 3; \ + } \ + } while (0) +#define P_WRITE_N_S24LE(V, WP, PAR, CON, WC) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + WRITE_S24LE(WP, (V)[i]); \ + WP += 3; \ + RING_CHECK(CON, WP); \ + } \ + WC += 3 * i; \ + } while (0) + +#define R_READ_LR_S16LE(LV, RV, RP, PAR, CON, RC) \ + do { \ + LV = READ_S16LE(RP); \ + RP += sizeof(int16_t); \ + RING_CHECK(CON, RP); \ + RC += sizeof(int16_t); \ + if ((PAR)->hw_channels == 1) \ + RV = LV; \ + else { \ + RV = READ_S16LE(RP); \ + RP += sizeof(int16_t); \ + RING_CHECK(CON, RP); \ + RC += sizeof(int16_t); \ + } \ + } while (0) +#define R_WRITE_LR_S16LE(LV, RV, WP, PAR, WC) \ + do { \ + if ((PAR)->channels == 1) { \ + WRITE_S16LE(WP, (LV + RV) / 2); \ + WP += sizeof(int16_t); \ + WC += sizeof(int16_t); \ + } else { \ + WRITE_S16LE(WP, LV); \ + WP += sizeof(int16_t); \ + WRITE_S16LE(WP, RV); \ + WP += sizeof(int16_t); \ + WC += sizeof(int16_t) * 2; \ + } \ + } while (0) +#define R_READ_N_S16LE(V, RP, PAR, CON, RC) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + (V)[i] = READ_S16LE(RP); \ + RP += sizeof(int16_t); \ + RING_CHECK(CON, RP); \ + RC += sizeof(int16_t); \ + } \ + } while (0) +#define R_WRITE_N_S16LE(V, WP, PAR, WC) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + WRITE_S16LE(WP, (V)[i]); \ + WP += sizeof(int16_t); \ + } \ + WC += sizeof(int16_t) * i; \ + } while (0) +#define R_READ_LR_S24LE(LV, RV, RP, PAR, CON, RC) \ + do { \ + LV = READ_S24LE(RP); \ + RP += 3; \ + RING_CHECK(CON, RP); \ + RC += 3; \ + if ((PAR)->hw_channels == 1) \ + RV = LV; \ + else { \ + RV = READ_S24LE(RP); \ + RP += 3; \ + RING_CHECK(CON, RP); \ + RC += 3; \ + } \ + } while (0) +#define R_WRITE_LR_S24LE(LV, RV, WP, PAR, WC) \ + do { \ + if ((PAR)->channels == 1) { \ + WRITE_S24LE(WP, (LV + RV) / 2); \ + WP += 3; \ + WC += 3; \ + } else { \ + WRITE_S24LE(WP, LV); \ + WP += 3; \ + WRITE_S24LE(WP, RV); \ + WP += 3; \ + WC += 3 * 2; \ + } \ + } while (0) +#define R_READ_N_S24LE(V, RP, PAR, CON, RC) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + (V)[i] = READ_S24LE(RP); \ + RP += 3; \ + RING_CHECK(CON, RP); \ + RC += 3; \ + } \ + } while (0) +#define R_WRITE_N_S24LE(V, WP, PAR, WC) \ + do { \ + int i; \ + for (i = 0; i < (PAR)->channels; i++) { \ + WRITE_S24LE(WP, (V)[i]); \ + WP += 3; \ + } \ + WC += 3 * i; \ + } while (0) + +/* + * Function templates + * + * Source may be 1 sample. Destination buffer must have space for converted + * source. + * Don't use them for 32bit data because this linear interpolation overflows + * for 32bit data. + */ +#define AUCONV_PLAY_SLINEAR_CHANNELS_LE(BITS) \ +static int \ +auconv_play_slinear##BITS##_channels_le(struct auconv_context *context, \ + const struct audio_params *params, \ + uint8_t *dest, const uint8_t *src, \ + int srcsize) \ +{ \ + int wrote; \ + uint8_t *w; \ + const uint8_t *r; \ + const uint8_t *src_end; \ + register int32_t lv, rv; \ + int32_t prev_l, prev_r, next_l, next_r, c256; \ + \ + wrote = 0; \ + w = dest; \ + r = src; \ + src_end = src + srcsize; \ + if (params->sample_rate == params->hw_sample_rate) { \ + while (r < src_end) { \ + P_READ_LR_S##BITS##LE(lv, rv, r, params); \ + P_WRITE_LR_S##BITS##LE(lv, rv, w, params, context, wrote); \ + } \ + } else if (params->hw_sample_rate < params->sample_rate) { \ + for (;;) { \ + do { \ + if (r >= src_end) \ + return wrote; \ + P_READ_LR_S##BITS##LE(lv, rv, r, params); \ + context->count += params->hw_sample_rate; \ + } while (context->count < params->sample_rate); \ + context->count -= params->sample_rate; \ + P_WRITE_LR_S##BITS##LE(lv, rv, w, params, context, wrote); \ + } \ + } else { \ + /* Initial value of context->count is params->sample_rate */ \ + prev_l = context->prev[0]; \ + prev_r = context->prev[1]; \ + P_READ_LR_S##BITS##LE(next_l, next_r, r, params); \ + for (;;) { \ + c256 = context->count * 256 / params->hw_sample_rate; \ + lv = (c256 * next_l + (256 - c256) * prev_l) >> 8; \ + rv = (c256 * next_r + (256 - c256) * prev_r) >> 8; \ + P_WRITE_LR_S##BITS##LE(lv, rv, w, params, context, wrote); \ + context->count += params->sample_rate; \ + if (context->count >= params->hw_sample_rate) { \ + context->count -= params->hw_sample_rate; \ + prev_l = next_l; \ + prev_r = next_r; \ + if (r >= src_end) \ + break; \ + P_READ_LR_S##BITS##LE(next_l, next_r, r, params); \ + } \ + } \ + context->prev[0] = next_l; \ + context->prev[1] = next_r; \ + } \ + return wrote; \ +} + +#define AUCONV_PLAY_SLINEAR_LE(BITS) \ +static int \ +auconv_play_slinear##BITS##_le(struct auconv_context *context, \ + const struct audio_params *params, \ + uint8_t *dest, const uint8_t *src, \ + int srcsize) \ +{ \ + int wrote; \ + uint8_t *w; \ + const uint8_t *r; \ + const uint8_t *src_end; \ + int32_t v[AUDIO_MAX_CHANNELS]; \ + int32_t prev[AUDIO_MAX_CHANNELS], next[AUDIO_MAX_CHANNELS], c256; \ + int i, values_size; \ + \ + wrote = 0; \ + w = dest; \ + r = src; \ + src_end = src + srcsize; \ + if (params->sample_rate == params->hw_sample_rate) { \ + while (r < src_end) { \ + P_READ_N_S##BITS##LE(v, r, params); \ + P_WRITE_N_S##BITS##LE(v, w, params, context, wrote); \ + } \ + } else if (params->hw_sample_rate < params->sample_rate) { \ + for (;;) { \ + do { \ + if (r >= src_end) \ + return wrote; \ + P_READ_N_S##BITS##LE(v, r, params); \ + context->count += params->hw_sample_rate; \ + } while (context->count < params->sample_rate); \ + context->count -= params->sample_rate; \ + P_WRITE_N_S##BITS##LE(v, w, params, context, wrote); \ + } \ + } else { \ + /* Initial value of context->count is params->sample_rate */ \ + values_size = sizeof(int32_t) * params->channels; \ + memcpy(prev, context->prev, values_size); \ + P_READ_N_S##BITS##LE(next, r, params); \ + for (;;) { \ + c256 = context->count * 256 / params->hw_sample_rate; \ + for (i = 0; i < params->channels; i++) \ + v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \ + P_WRITE_N_S##BITS##LE(v, w, params, context, wrote); \ + context->count += params->sample_rate; \ + if (context->count >= params->hw_sample_rate) { \ + context->count -= params->hw_sample_rate; \ + memcpy(prev, next, values_size); \ + if (r >= src_end) \ + break; \ + P_READ_N_S##BITS##LE(next, r, params); \ + } \ + } \ + memcpy(context->prev, next, values_size); \ + } \ + return wrote; \ +} + +#define AUCONV_RECORD_SLINEAR_CHANNELS_LE(BITS) \ +static int \ +auconv_record_slinear##BITS##_channels_le(struct auconv_context *context, \ + const struct audio_params *params, \ + uint8_t *dest, const uint8_t *src, \ + int srcsize) \ +{ \ + int wrote, rsize; \ + uint8_t *w; \ + const uint8_t *r; \ + register int32_t lv, rv; \ + int32_t prev_l, prev_r, next_l, next_r, c256; \ + \ + wrote = 0; \ + rsize = 0; \ + w = dest; \ + r = src; \ + if (params->sample_rate == params->hw_sample_rate) { \ + while (rsize < srcsize) { \ + R_READ_LR_S##BITS##LE(lv, rv, r, params, context, rsize); \ + R_WRITE_LR_S##BITS##LE(lv, rv, w, params, wrote); \ + } \ + } else if (params->sample_rate < params->hw_sample_rate) { \ + for (;;) { \ + do { \ + if (rsize >= srcsize) \ + return wrote; \ + R_READ_LR_S##BITS##LE(lv, rv, r, params, \ + context, rsize); \ + context->count += params->sample_rate; \ + } while (context->count < params->hw_sample_rate); \ + context->count -= params->hw_sample_rate; \ + R_WRITE_LR_S##BITS##LE(lv, rv, w, params, wrote); \ + } \ + } else { \ + /* Initial value of context->count is params->hw_sample_rate */ \ + prev_l = context->prev[0]; \ + prev_r = context->prev[1]; \ + R_READ_LR_S##BITS##LE(next_l, next_r, r, params, context, rsize); \ + for (;;) { \ + c256 = context->count * 256 / params->sample_rate; \ + lv = (c256 * next_l + (256 - c256) * prev_l) >> 8; \ + rv = (c256 * next_r + (256 - c256) * prev_r) >> 8; \ + R_WRITE_LR_S##BITS##LE(lv, rv, w, params, wrote); \ + context->count += params->hw_sample_rate; \ + if (context->count >= params->sample_rate) { \ + context->count -= params->sample_rate; \ + prev_l = next_l; \ + prev_r = next_r; \ + if (rsize >= srcsize) \ + break; \ + R_READ_LR_S##BITS##LE(next_l, next_r, r, \ + params, context, rsize); \ + } \ + } \ + context->prev[0] = next_l; \ + context->prev[1] = next_r; \ + } \ + return wrote; \ +} + +#define AUCONV_RECORD_SLINEAR_LE(BITS) \ +static int \ +auconv_record_slinear##BITS##_le(struct auconv_context *context, \ + const struct audio_params *params, \ + uint8_t *dest, const uint8_t *src, \ + int srcsize) \ +{ \ + int wrote, rsize; \ + uint8_t *w; \ + const uint8_t *r; \ + int32_t v[AUDIO_MAX_CHANNELS]; \ + int32_t prev[AUDIO_MAX_CHANNELS], next[AUDIO_MAX_CHANNELS], c256; \ + int i, values_size; \ + \ + wrote = 0; \ + rsize = 0; \ + w = dest; \ + r = src; \ + if (params->sample_rate == params->hw_sample_rate) { \ + while (rsize < srcsize) { \ + R_READ_N_S##BITS##LE(v, r, params, context, rsize); \ + R_WRITE_N_S##BITS##LE(v, w, params, wrote); \ + } \ + } else if (params->sample_rate < params->hw_sample_rate) { \ + for (;;) { \ + do { \ + if (rsize >= srcsize) \ + return wrote; \ + R_READ_N_S##BITS##LE(v, r, params, context, rsize); \ + context->count += params->sample_rate; \ + } while (context->count < params->hw_sample_rate); \ + context->count -= params->hw_sample_rate; \ + R_WRITE_N_S##BITS##LE(v, w, params, wrote); \ + } \ + } else { \ + /* Initial value of context->count is params->hw_sample_rate */ \ + values_size = sizeof(int32_t) * params->channels; \ + memcpy(prev, context->prev, values_size); \ + R_READ_N_S##BITS##LE(next, r, params, context, rsize); \ + for (;;) { \ + c256 = context->count * 256 / params->sample_rate; \ + for (i = 0; i < params->channels; i++) \ + v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \ + R_WRITE_N_S##BITS##LE(v, w, params, wrote); \ + context->count += params->hw_sample_rate; \ + if (context->count >= params->sample_rate) { \ + context->count -= params->sample_rate; \ + memcpy(prev, next, values_size); \ + if (rsize >= srcsize) \ + break; \ + R_READ_N_S##BITS##LE(next, r, params, context, rsize); \ + } \ + } \ + memcpy(context->prev, next, values_size); \ + } \ + return wrote; \ +} + +AUCONV_PLAY_SLINEAR_LE(16) +AUCONV_PLAY_SLINEAR_LE(24) +AUCONV_PLAY_SLINEAR_CHANNELS_LE(16) +AUCONV_PLAY_SLINEAR_CHANNELS_LE(24) +AUCONV_RECORD_SLINEAR_LE(16) +AUCONV_RECORD_SLINEAR_LE(24) +AUCONV_RECORD_SLINEAR_CHANNELS_LE(16) +AUCONV_RECORD_SLINEAR_CHANNELS_LE(24) diff --git a/sys/dev/aurateconvproto.h b/sys/dev/aurateconvproto.h new file mode 100644 index 000000000000..c9dd3d11455e --- /dev/null +++ b/sys/dev/aurateconvproto.h @@ -0,0 +1,64 @@ +/* $NetBSD: aurateconvproto.h,v 1.1 2002/03/09 20:30:43 kent Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by TAMURA Kent + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_DEV_AURATECONVPROTO_H_ +#define _SYS_DEV_AURATECONVPROTO_H_ + +#include "audio_if.h" +#include "aurateconv.h" + +#define AUDIO_MAX_CHANNELS 6 +extern int auconv_check_params(const struct audio_params *); + +#if NAURATECONV > 0 +struct auconv_context { + long count; + int32_t prev[AUDIO_MAX_CHANNELS]; + uint8_t *ring_start; + uint8_t *ring_end; +}; + +extern void auconv_init_context(struct auconv_context *, long, long, uint8_t *, + uint8_t *); +extern int auconv_play(struct auconv_context *, const struct audio_params *, + uint8_t *, const uint8_t *, int); +extern int auconv_record(struct auconv_context *, const struct audio_params *, + uint8_t *, const uint8_t *, int); +#endif + +#endif /* _SYS_DEV_AURATECONVPROTO_H_ */ diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index b676c10fe49a..093d7bc2942b 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $NetBSD: files.pci,v 1.162 2002/02/02 18:37:46 jdolecek Exp $ +# $NetBSD: files.pci,v 1.163 2002/03/09 20:30:44 kent Exp $ # # Config file and device description for machine-independent PCI code. # Included by ports that need it. Requires that the SCSI files be @@ -280,7 +280,7 @@ attach eap at pci file dev/pci/eap.c eap # Intel ICH AC'97 audio -device auich: audio, auconv, mulaw, ac97 +device auich: audio, auconv, mulaw, ac97, aurateconv attach auich at pci file dev/pci/auich.c auich diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index f9d99eed347e..a8fbf44bbaf4 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $NetBSD: files.usb,v 1.40 2002/01/07 17:44:45 drochner Exp $ +# $NetBSD: files.usb,v 1.41 2002/03/09 20:30:44 kent Exp $ # # Config file and device description for machine-independent USB code. # Included by ports that need it. Ports that use it must provide @@ -31,7 +31,7 @@ define ezload file dev/usb/ezload.c ezload # Audio devices -device uaudio: audio, auconv, mulaw +device uaudio: audio, auconv, mulaw, aurateconv attach uaudio at uhub file dev/usb/uaudio.c uaudio