495 lines · 10.3 KB · C
RawDownload
/* * FAAC - Freeware Advanced Audio Coder * Copyright (C) 2002 Krzysztof Nikiel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details.  * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * $Id: input.c,v 1.21 2017/07/02 14:35:23 knik Exp $ */ #ifdef HAVE_CONFIG_H#include "config.h"#endif #include <stdio.h>#include <stdlib.h>#include <string.h> #ifdef _WIN32#include <io.h>#include <fcntl.h>#endif #include "input.h" #define SWAP32(x) (((x & 0xff) << 24) | ((x & 0xff00) << 8) \	| ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24))#define SWAP16(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) #ifdef WORDS_BIGENDIAN# define UINT32(x) SWAP32(x)# define UINT16(x) SWAP16(x)#else# define UINT32(x) (x)# define UINT16(x) (x)#endif typedef struct{  uint32_t label;           /* 'RIFF' */  uint32_t length;        /* Length of rest of file */  uint32_t chunk_type;      /* 'WAVE' */}riff_t; typedef struct{  uint32_t label;  uint32_t len;}riffsub_t; #ifdef _MSC_VER#pragma pack(push, 1)#elif defined(__plan9__)#pragma pack on#endif #define WAVE_FORMAT_PCM		1#define WAVE_FORMAT_FLOAT	3#define WAVE_FORMAT_EXTENSIBLE	0xfffestruct WAVEFORMATEX{  uint16_t wFormatTag;  uint16_t nChannels;  uint32_t nSamplesPerSec;  uint32_t nAvgBytesPerSec;  uint16_t nBlockAlign;  uint16_t wBitsPerSample;  uint16_t cbSize;}#ifdef __GNUC____attribute__((packed))#endif; struct WAVEFORMATEXTENSIBLE{  struct WAVEFORMATEX Format;  union {    uint16_t wValidBitsPerSample;	// bits of precision    uint16_t wSamplesPerBlock;		// valid if wBitsPerSample==0    uint16_t wReserved;		// If neither applies, set to zero.  } Samples;  uint32_t dwChannelMask;		// which channels are present in stream  unsigned char SubFormat[16];		// guid}#ifdef __GNUC____attribute__((packed))#endif; #ifdef _MSC_VER#pragma pack(pop)#elif defined(__plan9__)#pragma pack off#endif static unsigned char waveformat_pcm_guid[16] ={  WAVE_FORMAT_PCM,0,0,0,  0x00, 0x00,  0x10, 0x00,  0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; static void unsuperr(const char *name){  fprintf(stderr, "%s: file format not supported\n", name);} static void seekcur(FILE *f, int ofs){    int cnt;     for (cnt = 0; cnt < ofs; cnt++)        fgetc(f);} static int seekchunk(FILE *f, riffsub_t *riffsub, char *name){ int skipped;  for(skipped = 0; skipped < 10; skipped++) {   if (fread(riffsub, 1, sizeof(*riffsub), f) != sizeof(*riffsub))     return 0;    riffsub->len = UINT32(riffsub->len);   if (riffsub->len & 1)     riffsub->len++;    if (!memcmp(&(riffsub->label), name, 4))     return 1;    seekcur(f, riffsub->len); }  return 0;} pcmfile_t *wav_open_read(const char *name, int rawinput){  FILE *wave_f;  riff_t riff;  riffsub_t riffsub;  struct WAVEFORMATEXTENSIBLE wave;  char *riffl = "RIFF";  char *wavel = "WAVE";  char *fmtl = "fmt ";  char *datal = "data";  int fmtsize;  pcmfile_t *sndf;  int dostdin = 0;   if (!strcmp(name, "-"))  {#ifdef _WIN32    _setmode(_fileno(stdin), O_BINARY);#endif    wave_f = stdin;    dostdin = 1;  }  else if (!(wave_f = fopen(name, "rb")))  {    perror(name);    return NULL;  }   if (!rawinput) // header input  {    if (fread(&riff, 1, sizeof(riff), wave_f) != sizeof(riff))      return NULL;    if (memcmp(&(riff.label), riffl, 4))      return NULL;    if (memcmp(&(riff.chunk_type), wavel, 4))      return NULL;     if (!seekchunk(wave_f, &riffsub, fmtl))      return NULL;     if (memcmp(&(riffsub.label), fmtl, 4))        return NULL;    memset(&wave, 0, sizeof(wave));     fmtsize = (riffsub.len < sizeof(wave)) ? riffsub.len : sizeof(wave);    // check if format is at least 16 bytes long    if (fmtsize < 16)	return NULL;    if (fread(&wave, 1, fmtsize, wave_f) != fmtsize)        return NULL;     seekcur(wave_f, riffsub.len - fmtsize);     if (!seekchunk(wave_f, &riffsub, datal))      return NULL;     if (UINT16(wave.Format.wFormatTag) != WAVE_FORMAT_PCM && UINT16(wave.Format.wFormatTag) != WAVE_FORMAT_FLOAT)    {      if (UINT16(wave.Format.wFormatTag) == WAVE_FORMAT_EXTENSIBLE)      {        if (UINT16(wave.Format.cbSize) < 22) // struct too small          return NULL;        if (memcmp(wave.SubFormat, waveformat_pcm_guid, 16))        {          waveformat_pcm_guid[0] = WAVE_FORMAT_FLOAT;          if (memcmp(wave.SubFormat, waveformat_pcm_guid, 16))          {                      unsuperr(name);            return NULL;          }        }      }      else      {        unsuperr(name);        return NULL;      }    }  }   sndf = (pcmfile_t*)malloc(sizeof(*sndf));  memset(sndf, 0, sizeof(*sndf));  sndf->f = wave_f;   if (UINT16(wave.Format.wFormatTag) == WAVE_FORMAT_FLOAT) {    sndf->isfloat = 1;  } else {    sndf->isfloat = (wave.SubFormat[0] == WAVE_FORMAT_FLOAT);  }  if (rawinput)  {    sndf->bigendian = 1;    if (dostdin)      sndf->samples = 0;    else    {      fseek(sndf->f, 0 , SEEK_END);      sndf->samples = ftell(sndf->f);      rewind(sndf->f);    }  }  else  {    sndf->bigendian = 0;    sndf->channels = UINT16(wave.Format.nChannels);    sndf->samplebytes = UINT16(wave.Format.wBitsPerSample) / 8;    sndf->samplerate = UINT32(wave.Format.nSamplesPerSec);    if (!sndf->samplebytes || !sndf->channels)      return NULL;    sndf->samples = riffsub.len / (sndf->samplebytes * sndf->channels);  }  return sndf;}  static void chan_remap(int32_t *buf, int channels, int blocks, int *map){  int i;  int32_t *tmp = (int32_t*)malloc(channels * sizeof(int32_t));   for (i = 0; i < blocks; i++)  {    int chn;     memcpy(tmp, buf + i * channels, sizeof(int32_t) * channels);     for (chn = 0; chn < channels; chn++)      buf[i * channels + chn] = tmp[map[chn]];  }  free(tmp);} size_t wav_read_float32(pcmfile_t *sndf, float *buf, size_t num, int *map){  size_t cnt;  size_t isize;  char *bufi;   if ((sndf->samplebytes > 4) || (sndf->samplebytes < 1))    return 0;   isize = num * sndf->samplebytes;  bufi = (char*)(buf + num);  bufi -= isize;  isize = fread(bufi, 1, isize, sndf->f);  isize /= sndf->samplebytes;   // perform in-place conversion  for (cnt = 0; cnt < num; cnt++)  {      if (cnt >= isize)          break;       if (sndf->isfloat)      {          switch (sndf->samplebytes) {          case 4:              buf[cnt] *= 32768.0;              break;          default:              return 0;          }          continue;      }       switch (sndf->samplebytes)      {      case 1:          {              uint8_t *in = (uint8_t*)bufi;              uint8_t s = in[cnt];               buf[cnt] = ((float)s - 128.0) * (float)256;          }          break;      case 2:          {              int16_t *in = (int16_t*)bufi;              int16_t s = in[cnt];#ifdef WORDS_BIGENDIAN              if (!sndf->bigendian)#else              if (sndf->bigendian)#endif                  buf[cnt] = (float)SWAP16(s);              else                  buf[cnt] = (float)s;          }          break;      case 3:          {              int s;              uint8_t *in = (uint8_t*)bufi;              in += 3 * cnt;               if (!sndf->bigendian)                  s = in[0] | (in[1] << 8) | (in[2] << 16);              else                  s = (in[0] << 16) | (in[1] << 8) | in[2];               // fix sign              if (s & 0x800000)                  s |= 0xff000000;               buf[cnt] = (float)s / 256;          }        break;      case 4:          {              int32_t *in = (int32_t*)bufi;              int s = in[cnt];#ifdef WORDS_BIGENDIAN              if (!sndf->bigendian)#else              if (sndf->bigendian)#endif                  buf[cnt] = (float)SWAP32(s) / 65536;              else                  buf[cnt] = (float)s / 65536;          }          break;      default:          return 0;      }  }   if (map)    chan_remap((int32_t *)buf, sndf->channels, cnt / sndf->channels, map);   return cnt;} size_t wav_read_int24(pcmfile_t *sndf, int32_t *buf, size_t num, int *map){  int size;  int i;  uint8_t *bufi;   if ((sndf->samplebytes > 4) || (sndf->samplebytes < 1))    return 0;   bufi = (uint8_t *)buf + sizeof(*buf) * num - sndf->samplebytes * (num - 1) - sizeof(*buf);   size = fread(bufi, sndf->samplebytes, num, sndf->f);   // convert to 24 bit  // fix endianness  switch (sndf->samplebytes) {  case 1:    /* this is endian clean */    for (i = 0; i < size; i++)      buf[i] = (bufi[i] - 128) * 65536;    break;   case 2:#ifdef WORDS_BIGENDIAN    if (!sndf->bigendian)#else    if (sndf->bigendian)#endif    {      // swap bytes      for (i = 0; i < size; i++)      {	int16_t s = ((int16_t *)bufi)[i]; 	s = SWAP16(s); 	buf[i] = ((uint32_t)s) << 8;      }    }    else    {      // no swap      for (i = 0; i < size; i++)      {	int s = ((int16_t *)bufi)[i]; 	buf[i] = s << 8;      }    }    break;   case 3:    if (!sndf->bigendian)    {      for (i = 0; i < size; i++)      {	int s = bufi[3 * i] | (bufi[3 * i + 1] << 8) | (bufi[3 * i + 2] << 16);         // fix sign	if (s & 0x800000)          s |= 0xff000000; 	buf[i] = s;      }    }    else // big endian input    {      for (i = 0; i < size; i++)      {	int s = (bufi[3 * i] << 16) | (bufi[3 * i + 1] << 8) | bufi[3 * i + 2];         // fix sign	if (s & 0x800000)          s |= 0xff000000; 	buf[i] = s;      }    }    break;   case 4:#ifdef WORDS_BIGENDIAN    if (!sndf->bigendian)#else    if (sndf->bigendian)#endif    {      // swap bytes      for (i = 0; i < size; i++)      {	int s = buf[i]; 	buf[i] = SWAP32(s);      }    }    break;  }   if (map)    chan_remap(buf, sndf->channels, size / sndf->channels, map);   return size;} int wav_close(pcmfile_t *sndf){  int i = fclose(sndf->f);  free(sndf);  return i;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t