packages feed

lame-0.1.0: cbits/helpers.c

/*
 * This file is part of ‘lame’ package.
 *
 * Copyright © 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 "helpers.h"

int id3tag_set_textinfo_utf16_
  ( lame_global_flags *gfp
  , const char *id
  , const uint16_t *raw_text
  , int len)
{
  uint16_t *text = alloca(sizeof(uint16_t) * (len + 2));
  int i;
  *(text + 0) = 0xfeff; /* BOM */
  for (i = 0; i < len; i++)
    {
      *(text + i + 1) = *(raw_text + i);
    }
  *(text + len + 1) = 0;
  return id3tag_set_textinfo_utf16(gfp, id, text);
}

int id3tag_set_comment_utf16_
  ( lame_global_flags *gfp
  , const uint16_t *raw_text
  , int len )
{
  uint16_t *text = alloca(sizeof(uint16_t) * (len + 2));
  int i;
  *(text + 0) = 0xfeff; /* BOM */
  for (i = 0; i < len; i++)
    {
      *(text + i + 1) = *(raw_text + i);
    }
  *(text + len + 1) = 0;
  return id3tag_set_comment_utf16(gfp, 0, 0, text);
}

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

int lame_encoding_helper
  ( lame_global_flags *gfp
  , uint64_t data_offset
  , uint64_t data_size
  , uint16_t sample_format
  , uint16_t bits_per_sample
  , const char * ifile_name
  , const char * ofile_name )
{
  unsigned channels = lame_get_num_channels(gfp);
  unsigned msw = round_to_bytes(bits_per_sample);
  unsigned block_align = channels * msw;
  uint64_t samples_to_process = data_size / block_align;
  uint64_t read_size = 0xffff; /* we need a bit more here because of pictures in metadata */
  void *buffer = malloc(read_size * block_align);
  size_t mp3buffer_size = 1.3 * read_size + 7200;
  void *mp3buffer = malloc(mp3buffer_size);
  int imp3, status;
  FILE *ifile = fopen(ifile_name, "r");
  FILE *ofile = fopen(ofile_name, "w");
  uint64_t samples;

  if ((data_size % block_align) ||
      bits_per_sample <= 8      ||
      (sample_format == 0 && bits_per_sample > 16))
    {
      free(buffer);
      fclose(ifile);
      fclose(ofile);
      return -1;
    }

  /* move position indicator to beginning of audio data */
  fseek(ifile, data_offset, SEEK_SET);

  while (samples_to_process)
    {
      /* The reading happens by blocks. Every block has read_size samples in
       * it (multi-channel samples, that is). Since we will be using the
       * value returned by fread as indicator of whether something went
       * wrong or not, we need to know beforehand how many samples we need
       * to read. */
      samples = read_size <= samples_to_process ? read_size : samples_to_process;

      /* Read the samples into the “raw” buffer, fail by returning false if
       * number of read samples differs from the expected. */
      if (fread(buffer, block_align, samples, ifile) != samples)
        {
          free(buffer);
          fclose(ifile);
          fclose(ofile);
          return -1;
        }

      switch (sample_format)
        {
        case LAME_HASKELL_INT: /* samples are integers */
          imp3 = lame_encode_buffer_interleaved
            (gfp, buffer, samples, mp3buffer, mp3buffer_size);
          break;
        case LAME_HASKELL_FLOAT: /* samples are 32 bit floats */
          imp3 = lame_encode_buffer_interleaved_ieee_float
            (gfp, buffer, samples, mp3buffer, mp3buffer_size);
          break;
        case LAME_HASKELL_DOUBLE: /* samples are 64 bit floats (doubles) */
          imp3 = lame_encode_buffer_interleaved_ieee_double
            (gfp, buffer, samples, mp3buffer, mp3buffer_size);
          break;
        default: /* got something else? you're screwed */
          free(buffer);
          fclose(ifile);
          fclose(ofile);
          return -1;
        }

      if (imp3 < 0)
        {
          free(buffer);
          fclose(ifile);
          fclose(ofile);
          return -1;
        }

      status = (int) fwrite(mp3buffer, 1, imp3, ofile);

      if (status != imp3)
        {
          free(buffer);
          fclose(ifile);
          fclose(ofile);
          return -1;
        }

      samples_to_process -= samples;
    }

  if (lame_get_nogap_total(gfp) > 0)
    imp3 = lame_encode_flush_nogap(gfp, mp3buffer, mp3buffer_size);
  else
    imp3 = lame_encode_flush(gfp, mp3buffer, mp3buffer_size);

      if (imp3 < 0)
        {
          free(buffer);
          fclose(ifile);
          fclose(ofile);
          return -1;
        }

  status = (int) fwrite(mp3buffer, 1, imp3, ofile);

  free(buffer);
  fclose(ifile);
  fclose(ofile);

  return (status == imp3) ? 0 : -1;
}