The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/msm6258.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: b64b8c242660649aa2262385307bd4b8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.