linux/sound/core/pcm_misc.c
<<
>>
Prefs
   1/*
   2 *  PCM Interface - misc routines
   3 *  Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz>
   4 *
   5 *
   6 *   This library is free software; you can redistribute it and/or modify
   7 *   it under the terms of the GNU Library General Public License as
   8 *   published by the Free Software Foundation; either version 2 of
   9 *   the License, or (at your option) any later version.
  10 *
  11 *   This program is distributed in the hope that it will be useful,
  12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *   GNU Library General Public License for more details.
  15 *
  16 *   You should have received a copy of the GNU Library General Public
  17 *   License along with this library; if not, write to the Free Software
  18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  19 *
  20 */
  21  
  22#include <linux/time.h>
  23#include <sound/core.h>
  24#include <sound/pcm.h>
  25#define SND_PCM_FORMAT_UNKNOWN (-1)
  26
  27/* NOTE: "signed" prefix must be given below since the default char is
  28 *       unsigned on some architectures!
  29 */
  30struct pcm_format_data {
  31        unsigned char width;    /* bit width */
  32        unsigned char phys;     /* physical bit width */
  33        signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */
  34        signed char signd;      /* 0 = unsigned, 1 = signed, -1 = others */
  35        unsigned char silence[8];       /* silence data to fill */
  36};
  37
  38/* we do lots of calculations on snd_pcm_format_t; shut up sparse */
  39#define INT     __force int
  40
  41static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
  42        [SNDRV_PCM_FORMAT_S8] = {
  43                .width = 8, .phys = 8, .le = -1, .signd = 1,
  44                .silence = {},
  45        },
  46        [SNDRV_PCM_FORMAT_U8] = {
  47                .width = 8, .phys = 8, .le = -1, .signd = 0,
  48                .silence = { 0x80 },
  49        },
  50        [SNDRV_PCM_FORMAT_S16_LE] = {
  51                .width = 16, .phys = 16, .le = 1, .signd = 1,
  52                .silence = {},
  53        },
  54        [SNDRV_PCM_FORMAT_S16_BE] = {
  55                .width = 16, .phys = 16, .le = 0, .signd = 1,
  56                .silence = {},
  57        },
  58        [SNDRV_PCM_FORMAT_U16_LE] = {
  59                .width = 16, .phys = 16, .le = 1, .signd = 0,
  60                .silence = { 0x00, 0x80 },
  61        },
  62        [SNDRV_PCM_FORMAT_U16_BE] = {
  63                .width = 16, .phys = 16, .le = 0, .signd = 0,
  64                .silence = { 0x80, 0x00 },
  65        },
  66        [SNDRV_PCM_FORMAT_S24_LE] = {
  67                .width = 24, .phys = 32, .le = 1, .signd = 1,
  68                .silence = {},
  69        },
  70        [SNDRV_PCM_FORMAT_S24_BE] = {
  71                .width = 24, .phys = 32, .le = 0, .signd = 1,
  72                .silence = {},
  73        },
  74        [SNDRV_PCM_FORMAT_U24_LE] = {
  75                .width = 24, .phys = 32, .le = 1, .signd = 0,
  76                .silence = { 0x00, 0x00, 0x80 },
  77        },
  78        [SNDRV_PCM_FORMAT_U24_BE] = {
  79                .width = 24, .phys = 32, .le = 0, .signd = 0,
  80                .silence = { 0x00, 0x80, 0x00, 0x00 },
  81        },
  82        [SNDRV_PCM_FORMAT_S32_LE] = {
  83                .width = 32, .phys = 32, .le = 1, .signd = 1,
  84                .silence = {},
  85        },
  86        [SNDRV_PCM_FORMAT_S32_BE] = {
  87                .width = 32, .phys = 32, .le = 0, .signd = 1,
  88                .silence = {},
  89        },
  90        [SNDRV_PCM_FORMAT_U32_LE] = {
  91                .width = 32, .phys = 32, .le = 1, .signd = 0,
  92                .silence = { 0x00, 0x00, 0x00, 0x80 },
  93        },
  94        [SNDRV_PCM_FORMAT_U32_BE] = {
  95                .width = 32, .phys = 32, .le = 0, .signd = 0,
  96                .silence = { 0x80, 0x00, 0x00, 0x00 },
  97        },
  98        [SNDRV_PCM_FORMAT_FLOAT_LE] = {
  99                .width = 32, .phys = 32, .le = 1, .signd = -1,
 100                .silence = {},
 101        },
 102        [SNDRV_PCM_FORMAT_FLOAT_BE] = {
 103                .width = 32, .phys = 32, .le = 0, .signd = -1,
 104                .silence = {},
 105        },
 106        [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
 107                .width = 64, .phys = 64, .le = 1, .signd = -1,
 108                .silence = {},
 109        },
 110        [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
 111                .width = 64, .phys = 64, .le = 0, .signd = -1,
 112                .silence = {},
 113        },
 114        [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
 115                .width = 32, .phys = 32, .le = 1, .signd = -1,
 116                .silence = {},
 117        },
 118        [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
 119                .width = 32, .phys = 32, .le = 0, .signd = -1,
 120                .silence = {},
 121        },
 122        [SNDRV_PCM_FORMAT_MU_LAW] = {
 123                .width = 8, .phys = 8, .le = -1, .signd = -1,
 124                .silence = { 0x7f },
 125        },
 126        [SNDRV_PCM_FORMAT_A_LAW] = {
 127                .width = 8, .phys = 8, .le = -1, .signd = -1,
 128                .silence = { 0x55 },
 129        },
 130        [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
 131                .width = 4, .phys = 4, .le = -1, .signd = -1,
 132                .silence = {},
 133        },
 134        [SNDRV_PCM_FORMAT_G723_24] = {
 135                .width = 3, .phys = 3, .le = -1, .signd = -1,
 136                .silence = {},
 137        },
 138        [SNDRV_PCM_FORMAT_G723_40] = {
 139                .width = 5, .phys = 5, .le = -1, .signd = -1,
 140                .silence = {},
 141        },
 142        /* FIXME: the following three formats are not defined properly yet */
 143        [SNDRV_PCM_FORMAT_MPEG] = {
 144                .le = -1, .signd = -1,
 145        },
 146        [SNDRV_PCM_FORMAT_GSM] = {
 147                .le = -1, .signd = -1,
 148        },
 149        [SNDRV_PCM_FORMAT_SPECIAL] = {
 150                .le = -1, .signd = -1,
 151        },
 152        [SNDRV_PCM_FORMAT_S24_3LE] = {
 153                .width = 24, .phys = 24, .le = 1, .signd = 1,
 154                .silence = {},
 155        },
 156        [SNDRV_PCM_FORMAT_S24_3BE] = {
 157                .width = 24, .phys = 24, .le = 0, .signd = 1,
 158                .silence = {},
 159        },
 160        [SNDRV_PCM_FORMAT_U24_3LE] = {
 161                .width = 24, .phys = 24, .le = 1, .signd = 0,
 162                .silence = { 0x00, 0x00, 0x80 },
 163        },
 164        [SNDRV_PCM_FORMAT_U24_3BE] = {
 165                .width = 24, .phys = 24, .le = 0, .signd = 0,
 166                .silence = { 0x80, 0x00, 0x00 },
 167        },
 168        [SNDRV_PCM_FORMAT_S20_3LE] = {
 169                .width = 20, .phys = 24, .le = 1, .signd = 1,
 170                .silence = {},
 171        },
 172        [SNDRV_PCM_FORMAT_S20_3BE] = {
 173                .width = 20, .phys = 24, .le = 0, .signd = 1,
 174                .silence = {},
 175        },
 176        [SNDRV_PCM_FORMAT_U20_3LE] = {
 177                .width = 20, .phys = 24, .le = 1, .signd = 0,
 178                .silence = { 0x00, 0x00, 0x08 },
 179        },
 180        [SNDRV_PCM_FORMAT_U20_3BE] = {
 181                .width = 20, .phys = 24, .le = 0, .signd = 0,
 182                .silence = { 0x08, 0x00, 0x00 },
 183        },
 184        [SNDRV_PCM_FORMAT_S18_3LE] = {
 185                .width = 18, .phys = 24, .le = 1, .signd = 1,
 186                .silence = {},
 187        },
 188        [SNDRV_PCM_FORMAT_S18_3BE] = {
 189                .width = 18, .phys = 24, .le = 0, .signd = 1,
 190                .silence = {},
 191        },
 192        [SNDRV_PCM_FORMAT_U18_3LE] = {
 193                .width = 18, .phys = 24, .le = 1, .signd = 0,
 194                .silence = { 0x00, 0x00, 0x02 },
 195        },
 196        [SNDRV_PCM_FORMAT_U18_3BE] = {
 197                .width = 18, .phys = 24, .le = 0, .signd = 0,
 198                .silence = { 0x02, 0x00, 0x00 },
 199        },
 200        [SNDRV_PCM_FORMAT_G723_24_1B] = {
 201                .width = 3, .phys = 8, .le = -1, .signd = -1,
 202                .silence = {},
 203        },
 204        [SNDRV_PCM_FORMAT_G723_40_1B] = {
 205                .width = 5, .phys = 8, .le = -1, .signd = -1,
 206                .silence = {},
 207        },
 208};
 209
 210
 211/**
 212 * snd_pcm_format_signed - Check the PCM format is signed linear
 213 * @format: the format to check
 214 *
 215 * Returns 1 if the given PCM format is signed linear, 0 if unsigned
 216 * linear, and a negative error code for non-linear formats.
 217 */
 218int snd_pcm_format_signed(snd_pcm_format_t format)
 219{
 220        int val;
 221        if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
 222                return -EINVAL;
 223        if ((val = pcm_formats[(INT)format].signd) < 0)
 224                return -EINVAL;
 225        return val;
 226}
 227
 228EXPORT_SYMBOL(snd_pcm_format_signed);
 229
 230/**
 231 * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
 232 * @format: the format to check
 233 *
 234 * Returns 1 if the given PCM format is unsigned linear, 0 if signed
 235 * linear, and a negative error code for non-linear formats.
 236 */
 237int snd_pcm_format_unsigned(snd_pcm_format_t format)
 238{
 239        int val;
 240
 241        val = snd_pcm_format_signed(format);
 242        if (val < 0)
 243                return val;
 244        return !val;
 245}
 246
 247EXPORT_SYMBOL(snd_pcm_format_unsigned);
 248
 249/**
 250 * snd_pcm_format_linear - Check the PCM format is linear
 251 * @format: the format to check
 252 *
 253 * Returns 1 if the given PCM format is linear, 0 if not.
 254 */
 255int snd_pcm_format_linear(snd_pcm_format_t format)
 256{
 257        return snd_pcm_format_signed(format) >= 0;
 258}
 259
 260EXPORT_SYMBOL(snd_pcm_format_linear);
 261
 262/**
 263 * snd_pcm_format_little_endian - Check the PCM format is little-endian
 264 * @format: the format to check
 265 *
 266 * Returns 1 if the given PCM format is little-endian, 0 if
 267 * big-endian, or a negative error code if endian not specified.
 268 */
 269int snd_pcm_format_little_endian(snd_pcm_format_t format)
 270{
 271        int val;
 272        if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
 273                return -EINVAL;
 274        if ((val = pcm_formats[(INT)format].le) < 0)
 275                return -EINVAL;
 276        return val;
 277}
 278
 279EXPORT_SYMBOL(snd_pcm_format_little_endian);
 280
 281/**
 282 * snd_pcm_format_big_endian - Check the PCM format is big-endian
 283 * @format: the format to check
 284 *
 285 * Returns 1 if the given PCM format is big-endian, 0 if
 286 * little-endian, or a negative error code if endian not specified.
 287 */
 288int snd_pcm_format_big_endian(snd_pcm_format_t format)
 289{
 290        int val;
 291
 292        val = snd_pcm_format_little_endian(format);
 293        if (val < 0)
 294                return val;
 295        return !val;
 296}
 297
 298EXPORT_SYMBOL(snd_pcm_format_big_endian);
 299
 300/**
 301 * snd_pcm_format_width - return the bit-width of the format
 302 * @format: the format to check
 303 *
 304 * Returns the bit-width of the format, or a negative error code
 305 * if unknown format.
 306 */
 307int snd_pcm_format_width(snd_pcm_format_t format)
 308{
 309        int val;
 310        if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
 311                return -EINVAL;
 312        if ((val = pcm_formats[(INT)format].width) == 0)
 313                return -EINVAL;
 314        return val;
 315}
 316
 317EXPORT_SYMBOL(snd_pcm_format_width);
 318
 319/**
 320 * snd_pcm_format_physical_width - return the physical bit-width of the format
 321 * @format: the format to check
 322 *
 323 * Returns the physical bit-width of the format, or a negative error code
 324 * if unknown format.
 325 */
 326int snd_pcm_format_physical_width(snd_pcm_format_t format)
 327{
 328        int val;
 329        if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
 330                return -EINVAL;
 331        if ((val = pcm_formats[(INT)format].phys) == 0)
 332                return -EINVAL;
 333        return val;
 334}
 335
 336EXPORT_SYMBOL(snd_pcm_format_physical_width);
 337
 338/**
 339 * snd_pcm_format_size - return the byte size of samples on the given format
 340 * @format: the format to check
 341 * @samples: sampling rate
 342 *
 343 * Returns the byte size of the given samples for the format, or a
 344 * negative error code if unknown format.
 345 */
 346ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
 347{
 348        int phys_width = snd_pcm_format_physical_width(format);
 349        if (phys_width < 0)
 350                return -EINVAL;
 351        return samples * phys_width / 8;
 352}
 353
 354EXPORT_SYMBOL(snd_pcm_format_size);
 355
 356/**
 357 * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
 358 * @format: the format to check
 359 *
 360 * Returns the format pattern to fill or NULL if error.
 361 */
 362const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
 363{
 364        if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
 365                return NULL;
 366        if (! pcm_formats[(INT)format].phys)
 367                return NULL;
 368        return pcm_formats[(INT)format].silence;
 369}
 370
 371EXPORT_SYMBOL(snd_pcm_format_silence_64);
 372
 373/**
 374 * snd_pcm_format_set_silence - set the silence data on the buffer
 375 * @format: the PCM format
 376 * @data: the buffer pointer
 377 * @samples: the number of samples to set silence
 378 *
 379 * Sets the silence data on the buffer for the given samples.
 380 *
 381 * Returns zero if successful, or a negative error code on failure.
 382 */
 383int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
 384{
 385        int width;
 386        unsigned char *dst, *pat;
 387
 388        if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
 389                return -EINVAL;
 390        if (samples == 0)
 391                return 0;
 392        width = pcm_formats[(INT)format].phys; /* physical width */
 393        pat = pcm_formats[(INT)format].silence;
 394        if (! width)
 395                return -EINVAL;
 396        /* signed or 1 byte data */
 397        if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
 398                unsigned int bytes = samples * width / 8;
 399                memset(data, *pat, bytes);
 400                return 0;
 401        }
 402        /* non-zero samples, fill using a loop */
 403        width /= 8;
 404        dst = data;
 405#if 0
 406        while (samples--) {
 407                memcpy(dst, pat, width);
 408                dst += width;
 409        }
 410#else
 411        /* a bit optimization for constant width */
 412        switch (width) {
 413        case 2:
 414                while (samples--) {
 415                        memcpy(dst, pat, 2);
 416                        dst += 2;
 417                }
 418                break;
 419        case 3:
 420                while (samples--) {
 421                        memcpy(dst, pat, 3);
 422                        dst += 3;
 423                }
 424                break;
 425        case 4:
 426                while (samples--) {
 427                        memcpy(dst, pat, 4);
 428                        dst += 4;
 429                }
 430                break;
 431        case 8:
 432                while (samples--) {
 433                        memcpy(dst, pat, 8);
 434                        dst += 8;
 435                }
 436                break;
 437        }
 438#endif
 439        return 0;
 440}
 441
 442EXPORT_SYMBOL(snd_pcm_format_set_silence);
 443
 444/**
 445 * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
 446 * @runtime: the runtime instance
 447 *
 448 * Determines the rate_min and rate_max fields from the rates bits of
 449 * the given runtime->hw.
 450 *
 451 * Returns zero if successful.
 452 */
 453int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
 454{
 455        int i;
 456        for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
 457                if (runtime->hw.rates & (1 << i)) {
 458                        runtime->hw.rate_min = snd_pcm_known_rates.list[i];
 459                        break;
 460                }
 461        }
 462        for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
 463                if (runtime->hw.rates & (1 << i)) {
 464                        runtime->hw.rate_max = snd_pcm_known_rates.list[i];
 465                        break;
 466                }
 467        }
 468        return 0;
 469}
 470
 471EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
 472
 473/**
 474 * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
 475 * @rate: the sample rate to convert
 476 *
 477 * Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
 478 * SNDRV_PCM_RATE_KNOT for an unknown rate.
 479 */
 480unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
 481{
 482        unsigned int i;
 483
 484        for (i = 0; i < snd_pcm_known_rates.count; i++)
 485                if (snd_pcm_known_rates.list[i] == rate)
 486                        return 1u << i;
 487        return SNDRV_PCM_RATE_KNOT;
 488}
 489EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
 490