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