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/aurateconv.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: aurateconv.c,v 1.9 2003/12/31 13:51:28 bjh21 Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by TAMURA Kent
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: aurateconv.c,v 1.9 2003/12/31 13:51:28 bjh21 Exp $");
   41 
   42 #include <sys/systm.h>
   43 #include <sys/types.h>
   44 #include <sys/device.h>
   45 #include <sys/errno.h>
   46 #include <sys/select.h>
   47 #include <sys/audioio.h>
   48 
   49 #include <dev/audio_if.h>
   50 #include <dev/audiovar.h>
   51 
   52 #ifdef AURATECONV_DEBUG
   53 #define DPRINTF(x)      printf x
   54 #else
   55 #define DPRINTF(x)
   56 #endif
   57 
   58 static int auconv_play_slinear16_LE(struct auconv_context *,
   59         const struct audio_params *, uint8_t *, const uint8_t *, int);
   60 static int auconv_play_slinear24_LE(struct auconv_context *,
   61         const struct audio_params *, uint8_t *, const uint8_t *, int);
   62 static int auconv_play_slinear16_BE(struct auconv_context *,
   63         const struct audio_params *, uint8_t *, const uint8_t *, int);
   64 static int auconv_play_slinear24_BE(struct auconv_context *,
   65         const struct audio_params *, uint8_t *, const uint8_t *, int);
   66 
   67 static int auconv_record_slinear16_LE(struct auconv_context *,
   68         const struct audio_params *, uint8_t *, const uint8_t *, int);
   69 static int auconv_record_slinear24_LE(struct auconv_context *,
   70         const struct audio_params *, uint8_t *, const uint8_t *, int);
   71 static int auconv_record_slinear16_BE(struct auconv_context *,
   72         const struct audio_params *, uint8_t *, const uint8_t *, int);
   73 static int auconv_record_slinear24_BE(struct auconv_context *,
   74         const struct audio_params *, uint8_t *, const uint8_t *, int);
   75 
   76 int
   77 auconv_check_params(const struct audio_params *params)
   78 {
   79         DPRINTF(("auconv_check_params: rate=%ld:%ld chan=%d:%d prec=%d:%d "
   80                  "enc=%d:%d\n", params->sample_rate, params->hw_sample_rate,
   81                  params->channels, params->hw_channels, params->precision,
   82                  params->hw_precision, params->encoding, params->hw_encoding));
   83         if (params->hw_channels == params->channels
   84             && params->hw_sample_rate == params->sample_rate)
   85                 return 0;       /* No conversion */
   86 
   87         if ((params->hw_encoding != AUDIO_ENCODING_SLINEAR_LE
   88              && params->hw_encoding != AUDIO_ENCODING_SLINEAR_BE)
   89             || (params->hw_precision != 16 && params->hw_precision != 24))
   90                 return (EINVAL);
   91 
   92         if (params->hw_channels != params->channels) {
   93                 if (params->hw_channels == 1 && params->channels == 2) {
   94                         /* Ok */
   95                 } else if (params->hw_channels == 2 && params->channels == 1) {
   96                         /* Ok */
   97                 } else if (params->hw_channels > params->channels) {
   98                         /* Ok */
   99                 } else
  100                         return (EINVAL);
  101         }
  102         if (params->hw_channels > AUDIO_MAX_CHANNELS
  103             || params->channels > AUDIO_MAX_CHANNELS)
  104                 return (EINVAL);
  105 
  106         if (params->hw_sample_rate != params->sample_rate)
  107                 if (params->hw_sample_rate <= 0 || params->sample_rate <= 0)
  108                         return (EINVAL);
  109         return 0;
  110 }
  111 
  112 void
  113 auconv_init_context(struct auconv_context *context, long src_rate,
  114                     long dst_rate, uint8_t *start, uint8_t *end)
  115 {
  116         int i;
  117 
  118         context->ring_start = start;
  119         context->ring_end = end;
  120         if (dst_rate > src_rate) {
  121                 context->count = src_rate;
  122         } else {
  123                 context->count = 0;
  124         }
  125         for (i = 0; i < AUDIO_MAX_CHANNELS; i++)
  126                 context->prev[i] = 0;
  127 }
  128 
  129 /*
  130  * src is a ring buffer.
  131  */
  132 int
  133 auconv_record(struct auconv_context *context,
  134               const struct audio_params *params, uint8_t *dest,
  135               const uint8_t *src, int srcsize)
  136 {
  137         if (params->hw_sample_rate == params->sample_rate
  138             && params->hw_channels == params->channels) {
  139                 int n;
  140 
  141                 n = context->ring_end - src;
  142                 if (srcsize <= n)
  143                         memcpy(dest, src, srcsize);
  144                 else {
  145                         memcpy(dest, src, n);
  146                         memcpy(dest + n, context->ring_start, srcsize - n);
  147                 }
  148                 return srcsize;
  149         }
  150 
  151         switch (params->hw_encoding) {
  152         case AUDIO_ENCODING_SLINEAR_LE:
  153                 switch (params->hw_precision) {
  154                 case 16:
  155                         return auconv_record_slinear16_LE(context, params,
  156                                                           dest, src, srcsize);
  157                 case 24:
  158                         return auconv_record_slinear24_LE(context, params,
  159                                                           dest, src, srcsize);
  160                 }
  161                 break;
  162         case AUDIO_ENCODING_SLINEAR_BE:
  163                 switch (params->hw_precision) {
  164                 case 16:
  165                         return auconv_record_slinear16_BE(context, params,
  166                                                           dest, src, srcsize);
  167                 case 24:
  168                         return auconv_record_slinear24_BE(context, params,
  169                                                           dest, src, srcsize);
  170                 }
  171                 break;
  172         default:
  173                 /* This should be rejected in auconv_check_params() */
  174                 printf("auconv_record: unimplemented encoding: %d\n",
  175                        params->hw_encoding);
  176                 return 0;
  177         }
  178         printf("auconv_record: unimplemented precision: %d\n",
  179                params->hw_precision);
  180         return 0;
  181 }
  182 
  183 /*
  184  * dest is a ring buffer.
  185  */
  186 int
  187 auconv_play(struct auconv_context *context, const struct audio_params *params,
  188             uint8_t *dest, const uint8_t *src, int srcsize)
  189 {
  190         int n;
  191 
  192         if (params->hw_sample_rate == params->sample_rate
  193             && params->hw_channels == params->channels) {
  194                 n = context->ring_end - dest;
  195                 if (srcsize <= n) {
  196                         memcpy(dest, src, srcsize);
  197                 } else {
  198                         memcpy(dest, src, n);
  199                         memcpy(context->ring_start, src + n, srcsize - n);
  200                 }
  201                 return srcsize;
  202         }
  203 
  204         switch (params->hw_encoding) {
  205         case AUDIO_ENCODING_SLINEAR_LE:
  206                 switch (params->hw_precision) {
  207                 case 16:
  208                         return auconv_play_slinear16_LE(context, params,
  209                                                         dest, src, srcsize);
  210                 case 24:
  211                         return auconv_play_slinear24_LE(context, params,
  212                                                         dest, src, srcsize);
  213                 }
  214                 break;
  215         case AUDIO_ENCODING_SLINEAR_BE:
  216                 switch (params->hw_precision) {
  217                 case 16:
  218                         return auconv_play_slinear16_BE(context, params,
  219                                                         dest, src, srcsize);
  220                 case 24:
  221                         return auconv_play_slinear24_BE(context, params,
  222                                                         dest, src, srcsize);
  223                 }
  224                 break;
  225         default:
  226                 /* This should be rejected in auconv_check_params() */
  227                 printf("auconv_play: unimplemented encoding: %d\n",
  228                        params->hw_encoding);
  229                 return 0;
  230         }
  231         printf("auconv_play: unimplemented precision: %d\n",
  232                params->hw_precision);
  233         return 0;
  234 }
  235 
  236 
  237 #define RING_CHECK(C, V)        \
  238         do { \
  239                 if (V >= (C)->ring_end) \
  240                         V = (C)->ring_start; \
  241         } while (/*CONSTCOND*/ 0)
  242 
  243 #define READ_S8LE(P)            *(int8_t*)(P)
  244 #define WRITE_S8LE(P, V)        *(int8_t*)(P) = V
  245 #define READ_S8BE(P)            *(int8_t*)(P)
  246 #define WRITE_S8BE(P, V)        *(int8_t*)(P) = V
  247 #if BYTE_ORDER == LITTLE_ENDIAN
  248 # define READ_S16LE(P)          *(int16_t*)(P)
  249 # define WRITE_S16LE(P, V)      *(int16_t*)(P) = V
  250 # define READ_S16BE(P)          (int16_t)((P)[0] | ((P)[1]<<8))
  251 # define WRITE_S16BE(P, V)      \
  252         do { \
  253                 int vv = V; \
  254                 (P)[0] = vv; \
  255                 (P)[1] = vv >> 8; \
  256         } while (/*CONSTCOND*/ 0)
  257 #else
  258 # define READ_S16LE(P)          (int16_t)((P)[0] | ((P)[1]<<8))
  259 # define WRITE_S16LE(P, V)      \
  260         do { \
  261                 int vv = V; \
  262                 (P)[0] = vv; \
  263                 (P)[1] = vv >> 8; \
  264         } while (/*CONSTCOND*/ 0)
  265 # define READ_S16BE(P)          *(int16_t*)(P)
  266 # define WRITE_S16BE(P, V)      *(int16_t*)(P) = V
  267 #endif
  268 #define READ_S24LE(P)           (int32_t)((P)[0] | ((P)[1]<<8) | (((int8_t)((P)[2]))<<16))
  269 #define WRITE_S24LE(P, V)       \
  270         do { \
  271                 int vvv = V; \
  272                 (P)[0] = vvv; \
  273                 (P)[1] = vvv >> 8; \
  274                 (P)[2] = vvv >> 16; \
  275         } while (/*CONSTCOND*/ 0)
  276 #define READ_S24BE(P)           (int32_t)((P)[2] | ((P)[1]<<8) | (((int8_t)((P)[0]))<<16))
  277 #define WRITE_S24BE(P, V)       \
  278         do { \
  279                 int vvv = V; \
  280                 (P)[0] = vvv >> 16; \
  281                 (P)[1] = vvv >> 8; \
  282                 (P)[2] = vvv; \
  283         } while (/*CONSTCOND*/ 0)
  284 
  285 #define P_READ_Sn(BITS, EN, V, RP, PAR) \
  286         do { \
  287                 int j; \
  288                 for (j = 0; j < (PAR)->channels; j++) { \
  289                         (V)[j] = READ_S##BITS##EN(RP); \
  290                         RP += (BITS) / NBBY; \
  291                 } \
  292         } while (/*CONSTCOND*/ 0)
  293 #define P_WRITE_Sn(BITS, EN, V, WP, PAR, CON, WC)       \
  294         do { \
  295                 if ((PAR)->channels == 2 && (PAR)->hw_channels == 1) { \
  296                         WRITE_S##BITS##EN(WP, ((V)[0] + (V)[1]) / 2); \
  297                         WP += (BITS) / NBBY; \
  298                         RING_CHECK(CON, WP); \
  299                         WC += (BITS) / NBBY; \
  300                 } else { /* channels <= hw_channels */ \
  301                         int j; \
  302                         for (j = 0; j < (PAR)->channels; j++) { \
  303                                 WRITE_S##BITS##EN(WP, (V)[j]); \
  304                                 WP += (BITS) / NBBY; \
  305                                 RING_CHECK(CON, WP); \
  306                         } \
  307                         if (j == 1 && 1 < (PAR)->hw_channels) { \
  308                                 WRITE_S##BITS##EN(WP, (V)[0]); \
  309                                 WP += (BITS) / NBBY; \
  310                                 RING_CHECK(CON, WP); \
  311                                 j++; \
  312                         } \
  313                         for (; j < (PAR)->hw_channels; j++) { \
  314                                 WRITE_S##BITS##EN(WP, 0); \
  315                                 WP += (BITS) / NBBY; \
  316                                 RING_CHECK(CON, WP); \
  317                         } \
  318                         WC += (BITS) / NBBY * j; \
  319                 } \
  320         } while (/*CONSTCOND*/ 0)
  321 
  322 #define R_READ_Sn(BITS, EN, V, RP, PAR, CON, RC)        \
  323         do { \
  324                 int j; \
  325                 for (j = 0; j < (PAR)->hw_channels; j++) { \
  326                         (V)[j] = READ_S##BITS##EN(RP); \
  327                         RP += (BITS) / NBBY; \
  328                         RING_CHECK(CON, RP); \
  329                         RC += (BITS) / NBBY; \
  330                 } \
  331         } while (/*CONSTCOND*/ 0)
  332 #define R_WRITE_Sn(BITS, EN, V, WP, PAR, WC)    \
  333         do { \
  334                 if ((PAR)->channels == 2 && (PAR)->hw_channels == 1) { \
  335                         WRITE_S##BITS##EN(WP, (V)[0]); \
  336                         WP += (BITS) / NBBY; \
  337                         WRITE_S##BITS##EN(WP, (V)[0]); \
  338                         WP += (BITS) / NBBY; \
  339                         WC += (BITS) / NBBY * 2; \
  340                 } else if ((PAR)->channels == 1 && (PAR)->hw_channels >= 2) { \
  341                         WRITE_S##BITS##EN(WP, ((V)[0] + (V)[1]) / 2); \
  342                         WP += (BITS) / NBBY; \
  343                         WC += (BITS) / NBBY; \
  344                 } else {        /* channels <= hw_channels */ \
  345                         int j; \
  346                         for (j = 0; j < (PAR)->channels; j++) { \
  347                                 WRITE_S##BITS##EN(WP, (V)[j]); \
  348                                 WP += (BITS) / NBBY; \
  349                         } \
  350                         WC += (BITS) / NBBY * j; \
  351                 } \
  352         } while (/*CONSTCOND*/ 0)
  353 
  354 /*
  355  * Function templates
  356  *
  357  *   Source may be 1 sample.  Destination buffer must have space for converted
  358  *   source.
  359  *   Don't use them for 32bit data because this linear interpolation overflows
  360  *   for 32bit data.
  361  */
  362 #define AUCONV_PLAY_SLINEAR(BITS, EN)   \
  363 static int \
  364 auconv_play_slinear##BITS##_##EN (struct auconv_context *context, \
  365                                const struct audio_params *params, \
  366                                uint8_t *dest, const uint8_t *src, \
  367                                int srcsize) \
  368 { \
  369         int wrote; \
  370         uint8_t *w; \
  371         const uint8_t *r; \
  372         const uint8_t *src_end; \
  373         int32_t v[AUDIO_MAX_CHANNELS]; \
  374         int32_t prev[AUDIO_MAX_CHANNELS], next[AUDIO_MAX_CHANNELS], c256; \
  375         int i, values_size; \
  376  \
  377         wrote = 0; \
  378         w = dest; \
  379         r = src; \
  380         src_end = src + srcsize; \
  381         if (params->sample_rate == params->hw_sample_rate) { \
  382                 while (r < src_end) { \
  383                         P_READ_Sn(BITS, EN, v, r, params); \
  384                         P_WRITE_Sn(BITS, EN, v, w, params, context, wrote); \
  385                 } \
  386         } else if (params->hw_sample_rate < params->sample_rate) { \
  387                 for (;;) { \
  388                         do { \
  389                                 if (r >= src_end) \
  390                                         return wrote; \
  391                                 P_READ_Sn(BITS, EN, v, r, params); \
  392                                 context->count += params->hw_sample_rate; \
  393                         } while (context->count < params->sample_rate); \
  394                         context->count -= params->sample_rate; \
  395                         P_WRITE_Sn(BITS, EN, v, w, params, context, wrote); \
  396                 } \
  397         } else { \
  398                 /* Initial value of context->count is params->sample_rate */ \
  399                 values_size = sizeof(int32_t) * params->channels; \
  400                 memcpy(prev, context->prev, values_size); \
  401                 P_READ_Sn(BITS, EN, next, r, params); \
  402                 for (;;) { \
  403                         c256 = context->count * 256 / params->hw_sample_rate; \
  404                         for (i = 0; i < params->channels; i++) \
  405                                 v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \
  406                         P_WRITE_Sn(BITS, EN, v, w, params, context, wrote); \
  407                         context->count += params->sample_rate; \
  408                         if (context->count >= params->hw_sample_rate) { \
  409                                 context->count -= params->hw_sample_rate; \
  410                                 memcpy(prev, next, values_size); \
  411                                 if (r >= src_end) \
  412                                         break; \
  413                                 P_READ_Sn(BITS, EN, next, r, params); \
  414                         } \
  415                 } \
  416                 memcpy(context->prev, next, values_size); \
  417         } \
  418         return wrote; \
  419 }
  420 
  421 #define AUCONV_RECORD_SLINEAR(BITS, EN) \
  422 static int \
  423 auconv_record_slinear##BITS##_##EN (struct auconv_context *context, \
  424                                  const struct audio_params *params, \
  425                                  uint8_t *dest, const uint8_t *src, \
  426                                  int srcsize) \
  427 { \
  428         int wrote, rsize; \
  429         uint8_t *w; \
  430         const uint8_t *r; \
  431         int32_t v[AUDIO_MAX_CHANNELS]; \
  432         int32_t prev[AUDIO_MAX_CHANNELS], next[AUDIO_MAX_CHANNELS], c256; \
  433         int i, values_size; \
  434  \
  435         wrote = 0; \
  436         rsize = 0; \
  437         w = dest; \
  438         r = src; \
  439         if (params->sample_rate == params->hw_sample_rate) { \
  440                 while (rsize < srcsize) { \
  441                         R_READ_Sn(BITS, EN, v, r, params, context, rsize); \
  442                         R_WRITE_Sn(BITS, EN, v, w, params, wrote); \
  443                 } \
  444         } else if (params->sample_rate < params->hw_sample_rate) { \
  445                 for (;;) { \
  446                         do { \
  447                                 if (rsize >= srcsize) \
  448                                         return wrote; \
  449                                 R_READ_Sn(BITS, EN, v, r, params, context, rsize); \
  450                                 context->count += params->sample_rate; \
  451                         } while (context->count < params->hw_sample_rate); \
  452                         context->count -= params->hw_sample_rate; \
  453                         R_WRITE_Sn(BITS, EN, v, w, params, wrote); \
  454                 } \
  455         } else { \
  456                 /* Initial value of context->count is params->hw_sample_rate */ \
  457                 values_size = sizeof(int32_t) * params->hw_channels; \
  458                 memcpy(prev, context->prev, values_size); \
  459                 R_READ_Sn(BITS, EN, next, r, params, context, rsize); \
  460                 for (;;) { \
  461                         c256 = context->count * 256 / params->sample_rate; \
  462                         for (i = 0; i < params->hw_channels; i++) \
  463                                 v[i] = (c256 * next[i] + (256 - c256) * prev[i]) >> 8; \
  464                         R_WRITE_Sn(BITS, EN, v, w, params, wrote); \
  465                         context->count += params->hw_sample_rate; \
  466                         if (context->count >= params->sample_rate) { \
  467                                 context->count -= params->sample_rate; \
  468                                 memcpy(prev, next, values_size); \
  469                                 if (rsize >= srcsize) \
  470                                         break; \
  471                                 R_READ_Sn(BITS, EN, next, r, params, context, rsize); \
  472                         } \
  473                 } \
  474                 memcpy(context->prev, next, values_size); \
  475         } \
  476         return wrote; \
  477 }
  478 
  479 AUCONV_PLAY_SLINEAR(16, LE)
  480 AUCONV_PLAY_SLINEAR(24, LE)
  481 AUCONV_PLAY_SLINEAR(16, BE)
  482 AUCONV_PLAY_SLINEAR(24, BE)
  483 AUCONV_RECORD_SLINEAR(16, LE)
  484 AUCONV_RECORD_SLINEAR(24, LE)
  485 AUCONV_RECORD_SLINEAR(16, BE)
  486 AUCONV_RECORD_SLINEAR(24, BE)

Cache object: 65ef015815dbe9537e53d34b33d81369


[ 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.