Home | History | Annotate | Line # | Download | only in ic
msm6258.c revision 1.18.2.2
      1  1.18.2.2  isaki /*	$NetBSD: msm6258.c,v 1.18.2.2 2017/07/15 10:17:10 isaki Exp $	*/
      2  1.18.2.2  isaki 
      3  1.18.2.2  isaki /*
      4  1.18.2.2  isaki  * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
      5  1.18.2.2  isaki  *
      6  1.18.2.2  isaki  * Redistribution and use in source and binary forms, with or without
      7  1.18.2.2  isaki  * modification, are permitted provided that the following conditions
      8  1.18.2.2  isaki  * are met:
      9  1.18.2.2  isaki  * 1. Redistributions of source code must retain the above copyright
     10  1.18.2.2  isaki  *    notice, this list of conditions and the following disclaimer.
     11  1.18.2.2  isaki  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.18.2.2  isaki  *    notice, this list of conditions and the following disclaimer in the
     13  1.18.2.2  isaki  *    documentation and/or other materials provided with the distribution.
     14  1.18.2.2  isaki  *
     15  1.18.2.2  isaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  1.18.2.2  isaki  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  1.18.2.2  isaki  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  1.18.2.2  isaki  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  1.18.2.2  isaki  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     20  1.18.2.2  isaki  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21  1.18.2.2  isaki  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     22  1.18.2.2  isaki  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     23  1.18.2.2  isaki  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  1.18.2.2  isaki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  1.18.2.2  isaki  * SUCH DAMAGE.
     26  1.18.2.2  isaki  */
     27  1.18.2.2  isaki 
     28  1.18.2.2  isaki /*
     29  1.18.2.2  isaki  * OKI MSM6258 ADPCM voice synthesizer codec.
     30  1.18.2.2  isaki  */
     31  1.18.2.2  isaki 
     32  1.18.2.2  isaki #include <sys/cdefs.h>
     33  1.18.2.2  isaki __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.18.2.2 2017/07/15 10:17:10 isaki Exp $");
     34  1.18.2.2  isaki 
     35  1.18.2.2  isaki #include <sys/systm.h>
     36  1.18.2.2  isaki #include <sys/device.h>
     37  1.18.2.2  isaki #include <sys/kmem.h>
     38  1.18.2.2  isaki #include <sys/select.h>
     39  1.18.2.2  isaki #include <sys/audioio.h>
     40  1.18.2.2  isaki 
     41  1.18.2.2  isaki #include <dev/audio_if.h>
     42  1.18.2.2  isaki #include <dev/auconv.h>
     43  1.18.2.2  isaki #include <dev/audiovar.h>
     44  1.18.2.2  isaki #include <dev/mulaw.h>
     45  1.18.2.2  isaki #include <dev/ic/msm6258var.h>
     46  1.18.2.2  isaki 
     47  1.18.2.2  isaki struct msm6258_codecvar {
     48  1.18.2.2  isaki 	stream_filter_t	base;
     49  1.18.2.2  isaki 	short		mc_amp;
     50  1.18.2.2  isaki 	char		mc_estim;
     51  1.18.2.2  isaki };
     52  1.18.2.2  isaki 
     53  1.18.2.2  isaki static stream_filter_t *msm6258_factory
     54  1.18.2.2  isaki 	(struct audio_softc *,
     55  1.18.2.2  isaki 	 int (*)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int));
     56  1.18.2.2  isaki static void msm6258_dtor(struct stream_filter *);
     57  1.18.2.2  isaki static inline uint8_t	pcm2adpcm_step(struct msm6258_codecvar *, int16_t);
     58  1.18.2.2  isaki static inline int16_t	adpcm2pcm_step(struct msm6258_codecvar *, uint8_t);
     59  1.18.2.2  isaki 
     60  1.18.2.2  isaki static const int adpcm_estimindex[16] = {
     61  1.18.2.2  isaki 	 2,  6,  10,  14,  18,  22,  26,  30,
     62  1.18.2.2  isaki 	-2, -6, -10, -14, -18, -22, -26, -30
     63  1.18.2.2  isaki };
     64  1.18.2.2  isaki 
     65  1.18.2.2  isaki static const int adpcm_estim[49] = {
     66  1.18.2.2  isaki 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
     67  1.18.2.2  isaki 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
     68  1.18.2.2  isaki 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
     69  1.18.2.2  isaki 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
     70  1.18.2.2  isaki 	724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
     71  1.18.2.2  isaki };
     72  1.18.2.2  isaki 
     73  1.18.2.2  isaki static const int adpcm_estimstep[16] = {
     74  1.18.2.2  isaki 	-1, -1, -1, -1, 2, 4, 6, 8,
     75  1.18.2.2  isaki 	-1, -1, -1, -1, 2, 4, 6, 8
     76  1.18.2.2  isaki };
     77  1.18.2.2  isaki 
     78  1.18.2.2  isaki static stream_filter_t *
     79  1.18.2.2  isaki msm6258_factory(struct audio_softc *asc,
     80  1.18.2.2  isaki     int (*fetch_to)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int))
     81  1.18.2.2  isaki {
     82  1.18.2.2  isaki 	struct msm6258_codecvar *this;
     83  1.18.2.2  isaki 
     84  1.18.2.2  isaki 	this = kmem_alloc(sizeof(struct msm6258_codecvar), KM_SLEEP);
     85  1.18.2.2  isaki 	this->base.base.fetch_to = fetch_to;
     86  1.18.2.2  isaki 	this->base.dtor = msm6258_dtor;
     87  1.18.2.2  isaki 	this->base.set_fetcher = stream_filter_set_fetcher;
     88  1.18.2.2  isaki 	this->base.set_inputbuffer = stream_filter_set_inputbuffer;
     89  1.18.2.2  isaki 	return &this->base;
     90  1.18.2.2  isaki }
     91  1.18.2.2  isaki 
     92  1.18.2.2  isaki static void
     93  1.18.2.2  isaki msm6258_dtor(struct stream_filter *this)
     94  1.18.2.2  isaki {
     95  1.18.2.2  isaki 	if (this != NULL)
     96  1.18.2.2  isaki 		kmem_free(this, sizeof(struct msm6258_codecvar));
     97  1.18.2.2  isaki }
     98  1.18.2.2  isaki 
     99  1.18.2.2  isaki /*
    100  1.18.2.2  isaki  * signed 16bit linear PCM -> OkiADPCM
    101  1.18.2.2  isaki  */
    102  1.18.2.2  isaki static inline uint8_t
    103  1.18.2.2  isaki pcm2adpcm_step(struct msm6258_codecvar *mc, int16_t a)
    104  1.18.2.2  isaki {
    105  1.18.2.2  isaki 	int estim = (int)mc->mc_estim;
    106  1.18.2.2  isaki 	int df;
    107  1.18.2.2  isaki 	short dl, c;
    108  1.18.2.2  isaki 	uint8_t b;
    109  1.18.2.2  isaki 	uint8_t s;
    110  1.18.2.2  isaki 
    111  1.18.2.2  isaki 	df = a - mc->mc_amp;
    112  1.18.2.2  isaki 	dl = adpcm_estim[estim];
    113  1.18.2.2  isaki 	c = (df / 16) * 8 / dl;
    114  1.18.2.2  isaki 	if (df < 0) {
    115  1.18.2.2  isaki 		b = (unsigned char)(-c) / 2;
    116  1.18.2.2  isaki 		s = 0x08;
    117  1.18.2.2  isaki 	} else {
    118  1.18.2.2  isaki 		b = (unsigned char)(c) / 2;
    119  1.18.2.2  isaki 		s = 0;
    120  1.18.2.2  isaki 	}
    121  1.18.2.2  isaki 	if (b > 7)
    122  1.18.2.2  isaki 		b = 7;
    123  1.18.2.2  isaki 	s |= b;
    124  1.18.2.2  isaki 	mc->mc_amp += (short)(adpcm_estimindex[(int)s] * dl);
    125  1.18.2.2  isaki 	estim += adpcm_estimstep[b];
    126  1.18.2.2  isaki 	if (estim < 0)
    127  1.18.2.2  isaki 		estim = 0;
    128  1.18.2.2  isaki 	else if (estim > 48)
    129  1.18.2.2  isaki 		estim = 48;
    130  1.18.2.2  isaki 
    131  1.18.2.2  isaki 	mc->mc_estim = estim;
    132  1.18.2.2  isaki 	return s;
    133  1.18.2.2  isaki }
    134  1.18.2.2  isaki 
    135  1.18.2.2  isaki #define DEFINE_FILTER(name)	\
    136  1.18.2.2  isaki static int \
    137  1.18.2.2  isaki name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
    138  1.18.2.2  isaki stream_filter_t * \
    139  1.18.2.2  isaki name(struct audio_softc *sc, const audio_params_t *from, \
    140  1.18.2.2  isaki      const audio_params_t *to) \
    141  1.18.2.2  isaki { \
    142  1.18.2.2  isaki 	return msm6258_factory(sc, name##_fetch_to); \
    143  1.18.2.2  isaki } \
    144  1.18.2.2  isaki static int \
    145  1.18.2.2  isaki name##_fetch_to(struct audio_softc *asc, stream_fetcher_t *self, audio_stream_t *dst, int max_used)
    146  1.18.2.2  isaki 
    147  1.18.2.2  isaki DEFINE_FILTER(msm6258_slinear16_to_adpcm)
    148  1.18.2.2  isaki {
    149  1.18.2.2  isaki 	stream_filter_t *this;
    150  1.18.2.2  isaki 	struct msm6258_codecvar *mc;
    151  1.18.2.2  isaki 	uint8_t *d;
    152  1.18.2.2  isaki 	const uint8_t *s;
    153  1.18.2.2  isaki 	int m, err, enc_src;
    154  1.18.2.2  isaki 
    155  1.18.2.2  isaki 	this = (stream_filter_t *)self;
    156  1.18.2.2  isaki 	mc = (struct msm6258_codecvar *)self;
    157  1.18.2.2  isaki 	if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used * 4)))
    158  1.18.2.2  isaki 		return err;
    159  1.18.2.2  isaki 	m = dst->end - dst->start;
    160  1.18.2.2  isaki 	m = min(m, max_used);
    161  1.18.2.2  isaki 	d = dst->inp;
    162  1.18.2.2  isaki 	s = this->src->outp;
    163  1.18.2.2  isaki 	enc_src = this->src->param.encoding;
    164  1.18.2.2  isaki 	if (enc_src == AUDIO_ENCODING_SLINEAR_LE) {
    165  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 4) {
    166  1.18.2.2  isaki 			uint8_t f;
    167  1.18.2.2  isaki 			int16_t ss;
    168  1.18.2.2  isaki #if BYTE_ORDER == LITTLE_ENDIAN
    169  1.18.2.2  isaki 			ss = *(const int16_t*)s;
    170  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 2);
    171  1.18.2.2  isaki 			f  = pcm2adpcm_step(mc, ss);
    172  1.18.2.2  isaki 			ss = *(const int16_t*)s;
    173  1.18.2.2  isaki #else
    174  1.18.2.2  isaki 			ss = (s[1] << 8) | s[0];
    175  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 2);
    176  1.18.2.2  isaki 			f  = pcm2adpcm_step(mc, ss);
    177  1.18.2.2  isaki 			ss = (s[1] << 8) | s[0];
    178  1.18.2.2  isaki #endif
    179  1.18.2.2  isaki 			f |= pcm2adpcm_step(mc, ss) << 4;
    180  1.18.2.2  isaki 			*d = f;
    181  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    182  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 2);
    183  1.18.2.2  isaki 		}
    184  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    185  1.18.2.2  isaki 	} else if (enc_src == AUDIO_ENCODING_SLINEAR_BE) {
    186  1.18.2.2  isaki #else
    187  1.18.2.2  isaki 	} else {
    188  1.18.2.2  isaki #endif
    189  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 4) {
    190  1.18.2.2  isaki 			uint8_t f;
    191  1.18.2.2  isaki 			int16_t ss;
    192  1.18.2.2  isaki #if BYTE_ORDER == BIG_ENDIAN
    193  1.18.2.2  isaki 			ss = *(const int16_t*)s;
    194  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 2);
    195  1.18.2.2  isaki 			f  = pcm2adpcm_step(mc, ss);
    196  1.18.2.2  isaki 			ss = *(const int16_t*)s;
    197  1.18.2.2  isaki #else
    198  1.18.2.2  isaki 			ss = (s[0] << 8) | s[1];
    199  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 2);
    200  1.18.2.2  isaki 			f  = pcm2adpcm_step(mc, ss);
    201  1.18.2.2  isaki 			ss = (s[0] << 8) | s[1];
    202  1.18.2.2  isaki #endif
    203  1.18.2.2  isaki 			f |= pcm2adpcm_step(mc, ss) << 4;
    204  1.18.2.2  isaki 			*d = f;
    205  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    206  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 2);
    207  1.18.2.2  isaki 		}
    208  1.18.2.2  isaki 	}
    209  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    210  1.18.2.2  isaki 	else {
    211  1.18.2.2  isaki 		panic("msm6258_slinear16_to_adpcm: unsupported enc_src(%d)", enc_src);
    212  1.18.2.2  isaki 	}
    213  1.18.2.2  isaki #endif
    214  1.18.2.2  isaki 	dst->inp = d;
    215  1.18.2.2  isaki 	this->src->outp = s;
    216  1.18.2.2  isaki 	return 0;
    217  1.18.2.2  isaki }
    218  1.18.2.2  isaki 
    219  1.18.2.2  isaki DEFINE_FILTER(msm6258_linear8_to_adpcm)
    220  1.18.2.2  isaki {
    221  1.18.2.2  isaki 	stream_filter_t *this;
    222  1.18.2.2  isaki 	struct msm6258_codecvar *mc;
    223  1.18.2.2  isaki 	uint8_t *d;
    224  1.18.2.2  isaki 	const uint8_t *s;
    225  1.18.2.2  isaki 	int m, err, enc_src;
    226  1.18.2.2  isaki 
    227  1.18.2.2  isaki 	this = (stream_filter_t *)self;
    228  1.18.2.2  isaki 	mc = (struct msm6258_codecvar *)self;
    229  1.18.2.2  isaki 	if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used * 2)))
    230  1.18.2.2  isaki 		return err;
    231  1.18.2.2  isaki 	m = dst->end - dst->start;
    232  1.18.2.2  isaki 	m = min(m, max_used);
    233  1.18.2.2  isaki 	d = dst->inp;
    234  1.18.2.2  isaki 	s = this->src->outp;
    235  1.18.2.2  isaki 	enc_src = this->src->param.encoding;
    236  1.18.2.2  isaki 	if (enc_src == AUDIO_ENCODING_SLINEAR_LE) {
    237  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 4) {
    238  1.18.2.2  isaki 			uint8_t f;
    239  1.18.2.2  isaki 			int16_t ss;
    240  1.18.2.2  isaki 			ss = ((int16_t)s[0]) * 256;
    241  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    242  1.18.2.2  isaki 			f  = pcm2adpcm_step(mc, ss);
    243  1.18.2.2  isaki 			ss = ((int16_t)s[0]) * 256;
    244  1.18.2.2  isaki 			f |= pcm2adpcm_step(mc, ss) << 4;
    245  1.18.2.2  isaki 			*d = f;
    246  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    247  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    248  1.18.2.2  isaki 		}
    249  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    250  1.18.2.2  isaki 	} else if (enc_src == AUDIO_ENCODING_ULINEAR_LE) {
    251  1.18.2.2  isaki #else
    252  1.18.2.2  isaki 	} else {
    253  1.18.2.2  isaki #endif
    254  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 4) {
    255  1.18.2.2  isaki 			uint8_t f;
    256  1.18.2.2  isaki 			int16_t ss;
    257  1.18.2.2  isaki 			ss = ((int16_t)(s[0] ^ 0x80)) * 256;
    258  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    259  1.18.2.2  isaki 			f  = pcm2adpcm_step(mc, ss);
    260  1.18.2.2  isaki 			ss = ((int16_t)(s[0] ^ 0x80)) * 256;
    261  1.18.2.2  isaki 			f |= pcm2adpcm_step(mc, ss) << 4;
    262  1.18.2.2  isaki 			*d = f;
    263  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    264  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    265  1.18.2.2  isaki 		}
    266  1.18.2.2  isaki 	}
    267  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    268  1.18.2.2  isaki 	else {
    269  1.18.2.2  isaki 		panic("msm6258_linear8_to_adpcm: unsupported enc_src(%d)", enc_src);
    270  1.18.2.2  isaki 	}
    271  1.18.2.2  isaki #endif
    272  1.18.2.2  isaki 	dst->inp = d;
    273  1.18.2.2  isaki 	this->src->outp = s;
    274  1.18.2.2  isaki 	return 0;
    275  1.18.2.2  isaki }
    276  1.18.2.2  isaki 
    277  1.18.2.2  isaki /*
    278  1.18.2.2  isaki  * OkiADPCM -> signed 16bit linear PCM
    279  1.18.2.2  isaki  */
    280  1.18.2.2  isaki static inline int16_t
    281  1.18.2.2  isaki adpcm2pcm_step(struct msm6258_codecvar *mc, uint8_t b)
    282  1.18.2.2  isaki {
    283  1.18.2.2  isaki 	int estim = (int)mc->mc_estim;
    284  1.18.2.2  isaki 
    285  1.18.2.2  isaki 	mc->mc_amp += adpcm_estim[estim] * adpcm_estimindex[b];
    286  1.18.2.2  isaki 	estim += adpcm_estimstep[b];
    287  1.18.2.2  isaki 
    288  1.18.2.2  isaki 	if (estim < 0)
    289  1.18.2.2  isaki 		estim = 0;
    290  1.18.2.2  isaki 	else if (estim > 48)
    291  1.18.2.2  isaki 		estim = 48;
    292  1.18.2.2  isaki 
    293  1.18.2.2  isaki 	mc->mc_estim = estim;
    294  1.18.2.2  isaki 
    295  1.18.2.2  isaki 	return mc->mc_amp;
    296  1.18.2.2  isaki }
    297  1.18.2.2  isaki 
    298  1.18.2.2  isaki DEFINE_FILTER(msm6258_adpcm_to_slinear16)
    299  1.18.2.2  isaki {
    300  1.18.2.2  isaki 	stream_filter_t *this;
    301  1.18.2.2  isaki 	struct msm6258_codecvar *mc;
    302  1.18.2.2  isaki 	uint8_t *d;
    303  1.18.2.2  isaki 	const uint8_t *s;
    304  1.18.2.2  isaki 	int m, err, enc_dst;
    305  1.18.2.2  isaki 
    306  1.18.2.2  isaki 	this = (stream_filter_t *)self;
    307  1.18.2.2  isaki 	mc = (struct msm6258_codecvar *)self;
    308  1.18.2.2  isaki 	max_used = (max_used + 3) & ~3; /* round up multiple of 4 */
    309  1.18.2.2  isaki 	if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used / 4)))
    310  1.18.2.2  isaki 		return err;
    311  1.18.2.2  isaki 	m = (dst->end - dst->start) & ~3;
    312  1.18.2.2  isaki 	m = min(m, max_used);
    313  1.18.2.2  isaki 	d = dst->inp;
    314  1.18.2.2  isaki 	s = this->src->outp;
    315  1.18.2.2  isaki 	enc_dst = dst->param.encoding;
    316  1.18.2.2  isaki 	if (enc_dst == AUDIO_ENCODING_SLINEAR_LE) {
    317  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 1) {
    318  1.18.2.2  isaki 			uint8_t a;
    319  1.18.2.2  isaki 			int16_t s1, s2;
    320  1.18.2.2  isaki 			a = s[0];
    321  1.18.2.2  isaki 			s1 = adpcm2pcm_step(mc, a & 0x0f);
    322  1.18.2.2  isaki 			s2 = adpcm2pcm_step(mc, a >> 4);
    323  1.18.2.2  isaki #if BYTE_ORDER == LITTLE_ENDIAN
    324  1.18.2.2  isaki 			*(int16_t*)d = s1;
    325  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 2);
    326  1.18.2.2  isaki 			*(int16_t*)d = s2;
    327  1.18.2.2  isaki #else
    328  1.18.2.2  isaki 			d[0] = s1;
    329  1.18.2.2  isaki 			d[1] = s1 >> 8;
    330  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 2);
    331  1.18.2.2  isaki 			d[0] = s2;
    332  1.18.2.2  isaki 			d[1] = s2 >> 8;
    333  1.18.2.2  isaki #endif
    334  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 2);
    335  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    336  1.18.2.2  isaki 		}
    337  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    338  1.18.2.2  isaki 	} else if (enc_dst == AUDIO_ENCODING_SLINEAR_BE) {
    339  1.18.2.2  isaki #else
    340  1.18.2.2  isaki 	} else {
    341  1.18.2.2  isaki #endif
    342  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 1) {
    343  1.18.2.2  isaki 			uint8_t a;
    344  1.18.2.2  isaki 			int16_t s1, s2;
    345  1.18.2.2  isaki 			a = s[0];
    346  1.18.2.2  isaki 			s1 = adpcm2pcm_step(mc, a & 0x0f);
    347  1.18.2.2  isaki 			s2 = adpcm2pcm_step(mc, a >> 4);
    348  1.18.2.2  isaki #if BYTE_ORDER == BIG_ENDIAN
    349  1.18.2.2  isaki 			*(int16_t*)d = s1;
    350  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 2);
    351  1.18.2.2  isaki 			*(int16_t*)d = s2;
    352  1.18.2.2  isaki #else
    353  1.18.2.2  isaki 			d[1] = s1;
    354  1.18.2.2  isaki 			d[0] = s1 >> 8;
    355  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 2);
    356  1.18.2.2  isaki 			d[1] = s2;
    357  1.18.2.2  isaki 			d[0] = s2 >> 8;
    358  1.18.2.2  isaki #endif
    359  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 2);
    360  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    361  1.18.2.2  isaki 		}
    362  1.18.2.2  isaki 	}
    363  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    364  1.18.2.2  isaki 	else {
    365  1.18.2.2  isaki 		panic("msm6258_adpcm_to_slinear16: unsupported enc_dst(%d)", enc_dst);
    366  1.18.2.2  isaki 	}
    367  1.18.2.2  isaki #endif
    368  1.18.2.2  isaki 	dst->inp = d;
    369  1.18.2.2  isaki 	this->src->outp = s;
    370  1.18.2.2  isaki 	return 0;
    371  1.18.2.2  isaki }
    372  1.18.2.2  isaki 
    373  1.18.2.2  isaki DEFINE_FILTER(msm6258_adpcm_to_linear8)
    374  1.18.2.2  isaki {
    375  1.18.2.2  isaki 	stream_filter_t *this;
    376  1.18.2.2  isaki 	struct msm6258_codecvar *mc;
    377  1.18.2.2  isaki 	uint8_t *d;
    378  1.18.2.2  isaki 	const uint8_t *s;
    379  1.18.2.2  isaki 	int m, err, enc_dst;
    380  1.18.2.2  isaki 
    381  1.18.2.2  isaki 	this = (stream_filter_t *)self;
    382  1.18.2.2  isaki 	mc = (struct msm6258_codecvar *)self;
    383  1.18.2.2  isaki 	max_used = (max_used + 1) & ~1; /* round up multiple of 4 */
    384  1.18.2.2  isaki 	if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used / 2)))
    385  1.18.2.2  isaki 		return err;
    386  1.18.2.2  isaki 	m = (dst->end - dst->start) & ~1;
    387  1.18.2.2  isaki 	m = min(m, max_used);
    388  1.18.2.2  isaki 	d = dst->inp;
    389  1.18.2.2  isaki 	s = this->src->outp;
    390  1.18.2.2  isaki 	enc_dst = dst->param.encoding;
    391  1.18.2.2  isaki 	if (enc_dst == AUDIO_ENCODING_SLINEAR_LE) {
    392  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 1) {
    393  1.18.2.2  isaki 			uint8_t a;
    394  1.18.2.2  isaki 			int16_t s1, s2;
    395  1.18.2.2  isaki 			a = s[0];
    396  1.18.2.2  isaki 			s1 = adpcm2pcm_step(mc, a & 0x0f);
    397  1.18.2.2  isaki 			s2 = adpcm2pcm_step(mc, a >> 4);
    398  1.18.2.2  isaki 			d[0] = s1 / 266;
    399  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    400  1.18.2.2  isaki 			d[0] = s2 / 266;
    401  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    402  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    403  1.18.2.2  isaki 		}
    404  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    405  1.18.2.2  isaki 	} else if (enc_dst == AUDIO_ENCODING_ULINEAR_LE) {
    406  1.18.2.2  isaki #else
    407  1.18.2.2  isaki 	} else {
    408  1.18.2.2  isaki #endif
    409  1.18.2.2  isaki 		while (dst->used < m && this->src->used >= 1) {
    410  1.18.2.2  isaki 			uint8_t a;
    411  1.18.2.2  isaki 			int16_t s1, s2;
    412  1.18.2.2  isaki 			a = s[0];
    413  1.18.2.2  isaki 			s1 = adpcm2pcm_step(mc, a & 0x0f);
    414  1.18.2.2  isaki 			s2 = adpcm2pcm_step(mc, a >> 4);
    415  1.18.2.2  isaki 			d[0] = (s1 / 266) ^ 0x80;
    416  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    417  1.18.2.2  isaki 			d[0] = (s2 / 266) ^ 0x80;
    418  1.18.2.2  isaki 			d = audio_stream_add_inp(dst, d, 1);
    419  1.18.2.2  isaki 			s = audio_stream_add_outp(this->src, s, 1);
    420  1.18.2.2  isaki 		}
    421  1.18.2.2  isaki 	}
    422  1.18.2.2  isaki #if defined(DIAGNOSTIC)
    423  1.18.2.2  isaki 	else {
    424  1.18.2.2  isaki 		panic("msm6258_adpcm_to_linear8: unsupported enc_dst(%d)", enc_dst);
    425  1.18.2.2  isaki 	}
    426  1.18.2.2  isaki #endif
    427  1.18.2.2  isaki 	dst->inp = d;
    428  1.18.2.2  isaki 	this->src->outp = s;
    429  1.18.2.2  isaki 	return 0;
    430  1.18.2.2  isaki }
    431