Move sampling rate conversion functions to aurateconv.c.

Introduce "aurateconv" attribute for audio devices.
Add aurateconv to uaudio and auich.
(due to kern/15845 and kern/15848)
This commit is contained in:
kent 2002-03-09 20:30:42 +00:00
parent d76e3cd5fe
commit a1f23f2a90
7 changed files with 800 additions and 650 deletions

View File

@ -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 <sys/cdefs.h>
__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 <sys/systm.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/audioio.h>
#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)

View File

@ -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 <sys/cdefs.h>
__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)
{

View File

@ -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 */

684
sys/dev/aurateconv.c Normal file
View File

@ -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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: aurateconv.c,v 1.1 2002/03/09 20:30:43 kent Exp $");
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/audioio.h>
#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)

64
sys/dev/aurateconvproto.h Normal file
View File

@ -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_ */

View File

@ -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

View File

@ -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