diff options
Diffstat (limited to 'cmd/ossplay/ossplay_decode.c')
-rw-r--r-- | cmd/ossplay/ossplay_decode.c | 1783 |
1 files changed, 1783 insertions, 0 deletions
diff --git a/cmd/ossplay/ossplay_decode.c b/cmd/ossplay/ossplay_decode.c new file mode 100644 index 0000000..cf769af --- /dev/null +++ b/cmd/ossplay/ossplay_decode.c @@ -0,0 +1,1783 @@ +/* + * Purpose: Sample format decode routines for ossplay + * + */ +/* + * + * 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. + * + */ + +#include "ossplay_decode.h" +#include "ossplay_wparser.h" + +typedef struct cradpcm_values { + const unsigned char * const * table; + + signed char limit; + signed char shift; + signed char step; + unsigned char ratio; + unsigned char pred; +} +cradpcm_values_t; + +typedef struct fib_values { + unsigned char pred; + const signed char * table; +} +fib_values_t; + +typedef struct ima_values { + int channels; + int16 pred[MAX_CHANNELS]; + int8 index[MAX_CHANNELS]; +} +ima_values_t; + +#ifdef SRC_SUPPORT +/* + * For actual use, we can rely on vmix. + * This is useful for testing though. + */ +#include "../../kernel/framework/audio/oss_grc3.c" + +typedef struct grc_values { + int bits; + int channels; + int speed; + int ospeed; + int obsize; + grc3state_t grc[]; +} grc_data_t; +static decfunc_t decode_src; +static decfunc_t decode_mono_to_stereo; +static grc_data_t * setup_grc3 (int, int, int, int, int); +#endif + +extern int amplification, eflag, force_speed, force_fmt, force_channels; +extern flag int_conv, overwrite, verbose; +extern char audio_devname[32]; +extern off_t (*ossplay_lseek) (int, off_t, int); +extern double seek_time; +extern const format_t format_a[]; + +static void decode_ima (unsigned char *, unsigned char *, ssize_t, int16 *, + int8 *, int, int); +static void decode_ima_3bits (unsigned char *, unsigned char *, ssize_t, + int16 *, int8 *, int, int); +static decfunc_t decode_24; +static decfunc_t decode_8_to_s16; +static decfunc_t decode_amplify; +static decfunc_t decode_cr; +static decfunc_t decode_double64_be; +static decfunc_t decode_double64_le; +static decfunc_t decode_endian; +static decfunc_t decode_fib; +static decfunc_t decode_float32_be; +static decfunc_t decode_float32_le; +static decfunc_t decode_mac_ima; +static decfunc_t decode_ms_ima; +static decfunc_t decode_ms_adpcm; +static decfunc_t decode_nul; +static decfunc_t decode_raw_ima; + +static int32 float32_to_s32 (int, int, int); +static int32 double64_to_s32 (int, int32, int32, int); + +static cradpcm_values_t * setup_cr (int, int); +static fib_values_t * setup_fib (int, int); +static decoders_queue_t * setup_normalize (int *, int *, decoders_queue_t *); + +static seekfunc_t seek_normal; +static seekfunc_t seek_compressed; + +static readfunc_t read_normal; + +#ifdef OGG_SUPPORT +static readfunc_t read_ogg; +static seekfunc_t seek_ogg; +#endif + +errors_t +decode_sound (dspdev_t * dsp, int fd, big_t filesize, int format, + int channels, int speed, void * metadata) +{ + decoders_queue_t * dec, * decoders; + readfunc_t * readf; + seekfunc_t * seekf; + int bsize, obsize; + double constant, total_time; + errors_t ret = E_DECODE; + + if (force_speed != 0) speed = force_speed; + if (force_channels != 0) channels = force_channels; + if (force_fmt != 0) format = force_fmt; + if ((channels > MAX_CHANNELS) || (channels == 0)) + { + print_msg (ERRORM, "An unreasonable number of channels (%d), aborting\n", + channels); + return E_DECODE; + } + + constant = format2bits (format) * speed * channels / 8.0; + if (constant == 0) return E_DECODE; /* Shouldn't ever happen */ +#if 0 + /* + * There is no reason to use SNDCTL_DSP_GETBLKSIZE in applications like this. + * Using some fixed local buffer size will work equally well. + */ + ioctl (dsp->fd, SNDCTL_DSP_GETBLKSIZE, &bsize); +#else + bsize = PLAYBUF_SIZE; +#endif + + if (filesize < 2) return E_OK; + decoders = dec = (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + dec->next = NULL; + dec->flag = 0; + seekf = seek_normal; + readf = read_normal; + if (filesize != BIG_SPECIAL) total_time = filesize / constant; + else total_time = 0; + + switch (format) + { + case AFMT_MS_ADPCM: + if (metadata == NULL) + { + msadpcm_values_t * val = + (msadpcm_values_t *)ossplay_malloc (sizeof (msadpcm_values_t)); + + val->channels = channels; + if (speed < 22000) val->nBlockAlign = 256; + else if (speed < 44000) val->nBlockAlign = 512; + else val->nBlockAlign = 1024; + val->wSamplesPerBlock = 8 * (val->nBlockAlign - 7 * channels) / (4 * channels) + 2; + val->wNumCoeff = 7; + val->coeff[0].coeff1 = 256; val->coeff[0].coeff2 = 0; + val->coeff[1].coeff1 = 512; val->coeff[1].coeff2 = -256; + val->coeff[2].coeff1 = 0; val->coeff[2].coeff2 = 0; + val->coeff[3].coeff1 = 192; val->coeff[3].coeff2 = 64; + val->coeff[4].coeff1 = 240; val->coeff[4].coeff2 = 0; + val->coeff[5].coeff1 = 460; val->coeff[5].coeff2 = -208; + val->coeff[6].coeff1 = 392; val->coeff[6].coeff2 = -232; + + /* total_time = val->wSamplesPerBlock * filesize / val->nBlockAlign / constant; */ + bsize = val->nBlockAlign; + total_time = 0; + dec->metadata = (void *)val; + dec->flag = FREE_META; + } + else + { + msadpcm_values_t * val = (msadpcm_values_t *)metadata; + + /* Let's try anyway */ + if (val->nBlockAlign == 0) + { + val->nBlockAlign = filesize - filesize % 4; + } + else + { + total_time = val->wSamplesPerBlock * filesize * channels / + val->nBlockAlign / constant / 2; /* 4/8 == 1/2 */ + } + bsize = val->nBlockAlign; + dec->metadata = metadata; + } + + dec->decoder = decode_ms_adpcm; + obsize = 4 * bsize; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag |= FREE_OBUF; + seekf = seek_compressed; + + format = AFMT_S16_NE; + break; + case AFMT_MS_IMA_ADPCM: + case AFMT_MS_IMA_ADPCM_3BITS: + dec->metadata = metadata; + if (dec->metadata == NULL) + { + msadpcm_values_t * val = + (msadpcm_values_t *)ossplay_malloc (sizeof (msadpcm_values_t)); + + val->channels = channels; + val->bits = (format == AFMT_MS_IMA_ADPCM)?4:3; + val->nBlockAlign = 256 * channels * (speed > 11000)?speed/11000:1; + } + else + { + msadpcm_values_t * val = (msadpcm_values_t *)metadata; + + /* Let's try anyway - some cameras make defective WAVs */ + if (val->nBlockAlign == 0) + { + val->nBlockAlign = filesize - filesize % 4; + } + else + { + total_time = val->wSamplesPerBlock * filesize * val->bits * channels / + val->nBlockAlign / constant / 8.0; + } + bsize = val->nBlockAlign; + } + + dec->decoder = decode_ms_ima; + if (format == AFMT_MS_IMA_ADPCM_3BITS) + obsize = (bsize * 16)/3 + 2; + /* + * 8 sample words per 3 bytes, each expanding to 2 bytes, plus 2 bytes + * to deal with fractions. Slight overestimation because bsize + * includes the headers too. + */ + else + obsize = 4 * bsize; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag = FREE_OBUF; + seekf = seek_compressed; + + format = AFMT_S16_NE; + break; + case AFMT_MAC_IMA_ADPCM: + dec->metadata = (void *)(intptr)channels; + dec->decoder = decode_mac_ima; + bsize -= bsize % (MAC_IMA_BLKLEN * channels); + obsize = 4 * bsize; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag = FREE_OBUF; + seekf = seek_compressed; + + format = AFMT_S16_NE; + break; + case AFMT_IMA_ADPCM: + dec->metadata = (void *)ossplay_malloc (sizeof (ima_values_t)); + memset (dec->metadata, 0, sizeof (ima_values_t)); + ((ima_values_t *)(dec->metadata))->channels = channels; + + dec->decoder = decode_raw_ima; + obsize = 4 * bsize; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag = FREE_OBUF | FREE_META; + seekf = seek_compressed; + + format = AFMT_S16_NE; + break; + case AFMT_CR_ADPCM_2: + case AFMT_CR_ADPCM_3: + case AFMT_CR_ADPCM_4: + dec->metadata = (void *)setup_cr (fd, format);; + if (dec->metadata == NULL) goto exit; + dec->decoder = decode_cr; + obsize = ((cradpcm_values_t *)dec->metadata)->ratio * bsize; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag = FREE_OBUF | FREE_META; + seekf = seek_compressed; + + if (filesize != BIG_SPECIAL) filesize--; + format = AFMT_U8; + break; + case AFMT_FIBO_DELTA: + case AFMT_EXP_DELTA: + dec->metadata = (void *)setup_fib (fd, format);; + if (dec->metadata == NULL) goto exit; + dec->decoder = decode_fib; + obsize = 2 * bsize; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag = FREE_OBUF | FREE_META; + seekf = seek_compressed; + + if (filesize != BIG_SPECIAL) filesize--; + format = AFMT_U8; + break; + case AFMT_S24_PACKED: + case AFMT_S24_PACKED_BE: + dec->metadata = (void *)(intptr)format; + dec->decoder = decode_24; + bsize -= bsize % 3; + obsize = bsize/3*4; + dec->outbuf = (unsigned char *)ossplay_malloc (obsize); + dec->flag = FREE_OBUF; + + format = AFMT_S32_NE; + break; + case AFMT_FLOAT32_BE: + case AFMT_FLOAT32_LE: + if (format == AFMT_FLOAT32_BE) dec->decoder = decode_float32_be; + else dec->decoder = decode_float32_le; + bsize -= bsize % 4; + obsize = bsize; + dec->outbuf = NULL; + + format = AFMT_S32_NE; + break; + case AFMT_DOUBLE64_BE: + case AFMT_DOUBLE64_LE: + if (format == AFMT_DOUBLE64_BE) dec->decoder = decode_double64_be; + else dec->decoder = decode_double64_le; + bsize -= bsize % 8; + obsize = bsize/2; + dec->outbuf = NULL; + + format = AFMT_S32_NE; + break; +#ifdef OGG_SUPPORT + case AFMT_VORBIS: + readf = read_ogg; + dec->decoder = decode_nul; + dec->metadata = metadata; + obsize = bsize; + if (metadata == NULL) goto exit; + else + { + ogg_data_t * val = (ogg_data_t *)metadata; + if (val->f->ov_seekable (&val->vf)) + { + seekf = seek_ogg; + total_time = val->f->ov_time_total (&val->vf, -1); + } + else + { + seekf = NULL; + total_time = 0; + } + } + + format = AFMT_S16_NE; + break; +#endif + default: + dec->decoder = decode_nul; + + obsize = bsize; + break; + } + + if (int_conv) + decoders = setup_normalize (&format, &obsize, decoders); + + if ((amplification > 0) && (amplification != 100)) + { + decoders->next = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + decoders = decoders->next; + decoders->metadata = (void *)(intptr)format; + decoders->decoder = decode_amplify; + decoders->next = NULL; + decoders->outbuf = NULL; + decoders->flag = 0; + } + + ret = setup_device (dsp, format, channels, speed); + if (ret == E_FORMAT_UNSUPPORTED) + { + int i, tmp; + + for (i = 0; format_a[i].name != NULL; i++) + if (format_a[i].fmt == format) + { + tmp = format_a[i].may_conv; + if ((tmp == 0) || (tmp == format)) continue; + print_msg (WARNM, "Converting to format %s\n", + sample_format_name (tmp)); + ret = setup_device (dsp, tmp, channels, speed); + if (ret == E_FORMAT_UNSUPPORTED) goto exit; + decoders = setup_normalize (&format, &obsize, decoders); + goto dcont; + } + goto exit; + } + +dcont: +#ifdef SRC_SUPPORT + if ((ret == E_CHANNELS_UNSUPPORTED) && (channels == 1)) { + channels = 2; + if ((ret = setup_device (dsp, format, channels, speed))) goto exit; + decoders->next = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + decoders = decoders->next; + decoders->metadata = (void *)(intptr)format; + decoders->decoder = decode_mono_to_stereo; + decoders->next = NULL; + obsize *= 2; + decoders->outbuf = (unsigned char *)ossplay_malloc (obsize); + decoders->flag = FREE_OBUF; + } +#endif + + if (ret) goto exit; +#ifdef SRC_SUPPORT + if (dsp->speed != speed) { + if ((format == AFMT_MU_LAW) || (format == AFMT_A_LAW)) + decoders = setup_normalize (&format, &obsize, decoders); + decoders->next = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + decoders = decoders->next; + decoders->decoder = decode_src; + decoders->next = NULL; + obsize *= (dsp->speed / speed + 1) * channels * sizeof (int); + decoders->metadata = + (void *)setup_grc3 (format, channels, dsp->speed, speed, obsize); + decoders->outbuf = (unsigned char *)ossplay_malloc (obsize); + decoders->flag = FREE_OBUF | FREE_META; + speed = dsp->speed; + } +#endif + + ret = play (dsp, fd, &filesize, bsize, total_time, constant, readf, + dec, seekf); + +exit: + decoders = dec; + while (decoders != NULL) + { + if (decoders->flag & FREE_META) ossplay_free (decoders->metadata); + if (decoders->flag & FREE_OBUF) ossplay_free (decoders->outbuf); + decoders = decoders->next; + ossplay_free (dec); + dec = decoders; + } + + return ret; +} + +errors_t +encode_sound (dspdev_t * dsp, fctypes_t type, const char * fname, int format, + int channels, int speed, double data_time) +{ + big_t data_size = 0; + double constant; + int fd = -1; + decoders_queue_t * dec, * decoders = NULL; + errors_t ret; + FILE * wave_fp; + + if ((ret = setup_device (dsp, format, channels, speed))) return ret; + constant = format2bits (format) * speed * channels / 8.0; + + if (data_time != 0) data_size = data_time * constant; + + if (strcmp (fname, "-") == 0) { + wave_fp = fdopen (1, "wb"); + } else { + fd = open (fname, O_WRONLY | O_CREAT | (overwrite?O_TRUNC:O_EXCL), 0644); + if (fd == -1) { + perror (fname); + return E_ENCODE; + } + wave_fp = fdopen (fd, "wb"); + } + + if (wave_fp == NULL) + { + perror (fname); + if (fd != -1) close (fd); + return E_ENCODE; + } + + if (channels == 1) + print_msg (VERBOSEM, "Recording wav: Speed %dHz %d bits Mono\n", + speed, (int)format2bits (format)); + if (channels == 2) + print_msg (VERBOSEM, "Recording wav: Speed %dHz %d bits Stereo\n", + speed, (int)format2bits (format)); + if (channels > 2) + print_msg (VERBOSEM, "Recording wav: Speed %dHz %d bits %d channels\n", + speed, (int)format2bits (format), channels); + + /* + * Write the initial header + */ + if (write_head (wave_fp, type, data_size, format, channels, speed)) + return E_ENCODE; + + decoders = dec = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + dec->next = NULL; + dec->flag = 0; + dec->decoder = decode_nul; + + if ((amplification > 0) && (amplification != 100)) + { + decoders->next = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + decoders = decoders->next; + decoders->metadata = (void *)(intptr)format; + decoders->decoder = decode_amplify; + decoders->next = NULL; + decoders->outbuf = NULL; + decoders->flag = 0; + } + + ret = record (dsp, wave_fp, fname, constant, data_time, &data_size, dec); + + finalize_head (wave_fp, type, data_size, format, channels, speed); + fflush (wave_fp); + /* + * EINVAL and EROFS are returned for "special files which don't support + * syncronization". The user should already know he's writing to a special + * file (e.g. "ossrecord /dev/null"), so no need to warn. + */ + if ((fsync (fileno (wave_fp)) == -1) && (errno != EINVAL) && (errno != EROFS)) + { + perror (fname); + ret = E_ENCODE; + } + if (fclose (wave_fp) != 0) + { + perror (fname); + ret = E_ENCODE; + } + + decoders = dec; + while (decoders != NULL) + { + if (decoders->flag & FREE_META) ossplay_free (decoders->metadata); + if (decoders->flag & FREE_OBUF) ossplay_free (decoders->outbuf); + decoders = decoders->next; + ossplay_free (dec); + dec = decoders; + } + return ret; +} + +static ssize_t +decode_24 (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + big_t outlen = 0; + ssize_t i; + int v1; + uint32 * u32; + int32 sample_s32, * outbuf = (int32 *) * obuf; + int format = (int)(intptr)metadata; + + if (format == AFMT_S24_PACKED) v1 = 8; + else v1 = 24; + + for (i = 0; i < l-2; i += 3) + { + u32 = (uint32 *) &sample_s32; /* Alias */ + + *u32 = (buf[i] << v1) | (buf[i + 1] << 16) | (buf[i + 2] << (32-v1)); + outbuf[outlen++] = sample_s32; + } + + return 4 * outlen; +} + +static fib_values_t * +setup_fib (int fd, int format) +{ + static const signed char CodeToDelta[16] = { + -34, -21, -13, -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8, 13, 21 + }; + static const signed char CodeToExpDelta[16] = { + -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 + }; + unsigned char buf; + fib_values_t * val; + + if (read (fd, &buf, 1) <= 0) return NULL; + val = (fib_values_t *)ossplay_malloc (sizeof (fib_values_t)); + if (format == AFMT_EXP_DELTA) val->table = CodeToExpDelta; + else val->table = CodeToDelta; + + val->pred = buf; + + return val; +} + +static cradpcm_values_t * +setup_cr (int fd, int format) +{ + static const unsigned char T2[4][3] = { + { 128, 6, 1 }, + { 32, 4, 1 }, + { 8, 2, 1 }, + { 2, 0, 1 } + }; + + static const unsigned char T3[3][3] = { + { 128, 5, 3 }, + { 16, 2, 3 }, + { 2, 0, 1 } + }; + + static const unsigned char T4[2][3] = { + { 128, 4, 7 }, + { 8, 0, 7 } + }; + + static const unsigned char * t_row[4]; + + unsigned char buf; + cradpcm_values_t * val; + int i; + + if (read (fd, &buf, 1) <= 0) return NULL; + val = (cradpcm_values_t *)ossplay_malloc (sizeof (cradpcm_values_t)); + val->table = t_row; + + if (format == AFMT_CR_ADPCM_2) + { + val->limit = 1; + val->step = val->shift = 2; + val->ratio = 4; + for (i=0; i < 4; i++) t_row[i] = T2[i]; + } + else if (format == AFMT_CR_ADPCM_3) + { + val->limit = 3; + val->ratio = 3; + val->step = val->shift = 0; + for (i=0; i < 3; i++) t_row[i] = T3[i]; + } + else /* if (format == AFMT_CR_ADPCM_4) */ + { + val->limit = 5; + val->ratio = 2; + val->step = val->shift = 0; + for (i=0; i < 2; i++) t_row[i] = T4[i]; + } + + val->pred = buf; + + return val; +} + +static ssize_t +decode_8_to_s16 (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + int format = (int)(intptr)metadata; + ssize_t i; + int16 * outbuf = (int16 *) * obuf; + static const int16 mu_law_table[256] = { + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364,-9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 + }; + + static const int16 a_law_table[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 + }; + + switch (format) + { + case AFMT_U8: + for (i = 0; i < l; i++) outbuf[i] = (buf[i] - 128) << 8; + break; + case AFMT_S8: + for (i = 0; i < l; i++) outbuf[i] = buf[i] << 8; + break; + case AFMT_MU_LAW: + for (i = 0; i < l; i++) outbuf[i] = mu_law_table[buf[i]]; + break; + case AFMT_A_LAW: + for (i = 0; i < l; i++) outbuf[i] = a_law_table[buf[i]]; + break; + } + + return 2*l; +} + +static ssize_t +decode_cr (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + cradpcm_values_t * val = (cradpcm_values_t *) metadata; + int j, pred = val->pred, step = val->step; + unsigned char value; + signed char sign; + ssize_t i; + + for (i=0; i < l; i++) + for (j=0; j < val->ratio; j++) + { + sign = (buf[i] & val->table[j][0])?-1:1; + value = (buf[i] >> val->table[j][1]) & val->table[j][2]; + pred += sign*(value << step); + if (pred > 255) pred = 255; + else if (pred < 0) pred = 0; + (*obuf)[val->ratio*i+j] = pred; + if ((value >= val->limit) && (step < 3+val->shift)) step++; + if ((value == 0) && (step > val->shift)) step--; + } + + val->pred = pred; + val->step = step; + return val->ratio*l; +} + +static ssize_t +decode_fib (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + fib_values_t * val = (fib_values_t *)metadata; + int x = val->pred; + unsigned char d; + ssize_t i; + + for (i = 0; i < 2*l; i++) + { + d = buf[i/2]; + if (i & 1) d &= 0xF; + else d >>= 4; + x += val->table[d]; + if (x > 255) x = 255; + if (x < 0) x = 0; + (*obuf)[i] = x; + } + + val->pred = x; + return 2*l; +} + +static ssize_t +decode_ms_adpcm (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + msadpcm_values_t * val = (msadpcm_values_t *)metadata; + + int error_delta, i_delta, i = 0, nib = 0, channels = val->channels; + int AdaptionTable[16] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + ssize_t outp = 0, x = 0; + int16 * wbuf = (int16 *)*obuf; + int32 delta[MAX_CHANNELS], samp1[MAX_CHANNELS], samp2[MAX_CHANNELS], + predictor[MAX_CHANNELS], new_samp, pred, n = 0; + +/* + * Playback procedure + */ +#define OUT_SAMPLE(s) \ + do { \ + if (s > 32767) s = 32767; else if (s < -32768) s = -32768; \ + wbuf[outp++] = s; \ + n += 2; \ + } while(0) + +#define GETNIBBLE \ + ((nib == 0) ? \ + (buf[x + nib++] >> 4) & 0x0f : \ + buf[x++ + --nib] & 0x0f \ + ) + + for (i = 0; i < channels; i++) + { + predictor[i] = buf[x]; + if (predictor[i] > val->wNumCoeff) + /* Shouldn't ever happen */ + predictor[i] = val->wNumCoeff; + x++; + } + + for (i = 0; i < channels; i++) + { + delta[i] = (int16) le_int (&buf[x], 2); + x += 2; + } + + for (i = 0; i < channels; i++) + { + samp1[i] = (int16) le_int (&buf[x], 2); + x += 2; + OUT_SAMPLE (samp1[i]); + } + + for (i = 0; i < channels; i++) + { + samp2[i] = (int16) le_int (&buf[x], 2); + x += 2; + OUT_SAMPLE (samp2[i]); + } + + while (n < (val->wSamplesPerBlock * 2 * channels)) + for (i = 0; i < channels; i++) + { + pred = ((samp1[i] * val->coeff[predictor[i]].coeff1) + + (samp2[i] * val->coeff[predictor[i]].coeff2)) / 256; + + if (x > l) return 2*outp; + i_delta = error_delta = GETNIBBLE; + + if (i_delta & 0x08) + i_delta -= 0x10; /* Convert to signed */ + + new_samp = pred + (delta[i] * i_delta); + OUT_SAMPLE (new_samp); + + delta[i] = delta[i] * AdaptionTable[error_delta] / 256; + if (delta[i] < 16) delta[i] = 16; + + samp2[i] = samp1[i]; + samp1[i] = new_samp; + } + + return 2*outp; +} + +static ssize_t +decode_nul (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + *obuf = buf; + return l; +} + +static ssize_t +decode_endian (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + int format = (int)(intptr)metadata; + ssize_t i; + + switch (format) + { + case AFMT_S16_OE: + { + int16 * s = (int16 *)buf; + + for (i = 0; i < l / 2; i++) + s[i] = ((s[i] >> 8) & 0x00FF) | + ((s[i] << 8) & 0xFF00); + } + break; + case AFMT_S32_OE: + case AFMT_S24_OE: + { + int32 * s = (int32 *)buf; + + for (i = 0; i < l / 4; i++) + s[i] = ((s[i] >> 24) & 0x000000FF) | + ((s[i] << 8) & 0x00FF0000) | ((s[i] >> 8) & 0x0000FF00) | + ((s[i] << 24) & 0xFF000000); + } + break; +#ifdef OSS_LITTLE_ENDIAN + case AFMT_U16_BE: /* U16_BE -> S16_LE */ +#else + case AFMT_U16_LE: /* U16_LE -> S16_BE */ +#endif + { + int16 * s = (int16 *)buf; + + for (i = 0; i < l / 2; i++) + s[i] = (((s[i] >> 8) & 0x00FF) | ((s[i] << 8) & 0xFF00)) - + USHRT_MAX/2; + } + break; + /* Not an endian conversion, but included for completeness sake */ +#ifdef OSS_LITTLE_ENDIAN + case AFMT_U16_LE: /* U16_LE -> S16_LE */ +#else + case AFMT_U16_BE: /* U16_BE -> S16_BE */ +#endif + { + int16 * s = (int16 *)buf; + + for (i = 0; i < l / 2; i++) + s[i] -= USHRT_MAX/2; + } + break; + } + *obuf = buf; + return l; +} + +static ssize_t +decode_amplify (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + int format = (int)(intptr)metadata; + ssize_t i, len; + + switch (format) + { + case AFMT_S16_NE: + { + int16 *s = (int16 *)buf; + int32 tmp; + + len = l / 2; + for (i = 0; i < len ; i++) + { + tmp = (int32)s[i] * amplification / 100; + if (tmp > SHRT_MAX) s[i] = SHRT_MAX; + else if (tmp < SHRT_MIN) s[i] = SHRT_MIN; + else s[i] = tmp; + } + } + break; + case AFMT_S32_NE: + case AFMT_S24_NE: + { + int32 *s = (int32 *)buf; + sbig_t tmp; + + len = l / 4; + for (i = 0; i < len; i++) + { + tmp = (sbig_t)s[i] * amplification / 100; + if (tmp > S32_MAX) s[i] = S32_MAX; + else if (tmp < S32_MIN) s[i] = S32_MIN; + else s[i] = tmp; + } + } + break; + } + + *obuf = buf; + return l; +} + +static void +decode_ima (unsigned char * obuf, unsigned char * buf, ssize_t l, int16 * pred0, + int8 * index0, int channels, int ch) +{ + int j; + int32 pred = *pred0; + int16 step; + int16 * outbuf = (int16 *) obuf; + int8 index = *index0, value; + signed char sign; + ssize_t i; + static const int step_tab[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 + }; + + static const int8 iTab4[16] = + {-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8}; + + for (i=0; i < l; i++) + for (j=0; j < 2; j++) + { + value = (buf[i] >> 4*j) & 15; + + step = step_tab[index]; + index += iTab4[value]; + if (index < 0) index = 0; + else if (index > 88) index = 88; + + sign = 1 - 2 * ((value >> 3) & 1); + value &= 7; + + pred += sign * (2 * value + 1) * step / 4; + if (pred > 32767) pred = 32767; + else if (pred < -32768) pred = -32768; + + outbuf[channels*(2*i+j)+ch] = pred; + } + + *index0 = index; + *pred0 = pred; + + return; +} + +static void +decode_ima_3bits (unsigned char * obuf, unsigned char * buf, ssize_t l, + int16 * pred0, int8 * index0, int channels, int ch) +{ + int j; + signed char sign; + ssize_t i; + + int32 pred = *pred0, raw; + int8 index = *index0, value; + int16 * outbuf = (int16 *) obuf, step; + + static const int step_tab[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 + }; + + static const int8 iTab3[8] = + {-1, -1, 1, 2, -1, -1, 1, 2}; + + for (i=0; i < l-2; i += 3) + { + raw = buf[i] + (buf[i+1] << 8) + (buf[i+2] << 16); + for (j = 0; j < 8; j++) + { + value = (raw >> (3*j)) & 7; + + step = step_tab[index]; + index += iTab3[value]; + if (index < 0) index = 0; + else if (index > 88) index = 88; + + sign = 1 - 2 * ((value >> 2) & 1); + value &= 3; + + pred += sign * (2 * value + 1) * step / 4; + if (pred > 32767) pred = 32767; + else if (pred < -32768) pred = -32768; + + outbuf[channels*(8*i/3+j)+ch] = pred; + } + } + + *index0 = index; + *pred0 = pred; + + return; +} + +static ssize_t +decode_mac_ima (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + ssize_t len = 0, olen = 0; + int i, channels = (int)(intptr)metadata; + int16 pred; + int8 index; + + while (len < l) + { + for (i = 0; i < channels; i++) + { + if (len + MAC_IMA_BLKLEN > l) return olen; + pred = (int16)((buf[len] << 8) | (buf[len+1] & 128)); + index = buf[len+1] & 127; + if (index > 88) index = 88; + len += 2; + + decode_ima (*obuf + olen, buf + len, MAC_IMA_BLKLEN - 2, &pred, + &index, channels, i); + len += MAC_IMA_BLKLEN-2; + } + olen += 4*(MAC_IMA_BLKLEN - 2)*channels; + } + + return olen; +} + +static ssize_t +decode_ms_ima (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + int i; + ssize_t len = 0, olen = 0; + msadpcm_values_t * val = (msadpcm_values_t *)metadata; + int8 index[MAX_CHANNELS]; + int16 * outbuf = (int16 *) * obuf, pred[MAX_CHANNELS]; + + for (i = 0; i < val->channels; i++) + { + if (len >= l) return olen; + pred[i] = (int16) le_int (buf + len, 2); + /* + * The microsoft docs says the sample from the block header should be + * played. + */ + outbuf[i] = pred[i]; + olen += 2; + index[i] = buf[len + 2]; + if (index[i] > 88) index[i] = 88; + if (index[i] < 0) index[i] = 0; + len += 4; + } + + if (val->bits == 4) + while (len < l) + { + for (i = 0; i < val->channels; i++) + { + if (len + 4 > l) return olen; + decode_ima (*obuf + olen, buf + len, 4, &pred[i], &index[i], + val->channels, i); + len += 4; + } + olen += 2*8*val->channels; + } + else + { + unsigned char rbuf[12]; + int j; + + while (len < l) + { + if (len + 12*val->channels > l) return olen; + for (i = 0; i < val->channels; i++) + { + /* + * Each sample word for a channel in an IMA ADPCM RIFF file is 4 + * bits. This doesn't resolve to an integral number of samples + * in a 3 bit ADPCM, so we use a simple method around this. + * This shouldn't skip samples since the spec guarantees the + * number of sample words in a block is divisible by 3. + */ + for (j = 0; j < 12; j++) + rbuf[j] = buf[len + j%4 + (j/4)*(val->channels*4) + i*4]; + decode_ima_3bits (*obuf + olen, rbuf, 12, &pred[i], &index[i], + val->channels, i); + } + /* 12 = 3 words per channel, each containing 4 bytes */ + len += 12*val->channels; + /* 64 = 32 samples per channel, each expanding to 2 bytes */ + olen += 64*val->channels; + } + } + return olen; +} + +static ssize_t +decode_raw_ima (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + ima_values_t * val = (ima_values_t *)metadata; + ssize_t olen = 0; + + /* We can't tell if/how it's interleaved. */ + decode_ima (*obuf, buf, l, &val->pred[0], &val->index[0], 1, 0); + olen = 4*l; + + return olen; +} + +static ssize_t +decode_float32_be (unsigned char ** obuf, unsigned char * buf, ssize_t l, + void * metadata) +{ + ssize_t i; + int exp, man; + int32 * wbuf = (int32 *) buf; + + for (i=0; i < l-3; i += 4) + { + exp = ((buf[i] & 0x7F) << 1) | ((buf[i+1] & 0x80) / 0x80); + man = ((buf[i+1] & 0x7F) << 16) | (buf[i+2] << 8) | buf[i+3]; + + *wbuf++ = float32_to_s32 (exp, man, (buf[i] & 0x80)); + } + + *obuf = buf; + return l; +} + +static ssize_t +decode_float32_le (unsigned char ** obuf, unsigned char * buf, ssize_t l, + void * metadata) +{ + ssize_t i; + int exp, man; + int32 * wbuf = (int32 *) buf; + + for (i=0; i < l-3; i += 4) + { + exp = ((buf[i+3] & 0x7F) << 1) | ((buf[i+2] & 0x80) / 0x80); + man = ((buf[i+2] & 0x7F) << 16) | (buf[i+1] << 8) | buf[i]; + + *wbuf++ = float32_to_s32 (exp, man, (buf[i+3] & 0x80)); + } + + *obuf = buf; + return l; +} + +static ssize_t +decode_double64_be (unsigned char ** obuf, unsigned char * buf, ssize_t l, + void * metadata) +{ + ssize_t i; + int exp; + int32 * wbuf = (int32 *) buf, lower, upper; + + for (i=0; i < l-7; i += 8) + { + exp = ((buf[i] & 0x7F) << 4) | ((buf[i+1] >> 4) & 0xF) ; + + upper = ((buf[i+1] & 0xF) << 24) | (buf[i+2] << 16) | (buf[i+3] << 8) | + buf[i+4]; + lower = (buf[i+5] << 16) | (buf[i+6] << 8) | buf[i+7]; + + *wbuf++ = double64_to_s32 (exp, upper, lower, buf[i] & 0x80); + } + + *obuf = buf; + return l/2; +} + +static ssize_t +decode_double64_le (unsigned char ** obuf, unsigned char * buf, ssize_t l, + void * metadata) +{ + ssize_t i; + int exp; + int32 * wbuf = (int32 *) buf, lower, upper; + + for (i=0; i < l-7; i += 8) + { + exp = ((buf[i+7] & 0x7F) << 4) | ((buf[i+6] >> 4) & 0xF); + + upper = ((buf[i+6] & 0xF) << 24) | (buf[i+5] << 16) | (buf[i+4] << 8) | + buf[i+3]; + lower = (buf[i+2] << 16) | (buf[i+1] << 8) | buf[i]; + + *wbuf++ = double64_to_s32 (exp, upper, lower, buf[i+7] & 0x80); + } + + *obuf = buf; + return l/2; +} + +static int32 +double64_to_s32 (int exp, int32 upper, int32 lower, int sign) +{ + ldouble_t out, value; + + if ((exp != 0) && (exp != 2047)) + { + value = (upper + lower / ((double)0x1000000))/((double)0x10000000) + 1; + value = ossplay_ldexpl (value, exp - 1023); + } + else if (exp == 0) + { +#if 0 + int j; + + out = (upper + lower / ((double)0x1000000))/((double)0x10000000); + for (j=0; j < 73; j++) out /= 1 << 14; +#endif + /* So low, that it's pretty much 0 for us */ + return 0; + } + else /* exp == 2047 */ + { + /* + * Either NaN, or +/- Inf. 0 is almost as close an approximation of + * Inf as the maximum sample value.... + */ + print_msg (WARNM, "exp == 2047 in file!\n"); + return 0; + } + + out = (sign ? 1 : -1) * value * S32_MIN; + if (out > S32_MAX) out = S32_MAX; + else if (out < S32_MIN) out = S32_MIN; + + return out; +} + +static int32 +float32_to_s32 (int exp, int man, int sign) +{ + ldouble_t out, value; + + if ((exp != 0) && (exp != 255)) + { + value = man ? (float)man/(float)0x800000 + 1 : 0.0; + value = ossplay_ldexpl (value, exp - 127); + } + else if (exp == 0) + { +#if 0 + value = (float)man / (float)0x800000; + value /= 1UL << 31; value /= 1UL << 31; value /= 1UL << 32; + value /= 1UL << 32; +#endif + /* So low, that it's pretty much 0 for us */ + return 0; + } + else /* exp == 255 */ + { + /* + * Either NaN, or +/- Inf. 0 is almost as close an approximation of + * Inf as the maximum sample value.... + */ + print_msg (WARNM, "exp == 255 in file!\n"); + return 0; + } + + out = (sign ? 1 : -1) * value * S32_MIN; + if (out > S32_MAX) out = S32_MAX; + else if (out < S32_MIN) out = S32_MIN; + + return out; +} + +int +get_db_level (const unsigned char * buf, ssize_t l, int format) +{ +/* + * Display a rough recording level meter, and the elapsed time. + */ + static const unsigned char db_table[256] = { + /* Lookup table for log10(ix)*2, ix=0..255 */ + 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, + 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11 + }; + + int32 level, v = 0; + ssize_t i; + + level = 0; + if ((buf == NULL) || (l == 0)) return 0; + + switch (format) + { + case AFMT_U8: + { + uint8 * p; + + p = (uint8 *)buf; + + for (i = 0; i < l; i++) { + v = (*p++); + if (v > level) level = v; + } + } + case AFMT_S8: + { + int8 * p; + + p = (int8 *)buf; + + for (i = 0; i < l; i++) { + v = *p++; + if (v < 0) { + /* This can be false on a two's-complement machine */ + if (v != -v) v = -v; + else v = -(v+1); + } + if (v > level) level = v; + } + } + break; + + case AFMT_S16_NE: + { + int16 * p; + + p = (int16 *)buf; + + for (i = 0; i < l / 2; i++) { + v = *p++; + if (v < 0) { + if (v != -v) v = -v; + else v = -(v+1); + } + if (v > level) level = v; + } + } + level >>= 8; + break; + + case AFMT_S24_NE: + case AFMT_S32_NE: + { + int32 * p; + + p = (int32 *)buf; + + for (i = 0; i < l / 4; i++) { + v = *p++; + if (v < 0) { + if (v != -v) v = -v; + else v = -(v+1); + } + if (v > level) level = v; + } + } + level >>= 24; + break; + default: return -1; + } + + if (level > 255) level = 255; + v = db_table[level]; + + return v; +} + +static decoders_queue_t * +setup_normalize (int * format, int * obsize, decoders_queue_t * decoders) +{ + if ((*format == AFMT_S16_OE) || (*format == AFMT_S32_OE) || + (*format == AFMT_S24_OE) || (*format == AFMT_U16_LE) || + (*format == AFMT_U16_BE)) + { + decoders->next = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + decoders = decoders->next; + decoders->decoder = decode_endian; + decoders->metadata = (void *)(intptr)*format; + switch (*format) + { + case AFMT_S32_OE: *format = AFMT_S32_NE; break; + case AFMT_S24_OE: *format = AFMT_S24_NE; break; + default: *format = AFMT_S16_NE; break; + } + decoders->next = NULL; + decoders->outbuf = NULL; + decoders->flag = 0; + } + else if ((*format == AFMT_U8) || (*format == AFMT_MU_LAW) || + (*format == AFMT_S8) || (*format == AFMT_A_LAW)) + { + decoders->next = + (decoders_queue_t *)ossplay_malloc (sizeof (decoders_queue_t)); + decoders = decoders->next; + decoders->decoder = decode_8_to_s16; + decoders->metadata = (void *)(intptr)*format; + decoders->next = NULL; + *obsize *= 2; + decoders->outbuf = (unsigned char *)ossplay_malloc (*obsize); + decoders->flag = FREE_OBUF; + *format = AFMT_S16_NE; + } + return decoders; +} + +verbose_values_t * +setup_verbose (int format, double oconstant, double total_time) +{ + verbose_values_t * val; + + val = (verbose_values_t *)ossplay_malloc (sizeof (verbose_values_t)); + + if (total_time == 0) + { + val->tsecs = 0; + strcpy (val->tstring, "unknown"); + } + else + { + char * p; + + val->tsecs = total_time; + p = totime (val->tsecs); + strncpy (val->tstring, p, sizeof (val->tstring)); + ossplay_free (p); + val->tsecs -= UPDATE_EPSILON/1000; + } + + val->secs = 0; + val->secs_timer2 = 0; + val->next_sec = 0; + val->next_sec_timer2 = 0; + val->format = format; + val->constant = oconstant; + + return val; +} + +static errors_t +seek_normal (int fd, big_t * datamark, big_t filesize, double constant, + big_t rsize, int channels, void * metadata) +{ + big_t pos = seek_time * constant; + int ret; + + pos -= pos % channels; + if ((pos > filesize) || (pos < *datamark)) return E_DECODE; + + ret = ossplay_lseek (fd, pos - *datamark, SEEK_CUR); + if (ret == -1) + { + seek_time = 0; + return E_DECODE; + } + *datamark = ret; + + return E_OK; +} + +static errors_t +seek_compressed (int fd, big_t * datamark, big_t filesize, double constant, + big_t rsize, int channels, void * metadata) +/* + * We have to use this method because some compressed formats depend on the + * previous state of the decoder, and don't (yet?) have own seek function. + */ +{ + big_t pos = seek_time * constant; + + if (pos > filesize) + { + seek_time = 0; + return E_DECODE; + } + + if (*datamark + rsize < pos) + { + return SEEK_CONT_AFTER_DECODE; + } + else + { + /* Still not entirely accurate. */ + seek_time = *datamark / constant; + return E_OK; + } +} + +static ssize_t +read_normal (int fd, void * buf, size_t len, void * metadata) +{ + return read (fd, buf, len); +} + +#ifdef OGG_SUPPORT +static errors_t +seek_ogg (int fd, big_t * datamark, big_t filesize, double constant, + big_t rsize, int channels, void * metadata) +{ + ogg_data_t * val = (ogg_data_t *)metadata; + + if (val->f->ov_time_seek (&val->vf, seek_time) < 0) + { + seek_time = 0; + return E_DECODE; + } + *datamark = (big_t)val->f->ov_raw_tell (&val->vf); + return E_OK; +} + +static ssize_t +read_ogg (int fd, void * buf, size_t len, void * metadata) +{ + int c_bitstream; + ssize_t ret = 0; + ogg_data_t * val = (ogg_data_t *)metadata; + + if (val->setup == 1) + { + vorbis_info * vi; + + vi = val->f->ov_info (&val->vf, -1); + + ret = setup_device (val->dsp, AFMT_S16_NE, vi->channels, vi->rate); + if (ret < 0) return -1; + val->setup = 0; + } + + do + { +#if 0 + if (ret == OV_HOLE) + print_msg (NOTIFYM, "Hole in the OggVorbis stream!\n"); +#endif + c_bitstream = val->bitstream; + ret = (ssize_t)val->f->ov_read (&val->vf, (char *)buf, (int)len, +#ifdef OSS_LITTLE_ENDIAN + 0, +#else + 1, +#endif + 2, 1, &val->bitstream); + } + while (ret == OV_HOLE); + + if (ret == 0) return 0; + else if (ret < 0) return ret; + + if ((c_bitstream != val->bitstream) && (c_bitstream != -1)) + { + val->bitstream = c_bitstream; + val->setup = 1; + } + + return ret; +} +#endif + +#ifdef SRC_SUPPORT +#define GRC3_HIGH_QUALITY 4 +static ssize_t +decode_mono_to_stereo (unsigned char ** obuf, unsigned char * buf, + ssize_t l, void * metadata) +{ + ssize_t i; + int format = (int)(intptr)metadata; + + switch (format) { + case AFMT_U8: + case AFMT_S8: { + uint8 *r = (uint8 *)buf, *s = (uint8 *)*obuf; + for (i=0; i < l; i++) { + *s++ = *r; + *s++ = *r++; + } + } + break; + case AFMT_S16_LE: + case AFMT_S16_BE: { + int16 *r = (int16 *)buf, *s = (int16 *)*obuf; + + for (i = 0; i < l/2 ; i++) { + *s++ = *r; + *s++ = *r++; + } + } + break; + case AFMT_S32_LE: + case AFMT_S32_BE: + case AFMT_S24_LE: + case AFMT_S24_BE: { + int32 *r = (int32 *)buf, *s = (int32 *)*obuf; + + for (i = 0; i < l/4; i++) { + *s++ = *r; + *s++ = *r++; + } + } + break; + } + return 2*l; +} + +static ssize_t +decode_src (unsigned char ** obuf, unsigned char * buf, ssize_t l, void * metadata) +{ + grc_data_t * val = (grc_data_t *)metadata; + ssize_t outc = 0; + int i; + + for (i=0; i<val->channels; i++) { + outc += grc3_convert (&val->grc[i], val->bits, GRC3_HIGH_QUALITY, buf, + *obuf, 8 * l / val->channels / val->bits, + val->obsize / val->channels / sizeof (int), + val->channels, i); + } + + return outc * val->bits / 8; +} + +static grc_data_t * +setup_grc3 (int format, int channels, int speed, int ospeed, int obsize) +{ + int i; + grc_data_t * val = (grc_data_t *)ossplay_malloc (sizeof (grc_data_t) + + sizeof (grc3state_t) * channels); + + val->bits = format2bits (format); + val->channels = channels; + val->speed = speed; + val->ospeed = ospeed; + val->obsize = obsize; + + for (i=0; i<channels; i++) { + grc3_reset (&val->grc[i]); + grc3_setup (&val->grc[i], ospeed, speed); + } + + return val; +} +#endif + |