Open Sound System |
Do you have problems with sound/audio application development? Don't panic! Click here for help! |
This file is part of Open Sound System.
Copyright (C) 4Front Technologies 1996-2008.
This this source file is released under GPL v2 license (no other versions). See the COPYING file included in the main directory of this source distribution for the license terms and conditions.
#undef NO_COOKED_MODE #define AUDIO_C #define GRC 3 /* SINE_DEBUG enables internal test signal (sine wave) */ #undef SINE_DEBUG #include "oss_config.h" #include "ulaw.h" #define __int8_t_defined #include "grc3.h"
Audio format conversion stuff
#define CNV_NONE 0x00000000 #define CNV_SRC 0x00000001 #define CNV_CHNMASK 0x000000f0 #define CNV_M2S 0x00000010 #define CNV_S2M 0x00000020 #define CNV_MULT 0x00000040 #define CNV_Flog 0x00001000 #define CNV_F8bit 0x00002000 #define CNV_F16bit 0x00004000 #define CNV_F24bit 0x00008000 #define CNV_F32bit 0x00010000 #define CNV_Tlog 0x00100000 #define CNV_T8bit 0x00200000 #define CNV_T16bit 0x00400000 #define CNV_T24bit 0x00800000 #define CNV_T32bit 0x01000000 #define CNV_SIGN 0x10000000 #define CNV_ENDIAN 0x20000000 #define CNV_TOLOG 0x40000000 #define CNV_FROMLOG 0x80000000 static audio_format_info_t audio_format_info[] = { {"mu-Law", AFMT_MU_LAW, 0x80, 8, 0, ENDIAN_NONE, 1}, {"A-Law", AFMT_A_LAW, 0x80, 8, 0, ENDIAN_NONE, 1}, {"IMA-ADPCM", AFMT_IMA_ADPCM, 0x00, 4, 0, ENDIAN_NONE, 0, ALIGN_LSB, 1}, {"8", AFMT_U8, 0x80, 8, 1, ENDIAN_NONE, 0}, {"16(LE)", AFMT_S16_LE, 0x00, 16, 1, ENDIAN_LITTLE, 1}, {"16(BE)", AFMT_S16_BE, 0x00, 16, 1, ENDIAN_BIG, 1}, {"8(signed)", AFMT_S8, 0x00, 8, 1, ENDIAN_NONE, 1}, {"16(unsigned LE)", AFMT_U16_LE, 0x00, 16, 1, ENDIAN_LITTLE, 0}, {"16(unsigned BE)", AFMT_U16_BE, 0x00, 16, 1, ENDIAN_BIG, 0}, {"mp2/mp3", AFMT_MPEG, 0x00, 8, 0, ENDIAN_NONE, 0, ALIGN_LSB, 1}, {"AC3", AFMT_AC3, 0x00, 16, 0, ENDIAN_NONE, 0, ALIGN_LSB, 1}, {"SPDIF (RAW)", AFMT_SPDIF_RAW, 0x00, 32, 0, ENDIAN_NONE, 0, ALIGN_LSB, 1}, {"24(LE)", AFMT_S24_LE, 0x00, 32, 1, ENDIAN_LITTLE, 1, ALIGN_LSB}, {"24(BE)", AFMT_S24_BE, 0x00, 32, 1, ENDIAN_BIG, 1, ALIGN_LSB}, {"32(LE)", AFMT_S32_LE, 0x00, 32, 1, ENDIAN_LITTLE, 1}, {"32(BE)", AFMT_S32_BE, 0x00, 32, 1, ENDIAN_BIG, 1}, {"24(PACKED)", AFMT_S24_PACKED, 0x00, 24, 1, ENDIAN_LITTLE, 1, ALIGN_LSB}, {0, 0} }; audio_format_info_p oss_find_format (unsigned int fmt) { int i; i = 0; while (audio_format_info[i].fmt != 0) { if (audio_format_info[i].fmt == fmt) return &audio_format_info[i]; i++; } return NULL; } #if 0
Limiter stuff. Currently not in use.
static const unsigned char limit8[] = { /*-128*/ 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, /*-112*/ 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, /* -96*/ 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, /* -80*/ 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, /* -64*/ 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, /* -48*/ 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, /* -32*/ 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, /* -16*/ 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127, 128, /* 0*/ 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, /* 16*/ 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143, /* 32*/ 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, /* 48*/ 152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 159, /* 64*/ 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 167, /* 80*/ 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, 175, 175, /* 96*/ 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 181, 182, 182, 183, 183, /* 112*/ 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191 }; static __inline__ void limit_8bit (unsigned char *buf, int l) { int i; for (i = 0; i < l; i++) buf[i] = limit8[buf[i]]; } static __inline__ void limit_16bit (short *buf, int l) { int i; l /= sizeof (*buf); for (i = 0; i < l; i++) buf[i] /= 2; } static __inline__ void limit_32bit (int *buf, int l) { int i; l /= sizeof (*buf); for (i = 0; i < l; i++) buf[i] /= 2; } static const unsigned char unlimit8[] = { /* 0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 48*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64*/ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, /* 80*/ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, /* 96*/ 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, /* 112*/ 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, /* 128*/ 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, /* 144*/ 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, /* 160*/ 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, /* 176*/ 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, /* 192*/ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, /* 208*/ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, /* 224*/ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, /* 240*/ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; static __inline__ void unlimit_8bit (unsigned char *buf, int l) { int i; for (i = 0; i < l; i++) buf[i] = unlimit8[buf[i]]; } static __inline__ void unlimit_16bit (short *buf, int l) { int i; l /= sizeof (*buf); for (i = 0; i < l; i++) buf[i] *= 2; } static __inline__ void unlimit_32bit (int *buf, int l) { int i; l /= sizeof (*buf); for (i = 0; i < l; i++) buf[i] *= 2; } #endif /*ARGSUSED*/ static int do_src (adev_p adev, dmap_p dmap, int srcrate, int tgtrate, void *p1, void *p2, int *len, int channels, int bits, int ssize) { #if GRC == 2 int err, l, l1, l2; l = *len; err = src_convert (dmap->src, p1, l, bits, p2, 4096, 24, &l1, &l2, 0); *len = l2; if (l1 != l) cmn_err (CE_NOTE, "Everything not taken %d/%d\n", l1, l); #endif #if GRC == 3 int ch, l, size, nsamples, err; l = *len / ssize; size = TMP_CONVERT_BUF_SIZE / ssize; size /= channels; nsamples = l / channels; if (bits == 24) bits = 32; # ifdef DO_TIMINGS oss_timing_printf ("grc3_convert %d bytes / %d samples * %d channels in. ", *len, nsamples, channels); # endif #if 0 /* Limit the volume levels before calling GRC3 */ buf = p1; switch (ssize) { case 1: limit_8bit ((unsigned char *) buf, *len); break; case 2: limit_16bit ((short *) buf, *len); break; case 4: limit_32bit ((int *) buf, *len); break; } #endif for (ch = 0; ch < channels; ch++) { if ((err = grc3_convert (dmap->srcstate[ch], bits, adev->src_quality, /* Numbits, quality */ p1, p2, nsamples, size, channels, ch)) < 0) { cmn_err (CE_WARN, "SRC failed (%d), bits=%d, ssize=%d\n", err, bits, ssize); return OSS_EIO; } *len = ((grc3state_t *) dmap->srcstate[ch])->outsz * ssize * channels; VMEM_CHECK (p2, *len); } #if 0 buf = p2; switch (ssize) { case 1: unlimit_8bit ((unsigned char *) buf, *len); break; case 2: unlimit_16bit ((short *) buf, *len); break; case 4: unlimit_32bit ((int *) buf, *len); break; } #endif # ifdef DO_TIMINGS oss_timing_printf ("-> %d bytes, %d samples out, %d samples in", *len, ((grc3state_t *) dmap->srcstate[0])->outsz, ((grc3state_t *) dmap->srcstate[0])->insz); # endif #endif return 0; } static int setup_src (adev_p adev, dmap_p dmap, int srate, int trate, int sch, int tch) { int ch, nch; nch = sch; if (tch < nch) nch = tch; if (adev->src_quality < 1) adev->src_quality = 1; if (adev->src_quality > 5) adev->src_quality = 5; #if GRC == 2 if (nch > 2) { cmn_err (CE_WARN, "Too many channels for SRC (%d)\n", nch); return OSS_EIO; } { int val; val = src_find_output_rate (trate, srate); if (src_open (&dmap->src, srate, trate, nch, 0) != 0) { cmn_err (CE_CONT, "OSS audio: SRC open failed\n"); return OSS_EIO; } } #endif #if GRC == 3 if (nch > OSS_MAX_CONVERT_CHANNELS) { cmn_err (CE_WARN, "Too many channels for SRC (%d)\n", nch); return OSS_EIO; } #ifdef DO_TIMINGS oss_timing_printf ("grc3_setup %d -> %d Hz, %d channels", srate, trate, nch); #endif for (ch = 0; ch < nch; ch++) { if (dmap->srcstate[ch] == NULL) { dmap->srcstate[ch] = PMALLOC (dmap->osdev, sizeof (grc3state_t)); } grc3_reset (dmap->srcstate[ch]); grc3_setup (dmap->srcstate[ch], srate, trate); } #endif return 0; } #if !defined(__OpenBSD__) static __inline__ unsigned int swap32 (unsigned int x) { #if 1 unsigned int y = 0; unsigned char *a = ((unsigned char *) &x) + 3; unsigned char *b = (unsigned char *) &y; *b++ = *a--; *b++ = *a--; *b++ = *a--; *b++ = *a--; return y; #else /* Old version */ return ((x & 0x000000ff) << 24) | ((x & 0x0000ff00) << 8) | ((x & 0x00ff0000) >> 8) | ((x & 0xff000000) >> 24); #endif } #endif #ifdef SINE_DEBUG #define SIN_STEPS 48 static short sinebuf[48] = { 0, 4276, 8480, 12539, 16383, 19947, 23169, 25995, 28377, 30272, 31650, 32486, 32767, 32486, 31650, 30272, 28377, 25995, 23169, 19947, 16383, 12539, 8480, 4276, 0, -4276, -8480, -12539, -16383, -19947, -23169, -25995, -28377, -30272, -31650, -32486, -32767, -32486, -31650, -30272, -28377, -25995, -23169, -19947, -16383, -12539, -8480, -4276 }; static int sine_ptr = 0; #endif static int cnv_default (adev_p adev, dmap_p dmap, unsigned char **srcp, int *srcl, unsigned char **tgtp, sample_parms * source, sample_parms * target) { void *p1 = *srcp, *p2 = *tgtp, *tmpp; int len = *srcl, l, i;
Convert samples to 24 bit (32 bit lsb aligned) if necessary.
VMEM_CHECK (p1, len); VMEM_CHECK (p2, len); if (source->fmt != AFMT_S24_NE) switch (source->fmt) { case AFMT_U8: { unsigned char *fromp = p1; unsigned int *top = p2; l = len; len = l * sizeof (int); for (i = 0; i < l; i++) { *top++ = ((signed char) (*fromp++ ^ 0x80)) << 16; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S8: { char *fromp = p1; int *top = p2; int t; l = len; len = l * sizeof (int); for (i = 0; i < l; i++) { t = (*fromp++) << 24; *top++ = t >> 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_MU_LAW: { unsigned char *fromp = p1; unsigned int *top = p2; l = len; len = l * sizeof (int); for (i = 0; i < l; i++) { *top++ = ((signed char) (ulaw_dsp[(*fromp++)] ^ 0x80)) << 16; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S16_NE: { short *fromp = p1; int *top = p2; l = len / 2; len = l * sizeof (int); for (i = 0; i < l; i++) { *top++ = *fromp++ << 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S16_OE: { short *fromp = p1; int *top = p2; l = len / 2; len = l * sizeof (int); for (i = 0; i < l; i++) { short tmp; int t; tmp = *fromp++; /* Try to maintain the sign bit by shifting 8 bits too far */ t = ((tmp & 0xff) << 24) | ((tmp & 0xff00) << 8); *top++ = t >> 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S32_NE: { int *fromp = p1; int *top = p2; l = len / 4; /* len = l * sizeof (int); */ for (i = 0; i < l; i++) { *top++ = *fromp++ >> 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S32_OE: { int *fromp = p1; int *top = p2; l = len / 4; /* len = l * sizeof (int); */ for (i = 0; i < l; i++) { *top++ = swap32 (*fromp++) >> 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S24_OE: { int *fromp = p1; int *top = p2; l = len / 4; /* len = l * sizeof (int); */ for (i = 0; i < l; i++) { *top++ = swap32 ((unsigned int) (*fromp++)); } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S24_PACKED: { unsigned char *fromp = p1; int *top = p2; l = len / 3; len = l * sizeof (int); for (i = 0; i < l; i++) { int tmp = 0; #if 1 tmp |= (*fromp++); tmp |= (*fromp++) << 8; tmp |= (*fromp++) << 16; #else tmp |= (*fromp++) << 16; tmp |= (*fromp++) << 8; tmp |= (*fromp++); #endif *top++ = tmp; } tmpp = p1; p1 = p2; p2 = tmpp; } break; default: cmn_err (CE_WARN, "Unsupported conversion source format %08x\n", source->fmt); return OSS_EIO; } if (source->rate != target->rate && source->channels <= target->channels) { int err; VMEM_CHECK (p1, len); err = do_src (adev, dmap, source->rate, target->rate, p1, p2, &len, source->channels, 32, 4); if (err < 0) return err; tmpp = p1; p1 = p2; p2 = tmpp; }
Convert between mono and stereo
if (source->channels != target->channels) { VMEM_CHECK (p1, len); if (source->channels == 1 && target->channels == 2) { /* Mono -> Stereo */ int *fromp = p1, *top = p2; l = len / sizeof (int); /* Number of (mono) samples */ len = len * 2; /* Number of bytes will get doubled */ for (i = 0; i < l; i++) { *top++ = *fromp; *top++ = *fromp++; } tmpp = p1; p1 = p2; p2 = tmpp; } else if (source->channels == 2 && target->channels == 1) { /* Stereo -> mono */ int *fromp = p1, *top = p2; len = len / 2; /* Number of bytes will drop to a half */ l = len / sizeof (int); /* Number of (mono) samples */ for (i = 0; i < l; i++) { *top++ = *fromp++; /* Take just the left channel sample */ fromp++; /* discard the right channel one */ } tmpp = p1; p1 = p2; p2 = tmpp; } else { /* Multi channel conversions */ int *fromp = p1, *top = p2; int n, nc, sc, tc; l = len / sizeof (int); n = l / source->channels; len = len * target->channels / source->channels; tc = target->channels; sc = source->channels; nc = tc; if (nc > sc) nc = sc; memset (top, 0, len); for (i = 0; i < n; i++) { int c; for (c = 0; c < nc; c++) top[c] = fromp[c]; fromp += sc; top += tc; } tmpp = p1; p1 = p2; p2 = tmpp; } } if (source->rate != target->rate && source->channels > target->channels) { int err; VMEM_CHECK (p1, len); err = do_src (adev, dmap, source->rate, target->rate, p1, p2, &len, target->channels, 24, 4); if (err < 0) return err; tmpp = p1; p1 = p2; p2 = tmpp; } #ifdef SINE_DEBUG
Debugging stuff. Overwrite the sample buffer with pure sine wave.
{ int *p = p1; l = len / sizeof (int); for (i = 0; i < l; i += 2) { #if 1 *p++ = sinebuf[sine_ptr] << 15; /* Left chn */ *p++ = sinebuf[sine_ptr] << 15; /* Right chn */ sine_ptr = (sine_ptr + 1) % SIN_STEPS; #else static short pp = 0; *p++ = pp * 256; *p++ = pp * 256; pp++; #endif } } #endif
Finally convert the samples from internal 24 bit format to the target format
if (target->fmt != AFMT_S24_NE) switch (target->fmt) { case AFMT_U8: { unsigned int *fromp = p1; unsigned char *top = p2; l = len / sizeof (int); len = l; for (i = 0; i < l; i++) { *top++ = (*fromp++ >> 16) ^ 0x80; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S8: { int *fromp = p1; char *top = p2; l = len / sizeof (int); len = l; for (i = 0; i < l; i++) { *top++ = *fromp++ >> 16; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S16_NE: { int *fromp = p1; short *top = p2; l = len / sizeof (int); len = l * sizeof (short); for (i = 0; i < l; i++) { *top++ = *fromp++ >> 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S16_OE: { int *fromp = p1; unsigned char *top = p2; l = len / sizeof (int); len = l * sizeof (short); for (i = 0; i < l; i++) { int tmp; tmp = *fromp++ >> 8; *top++ = tmp & 0xff; *top++ = (tmp >> 8) & 0xff; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S32_NE: { int *fromp = p1; int *top = p2; l = len / 4; /* len = l * sizeof (int); */ for (i = 0; i < l; i++) { *top++ = *fromp++ << 8; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S32_OE: { int *fromp = p1; int *top = p2; l = len / 4; /* len = l * sizeof (int); */ for (i = 0; i < l; i++) { *top++ = swap32 ((unsigned int) (*fromp++ << 8)); } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S24_OE: { int *fromp = p1; int *top = p2; l = len / 4; /* len = l * sizeof (int); */ for (i = 0; i < l; i++) { *top++ = swap32 ((unsigned int) (*fromp++)); } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_S24_PACKED: { int *fromp = p1; unsigned char *top = p2; l = len / 4; len = l * 3; for (i = 0; i < l; i++) { int tmp = *fromp++; *top++ = tmp & 0xff; *top++ = (tmp >> 8) & 0xff; *top++ = (tmp >> 16) & 0xff; } tmpp = p1; p1 = p2; p2 = tmpp; } break; case AFMT_MU_LAW: { unsigned int *fromp = p1; unsigned char *top = p2; l = len / sizeof (int); len = l; for (i = 0; i < l; i++) { *top++ = dsp_ulaw[((*fromp++ >> 16) & 0xff) ^ 0x80]; } tmpp = p1; p1 = p2; p2 = tmpp; } break; default: cmn_err (CE_WARN, "Unsupported conversion target format %08x\n", target->fmt); return OSS_EIO; } VMEM_CHECK (p1, len); *srcl = len; *srcp = p1; *tgtp = p2; return 0; } static int cnv_srconly (adev_p adev, dmap_p dmap, unsigned char **srcp, int *srcl, unsigned char **tgtp, sample_parms * source, sample_parms * target) { void *p1 = *srcp, *p2 = *tgtp, *tmpp; int len = *srcl; int err; int ssize = 2; audio_format_info_p fmt; VMEM_CHECK (p1, len); VMEM_CHECK (p2, len); if ((fmt = oss_find_format (source->fmt)) == NULL) { cmn_err (CE_WARN, "Unknown audio format %x\n", source->fmt); return OSS_EIO; } switch (fmt->bits) { default: case 8: ssize = 1; break; case 16: ssize = 2; break; case 24: ssize = 4; break; case 32: ssize = 4; break; } err = do_src (adev, dmap, source->rate, target->rate, p1, p2, &len, source->channels, fmt->bits, ssize); if (err < 0) return err; tmpp = p1; p1 = p2; p2 = tmpp; VMEM_CHECK (p1, len); *srcl = len; *srcp = p1; *tgtp = p2; return 0; } #include "audiocnv.inc" static cnv_func_t select_converter (unsigned int cnv, int expand, audio_format_info_p src_f, audio_format_info_p tgt_f) { #if 1 { int expand2 = expand * 100 / UNIT_EXPAND; DDB (cmn_err (CE_CONT, "Expand = %d (%d.%02d)\n", expand, expand2 / 100, expand2 % 100)); DDB (cmn_err (CE_CONT, "Convert = %08x / ", cnv)); if (cnv & CNV_SRC) DDB (cmn_err (CE_CONT, "CNV_SRC ")); if (cnv & CNV_M2S) DDB (cmn_err (CE_CONT, "CNV_M2S ")); if (cnv & CNV_S2M) DDB (cmn_err (CE_CONT, "CNV_S2M ")); if (cnv & CNV_MULT) DDB (cmn_err (CE_CONT, "CNV_MULT ")); if (cnv & CNV_Flog) DDB (cmn_err (CE_CONT, "CNV_Flog ")); if (cnv & CNV_F8bit) DDB (cmn_err (CE_CONT, "CNV_F8bit ")); if (cnv & CNV_F16bit) DDB (cmn_err (CE_CONT, "CNV_F16bit ")); if (cnv & CNV_F24bit) DDB (cmn_err (CE_CONT, "CNV_F24bit ")); if (cnv & CNV_F32bit) DDB (cmn_err (CE_CONT, "CNV_F32bit ")); if (cnv & CNV_Tlog) DDB (cmn_err (CE_CONT, "CNV_Tlog ")); if (cnv & CNV_T8bit) DDB (cmn_err (CE_CONT, "CNV_T8bit ")); if (cnv & CNV_T16bit) DDB (cmn_err (CE_CONT, "CNV_T16bit ")); if (cnv & CNV_T24bit) DDB (cmn_err (CE_CONT, "CNV_T24bit ")); if (cnv & CNV_T32bit) DDB (cmn_err (CE_CONT, "CNV_T32bit ")); if (cnv & CNV_SIGN) DDB (cmn_err (CE_CONT, "CNV_SIGN ")); if (cnv & CNV_ENDIAN) DDB (cmn_err (CE_CONT, "CNV_ENDIAN ")); if (cnv & CNV_TOLOG) DDB (cmn_err (CE_CONT, "CNV_TOLOG ")); if (cnv & CNV_FROMLOG) DDB (cmn_err (CE_CONT, "CNV_FROMLOG ")); DDB (cmn_err (CE_CONT, "\n")); } DDB (cmn_err (CE_CONT, "\n")); #endif if (cnv == CNV_SRC) /* Only SRC is needed */ if (src_f->fmt & (CONVERTABLE_FORMATS & ~AFMT_MU_LAW)) /* Can convert this */ #ifdef OSS_BIG_ENDIAN if (src_f->endianess == ENDIAN_BIG) #else if (src_f->endianess == ENDIAN_LITTLE) #endif { DDB (cmn_err (CE_CONT, "Only SRC\n")); return cnv_srconly; } if (cnv & CNV_SRC) { /* Needs SRC together with some other conversion. Use the default. */ return cnv_default; } if (src_f->endianess != tgt_f->endianess) { /* Needs endianess handling - use the default for the time being. */ return cnv_default; } #ifdef OSS_BIG_ENDIAN if (src_f->endianess != ENDIAN_BIG) #else if (src_f->endianess != ENDIAN_LITTLE) #endif { /* Opposite endianess - use the default. */ return cnv_default; }
The remaining conversions don't use SRC and the endianess is native so they are easier to optimize.
switch (cnv) { case CNV_F8bit | CNV_T16bit: return cnv_F8bits_T16bits; case CNV_F8bit | CNV_T32bit: return cnv_F8bits_T32bits; case CNV_F16bit | CNV_T32bit: return cnv_F16bits_T32bits; case CNV_F32bit | CNV_T16bit: return cnv_F32bits_T16bits; case CNV_F32bit | CNV_T8bit: return cnv_F32bits_T8bits; case CNV_F16bit | CNV_T8bit: return cnv_F16bits_T8bits; } DDB (cmn_err (CE_CONT, "Will use the default converter\n")); return cnv_default; } /*ARGSUSED*/ int setup_format_conversions (adev_p adev, dmap_p dmap, sample_parms * source, sample_parms * target, sample_parms * user, sample_parms * device, int format_mask) { int expand = UNIT_EXPAND; unsigned int cnv = CNV_NONE; audio_format_info_p src_f, tgt_f; dmap->expand_factor = UNIT_EXPAND; if (source->fmt == AFMT_AC3) { source->channels = target->channels = 2; source->rate = target->rate; target->fmt = source->fmt; dmap->convert_mode = 0; dmap->convert_func = NULL; return 0; } if ((src_f = oss_find_format (source->fmt)) == NULL) { cmn_err (CE_CONT, "internal format error 1 (%x)\n", source->fmt); return OSS_EIO; } if ((tgt_f = oss_find_format (target->fmt)) == NULL) { cmn_err (CE_CONT, "internal format error 2\n"); return OSS_EIO; } #ifdef DO_TIMINGS oss_timing_printf ("Setting up format conversions for device %d", adev->engine_num); oss_timing_printf (" Speed %d->%d", source->rate, target->rate); oss_timing_printf (" Channels %d->%d", source->channels, target->channels); oss_timing_printf (" Format %02x/%s->%02x/%s", source->fmt, src_f->name, target->fmt, tgt_f->name); #endif DDB (cmn_err (CE_CONT, "Setting up format conversions for device %d\n", adev->engine_num)); DDB (cmn_err (CE_CONT, " Speed %d->%d\n", source->rate, target->rate)); DDB (cmn_err (CE_CONT, " Channels %d->%d\n", source->channels, target->channels)); DDB (cmn_err (CE_CONT, " Format %02x/%s->%02x/%s\n", source->fmt, src_f->name, target->fmt, tgt_f->name)); if (source->channels > OSS_MAX_CONVERT_CHANNELS || target->channels > OSS_MAX_CONVERT_CHANNELS) { cmn_err (CE_WARN, "Audio format conversions not supported with more than %d channels\n", OSS_MAX_CONVERT_CHANNELS); dmap->flags &= ~DMAP_COOKED; return OSS_EIO; } expand = (expand * target->rate) / source->rate; expand = (expand * target->channels) / source->channels; expand = (expand * tgt_f->bits) / src_f->bits; dmap->expand_factor = expand; if (source->rate != target->rate) cnv |= CNV_SRC; if (source->channels != target->channels) /* Change # of channels */ { if (target->channels > 2 || source->channels > 2) cnv |= CNV_MULT; else { if (source->channels == 1 && target->channels == 2) cnv |= CNV_M2S; else cnv |= CNV_S2M; } } if (source->fmt != target->fmt) { if (src_f->endianess != tgt_f->endianess) if (src_f->endianess != ENDIAN_NONE && tgt_f->endianess != ENDIAN_NONE) { /* Endianess change */ cnv |= CNV_ENDIAN; } if (src_f->endianess != ENDIAN_NONE && tgt_f->endianess != ENDIAN_NONE) if (src_f->is_signed != tgt_f->is_signed) { cnv |= CNV_SIGN; } if (src_f->bits != tgt_f->bits) { switch (src_f->bits) { case 8: cnv |= CNV_F8bit; break; case 16: cnv |= CNV_F16bit; break; case 24: cnv |= CNV_F24bit; break; case 32: cnv |= CNV_F32bit; break; default: cnv |= CNV_Flog; } switch (tgt_f->bits) { case 8: cnv |= CNV_T8bit; break; case 16: cnv |= CNV_T16bit; break; case 24: cnv |= CNV_T24bit; break; case 32: cnv |= CNV_T32bit; break; default: cnv |= CNV_Tlog; } } if (!src_f->is_linear) cnv |= CNV_FROMLOG; if (!tgt_f->is_linear) cnv |= CNV_TOLOG; } dmap->convert_mode = cnv; dmap->convert_func = select_converter (cnv, expand, src_f, tgt_f); dmap->tmpbuf_len = dmap->tmpbuf_ptr = 0; if (dmap->tmpbuf1 == NULL) { dmap->tmpbuf1 = PMALLOC (dmap->osdev, TMP_CONVERT_BUF_SIZE+512); } if (dmap->tmpbuf2 == NULL) { dmap->tmpbuf2 = PMALLOC (dmap->osdev, TMP_CONVERT_BUF_SIZE+512); } if (dmap->tmpbuf1 == NULL || dmap->tmpbuf2 == NULL) return OSS_ENOSPC; if (cnv & CNV_SRC) if (setup_src (adev, dmap, source->rate, target->rate, source->channels, target->channels) < 0) { cmn_err (CE_CONT, "internal format error 3\n"); return OSS_EIO; } return 0; }