mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-14 18:00:48 +00:00
This updates the minimum required cmake version and the libs that have updates for this. Ogg updated to master as of 20052025 Libsndfile updated to master as of 20052025 Opus minimum cmake version changed vorbis minimum cmake version changed
818 lines
23 KiB
C
818 lines
23 KiB
C
/*
|
|
** Copyright (C) 1999-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 <fcntl.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#include "sndfile.h"
|
|
#include "sfendian.h"
|
|
#include "common.h"
|
|
|
|
/*------------------------------------------------------------------------------
|
|
** Macros to handle big/little endian issues.
|
|
*/
|
|
|
|
#define FAP_MARKER (MAKE_MARKER ('f', 'a', 'p', ' '))
|
|
#define PAF_MARKER (MAKE_MARKER (' ', 'p', 'a', 'f'))
|
|
|
|
/*------------------------------------------------------------------------------
|
|
** Other defines.
|
|
*/
|
|
|
|
#define PAF_HEADER_LENGTH 2048
|
|
|
|
#define PAF24_SAMPLES_PER_BLOCK 10
|
|
#define PAF24_BLOCK_SIZE 32
|
|
|
|
/*------------------------------------------------------------------------------
|
|
** Typedefs.
|
|
*/
|
|
|
|
typedef struct
|
|
{ int version ;
|
|
int endianness ;
|
|
int samplerate ;
|
|
int format ;
|
|
int channels ;
|
|
int source ;
|
|
} PAF_FMT ;
|
|
|
|
typedef struct
|
|
{ int max_blocks, channels, blocksize ;
|
|
int read_block, write_block, read_count, write_count ;
|
|
sf_count_t sample_count ;
|
|
int *samples ;
|
|
int *block ;
|
|
int data [] ; /* ISO C99 struct flexible array. */
|
|
} PAF24_PRIVATE ;
|
|
|
|
/*------------------------------------------------------------------------------
|
|
** Private static functions.
|
|
*/
|
|
|
|
static int paf24_init (SF_PRIVATE *psf) ;
|
|
|
|
static int paf_read_header (SF_PRIVATE *psf) ;
|
|
static int paf_write_header (SF_PRIVATE *psf, int calc_length) ;
|
|
|
|
static sf_count_t paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
|
|
static sf_count_t paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
|
|
static sf_count_t paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
|
|
static sf_count_t paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
|
|
|
|
static sf_count_t paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
|
|
static sf_count_t paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
|
|
static sf_count_t paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
|
|
static sf_count_t paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
|
|
|
|
static sf_count_t paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
|
|
|
|
enum
|
|
{ PAF_PCM_16 = 0,
|
|
PAF_PCM_24 = 1,
|
|
PAF_PCM_S8 = 2
|
|
} ;
|
|
|
|
/*------------------------------------------------------------------------------
|
|
** Public function.
|
|
*/
|
|
|
|
int
|
|
paf_open (SF_PRIVATE *psf)
|
|
{ int subformat, error, endian ;
|
|
|
|
psf->dataoffset = PAF_HEADER_LENGTH ;
|
|
|
|
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
|
|
{ if ((error = paf_read_header (psf)))
|
|
return error ;
|
|
} ;
|
|
|
|
subformat = SF_CODEC (psf->sf.format) ;
|
|
|
|
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
|
|
{ if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PAF)
|
|
return SFE_BAD_OPEN_FORMAT ;
|
|
|
|
endian = SF_ENDIAN (psf->sf.format) ;
|
|
|
|
/* PAF is by default big endian. */
|
|
psf->endian = SF_ENDIAN_BIG ;
|
|
|
|
if (endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && (endian == SF_ENDIAN_CPU)))
|
|
psf->endian = SF_ENDIAN_LITTLE ;
|
|
|
|
if ((error = paf_write_header (psf, SF_FALSE)))
|
|
return error ;
|
|
|
|
psf->write_header = paf_write_header ;
|
|
} ;
|
|
|
|
switch (subformat)
|
|
{ case SF_FORMAT_PCM_S8 :
|
|
psf->bytewidth = 1 ;
|
|
error = pcm_init (psf) ;
|
|
break ;
|
|
|
|
case SF_FORMAT_PCM_16 :
|
|
psf->bytewidth = 2 ;
|
|
error = pcm_init (psf) ;
|
|
break ;
|
|
|
|
case SF_FORMAT_PCM_24 :
|
|
/* No bytewidth because of whacky 24 bit encoding. */
|
|
error = paf24_init (psf) ;
|
|
break ;
|
|
|
|
default : return SFE_PAF_UNKNOWN_FORMAT ;
|
|
} ;
|
|
|
|
return error ;
|
|
} /* paf_open */
|
|
|
|
/*------------------------------------------------------------------------------
|
|
*/
|
|
|
|
static int
|
|
paf_read_header (SF_PRIVATE *psf)
|
|
{ PAF_FMT paf_fmt ;
|
|
int marker ;
|
|
|
|
if (psf->filelength < PAF_HEADER_LENGTH)
|
|
return SFE_PAF_SHORT_HEADER ;
|
|
|
|
memset (&paf_fmt, 0, sizeof (paf_fmt)) ;
|
|
psf_binheader_readf (psf, "pm", 0, &marker) ;
|
|
|
|
psf_log_printf (psf, "Signature : '%M'\n", marker) ;
|
|
|
|
if (marker == PAF_MARKER)
|
|
{ psf_binheader_readf (psf, "E444444", &(paf_fmt.version), &(paf_fmt.endianness),
|
|
&(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ;
|
|
}
|
|
else if (marker == FAP_MARKER)
|
|
{ psf_binheader_readf (psf, "e444444", &(paf_fmt.version), &(paf_fmt.endianness),
|
|
&(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ;
|
|
}
|
|
else
|
|
return SFE_PAF_NO_MARKER ;
|
|
|
|
psf_log_printf (psf, "Version : %d\n", paf_fmt.version) ;
|
|
|
|
if (paf_fmt.version != 0)
|
|
{ psf_log_printf (psf, "*** Bad version number. should be zero.\n") ;
|
|
return SFE_PAF_VERSION ;
|
|
} ;
|
|
|
|
psf_log_printf (psf, "Sample Rate : %d\n", paf_fmt.samplerate) ;
|
|
psf_log_printf (psf, "Channels : %d\n", paf_fmt.channels) ;
|
|
|
|
psf_log_printf (psf, "Endianness : %d => ", paf_fmt.endianness) ;
|
|
if (paf_fmt.endianness)
|
|
{ psf_log_printf (psf, "Little\n", paf_fmt.endianness) ;
|
|
psf->endian = SF_ENDIAN_LITTLE ;
|
|
}
|
|
else
|
|
{ psf_log_printf (psf, "Big\n", paf_fmt.endianness) ;
|
|
psf->endian = SF_ENDIAN_BIG ;
|
|
} ;
|
|
|
|
if (paf_fmt.channels < 1 || paf_fmt.channels > SF_MAX_CHANNELS)
|
|
return SFE_PAF_BAD_CHANNELS ;
|
|
|
|
psf->datalength = psf->filelength - psf->dataoffset ;
|
|
|
|
psf_binheader_readf (psf, "p", (int) psf->dataoffset) ;
|
|
|
|
psf->sf.samplerate = paf_fmt.samplerate ;
|
|
psf->sf.channels = paf_fmt.channels ;
|
|
|
|
/* Only fill in type major. */
|
|
psf->sf.format = SF_FORMAT_PAF ;
|
|
|
|
psf_log_printf (psf, "Format : %d => ", paf_fmt.format) ;
|
|
|
|
/* PAF is by default big endian. */
|
|
psf->sf.format |= paf_fmt.endianness ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ;
|
|
|
|
switch (paf_fmt.format)
|
|
{ case PAF_PCM_S8 :
|
|
psf_log_printf (psf, "8 bit linear PCM\n") ;
|
|
psf->bytewidth = 1 ;
|
|
|
|
psf->sf.format |= SF_FORMAT_PCM_S8 ;
|
|
|
|
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
|
|
psf->sf.frames = psf->datalength / psf->blockwidth ;
|
|
break ;
|
|
|
|
case PAF_PCM_16 :
|
|
psf_log_printf (psf, "16 bit linear PCM\n") ;
|
|
psf->bytewidth = 2 ;
|
|
|
|
psf->sf.format |= SF_FORMAT_PCM_16 ;
|
|
|
|
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
|
|
psf->sf.frames = psf->datalength / psf->blockwidth ;
|
|
break ;
|
|
|
|
case PAF_PCM_24 :
|
|
psf_log_printf (psf, "24 bit linear PCM\n") ;
|
|
psf->bytewidth = 3 ;
|
|
|
|
psf->sf.format |= SF_FORMAT_PCM_24 ;
|
|
|
|
psf->blockwidth = 0 ;
|
|
psf->sf.frames = PAF24_SAMPLES_PER_BLOCK * psf->datalength /
|
|
(PAF24_BLOCK_SIZE * psf->sf.channels) ;
|
|
break ;
|
|
|
|
default : psf_log_printf (psf, "Unknown\n") ;
|
|
return SFE_PAF_UNKNOWN_FORMAT ;
|
|
break ;
|
|
} ;
|
|
|
|
psf_log_printf (psf, "Source : %d => ", paf_fmt.source) ;
|
|
|
|
switch (paf_fmt.source)
|
|
{ case 1 : psf_log_printf (psf, "Analog Recording\n") ;
|
|
break ;
|
|
case 2 : psf_log_printf (psf, "Digital Transfer\n") ;
|
|
break ;
|
|
case 3 : psf_log_printf (psf, "Multi-track Mixdown\n") ;
|
|
break ;
|
|
case 5 : psf_log_printf (psf, "Audio Resulting From DSP Processing\n") ;
|
|
break ;
|
|
default : psf_log_printf (psf, "Unknown\n") ;
|
|
break ;
|
|
} ;
|
|
|
|
return 0 ;
|
|
} /* paf_read_header */
|
|
|
|
static int
|
|
paf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length))
|
|
{ int paf_format ;
|
|
|
|
/* PAF header already written so no need to re-write. */
|
|
if (psf_ftell (psf) >= PAF_HEADER_LENGTH)
|
|
return 0 ;
|
|
|
|
psf->dataoffset = PAF_HEADER_LENGTH ;
|
|
|
|
switch (SF_CODEC (psf->sf.format))
|
|
{ case SF_FORMAT_PCM_S8 :
|
|
paf_format = PAF_PCM_S8 ;
|
|
break ;
|
|
|
|
case SF_FORMAT_PCM_16 :
|
|
paf_format = PAF_PCM_16 ;
|
|
break ;
|
|
|
|
case SF_FORMAT_PCM_24 :
|
|
paf_format = PAF_PCM_24 ;
|
|
break ;
|
|
|
|
default : return SFE_PAF_UNKNOWN_FORMAT ;
|
|
} ;
|
|
|
|
/* Reset the current header length to zero. */
|
|
psf->header.ptr [0] = 0 ;
|
|
psf->header.indx = 0 ;
|
|
|
|
if (psf->endian == SF_ENDIAN_BIG)
|
|
{ /* Marker, version, endianness, samplerate */
|
|
psf_binheader_writef (psf, "Em444", BHWm (PAF_MARKER), BHW4 (0), BHW4 (0), BHW4 (psf->sf.samplerate)) ;
|
|
/* format, channels, source */
|
|
psf_binheader_writef (psf, "E444", BHW4 (paf_format), BHW4 (psf->sf.channels), BHW4 (0)) ;
|
|
}
|
|
else if (psf->endian == SF_ENDIAN_LITTLE)
|
|
{ /* Marker, version, endianness, samplerate */
|
|
psf_binheader_writef (psf, "em444", BHWm (FAP_MARKER), BHW4 (0), BHW4 (1), BHW4 (psf->sf.samplerate)) ;
|
|
/* format, channels, source */
|
|
psf_binheader_writef (psf, "e444", BHW4 (paf_format), BHW4 (psf->sf.channels), BHW4 (0)) ;
|
|
} ;
|
|
|
|
/* Zero fill to dataoffset. */
|
|
psf_binheader_writef (psf, "z", BHWz ((size_t) (psf->dataoffset - psf->header.indx))) ;
|
|
|
|
psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
|
|
|
|
return psf->error ;
|
|
} /* paf_write_header */
|
|
|
|
/*===============================================================================
|
|
** 24 bit PAF files have a really weird encoding.
|
|
** For a mono file, 10 samples (each being 3 bytes) are packed into a 32 byte
|
|
** block. The 8 ints in this 32 byte block are then endian swapped (as ints)
|
|
** if necessary before being written to disk.
|
|
** For a stereo file, blocks of 10 samples from the same channel are encoded
|
|
** into 32 bytes as for the mono case. The 32 byte blocks are then interleaved
|
|
** on disk.
|
|
** Reading has to reverse the above process :-).
|
|
** Weird!!!
|
|
**
|
|
** The code below attempts to gain efficiency while maintaining readability.
|
|
*/
|
|
|
|
static int paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ;
|
|
static int paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ;
|
|
static int paf24_close (SF_PRIVATE *psf) ;
|
|
|
|
|
|
static int
|
|
paf24_init (SF_PRIVATE *psf)
|
|
{ PAF24_PRIVATE *ppaf24 ;
|
|
int paf24size ;
|
|
|
|
paf24size = sizeof (PAF24_PRIVATE) + psf->sf.channels *
|
|
(PAF24_BLOCK_SIZE + PAF24_SAMPLES_PER_BLOCK * sizeof (int)) ;
|
|
|
|
/*
|
|
** Not exactly sure why this needs to be here but the tests
|
|
** fail without it.
|
|
*/
|
|
psf->last_op = 0 ;
|
|
|
|
if (! (psf->codec_data = calloc (1, paf24size)))
|
|
return SFE_MALLOC_FAILED ;
|
|
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
ppaf24->channels = psf->sf.channels ;
|
|
ppaf24->samples = ppaf24->data ;
|
|
ppaf24->block = ppaf24->data + PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ;
|
|
|
|
ppaf24->blocksize = PAF24_BLOCK_SIZE * ppaf24->channels ;
|
|
|
|
if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR)
|
|
{ paf24_read_block (psf, ppaf24) ; /* Read first block. */
|
|
|
|
psf->read_short = paf24_read_s ;
|
|
psf->read_int = paf24_read_i ;
|
|
psf->read_float = paf24_read_f ;
|
|
psf->read_double = paf24_read_d ;
|
|
} ;
|
|
|
|
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
|
|
{ psf->write_short = paf24_write_s ;
|
|
psf->write_int = paf24_write_i ;
|
|
psf->write_float = paf24_write_f ;
|
|
psf->write_double = paf24_write_d ;
|
|
} ;
|
|
|
|
psf->seek = paf24_seek ;
|
|
psf->container_close = paf24_close ;
|
|
|
|
psf->filelength = psf_get_filelen (psf) ;
|
|
psf->datalength = psf->filelength - psf->dataoffset ;
|
|
|
|
if (psf->datalength % PAF24_BLOCK_SIZE)
|
|
{ if (psf->file.mode == SFM_READ)
|
|
psf_log_printf (psf, "*** Warning : file seems to be truncated.\n") ;
|
|
ppaf24->max_blocks = psf->datalength / ppaf24->blocksize + 1 ;
|
|
}
|
|
else
|
|
ppaf24->max_blocks = psf->datalength / ppaf24->blocksize ;
|
|
|
|
ppaf24->read_block = 0 ;
|
|
if (psf->file.mode == SFM_RDWR)
|
|
ppaf24->write_block = ppaf24->max_blocks ;
|
|
else
|
|
ppaf24->write_block = 0 ;
|
|
|
|
psf->sf.frames = PAF24_SAMPLES_PER_BLOCK * ppaf24->max_blocks ;
|
|
ppaf24->sample_count = psf->sf.frames ;
|
|
|
|
return 0 ;
|
|
} /* paf24_init */
|
|
|
|
static sf_count_t
|
|
paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
|
|
{ PAF24_PRIVATE *ppaf24 ;
|
|
int newblock, newsample ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
{ psf->error = SFE_INTERNAL ;
|
|
return PSF_SEEK_ERROR ;
|
|
} ;
|
|
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
if (mode == SFM_READ && ppaf24->write_count > 0)
|
|
paf24_write_block (psf, ppaf24) ;
|
|
|
|
newblock = offset / PAF24_SAMPLES_PER_BLOCK ;
|
|
newsample = offset % PAF24_SAMPLES_PER_BLOCK ;
|
|
|
|
switch (mode)
|
|
{ case SFM_READ :
|
|
if (psf->last_op == SFM_WRITE && ppaf24->write_count)
|
|
paf24_write_block (psf, ppaf24) ;
|
|
|
|
psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ;
|
|
ppaf24->read_block = newblock ;
|
|
paf24_read_block (psf, ppaf24) ;
|
|
ppaf24->read_count = newsample ;
|
|
break ;
|
|
|
|
case SFM_WRITE :
|
|
if (offset > ppaf24->sample_count)
|
|
{ psf->error = SFE_BAD_SEEK ;
|
|
return PSF_SEEK_ERROR ;
|
|
} ;
|
|
|
|
if (psf->last_op == SFM_WRITE && ppaf24->write_count)
|
|
paf24_write_block (psf, ppaf24) ;
|
|
|
|
psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ;
|
|
ppaf24->write_block = newblock ;
|
|
paf24_read_block (psf, ppaf24) ;
|
|
ppaf24->write_count = newsample ;
|
|
break ;
|
|
|
|
default :
|
|
psf->error = SFE_BAD_SEEK ;
|
|
return PSF_SEEK_ERROR ;
|
|
} ;
|
|
|
|
return newblock * PAF24_SAMPLES_PER_BLOCK + newsample ;
|
|
} /* paf24_seek */
|
|
|
|
static int
|
|
paf24_close (SF_PRIVATE *psf)
|
|
{ PAF24_PRIVATE *ppaf24 ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
|
|
{ if (ppaf24->write_count > 0)
|
|
paf24_write_block (psf, ppaf24) ;
|
|
} ;
|
|
|
|
return 0 ;
|
|
} /* paf24_close */
|
|
|
|
/*---------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24)
|
|
{ int k, channel ;
|
|
unsigned char *cptr ;
|
|
|
|
ppaf24->read_block ++ ;
|
|
ppaf24->read_count = 0 ;
|
|
|
|
if (ppaf24->read_block * PAF24_SAMPLES_PER_BLOCK > ppaf24->sample_count)
|
|
{ memset (ppaf24->samples, 0, PAF24_SAMPLES_PER_BLOCK * ppaf24->channels) ;
|
|
return 1 ;
|
|
} ;
|
|
|
|
/* Read the block. */
|
|
if ((k = (int) psf_fread (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize)
|
|
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, ppaf24->blocksize) ;
|
|
|
|
/* Do endian swapping if necessary. */
|
|
if ((CPU_IS_BIG_ENDIAN && psf->endian == SF_ENDIAN_LITTLE) || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_BIG))
|
|
endswap_int_array (ppaf24->block, 8 * ppaf24->channels) ;
|
|
|
|
/* Unpack block. */
|
|
for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
|
|
{ channel = k % ppaf24->channels ;
|
|
cptr = ((unsigned char *) ppaf24->block) + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
|
|
ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (((unsigned) cptr [2]) << 24) ;
|
|
} ;
|
|
|
|
return 1 ;
|
|
} /* paf24_read_block */
|
|
|
|
static int
|
|
paf24_read (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, int *ptr, int len)
|
|
{ int count, total = 0 ;
|
|
|
|
while (total < len)
|
|
{ if (ppaf24->read_block * PAF24_SAMPLES_PER_BLOCK >= ppaf24->sample_count)
|
|
{ memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ;
|
|
return total ;
|
|
} ;
|
|
|
|
if (ppaf24->read_count >= PAF24_SAMPLES_PER_BLOCK)
|
|
paf24_read_block (psf, ppaf24) ;
|
|
|
|
count = (PAF24_SAMPLES_PER_BLOCK - ppaf24->read_count) * ppaf24->channels ;
|
|
count = (len - total > count) ? count : len - total ;
|
|
|
|
memcpy (&(ptr [total]), &(ppaf24->samples [ppaf24->read_count * ppaf24->channels]), count * sizeof (int)) ;
|
|
total += count ;
|
|
ppaf24->read_count += count / ppaf24->channels ;
|
|
} ;
|
|
|
|
return total ;
|
|
} /* paf24_read */
|
|
|
|
static sf_count_t
|
|
paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
|
|
{ BUF_UNION ubuf ;
|
|
PAF24_PRIVATE *ppaf24 ;
|
|
int *iptr ;
|
|
int k, bufferlen, readcount, count ;
|
|
sf_count_t total = 0 ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
iptr = ubuf.ibuf ;
|
|
bufferlen = ARRAY_LEN (ubuf.ibuf) ;
|
|
while (len > 0)
|
|
{ readcount = (len >= bufferlen) ? bufferlen : (int) len ;
|
|
count = paf24_read (psf, ppaf24, iptr, readcount) ;
|
|
for (k = 0 ; k < readcount ; k++)
|
|
ptr [total + k] = iptr [k] >> 16 ;
|
|
total += count ;
|
|
len -= readcount ;
|
|
} ;
|
|
return total ;
|
|
} /* paf24_read_s */
|
|
|
|
static sf_count_t
|
|
paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
|
|
{ PAF24_PRIVATE *ppaf24 ;
|
|
int total ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
total = paf24_read (psf, ppaf24, ptr, len) ;
|
|
|
|
return total ;
|
|
} /* paf24_read_i */
|
|
|
|
static sf_count_t
|
|
paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
|
|
{ BUF_UNION ubuf ;
|
|
PAF24_PRIVATE *ppaf24 ;
|
|
int *iptr ;
|
|
int k, bufferlen, readcount, count ;
|
|
sf_count_t total = 0 ;
|
|
float normfact ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
normfact = (psf->norm_float == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ;
|
|
|
|
iptr = ubuf.ibuf ;
|
|
bufferlen = ARRAY_LEN (ubuf.ibuf) ;
|
|
while (len > 0)
|
|
{ readcount = (len >= bufferlen) ? bufferlen : (int) len ;
|
|
count = paf24_read (psf, ppaf24, iptr, readcount) ;
|
|
for (k = 0 ; k < readcount ; k++)
|
|
ptr [total + k] = normfact * iptr [k] ;
|
|
total += count ;
|
|
len -= readcount ;
|
|
} ;
|
|
return total ;
|
|
} /* paf24_read_f */
|
|
|
|
static sf_count_t
|
|
paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
|
|
{ BUF_UNION ubuf ;
|
|
PAF24_PRIVATE *ppaf24 ;
|
|
int *iptr ;
|
|
int k, bufferlen, readcount, count ;
|
|
sf_count_t total = 0 ;
|
|
double normfact ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
normfact = (psf->norm_double == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ;
|
|
|
|
iptr = ubuf.ibuf ;
|
|
bufferlen = ARRAY_LEN (ubuf.ibuf) ;
|
|
while (len > 0)
|
|
{ readcount = (len >= bufferlen) ? bufferlen : (int) len ;
|
|
count = paf24_read (psf, ppaf24, iptr, readcount) ;
|
|
for (k = 0 ; k < readcount ; k++)
|
|
ptr [total + k] = normfact * iptr [k] ;
|
|
total += count ;
|
|
len -= readcount ;
|
|
} ;
|
|
return total ;
|
|
} /* paf24_read_d */
|
|
|
|
/*---------------------------------------------------------------------------
|
|
*/
|
|
|
|
static int
|
|
paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24)
|
|
{ int k, nextsample, channel ;
|
|
unsigned char *cptr ;
|
|
|
|
/* First pack block. */
|
|
|
|
if (CPU_IS_LITTLE_ENDIAN)
|
|
{ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
|
|
{ channel = k % ppaf24->channels ;
|
|
cptr = ((unsigned char *) ppaf24->block) + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
|
|
nextsample = ppaf24->samples [k] >> 8 ;
|
|
cptr [0] = nextsample ;
|
|
cptr [1] = nextsample >> 8 ;
|
|
cptr [2] = nextsample >> 16 ;
|
|
} ;
|
|
|
|
/* Do endian swapping if necessary. */
|
|
if (psf->endian == SF_ENDIAN_BIG)
|
|
endswap_int_array (ppaf24->block, 8 * ppaf24->channels) ;
|
|
}
|
|
else if (CPU_IS_BIG_ENDIAN)
|
|
{ /* This is correct. */
|
|
for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
|
|
{ channel = k % ppaf24->channels ;
|
|
cptr = ((unsigned char *) ppaf24->block) + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
|
|
nextsample = ppaf24->samples [k] >> 8 ;
|
|
cptr [0] = nextsample ;
|
|
cptr [1] = nextsample >> 8 ;
|
|
cptr [2] = nextsample >> 16 ;
|
|
} ;
|
|
if (psf->endian == SF_ENDIAN_LITTLE)
|
|
endswap_int_array (ppaf24->block, 8 * ppaf24->channels) ;
|
|
} ;
|
|
|
|
/* Write block to disk. */
|
|
if ((k = (int) psf_fwrite (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize)
|
|
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, ppaf24->blocksize) ;
|
|
|
|
if (ppaf24->sample_count < ppaf24->write_block * PAF24_SAMPLES_PER_BLOCK + ppaf24->write_count)
|
|
ppaf24->sample_count = ppaf24->write_block * PAF24_SAMPLES_PER_BLOCK + ppaf24->write_count ;
|
|
|
|
if (ppaf24->write_count == PAF24_SAMPLES_PER_BLOCK)
|
|
{ ppaf24->write_block ++ ;
|
|
ppaf24->write_count = 0 ;
|
|
} ;
|
|
|
|
return 1 ;
|
|
} /* paf24_write_block */
|
|
|
|
static int
|
|
paf24_write (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, const int *ptr, int len)
|
|
{ int count, total = 0 ;
|
|
|
|
while (total < len)
|
|
{ count = (PAF24_SAMPLES_PER_BLOCK - ppaf24->write_count) * ppaf24->channels ;
|
|
|
|
if (count > len - total)
|
|
count = len - total ;
|
|
|
|
memcpy (&(ppaf24->samples [ppaf24->write_count * ppaf24->channels]), &(ptr [total]), count * sizeof (int)) ;
|
|
total += count ;
|
|
ppaf24->write_count += count / ppaf24->channels ;
|
|
|
|
if (ppaf24->write_count >= PAF24_SAMPLES_PER_BLOCK)
|
|
paf24_write_block (psf, ppaf24) ;
|
|
} ;
|
|
|
|
return total ;
|
|
} /* paf24_write */
|
|
|
|
static sf_count_t
|
|
paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
|
|
{ BUF_UNION ubuf ;
|
|
PAF24_PRIVATE *ppaf24 ;
|
|
int *iptr ;
|
|
int k, bufferlen, writecount = 0, count ;
|
|
sf_count_t total = 0 ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
iptr = ubuf.ibuf ;
|
|
bufferlen = ARRAY_LEN (ubuf.ibuf) ;
|
|
while (len > 0)
|
|
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
|
|
for (k = 0 ; k < writecount ; k++)
|
|
iptr [k] = ptr [total + k] << 16 ;
|
|
count = paf24_write (psf, ppaf24, iptr, writecount) ;
|
|
total += count ;
|
|
len -= writecount ;
|
|
if (count != writecount)
|
|
break ;
|
|
} ;
|
|
return total ;
|
|
} /* paf24_write_s */
|
|
|
|
static sf_count_t
|
|
paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
|
|
{ PAF24_PRIVATE *ppaf24 ;
|
|
int writecount, count ;
|
|
sf_count_t total = 0 ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
while (len > 0)
|
|
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
|
|
|
|
count = paf24_write (psf, ppaf24, ptr, writecount) ;
|
|
|
|
total += count ;
|
|
len -= count ;
|
|
if (count != writecount)
|
|
break ;
|
|
} ;
|
|
|
|
return total ;
|
|
} /* paf24_write_i */
|
|
|
|
static sf_count_t
|
|
paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
|
|
{ BUF_UNION ubuf ;
|
|
PAF24_PRIVATE *ppaf24 ;
|
|
int *iptr ;
|
|
int k, bufferlen, writecount = 0, count ;
|
|
sf_count_t total = 0 ;
|
|
float normfact ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ;
|
|
|
|
iptr = ubuf.ibuf ;
|
|
bufferlen = ARRAY_LEN (ubuf.ibuf) ;
|
|
while (len > 0)
|
|
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
|
|
for (k = 0 ; k < writecount ; k++)
|
|
iptr [k] = psf_lrintf (normfact * ptr [total + k]) ;
|
|
count = paf24_write (psf, ppaf24, iptr, writecount) ;
|
|
total += count ;
|
|
len -= writecount ;
|
|
if (count != writecount)
|
|
break ;
|
|
} ;
|
|
|
|
return total ;
|
|
} /* paf24_write_f */
|
|
|
|
static sf_count_t
|
|
paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
|
|
{ BUF_UNION ubuf ;
|
|
PAF24_PRIVATE *ppaf24 ;
|
|
int *iptr ;
|
|
int k, bufferlen, writecount = 0, count ;
|
|
sf_count_t total = 0 ;
|
|
double normfact ;
|
|
|
|
if (psf->codec_data == NULL)
|
|
return 0 ;
|
|
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
|
|
|
|
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ;
|
|
|
|
iptr = ubuf.ibuf ;
|
|
bufferlen = ARRAY_LEN (ubuf.ibuf) ;
|
|
while (len > 0)
|
|
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
|
|
for (k = 0 ; k < writecount ; k++)
|
|
iptr [k] = psf_lrint (normfact * ptr [total+k]) ;
|
|
count = paf24_write (psf, ppaf24, iptr, writecount) ;
|
|
total += count ;
|
|
len -= writecount ;
|
|
if (count != writecount)
|
|
break ;
|
|
} ;
|
|
|
|
return total ;
|
|
} /* paf24_write_d */
|
|
|