packages feed

flac-0.1.0: cbits/stream_decoder_helpers.c

/*
 * This file is part of ‘flac’ package.
 *
 * Copyright © 2016–2017 Mark Karpov
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name Mark Karpov nor the names of contributors may be used to
 *   endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS “AS IS” AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "stream_decoder_helpers.h"

static unsigned round_to_bytes(unsigned bits)
{
  return (bits + (bits % 8)) / 8;
}

static FLAC__StreamDecoderWriteStatus write_callback
  ( const FLAC__StreamDecoder *decoder
  , const FLAC__Frame *frame
  , const FLAC__int32 *const ibuffer[]
  , void *obuffer)
{
  FLAC__uint64 i, ch;
  unsigned channels = frame->header.channels;

  (void)decoder;

  switch (round_to_bytes(frame->header.bits_per_sample))
    {
      case 1:

        /* If sample width is equal or less than 8 bit, we deal with one
         * byte per sample and samples are unsigned as per WAVE spec. */
        for (i = 0; i < frame->header.blocksize; i++)
          {
            for (ch = 0; ch < channels; ch++)
              {
                /* Shift back into unsigned values by adding 0x7f. */
                *((FLAC__uint8 *)obuffer + i * channels + ch)
                  = (FLAC__uint8)ibuffer[ch][i] + 0x80;
              }
          }
        break;

      case 2:

        /* Here we have signed samples, each having width equal to 16
         * bits. */
        for (i = 0; i < frame->header.blocksize; i++)
          {
            for (ch = 0; ch < channels; ch++)
              {
                *((FLAC__int16 *)obuffer + i * channels + ch)
                  = (FLAC__int16)ibuffer[ch][i];
              }
          }
        break;

      case 3:

        /* Singed 24 bit samples. Going with 3 bytes step is not so
         * handy. */
        for (i = 0; i < frame->header.blocksize; i++)
          {
            for (ch = 0; ch < channels; ch++)
              {
                *(FLAC__int32 *)((FLAC__byte *)obuffer + (i * channels + ch) * 3)
                  = (FLAC__int32)ibuffer[ch][i];
              }
          }
        break;
    }

  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}

static void error_callback
  ( const FLAC__StreamDecoder *decoder
  , FLAC__StreamDecoderErrorStatus status
  , void *client_data )
{
  (void)decoder, (void)status, (void)client_data;
  return;
}

FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_helper
  ( FLAC__StreamDecoder *decoder
  , char *ifile_name
  , void *buffer )
{
  return FLAC__stream_decoder_init_file
    (decoder, ifile_name, write_callback, NULL, error_callback, buffer);
}