/*
-** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
+** Copyright (C) 1999-2014 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
# define WARN_UNUSED
#endif
-#define SF_BUFFER_LEN (8192*2)
-#define SF_FILENAME_LEN (512)
+#define SF_BUFFER_LEN (8192)
+#define SF_FILENAME_LEN (1024)
#define SF_SYSERR_LEN (256)
#define SF_MAX_STRINGS (32)
-#define SF_STR_BUFFER_LEN (8192)
-#define SF_HEADER_LEN (4100 + SF_STR_BUFFER_LEN)
+#define SF_HEADER_LEN (12292)
+#define SF_PARSELOG_LEN (2048)
#define PSF_SEEK_ERROR ((sf_count_t) -1)
-
#define BITWIDTH2BYTES(x) (((x) + 7) / 8)
/* For some reason sizeof returns an unsigned value which causes
#define NOT(x) (! (x))
-#if (COMPILER_IS_GCC == 1)
-#define SF_MAX(x,y) ({ \
+#if COMPILER_IS_GCC
+#define SF_MAX(x, y) ({ \
typeof (x) sf_max_x1 = (x) ; \
typeof (y) sf_max_y1 = (y) ; \
(void) (&sf_max_x1 == &sf_max_y1) ; \
sf_max_x1 > sf_max_y1 ? sf_max_x1 : sf_max_y1 ; })
-#define SF_MIN(x,y) ({ \
+#define SF_MIN(x, y) ({ \
typeof (x) sf_min_x2 = (x) ; \
typeof (y) sf_min_y2 = (y) ; \
(void) (&sf_min_x2 == &sf_min_y2) ; \
sf_min_x2 < sf_min_y2 ? sf_min_x2 : sf_min_y2 ; })
#else
-#define SF_MAX(a,b) ((a) > (b) ? (a) : (b))
-#define SF_MIN(a,b) ((a) < (b) ? (a) : (b))
+#define SF_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define SF_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
-#define SF_MAX_CHANNELS 256
+#define COMPILE_TIME_ASSERT(e) (sizeof (struct { int : - !! (e) ; }))
+
+
+#define SF_MAX_CHANNELS 1024
/*
-* Macros for spliting the format file of SF_INFI into contrainer type,
+* Macros for spliting the format file of SF_INFO into container type,
** codec type and endian-ness.
*/
#define SF_CONTAINER(x) ((x) & SF_FORMAT_TYPEMASK)
} ;
/*---------------------------------------------------------------------------------------
+*/
+
+typedef struct
+{ unsigned kuki_offset ;
+ unsigned pakt_offset ;
+
+ unsigned bits_per_sample ;
+ unsigned frames_per_packet ;
+
+ int64_t packets ;
+ int64_t valid_frames ;
+ int32_t priming_frames ;
+ int32_t remainder_frames ;
+} ALAC_DECODER_INFO ;
+
+/*---------------------------------------------------------------------------------------
** PEAK_CHUNK - This chunk type is common to both AIFF and WAVE files although their
** endian encodings are different.
*/
/* CAF */
unsigned int edit_number ;
-#if HAVE_FLEXIBLE_ARRAY
/* the per channel peak info */
PEAK_POS peaks [] ;
-#else
- /*
- ** This is not ISO compliant C. It works on some compilers which
- ** don't support the ISO standard flexible struct array which is
- ** used above. If your compiler doesn't like this I suggest you find
- ** youself a 1999 ISO C standards compilant compiler. GCC-3.X is
- ** highly recommended.
- */
- PEAK_POS peaks [0] ;
-#endif
} PEAK_INFO ;
static inline PEAK_INFO *
typedef struct
{ int type ;
int flags ;
- char *str ;
+ size_t offset ;
} STR_DATA ;
+typedef struct
+{ int64_t hash ;
+ char id [64] ;
+ unsigned id_size ;
+ uint32_t mark32 ;
+ sf_count_t offset ;
+ uint32_t len ;
+} READ_CHUNK ;
+
+typedef struct
+{ int64_t hash ;
+ uint32_t mark32 ;
+ uint32_t len ;
+ void *data ;
+} WRITE_CHUNK ;
+
+typedef struct
+{ uint32_t count ;
+ uint32_t used ;
+ READ_CHUNK *chunks ;
+} READ_CHUNKS ;
+typedef struct
+{ uint32_t count ;
+ uint32_t used ;
+ WRITE_CHUNK *chunks ;
+} WRITE_CHUNKS ;
+
+struct SF_CHUNK_ITERATOR
+{ uint32_t current ;
+ int64_t hash ;
+ char id [64] ;
+ unsigned id_size ;
+ SNDFILE *sndfile ;
+} ;
+
static inline size_t
make_size_t (int x)
{ return (size_t) x ;
typedef SF_BROADCAST_INFO_VAR (16 * 1024) SF_BROADCAST_INFO_16K ;
+typedef SF_CART_INFO_VAR (16 * 1024) SF_CART_INFO_16K ;
+
#if SIZEOF_WCHAR_T == 2
typedef wchar_t sfwchar_t ;
#else
typedef int16_t sfwchar_t ;
#endif
+
+static inline void *
+psf_memdup (const void *src, size_t n)
+{ void * mem = calloc (1, n & 3 ? n + 4 - (n & 3) : n) ;
+ return memcpy (mem, src, n) ;
+} /* psf_memdup */
+
/*
** This version of isprint specifically ignores any locale info. Its used for
** determining which characters can be printed in things like hexdumps.
} PSF_FILE ;
+
+typedef union
+{ double dbuf [SF_BUFFER_LEN / sizeof (double)] ;
+#if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
+ int64_t lbuf [SF_BUFFER_LEN / sizeof (int64_t)] ;
+#else
+ long lbuf [SF_BUFFER_LEN / sizeof (double)] ;
+#endif
+ float fbuf [SF_BUFFER_LEN / sizeof (float)] ;
+ int ibuf [SF_BUFFER_LEN / sizeof (int)] ;
+ short sbuf [SF_BUFFER_LEN / sizeof (short)] ;
+ char cbuf [SF_BUFFER_LEN / sizeof (char)] ;
+ signed char scbuf [SF_BUFFER_LEN / sizeof (signed char)] ;
+ unsigned char ucbuf [SF_BUFFER_LEN / sizeof (signed char)] ;
+} BUF_UNION ;
+
+
+
typedef struct sf_private_tag
{
/* Canary in a coal mine. */
char c [16] ;
} canary ;
- /* Force the compiler to double align the start of buffer. */
- union
- { double dbuf [SF_BUFFER_LEN / sizeof (double)] ;
-#if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
- int64_t lbuf [SF_BUFFER_LEN / sizeof (int64_t)] ;
-#else
- long lbuf [SF_BUFFER_LEN / sizeof (double)] ;
-#endif
- float fbuf [SF_BUFFER_LEN / sizeof (float)] ;
- int ibuf [SF_BUFFER_LEN / sizeof (int)] ;
- short sbuf [SF_BUFFER_LEN / sizeof (short)] ;
- char cbuf [SF_BUFFER_LEN / sizeof (char)] ;
- signed char scbuf [SF_BUFFER_LEN / sizeof (signed char)] ;
- unsigned char ucbuf [SF_BUFFER_LEN / sizeof (signed char)] ;
- } u ;
-
-
PSF_FILE file, rsrc ;
char syserr [SF_SYSERR_LEN] ;
- /* logbuffer and logindex should only be changed within the logging functions
+ /* parselog and indx should only be changed within the logging functions
** of common.c
*/
- char logbuffer [SF_BUFFER_LEN] ;
+ struct
+ { char buf [SF_PARSELOG_LEN] ;
+ int indx ;
+ } parselog ;
+
unsigned char header [SF_HEADER_LEN] ; /* Must be unsigned */
int rwf_endian ; /* Header endian-ness flag. */
/* Storage and housekeeping data for adding/reading strings from
** sound files.
*/
- STR_DATA strings [SF_MAX_STRINGS] ;
- char str_storage [SF_STR_BUFFER_LEN] ;
- char *str_end ;
- int str_flags ;
+ struct
+ { STR_DATA data [SF_MAX_STRINGS] ;
+ char *storage ;
+ size_t storage_len ;
+ size_t storage_used ;
+ uint32_t flags ;
+ } strings ;
/* Guard value. If this changes the buffers above have overflowed. */
int Magick ;
unsigned unique_id ;
- /* Index variables for maintaining logbuffer and header above. */
- int logindex ;
+ /* Index variables for maintaining parselog and header above. */
int headindex, headend ;
int has_text ;
/* Broadcast (EBU) Info */
SF_BROADCAST_INFO_16K *broadcast_16k ;
+ /* Cart (AES46) Info */
+ SF_CART_INFO_16K *cart_16k ;
+
/* Channel map data (if present) : an array of ints. */
int *channel_map ;
sf_count_t (*seek) (struct sf_private_tag*, int mode, sf_count_t samples_from_start) ;
int (*write_header) (struct sf_private_tag*, int calc_length) ;
int (*command) (struct sf_private_tag*, int command, void *data, int datasize) ;
+ int (*byterate) (struct sf_private_tag*) ;
/*
** Separate close functions for the codec and the container.
int virtual_io ;
SF_VIRTUAL_IO vio ;
void *vio_user_data ;
+
+ /* Chunk get/set. */
+ SF_CHUNK_ITERATOR *iterator ;
+
+ READ_CHUNKS rchunks ;
+ WRITE_CHUNKS wchunks ;
+
+ int (*set_chunk) (struct sf_private_tag*, const SF_CHUNK_INFO * chunk_info) ;
+ SF_CHUNK_ITERATOR * (*next_chunk_iterator) (struct sf_private_tag*, SF_CHUNK_ITERATOR * iterator) ;
+ int (*get_chunk_size) (struct sf_private_tag*, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ;
+ int (*get_chunk_data) (struct sf_private_tag*, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ;
} SF_PRIVATE ;
SFE_BAD_FILE_PTR,
SFE_BAD_INT_PTR,
SFE_BAD_STAT_SIZE,
+ SFE_NO_TEMP_DIR,
SFE_MALLOC_FAILED,
SFE_UNIMPLEMENTED,
SFE_BAD_READ_ALIGN,
SFE_CMD_HAS_DATA,
SFE_BAD_BROADCAST_INFO_SIZE,
SFE_BAD_BROADCAST_INFO_TOO_BIG,
+ SFE_BAD_CART_INFO_SIZE,
+ SFE_BAD_CART_INFO_TOO_BIG,
SFE_STR_NO_SUPPORT,
SFE_STR_NOT_WRITE,
SFE_WAV_BAD_LIST,
SFE_WAV_ADPCM_NOT4BIT,
SFE_WAV_ADPCM_CHANNELS,
+ SFE_WAV_ADPCM_SAMPLES,
SFE_WAV_GSM610_FORMAT,
SFE_WAV_UNKNOWN_CHUNK,
SFE_WAV_WVPK_DATA,
SFE_VORBIS_ENCODER_BUG,
SFE_RF64_NOT_RF64,
+ SFE_BAD_CHUNK_PTR,
+ SFE_UNKNOWN_CHUNK,
+ SFE_BAD_CHUNK_FORMAT,
+ SFE_BAD_CHUNK_MARKER,
+ SFE_BAD_CHUNK_DATA_PTR,
+ SFE_ALAC_FAIL_TMPFILE,
+ SFE_FILENAME_TOO_LONG,
SFE_MAX_ERROR /* This must be last in list. */
} ;
/* Functions for reading and writing floats and doubles on processors
** with non-IEEE floats/doubles.
*/
-float float32_be_read (unsigned char *cptr) ;
-float float32_le_read (unsigned char *cptr) ;
+float float32_be_read (const unsigned char *cptr) ;
+float float32_le_read (const unsigned char *cptr) ;
void float32_be_write (float in, unsigned char *out) ;
void float32_le_write (float in, unsigned char *out) ;
-double double64_be_read (unsigned char *cptr) ;
-double double64_le_read (unsigned char *cptr) ;
+double double64_be_read (const unsigned char *cptr) ;
+double double64_le_read (const unsigned char *cptr) ;
void double64_be_write (double in, unsigned char *out) ;
void double64_le_write (double in, unsigned char *out) ;
void append_snprintf (char * dest, size_t maxlen, const char * fmt, ...) ;
void psf_strlcpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax) ;
+sf_count_t psf_decode_frame_count (SF_PRIVATE *psf) ;
+
/* Functions used when writing file headers. */
int psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) ;
int mpc2k_open (SF_PRIVATE *psf) ;
int rf64_open (SF_PRIVATE *psf) ;
-/* In progress. Do not currently work. */
-
int ogg_vorbis_open (SF_PRIVATE *psf) ;
int ogg_speex_open (SF_PRIVATE *psf) ;
int ogg_pcm_open (SF_PRIVATE *psf) ;
+int ogg_opus_open (SF_PRIVATE *psf) ;
+int ogg_open (SF_PRIVATE *psf) ;
+/* In progress. Do not currently work. */
+
int mpeg_open (SF_PRIVATE *psf) ;
-int ogg_open (SF_PRIVATE *psf) ;
int rx2_open (SF_PRIVATE *psf) ;
int txw_open (SF_PRIVATE *psf) ;
int wve_open (SF_PRIVATE *psf) ;
int vox_adpcm_init (SF_PRIVATE *psf) ;
int flac_init (SF_PRIVATE *psf) ;
int g72x_init (SF_PRIVATE * psf) ;
+int alac_init (SF_PRIVATE *psf, const ALAC_DECODER_INFO * info) ;
int dither_init (SF_PRIVATE *psf, int mode) ;
** Chunk logging functions.
*/
-typedef struct
-{ struct
- { int chunk ;
- sf_count_t offset ;
- sf_count_t len ;
- } l [100] ;
+SF_CHUNK_ITERATOR * psf_get_chunk_iterator (SF_PRIVATE * psf, const char * marker_str) ;
+SF_CHUNK_ITERATOR * psf_next_chunk_iterator (const READ_CHUNKS * pchk , SF_CHUNK_ITERATOR *iterator) ;
+int psf_store_read_chunk_u32 (READ_CHUNKS * pchk, uint32_t marker, sf_count_t offset, uint32_t len) ;
+int psf_store_read_chunk_str (READ_CHUNKS * pchk, const char * marker, sf_count_t offset, uint32_t len) ;
+int psf_save_write_chunk (WRITE_CHUNKS * pchk, const SF_CHUNK_INFO * chunk_info) ;
+int psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker) ;
+int psf_find_read_chunk_m32 (const READ_CHUNKS * pchk, uint32_t marker) ;
+int psf_find_read_chunk_iterator (const READ_CHUNKS * pchk, const SF_CHUNK_ITERATOR * marker) ;
- int count ;
-} PRIV_CHUNK4 ;
+int psf_find_write_chunk (WRITE_CHUNKS * pchk, const char * marker) ;
-void pchk4_store (PRIV_CHUNK4 * pchk, int marker, sf_count_t offset, sf_count_t len) ;
-int pchk4_find (PRIV_CHUNK4 * pchk, int marker) ;
+static inline int
+fourcc_to_marker (const SF_CHUNK_INFO * chunk_info)
+{ const unsigned char * cptr ;
+
+ if (chunk_info->id_size != 4)
+ return 0 ;
+
+ cptr = (const unsigned char *) chunk_info->id ;
+ return (cptr [3] << 24) + (cptr [2] << 16) + (cptr [1] << 8) + cptr [0] ;
+} /* fourcc_to_marker */
/*------------------------------------------------------------------------------------
** Functions that work like OpenBSD's strlcpy/strlcat to replace strncpy/strncat.
int broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) ;
+SF_CART_INFO_16K * cart_var_alloc (void) ;
+int cart_var_set (SF_PRIVATE *psf, const SF_CART_INFO * date, size_t datasize) ;
+int cart_var_get (SF_PRIVATE *psf, SF_CART_INFO * data, size_t datasize) ;
+
typedef struct
{ int channels ;
int endianness ;
int audio_detect (SF_PRIVATE * psf, AUDIO_DETECT *ad, const unsigned char * data, int datalen) ;
int id3_skip (SF_PRIVATE * psf) ;
+void alac_get_desc_chunk_items (int subformat, uint32_t *fmt_flags, uint32_t *frames_per_packet) ;
+
+FILE * psf_open_tmpfile (char * fname, size_t fnamelen) ;
+
/*------------------------------------------------------------------------------------
** Helper/debug functions.
*/
int sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int count) ;
#endif
-#endif /* SNDFILE_COMMON_H */
+/*------------------------------------------------------------------------------------
+** Data conversion functions.
+*/
+
+void psf_f2s_array (const float *src, short *dest, int count, int normalize) ;
+void psf_f2s_clip_array (const float *src, short *dest, int count, int normalize) ;
+
+void psf_d2s_array (const double *src, short *dest, int count, int normalize) ;
+void psf_d2s_clip_array (const double *src, short *dest, int count, int normalize) ;
+
+void psf_f2i_array (const float *src, int *dest, int count, int normalize) ;
+void psf_f2i_clip_array (const float *src, int *dest, int count, int normalize) ;
+
+void psf_d2i_array (const double *src, int *dest, int count, int normalize) ;
+void psf_d2i_clip_array (const double *src, int *dest, int count, int normalize) ;
+
+/*------------------------------------------------------------------------------------
+** Left and right shift on int. According to the C standard, the left and right
+** shift operations applied to a negative integer results in undefined behavior.
+** These twp functions work around that.
+*/
+
+#if __GNUC__
+#define ALWAYS_INLINE __attribute__ ((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+static inline int32_t ALWAYS_INLINE
+arith_shift_left (int32_t x, int shift)
+{ return (int32_t) (((uint32_t) x) << shift) ;
+} /* arith_shift_left */
+
+static inline int32_t ALWAYS_INLINE
+arith_shift_right (int32_t x, int shift)
+{ if (x >= 0)
+ return x >> shift ;
+ return ~ ((~x) >> shift) ;
+} /* arith_shift_right */
+
+#endif /* SNDFILE_COMMON_H */