Torque3D/Engine/lib/libsndfile/src/caf.c
marauder2k7 a745fc3757 Initial commit
added libraries:
opus
flac
libsndfile

updated:
libvorbis
libogg
openal

- Everything works as expected for now. Bare in mind libsndfile needed the check for whether or not it could find the xiph libraries removed in order for this to work.
2024-03-21 17:33:47 +00:00

1034 lines
31 KiB
C

/*
** Copyright (C) 2005-2017 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program 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 program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <inttypes.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#include "chanmap.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define aac_MARKER MAKE_MARKER ('a', 'a', 'c', ' ')
#define alac_MARKER MAKE_MARKER ('a', 'l', 'a', 'c')
#define alaw_MARKER MAKE_MARKER ('a', 'l', 'a', 'w')
#define caff_MARKER MAKE_MARKER ('c', 'a', 'f', 'f')
#define chan_MARKER MAKE_MARKER ('c', 'h', 'a', 'n')
#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a')
#define desc_MARKER MAKE_MARKER ('d', 'e', 's', 'c')
#define edct_MARKER MAKE_MARKER ('e', 'd', 'c', 't')
#define free_MARKER MAKE_MARKER ('f', 'r', 'e', 'e')
#define ima4_MARKER MAKE_MARKER ('i', 'm', 'a', '4')
#define info_MARKER MAKE_MARKER ('i', 'n', 'f', 'o')
#define inst_MARKER MAKE_MARKER ('i', 'n', 's', 't')
#define kuki_MARKER MAKE_MARKER ('k', 'u', 'k', 'i')
#define lpcm_MARKER MAKE_MARKER ('l', 'p', 'c', 'm')
#define mark_MARKER MAKE_MARKER ('m', 'a', 'r', 'k')
#define midi_MARKER MAKE_MARKER ('m', 'i', 'd', 'i')
#define mp1_MARKER MAKE_MARKER ('.', 'm', 'p', '1')
#define mp2_MARKER MAKE_MARKER ('.', 'm', 'p', '2')
#define mp3_MARKER MAKE_MARKER ('.', 'm', 'p', '3')
#define ovvw_MARKER MAKE_MARKER ('o', 'v', 'v', 'w')
#define pakt_MARKER MAKE_MARKER ('p', 'a', 'k', 't')
#define peak_MARKER MAKE_MARKER ('p', 'e', 'a', 'k')
#define regn_MARKER MAKE_MARKER ('r', 'e', 'g', 'n')
#define strg_MARKER MAKE_MARKER ('s', 't', 'r', 'g')
#define umid_MARKER MAKE_MARKER ('u', 'm', 'i', 'd')
#define uuid_MARKER MAKE_MARKER ('u', 'u', 'i', 'd')
#define ulaw_MARKER MAKE_MARKER ('u', 'l', 'a', 'w')
#define MAC3_MARKER MAKE_MARKER ('M', 'A', 'C', '3')
#define MAC6_MARKER MAKE_MARKER ('M', 'A', 'C', '6')
#define CAF_PEAK_CHUNK_SIZE(ch) ((int) (sizeof (int) + ch * (sizeof (float) + 8)))
/*------------------------------------------------------------------------------
** Typedefs.
*/
typedef struct
{ uint8_t srate [8] ;
uint32_t fmt_id ;
uint32_t fmt_flags ;
uint32_t pkt_bytes ;
uint32_t frames_per_packet ;
uint32_t channels_per_frame ;
uint32_t bits_per_chan ;
} DESC_CHUNK ;
typedef struct
{ int chanmap_tag ;
ALAC_DECODER_INFO alac ;
} CAF_PRIVATE ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int caf_close (SF_PRIVATE *psf) ;
static int caf_read_header (SF_PRIVATE *psf) ;
static int caf_write_header (SF_PRIVATE *psf, int calc_length) ;
static int caf_write_tailer (SF_PRIVATE *psf) ;
static int caf_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;
static int caf_read_chanmap (SF_PRIVATE * psf, sf_count_t chunk_size) ;
static int caf_read_strings (SF_PRIVATE * psf, sf_count_t chunk_size) ;
static void caf_write_strings (SF_PRIVATE * psf, int location) ;
static int caf_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) ;
static SF_CHUNK_ITERATOR * caf_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) ;
static int caf_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ;
static int caf_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
caf_open (SF_PRIVATE *psf)
{ CAF_PRIVATE * pcaf ;
int subformat, format, error = 0 ;
if ((psf->container_data = calloc (1, sizeof (CAF_PRIVATE))) == NULL)
return SFE_MALLOC_FAILED ;
pcaf = psf->container_data ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = caf_read_header (psf)))
return error ;
psf->next_chunk_iterator = caf_next_chunk_iterator ;
psf->get_chunk_size = caf_get_chunk_size ;
psf->get_chunk_data = caf_get_chunk_data ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
format = SF_CONTAINER (psf->sf.format) ;
if (format != SF_FORMAT_CAF)
return SFE_BAD_OPEN_FORMAT ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
if (psf->file.mode != SFM_RDWR || psf->filelength < 44)
{ psf->filelength = 0 ;
psf->datalength = 0 ;
psf->dataoffset = 0 ;
psf->sf.frames = 0 ;
} ;
psf->strings.flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ;
/*
** By default, add the peak chunk to floating point files. Default behaviour
** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE).
*/
if (psf->file.mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE))
{ if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL)
return SFE_MALLOC_FAILED ;
psf->peak_info->peak_loc = SF_PEAK_START ;
} ;
if ((error = caf_write_header (psf, SF_FALSE)) != 0)
return error ;
psf->write_header = caf_write_header ;
psf->set_chunk = caf_set_chunk ;
} ;
psf->container_close = caf_close ;
psf->command = caf_command ;
switch (subformat)
{ case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_ULAW :
error = ulaw_init (psf) ;
break ;
case SF_FORMAT_ALAW :
error = alaw_init (psf) ;
break ;
/* Lite remove start */
case SF_FORMAT_FLOAT :
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE :
error = double64_init (psf) ;
break ;
case SF_FORMAT_ALAC_16 :
case SF_FORMAT_ALAC_20 :
case SF_FORMAT_ALAC_24 :
case SF_FORMAT_ALAC_32 :
if (psf->file.mode == SFM_READ)
/* Only pass the ALAC_DECODER_INFO in read mode. */
error = alac_init (psf, &pcaf->alac) ;
else
error = alac_init (psf, NULL) ;
break ;
/* Lite remove end */
default :
return SFE_UNSUPPORTED_ENCODING ;
} ;
return error ;
} /* caf_open */
static int
caf_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ caf_write_tailer (psf) ;
caf_write_header (psf, SF_TRUE) ;
} ;
return 0 ;
} /* caf_close */
static int
caf_command (SF_PRIVATE * psf, int command, void * UNUSED (data), int UNUSED (datasize))
{ CAF_PRIVATE *pcaf ;
if ((pcaf = psf->container_data) == NULL)
return SFE_INTERNAL ;
switch (command)
{ case SFC_SET_CHANNEL_MAP_INFO :
pcaf->chanmap_tag = aiff_caf_find_channel_layout_tag (psf->channel_map, psf->sf.channels) ;
return (pcaf->chanmap_tag != 0) ;
default :
break ;
} ;
return 0 ;
} /* caf_command */
/*------------------------------------------------------------------------------
*/
static int
decode_desc_chunk (SF_PRIVATE *psf, const DESC_CHUNK *desc)
{ int format = SF_FORMAT_CAF ;
psf->sf.channels = desc->channels_per_frame ;
if (desc->fmt_id == alac_MARKER)
{ CAF_PRIVATE *pcaf ;
if ((pcaf = psf->container_data) != NULL)
{ switch (desc->fmt_flags)
{ case 1 :
pcaf->alac.bits_per_sample = 16 ;
format |= SF_FORMAT_ALAC_16 ;
break ;
case 2 :
pcaf->alac.bits_per_sample = 20 ;
format |= SF_FORMAT_ALAC_20 ;
break ;
case 3 :
pcaf->alac.bits_per_sample = 24 ;
format |= SF_FORMAT_ALAC_24 ;
break ;
case 4 :
pcaf->alac.bits_per_sample = 32 ;
format |= SF_FORMAT_ALAC_32 ;
break ;
default :
psf_log_printf (psf, "Bad ALAC format flag value of %d\n", desc->fmt_flags) ;
} ;
pcaf->alac.frames_per_packet = desc->frames_per_packet ;
} ;
return format ;
} ;
format |= psf->endian == SF_ENDIAN_LITTLE ? SF_ENDIAN_LITTLE : 0 ;
if (desc->fmt_id == lpcm_MARKER && desc->fmt_flags & 1)
{ /* Floating point data. */
if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame)
{ psf->bytewidth = 4 ;
return format | SF_FORMAT_FLOAT ;
} ;
if (desc->bits_per_chan == 64 && desc->pkt_bytes == 8 * desc->channels_per_frame)
{ psf->bytewidth = 8 ;
return format | SF_FORMAT_DOUBLE ;
} ;
} ;
if (desc->fmt_id == lpcm_MARKER && (desc->fmt_flags & 1) == 0)
{ /* Integer data. */
if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame)
{ psf->bytewidth = 4 ;
return format | SF_FORMAT_PCM_32 ;
} ;
if (desc->bits_per_chan == 24 && desc->pkt_bytes == 3 * desc->channels_per_frame)
{ psf->bytewidth = 3 ;
return format | SF_FORMAT_PCM_24 ;
} ;
if (desc->bits_per_chan == 16 && desc->pkt_bytes == 2 * desc->channels_per_frame)
{ psf->bytewidth = 2 ;
return format | SF_FORMAT_PCM_16 ;
} ;
if (desc->bits_per_chan == 8 && desc->pkt_bytes == 1 * desc->channels_per_frame)
{ psf->bytewidth = 1 ;
return format | SF_FORMAT_PCM_S8 ;
} ;
} ;
if (desc->fmt_id == alaw_MARKER && desc->bits_per_chan == 8)
{ psf->bytewidth = 1 ;
return format | SF_FORMAT_ALAW ;
} ;
if (desc->fmt_id == ulaw_MARKER && desc->bits_per_chan == 8)
{ psf->bytewidth = 1 ;
return format | SF_FORMAT_ULAW ;
} ;
psf_log_printf (psf, "**** Unknown format identifier.\n") ;
return 0 ;
} /* decode_desc_chunk */
static int
caf_read_header (SF_PRIVATE *psf)
{ CAF_PRIVATE *pcaf ;
BUF_UNION ubuf ;
DESC_CHUNK desc ;
sf_count_t chunk_size ;
double srate ;
short version, flags ;
int marker, k, have_data = 0, error ;
if ((pcaf = psf->container_data) == NULL)
return SFE_INTERNAL ;
memset (&desc, 0, sizeof (desc)) ;
/* Set position to start of file to begin reading header. */
psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ;
psf_log_printf (psf, "%M\n Version : %d\n Flags : %x\n", marker, version, flags) ;
if (marker != caff_MARKER)
return SFE_CAF_NOT_CAF ;
psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, ubuf.ucbuf, 8) ;
srate = double64_be_read (ubuf.ucbuf) ;
snprintf (ubuf.cbuf, sizeof (ubuf.cbuf), "%5.3f", srate) ;
psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, ubuf.cbuf) ;
if (marker != desc_MARKER)
return SFE_CAF_NO_DESC ;
if (chunk_size < SIGNED_SIZEOF (DESC_CHUNK))
{ psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ;
return SFE_MALFORMED_FILE ;
} ;
psf->sf.samplerate = psf_lrint (srate) ;
psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.frames_per_packet,
&desc.channels_per_frame, &desc.bits_per_chan) ;
psf_log_printf (psf, " Format id : %M\n Format flags : %x\n Bytes / packet : %u\n"
" Frames / packet : %u\n Channels / frame : %u\n Bits / channel : %u\n",
desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.frames_per_packet, desc.channels_per_frame, desc.bits_per_chan) ;
if (desc.channels_per_frame > SF_MAX_CHANNELS)
{ psf_log_printf (psf, "**** Bad channels per frame value %u.\n", desc.channels_per_frame) ;
return SFE_MALFORMED_FILE ;
} ;
if (chunk_size > SIGNED_SIZEOF (DESC_CHUNK))
psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ;
psf->sf.channels = desc.channels_per_frame ;
while (1)
{ marker = 0 ;
chunk_size = 0 ;
psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ;
if (marker == 0)
{ sf_count_t pos = psf_ftell (psf) ;
psf_log_printf (psf, "Have 0 marker at position %D (0x%x).\n", pos, pos) ;
break ;
} ;
if (chunk_size < 0)
{ psf_log_printf (psf, "%M : %D *** Should be >= 0 ***\n", marker, chunk_size) ;
break ;
} ;
if (chunk_size > psf->filelength)
break ;
psf_store_read_chunk_u32 (&psf->rchunks, marker, psf_ftell (psf), chunk_size) ;
switch (marker)
{ case peak_MARKER :
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels))
{ psf_binheader_readf (psf, "j", (size_t) chunk_size) ;
psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
return SFE_CAF_BAD_PEAK ;
} ;
if (psf->peak_info)
{ psf_log_printf (psf, "*** Found existing peak info, using last one.\n") ;
free (psf->peak_info) ;
psf->peak_info = NULL ;
} ;
if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL)
return SFE_MALLOC_FAILED ;
/* read in rest of PEAK chunk. */
psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ;
psf_log_printf (psf, " edit count : %d\n", psf->peak_info->edit_number) ;
psf_log_printf (psf, " Ch Position Value\n") ;
for (k = 0 ; k < psf->sf.channels ; k++)
{ sf_count_t position ;
float value ;
psf_binheader_readf (psf, "Ef8", &value, &position) ;
psf->peak_info->peaks [k].value = value ;
psf->peak_info->peaks [k].position = position ;
snprintf (ubuf.cbuf, sizeof (ubuf.cbuf), " %2d %-12" PRId64 " %g\n", k, position, value) ;
psf_log_printf (psf, ubuf.cbuf) ;
} ;
psf->peak_info->peak_loc = SF_PEAK_START ;
break ;
case chan_MARKER :
if (chunk_size < 12)
{ psf_log_printf (psf, "%M : %D (should be >= 12)\n", marker, chunk_size) ;
psf_binheader_readf (psf, "j", (size_t) chunk_size) ;
break ;
}
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
if ((error = caf_read_chanmap (psf, chunk_size)))
return error ;
break ;
case free_MARKER :
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
psf_binheader_readf (psf, "j", (size_t) chunk_size) ;
break ;
case data_MARKER :
psf_binheader_readf (psf, "E4", &k) ;
if (chunk_size == -1)
{ psf_log_printf (psf, "%M : -1\n") ;
chunk_size = psf->filelength - psf->header.indx ;
}
else if (psf->filelength > 0 && chunk_size > psf->filelength - psf->header.indx + 10)
{ psf_log_printf (psf, "%M : %D (should be %D)\n", marker, chunk_size, psf->filelength - psf->header.indx - 8) ;
psf->datalength = psf->filelength - psf->header.indx - 8 ;
}
else
{ psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
/* Subtract the 4 bytes of the 'edit' field above. */
psf->datalength = chunk_size - 4 ;
} ;
psf_log_printf (psf, " edit : %u\n", k) ;
psf->dataoffset = psf->header.indx ;
if (psf->datalength + psf->dataoffset < psf->filelength)
psf->dataend = psf->datalength + psf->dataoffset ;
psf_binheader_readf (psf, "j", (size_t) psf->datalength) ;
have_data = 1 ;
break ;
case kuki_MARKER :
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
pcaf->alac.kuki_offset = psf_ftell (psf) - 12 ;
psf_binheader_readf (psf, "j", (size_t) chunk_size) ;
break ;
case pakt_MARKER :
if (chunk_size < 24)
{ psf_log_printf (psf, "%M : %D (should be > 24)\n", marker, chunk_size) ;
return SFE_MALFORMED_FILE ;
}
else if (chunk_size > psf->filelength - psf->header.indx)
{ psf_log_printf (psf, "%M : %D (should be < %D)\n", marker, chunk_size, psf->filelength - psf->header.indx) ;
return SFE_MALFORMED_FILE ;
}
else
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
psf_binheader_readf (psf, "E8844", &pcaf->alac.packets, &pcaf->alac.valid_frames,
&pcaf->alac.priming_frames, &pcaf->alac.remainder_frames) ;
psf_log_printf (psf,
" Packets : %D\n"
" Valid frames : %D\n"
" Priming frames : %d\n"
" Remainder frames : %d\n",
pcaf->alac.packets, pcaf->alac.valid_frames, pcaf->alac.priming_frames,
pcaf->alac.remainder_frames
) ;
if (pcaf->alac.packets == 0 && pcaf->alac.valid_frames == 0
&& pcaf->alac.priming_frames == 0 && pcaf->alac.remainder_frames == 0)
psf_log_printf (psf, "*** 'pakt' chunk header is all zero.\n") ;
pcaf->alac.pakt_offset = psf_ftell (psf) - 12 ;
psf_binheader_readf (psf, "j", (size_t) chunk_size - 24) ;
break ;
case info_MARKER :
if (chunk_size < 4)
{ psf_log_printf (psf, "%M : %D (should be > 4)\n", marker, chunk_size) ;
return SFE_MALFORMED_FILE ;
}
else if (chunk_size > psf->filelength - psf->header.indx)
{ psf_log_printf (psf, "%M : %D (should be < %D)\n", marker, chunk_size, psf->filelength - psf->header.indx) ;
return SFE_MALFORMED_FILE ;
} ;
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
if (chunk_size > 4)
caf_read_strings (psf, chunk_size - 4) ;
break ;
default :
psf_log_printf (psf, "%M : %D (skipped)\n", marker, chunk_size) ;
psf_binheader_readf (psf, "j", (size_t) chunk_size) ;
break ;
} ;
if (marker != data_MARKER && chunk_size >= 0xffffff00)
break ;
if (! psf->sf.seekable && have_data)
break ;
if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (chunk_size))
{ psf_log_printf (psf, "End\n") ;
break ;
} ;
} ;
if (have_data == 0)
{ psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ;
return SFE_MALFORMED_FILE ;
} ;
psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0)
return SFE_UNSUPPORTED_ENCODING ;
if (psf->bytewidth > 0)
psf->sf.frames = psf->datalength / psf->bytewidth ;
return 0 ;
} /* caf_read_header */
/*------------------------------------------------------------------------------
*/
static int
caf_write_header (SF_PRIVATE *psf, int calc_length)
{ BUF_UNION ubuf ;
CAF_PRIVATE *pcaf ;
DESC_CHUNK desc ;
sf_count_t current ;
uint32_t uk ;
int subformat, append_free_block = SF_TRUE ;
if ((pcaf = psf->container_data) == NULL)
return SFE_INTERNAL ;
memset (&desc, 0, sizeof (desc)) ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
if (psf->bytewidth > 0)
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
/* Reset the current header length to zero. */
psf->header.ptr [0] = 0 ;
psf->header.indx = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
/* 'caff' marker, version and flags. */
psf_binheader_writef (psf, "Em22", BHWm (caff_MARKER), BHW2 (1), BHW2 (0)) ;
/* 'desc' marker and chunk size. */
psf_binheader_writef (psf, "Em8", BHWm (desc_MARKER), BHW8 ((sf_count_t) (sizeof (DESC_CHUNK)))) ;
double64_be_write (1.0 * psf->sf.samplerate, ubuf.ucbuf) ;
psf_binheader_writef (psf, "b", BHWv (ubuf.ucbuf), BHWz (8)) ;
subformat = SF_CODEC (psf->sf.format) ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU))
psf->endian = SF_ENDIAN_BIG ;
else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_LITTLE || psf->endian == SF_ENDIAN_CPU))
psf->endian = SF_ENDIAN_LITTLE ;
if (psf->endian == SF_ENDIAN_LITTLE)
desc.fmt_flags = 2 ;
else
psf->endian = SF_ENDIAN_BIG ;
/* initial section (same for all, it appears) */
switch (subformat)
{ case SF_FORMAT_PCM_S8 :
desc.fmt_id = lpcm_MARKER ;
psf->bytewidth = 1 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 8 ;
break ;
case SF_FORMAT_PCM_16 :
desc.fmt_id = lpcm_MARKER ;
psf->bytewidth = 2 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 16 ;
break ;
case SF_FORMAT_PCM_24 :
psf->bytewidth = 3 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 24 ;
desc.fmt_id = lpcm_MARKER ;
break ;
case SF_FORMAT_PCM_32 :
desc.fmt_id = lpcm_MARKER ;
psf->bytewidth = 4 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 32 ;
break ;
case SF_FORMAT_FLOAT :
desc.fmt_id = lpcm_MARKER ;
desc.fmt_flags |= 1 ;
psf->bytewidth = 4 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 32 ;
break ;
case SF_FORMAT_DOUBLE :
desc.fmt_id = lpcm_MARKER ;
desc.fmt_flags |= 1 ;
psf->bytewidth = 8 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 64 ;
break ;
case SF_FORMAT_ALAW :
desc.fmt_id = alaw_MARKER ;
psf->bytewidth = 1 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 8 ;
break ;
case SF_FORMAT_ULAW :
desc.fmt_id = ulaw_MARKER ;
psf->bytewidth = 1 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.frames_per_packet = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 8 ;
break ;
case SF_FORMAT_ALAC_16 :
case SF_FORMAT_ALAC_20 :
case SF_FORMAT_ALAC_24 :
case SF_FORMAT_ALAC_32 :
desc.fmt_id = alac_MARKER ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.channels_per_frame = psf->sf.channels ;
alac_get_desc_chunk_items (subformat, &desc.fmt_flags, &desc.frames_per_packet) ;
append_free_block = SF_FALSE ;
break ;
default :
return SFE_UNIMPLEMENTED ;
} ;
psf_binheader_writef (psf, "mE44444", BHWm (desc.fmt_id), BHW4 (desc.fmt_flags), BHW4 (desc.pkt_bytes), BHW4 (desc.frames_per_packet), BHW4 (desc.channels_per_frame), BHW4 (desc.bits_per_chan)) ;
caf_write_strings (psf, SF_STR_LOCATE_START) ;
if (psf->peak_info != NULL)
{ int k ;
psf_binheader_writef (psf, "Em84", BHWm (peak_MARKER), BHW8 ((sf_count_t) CAF_PEAK_CHUNK_SIZE (psf->sf.channels)), BHW4 (psf->peak_info->edit_number)) ;
for (k = 0 ; k < psf->sf.channels ; k++)
psf_binheader_writef (psf, "Ef8", BHWf ((float) psf->peak_info->peaks [k].value), BHW8 (psf->peak_info->peaks [k].position)) ;
} ;
if (psf->channel_map && pcaf->chanmap_tag)
psf_binheader_writef (psf, "Em8444", BHWm (chan_MARKER), BHW8 ((sf_count_t) 12), BHW4 (pcaf->chanmap_tag), BHW4 (0), BHW4 (0)) ;
/* Write custom headers. */
for (uk = 0 ; uk < psf->wchunks.used ; uk++)
psf_binheader_writef (psf, "m44b", BHWm ((int) psf->wchunks.chunks [uk].mark32), BHW4 (0), BHW4 (psf->wchunks.chunks [uk].len), BHWv (psf->wchunks.chunks [uk].data), BHWz (psf->wchunks.chunks [uk].len)) ;
if (append_free_block)
{ /* Add free chunk so that the actual audio data starts at a multiple 0x1000. */
sf_count_t free_len = 0x1000 - psf->header.indx - 16 - 12 ;
while (free_len < 0)
free_len += 0x1000 ;
psf_binheader_writef (psf, "Em8z", BHWm (free_MARKER), BHW8 (free_len), BHWz (free_len)) ;
} ;
psf_binheader_writef (psf, "Em84", BHWm (data_MARKER), BHW8 (psf->datalength + 4), BHW4 (0)) ;
psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->header.indx ;
if (current < psf->dataoffset)
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
else if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* caf_write_header */
static int
caf_write_tailer (SF_PRIVATE *psf)
{
/* Reset the current header buffer length to zero. */
psf->header.ptr [0] = 0 ;
psf->header.indx = 0 ;
if (psf->bytewidth > 0 && psf->sf.seekable == SF_TRUE)
{ psf->datalength = psf->sf.frames * psf->bytewidth * psf->sf.channels ;
psf->dataend = psf->dataoffset + psf->datalength ;
} ;
if (psf->dataend > 0)
psf_fseek (psf, psf->dataend, SEEK_SET) ;
else
psf->dataend = psf_fseek (psf, 0, SEEK_END) ;
if (psf->dataend & 1)
psf_binheader_writef (psf, "z", BHWz (1)) ;
if (psf->strings.flags & SF_STR_LOCATE_END)
caf_write_strings (psf, SF_STR_LOCATE_END) ;
/* Write the tailer. */
if (psf->header.indx > 0)
psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
return 0 ;
} /* caf_write_tailer */
static int
caf_read_chanmap (SF_PRIVATE * psf, sf_count_t chunk_size)
{ const AIFF_CAF_CHANNEL_MAP * map_info ;
unsigned channel_bitmap, channel_decriptions, bytesread ;
int layout_tag ;
bytesread = psf_binheader_readf (psf, "E444", &layout_tag, &channel_bitmap, &channel_decriptions) ;
map_info = aiff_caf_of_channel_layout_tag (layout_tag) ;
psf_log_printf (psf, " Tag : %x\n", layout_tag) ;
if (map_info)
psf_log_printf (psf, " Layout : %s\n", map_info->name) ;
if (bytesread < chunk_size)
psf_binheader_readf (psf, "j", chunk_size - bytesread) ;
if (map_info && map_info->channel_map != NULL)
{ size_t chanmap_size = SF_MIN (psf->sf.channels, layout_tag & 0xff) * sizeof (psf->channel_map [0]) ;
free (psf->channel_map) ;
if ((psf->channel_map = malloc (chanmap_size)) == NULL)
return SFE_MALLOC_FAILED ;
memcpy (psf->channel_map, map_info->channel_map, chanmap_size) ;
} ;
return 0 ;
} /* caf_read_chanmap */
static uint32_t
string_hash32 (const char * str)
{ uint32_t hash = 0x87654321 ;
while (str [0])
{ hash = hash * 333 + str [0] ;
str ++ ;
} ;
return hash ;
} /* string_hash32 */
static int
caf_read_strings (SF_PRIVATE * psf, sf_count_t chunk_size)
{ char *buf ;
char *key, *value ;
uint32_t count, hash ;
if ((buf = malloc (chunk_size + 1)) == NULL)
return (psf->error = SFE_MALLOC_FAILED) ;
psf_binheader_readf (psf, "E4b", &count, buf, (size_t) chunk_size) ;
psf_log_printf (psf, " count: %u\n", count) ;
/* Force terminate `buf` to make sure. */
buf [chunk_size] = 0 ;
for (key = buf ; key < buf + chunk_size ; )
{ value = key + strlen (key) + 1 ;
if (value > buf + chunk_size)
break ;
psf_log_printf (psf, " %-12s : %s\n", key, value) ;
hash = string_hash32 (key) ;
switch (hash)
{ case 0xC4861943 : /* 'title' */
psf_store_string (psf, SF_STR_TITLE, value) ;
break ;
case 0xAD47A394 : /* 'software' */
psf_store_string (psf, SF_STR_SOFTWARE, value) ;
break ;
case 0x5D178E2A : /* 'copyright' */
psf_store_string (psf, SF_STR_COPYRIGHT, value) ;
break ;
case 0x60E4D0C8 : /* 'artist' */
psf_store_string (psf, SF_STR_ARTIST, value) ;
break ;
case 0x83B5D16A : /* 'genre' */
psf_store_string (psf, SF_STR_GENRE, value) ;
break ;
case 0x15E5FC88 : /* 'comment' */
case 0x7C297D5B : /* 'comments' */
psf_store_string (psf, SF_STR_COMMENT, value) ;
break ;
case 0x24A7C347 : /* 'tracknumber' */
psf_store_string (psf, SF_STR_TRACKNUMBER, value) ;
break ;
case 0x50A31EB7 : /* 'date' */
psf_store_string (psf, SF_STR_DATE, value) ;
break ;
case 0x6583545A : /* 'album' */
psf_store_string (psf, SF_STR_ALBUM, value) ;
break ;
case 0xE7C64B6C : /* 'license' */
psf_store_string (psf, SF_STR_LICENSE, value) ;
break ;
default :
psf_log_printf (psf, " Unhandled hash 0x%x : /* '%s' */\n", hash, key) ;
break ;
} ;
key = value + strlen (value) + 1 ;
} ;
free (buf) ;
return 0 ;
} /* caf_read_strings */
struct put_buffer
{ uint32_t index ;
char s [16 * 1024] ;
} ;
static uint32_t
put_key_value (struct put_buffer * buf, const char * key, const char * value)
{ uint32_t written ;
if (buf->index + strlen (key) + strlen (value) + 2 > sizeof (buf->s))
return 0 ;
written = snprintf (buf->s + buf->index, sizeof (buf->s) - buf->index, "%s%c%s%c", key, 0, value, 0) ;
if (buf->index + written >= sizeof (buf->s))
return 0 ;
buf->index += written ;
return 1 ;
} /* put_key_value */
static void
caf_write_strings (SF_PRIVATE * psf, int location)
{ struct put_buffer buf ;
const char * cptr ;
uint32_t k, string_count = 0 ;
memset (&buf, 0, sizeof (buf)) ;
for (k = 0 ; k < SF_MAX_STRINGS ; k++)
{ if (psf->strings.data [k].type == 0)
break ;
if (psf->strings.data [k].flags != location)
continue ;
if ((cptr = psf_get_string (psf, psf->strings.data [k].type)) == NULL)
continue ;
switch (psf->strings.data [k].type)
{ case SF_STR_TITLE :
string_count += put_key_value (&buf, "title", cptr) ;
break ;
case SF_STR_COPYRIGHT :
string_count += put_key_value (&buf, "copyright", cptr) ;
break ;
case SF_STR_SOFTWARE :
string_count += put_key_value (&buf, "software", cptr) ;
break ;
case SF_STR_ARTIST :
string_count += put_key_value (&buf, "artist", cptr) ;
break ;
case SF_STR_COMMENT :
string_count += put_key_value (&buf, "comment", cptr) ;
break ;
case SF_STR_DATE :
string_count += put_key_value (&buf, "date", cptr) ;
break ;
case SF_STR_ALBUM :
string_count += put_key_value (&buf, "album", cptr) ;
break ;
case SF_STR_LICENSE :
string_count += put_key_value (&buf, "license", cptr) ;
break ;
case SF_STR_TRACKNUMBER :
string_count += put_key_value (&buf, "tracknumber", cptr) ;
break ;
case SF_STR_GENRE :
string_count += put_key_value (&buf, "genre", cptr) ;
break ;
default :
break ;
} ;
} ;
if (string_count == 0 || buf.index == 0)
return ;
psf_binheader_writef (psf, "Em84b", BHWm (info_MARKER), BHW8 (buf.index + 4), BHW4 (string_count), BHWv (buf.s), BHWz (buf.index)) ;
} /* caf_write_strings */
/*==============================================================================
*/
static int
caf_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info)
{ return psf_save_write_chunk (&psf->wchunks, chunk_info) ;
} /* caf_set_chunk */
static SF_CHUNK_ITERATOR *
caf_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator)
{ return psf_next_chunk_iterator (&psf->rchunks, iterator) ;
} /* caf_next_chunk_iterator */
static int
caf_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info)
{ int indx ;
if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0)
return SFE_UNKNOWN_CHUNK ;
chunk_info->datalen = psf->rchunks.chunks [indx].len ;
return SFE_NO_ERROR ;
} /* caf_get_chunk_size */
static int
caf_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info)
{ int indx ;
sf_count_t pos ;
if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0)
return SFE_UNKNOWN_CHUNK ;
if (chunk_info->data == NULL)
return SFE_BAD_CHUNK_DATA_PTR ;
chunk_info->id_size = psf->rchunks.chunks [indx].id_size ;
memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ;
pos = psf_ftell (psf) ;
psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ;
psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ;
psf_fseek (psf, pos, SEEK_SET) ;
return SFE_NO_ERROR ;
} /* caf_get_chunk_data */