1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-25 00:48:10 +02:00
2015-04-07 22:10:17 -05:00

738 lines
22 KiB
C++

/***************************************************/
/*! \class FileRead
\brief STK audio file input class.
This class provides input support for various
audio file formats. Multi-channel (>2)
soundfiles are supported. The file data is
returned via an external StkFrames object
passed to the read() function. This class
does not store its own copy of the file data,
rather the data is read directly from disk.
FileRead currently supports uncompressed WAV,
AIFF/AIFC, SND (AU), MAT-file (Matlab), and
STK RAW file formats. Signed integer (8-,
16-, and 32-bit) and floating-point (32- and
64-bit) data types are supported. Compressed
data types are not supported.
STK RAW files have no header and are assumed
to contain a monophonic stream of 16-bit
signed integers in big-endian byte order at a
sample rate of 22050 Hz. MAT-file data should
be saved in an array with each data channel
filling a matrix row. The sample rate for
MAT-files is assumed to be 44100 Hz.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "string.h"
#include "FileRead.h"
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <cmath>
#include <cstdio>
/* this is defined in xlisp.h, but it seems a bad idea
* to create an stk dependency on xlisp, or to add a new
* security.h file to share between xlisp.h and stk
*/
extern "C" {
int ok_to_open(const char *filename, const char *mode);
}
using namespace Nyq;
FileRead :: FileRead()
: fd_(0)
{
}
FileRead :: FileRead( std::string fileName, bool typeRaw )
: fd_(0)
{
open( fileName, typeRaw );
}
FileRead :: ~FileRead()
{
if ( fd_ )
fclose( fd_ );
}
void FileRead :: close( void )
{
if ( fd_ ) fclose( fd_ );
fd_ = 0;
wavFile_ = false;
}
bool FileRead :: isOpen( void )
{
if ( fd_ ) return true;
else return false;
}
void FileRead :: open( std::string fileName, bool typeRaw )
{
// If another file is open, close it.
close();
// Try to open the file.
fd_ = NULL;
if (ok_to_open(fileName.c_str(), "rb"))
fd_ = fopen( fileName.c_str(), "rb" );
if ( !fd_ ) {
errorString_ << "FileRead::open: could not open or find file (" << fileName << ")!";
handleError( StkError::FILE_NOT_FOUND );
}
// Attempt to determine file type from header (unless RAW).
bool result = false;
if ( typeRaw )
result = getRawInfo( fileName.c_str() );
else {
char header[12];
if ( fread( &header, 4, 3, fd_ ) != 3 ) goto error;
if ( !strncmp( header, "RIFF", 4 ) &&
!strncmp( &header[8], "WAVE", 4 ) )
result = getWavInfo( fileName.c_str() );
else if ( !strncmp( header, ".snd", 4 ) )
result = getSndInfo( fileName.c_str() );
else if ( !strncmp( header, "FORM", 4 ) &&
( !strncmp( &header[8], "AIFF", 4 ) || !strncmp(&header[8], "AIFC", 4) ) )
result = getAifInfo( fileName.c_str() );
else {
if ( fseek( fd_, 126, SEEK_SET ) == -1 ) goto error;
if ( fread( &header, 2, 1, fd_ ) != 1 ) goto error;
if ( !strncmp( header, "MI", 2 ) ||
!strncmp( header, "IM", 2 ) )
result = getMatInfo( fileName.c_str() );
else {
errorString_ << "FileRead::open: file (" << fileName << ") format unknown.";
handleError( StkError::FILE_UNKNOWN_FORMAT );
}
}
}
// If here, we had a file type candidate but something else went wrong.
if ( result == false )
handleError( StkError::FILE_ERROR );
// Check for empty files.
if ( fileSize_ == 0 ) {
errorString_ << "FileRead::open: file (" << fileName << ") data size is zero!";
handleError( StkError::FILE_ERROR );
}
return;
error:
errorString_ << "FileRead::open: error reading file (" << fileName << ")!";
handleError( StkError::FILE_ERROR );
}
bool FileRead :: getRawInfo( const char *fileName )
{
// Use the system call "stat" to determine the file length.
struct stat filestat;
if ( stat(fileName, &filestat) == -1 ) {
errorString_ << "FileRead: Could not stat RAW file (" << fileName << ").";
return false;
}
// STK rawwave files have no header and are assumed to contain a
// monophonic stream of 16-bit signed integers in big-endian byte
// order at a sample rate of 22050 Hz.
channels_ = 1;
fileSize_ = (long) filestat.st_size / 2; // length in 2-byte samples
dataOffset_ = 0;
fileRate_ = 22050.0;
dataType_ = STK_SINT16;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
}
bool FileRead :: getWavInfo( const char *fileName )
{
// Find "format" chunk ... it must come before the "data" chunk.
char id[4];
SINT32 chunkSize;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "fmt ", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Check that the data is not compressed.
unsigned short format_tag;
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; // Read fmt chunk size.
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&format_tag);
swap32((unsigned char *)&chunkSize);
#endif
if ( format_tag == 0xFFFE ) { // WAVE_FORMAT_EXTENSIBLE
dataOffset_ = ftell(fd_);
if ( fseek(fd_, 14, SEEK_CUR) == -1 ) goto error;
unsigned short extSize;
if ( fread(&extSize, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&extSize);
#endif
if ( extSize == 0 ) goto error;
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error;
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&format_tag);
#endif
if ( fseek(fd_, dataOffset_, SEEK_SET) == -1 ) goto error;
}
if (format_tag != 1 && format_tag != 3 ) { // PCM = 1, FLOAT = 3
errorString_ << "FileRead: "<< fileName << " contains an unsupported data format type (" << format_tag << ").";
return false;
}
// Get number of channels from the header.
SINT16 temp;
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
channels_ = (unsigned int ) temp;
// Get file sample rate from the header.
SINT32 srate;
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&srate);
#endif
fileRate_ = (StkFloat) srate;
// Determine the data type.
dataType_ = 0;
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; // Locate bits_per_sample info.
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
if ( format_tag == 1 ) {
if (temp == 8)
dataType_ = STK_SINT8;
else if (temp == 16)
dataType_ = STK_SINT16;
else if (temp == 32)
dataType_ = STK_SINT32;
}
else if ( format_tag == 3 ) {
if (temp == 32)
dataType_ = STK_FLOAT32;
else if (temp == 64)
dataType_ = STK_FLOAT64;
}
if ( dataType_ == 0 ) {
errorString_ << "FileRead: " << temp << " bits per sample with data format " << format_tag << " are not supported (" << fileName << ").";
return false;
}
// Jump over any remaining part of the "fmt" chunk.
if ( fseek(fd_, chunkSize-16, SEEK_CUR) == -1 ) goto error;
// Find "data" chunk ... it must come after the "fmt" chunk.
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "data", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
chunkSize += chunkSize % 2; // chunk sizes must be even
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Get length of data from the header.
SINT32 bytes;
if ( fread(&bytes, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fileSize_ = 8 * bytes / temp / channels_; // sample frames
dataOffset_ = ftell(fd_);
byteswap_ = false;
#ifndef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
wavFile_ = true;
return true;
error:
errorString_ << "FileRead: error reading WAV file (" << fileName << ").";
return false;
}
bool FileRead :: getSndInfo( const char *fileName )
{
// Determine the data type.
UINT32 format;
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Locate format
if ( fread(&format, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&format);
#endif
if (format == 2) dataType_ = STK_SINT8;
else if (format == 3) dataType_ = STK_SINT16;
else if (format == 4) dataType_ = STK_SINT24;
else if (format == 5) dataType_ = STK_SINT32;
else if (format == 6) dataType_ = STK_FLOAT32;
else if (format == 7) dataType_ = STK_FLOAT64;
else {
errorString_ << "FileRead: data format in file " << fileName << " is not supported.";
return false;
}
// Get file sample rate from the header.
UINT32 srate;
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&srate);
#endif
fileRate_ = (StkFloat) srate;
// Get number of channels from the header.
UINT32 chans;
if ( fread(&chans, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chans);
#endif
channels_ = chans;
if ( fseek(fd_, 4, SEEK_SET) == -1 ) goto error;
if ( fread(&dataOffset_, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&dataOffset_);
#endif
// Get length of data from the header.
if ( fread(&fileSize_, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&fileSize_);
#endif
// Convert to sample frames.
if ( dataType_ == STK_SINT8 )
fileSize_ /= channels_;
if ( dataType_ == STK_SINT16 )
fileSize_ /= 2 * channels_;
else if ( dataType_ == STK_SINT24 )
fileSize_ /= 3 * channels_;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
fileSize_ /= 4 * channels_;
else if ( dataType_ == STK_FLOAT64 )
fileSize_ /= 8 * channels_;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "FileRead: Error reading SND file (" << fileName << ").";
return false;
}
bool FileRead :: getAifInfo( const char *fileName )
{
bool aifc = false;
char id[4];
// Determine whether this is AIFF or AIFC.
if ( fseek(fd_, 8, SEEK_SET) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
if ( !strncmp(id, "AIFC", 4) ) aifc = true;
// Find "common" chunk
SINT32 chunkSize;
if ( fread(&id, 4, 1, fd_) != 1) goto error;
while ( strncmp(id, "COMM", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
chunkSize += chunkSize % 2; // chunk sizes must be even
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Get number of channels from the header.
SINT16 temp;
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; // Jump over chunk size
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
channels_ = temp;
// Get length of data from the header.
SINT32 frames;
if ( fread(&frames, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&frames);
#endif
fileSize_ = frames; // sample frames
// Read the number of bits per sample.
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
// Get file sample rate from the header. For AIFF files, this value
// is stored in a 10-byte, IEEE Standard 754 floating point number,
// so we need to convert it first.
unsigned char srate[10];
unsigned char exp;
unsigned long mantissa;
unsigned long last;
if ( fread(&srate, 10, 1, fd_) != 1 ) goto error;
mantissa = (unsigned long) *(unsigned long *)(srate+2);
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&mantissa);
#endif
exp = 30 - *(srate+1);
last = 0;
while (exp--) {
last = mantissa;
mantissa >>= 1;
}
if (last & 0x00000001) mantissa++;
fileRate_ = (StkFloat) mantissa;
// Determine the data format.
dataType_ = 0;
if ( aifc == false ) {
if ( temp <= 8 ) dataType_ = STK_SINT8;
else if ( temp <= 16 ) dataType_ = STK_SINT16;
else if ( temp <= 24 ) dataType_ = STK_SINT24;
else if ( temp <= 32 ) dataType_ = STK_SINT32;
}
else {
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
if ( !strncmp(id, "NONE", 4) ) {
if ( temp <= 8 ) dataType_ = STK_SINT8;
else if ( temp <= 16 ) dataType_ = STK_SINT16;
else if ( temp <= 24 ) dataType_ = STK_SINT24;
else if ( temp <= 32 ) dataType_ = STK_SINT32;
}
else if ( (!strncmp(id, "fl32", 4) || !strncmp(id, "FL32", 4)) && temp == 32 ) dataType_ = STK_FLOAT32;
else if ( (!strncmp(id, "fl64", 4) || !strncmp(id, "FL64", 4)) && temp == 64 ) dataType_ = STK_FLOAT64;
}
if ( dataType_ == 0 ) {
errorString_ << "FileRead: AIFF/AIFC file (" << fileName << ") has unsupported data type (" << id << ").";
return false;
}
// Start at top to find data (SSND) chunk ... chunk order is undefined.
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error;
// Find data (SSND) chunk
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "SSND", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
chunkSize += chunkSize % 2; // chunk sizes must be even
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Skip over chunk size, offset, and blocksize fields
if ( fseek(fd_, 12, SEEK_CUR) == -1 ) goto error;
dataOffset_ = ftell(fd_);
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "FileRead: Error reading AIFF file (" << fileName << ").";
return false;
}
bool FileRead :: getMatInfo( const char *fileName )
{
// MAT-file formatting information is available at:
// http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf
// Verify this is a version 5 MAT-file format.
char head[4];
if ( fseek(fd_, 0, SEEK_SET) == -1 ) goto error;
if ( fread(&head, 4, 1, fd_) != 1 ) goto error;
// If any of the first 4 characters of the header = 0, then this is
// a Version 4 MAT-file.
if ( strstr(head, "0") ) {
errorString_ << "FileRead: " << fileName << " appears to be a Version 4 MAT-file, which is not currently supported.";
return false;
}
// Determine the endian-ness of the file.
char mi[2];
byteswap_ = false;
// Locate "M" and "I" characters in header.
if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error;
if ( fread(&mi, 2, 1, fd_) != 1) goto error;
#ifdef __LITTLE_ENDIAN__
if ( !strncmp(mi, "MI", 2) )
byteswap_ = true;
else if ( strncmp(mi, "IM", 2) ) goto error;
#else
if ( !strncmp(mi, "IM", 2))
byteswap_ = true;
else if ( strncmp(mi, "MI", 2) ) goto error;
#endif
// Check the data element type
SINT32 datatype;
if ( fread(&datatype, 4, 1, fd_) != 1 ) goto error;
if ( byteswap_ ) swap32((unsigned char *)&datatype);
if (datatype != 14) {
errorString_ << "FileRead: The file does not contain a single Matlab array (or matrix) data element.";
return false;
}
// Determine the array data type.
SINT32 tmp;
SINT32 size;
if ( fseek(fd_, 168, SEEK_SET) == -1 ) goto error;
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&tmp);
if (tmp == 1) { // array name > 4 characters
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; // get array name length
if (byteswap_) swap32((unsigned char *)&tmp);
size = (SINT32) ceil((float)tmp / 8);
if ( fseek(fd_, size*8, SEEK_CUR) == -1 ) goto error; // jump over array name
}
else { // array name <= 4 characters, compressed data element
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error;
}
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&tmp);
if ( tmp == 1 ) dataType_ = STK_SINT8;
else if ( tmp == 3 ) dataType_ = STK_SINT16;
else if ( tmp == 5 ) dataType_ = STK_SINT32;
else if ( tmp == 7 ) dataType_ = STK_FLOAT32;
else if ( tmp == 9 ) dataType_ = STK_FLOAT64;
else {
errorString_ << "FileRead: The MAT-file array data format (" << tmp << ") is not supported.";
return false;
}
// Get number of rows from the header.
SINT32 rows;
if ( fseek(fd_, 160, SEEK_SET) == -1 ) goto error;
if ( fread(&rows, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&rows);
// Get number of columns from the header.
SINT32 columns;
if ( fread(&columns, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&columns);
// Assume channels = smaller of rows or columns.
if (rows < columns) {
channels_ = rows;
fileSize_ = columns;
}
else {
errorString_ << "FileRead: Transpose the MAT-file array so that audio channels fill matrix rows (not columns).";
return false;
}
// Move read pointer to the data in the file.
SINT32 headsize;
if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
if ( fread(&headsize, 4, 1, fd_) != 1 ) goto error; // file size from 132nd byte
if (byteswap_) swap32((unsigned char *)&headsize);
headsize -= fileSize_ * 8 * channels_;
if ( fseek(fd_, headsize, SEEK_CUR) == -1 ) goto error;
dataOffset_ = ftell(fd_);
// Assume MAT-files have 44100 Hz sample rate.
fileRate_ = 44100.0;
return true;
error:
errorString_ << "FileRead: Error reading MAT-file (" << fileName << ").";
return false;
}
void FileRead :: read( StkFrames& buffer, unsigned long startFrame, bool doNormalize )
{
// Make sure we have an open file.
if ( fd_ == 0 ) {
errorString_ << "FileRead::read: a file is not open!";
Stk::handleError( StkError::WARNING );
return;
}
// Check the buffer size.
unsigned int nFrames = buffer.frames();
if ( nFrames == 0 ) {
errorString_ << "FileRead::read: StkFrames buffer size is zero ... no data read!";
Stk::handleError( StkError::WARNING );
return;
}
if ( buffer.channels() != channels_ ) {
errorString_ << "FileRead::read: StkFrames argument has incompatible number of channels!";
Stk::handleError( StkError::FUNCTION_ARGUMENT );
}
// Check for file end.
if ( startFrame + nFrames >= fileSize_ )
nFrames = fileSize_ - startFrame;
long i, nSamples = (long) ( nFrames * channels_ );
unsigned long offset = startFrame * channels_;
// Read samples into StkFrames data buffer.
if ( dataType_ == STK_SINT16 ) {
SINT16 *buf = (SINT16 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*2), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 2, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
SINT16 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap16( (unsigned char *) ptr++ );
}
if ( doNormalize ) {
StkFloat gain = 1.0 / 32768.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
}
else if ( dataType_ == STK_SINT32 ) {
SINT32 *buf = (SINT32 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*4 ), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
SINT32 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap32( (unsigned char *) ptr++ );
}
if ( doNormalize ) {
StkFloat gain = 1.0 / 2147483648.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
}
else if ( dataType_ == STK_FLOAT32 ) {
FLOAT32 *buf = (FLOAT32 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*4), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
FLOAT32 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap32( (unsigned char *) ptr++ );
}
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
else if ( dataType_ == STK_FLOAT64 ) {
FLOAT64 *buf = (FLOAT64 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*8), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 8, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
FLOAT64 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap64( (unsigned char *) ptr++ );
}
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
else if ( dataType_ == STK_SINT8 && wavFile_ ) { // 8-bit WAV data is unsigned!
unsigned char *buf = (unsigned char *) &buffer[0];
if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples, 1, fd_) != 1 ) goto error;
if ( doNormalize ) {
StkFloat gain = 1.0 / 128.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = ( buf[i] - 128 ) * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] - 128.0;
}
}
else if ( dataType_ == STK_SINT8 ) { // signed 8-bit data
char *buf = (char *) &buffer[0];
if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples, 1, fd_ ) != 1 ) goto error;
if ( doNormalize ) {
StkFloat gain = 1.0 / 128.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
}
else if ( dataType_ == STK_SINT24 ) {
// 24-bit values are harder to import efficiently since there is
// no native 24-bit type. The following routine works but is much
// less efficient that that used for the other data types.
SINT32 buf;
StkFloat gain = 1.0 / 8388608.0;
if ( fseek(fd_, dataOffset_+(offset*3), SEEK_SET ) == -1 ) goto error;
for ( i=0; i<nSamples; i++ ) {
if ( fread( &buf, 3, 1, fd_ ) != 1 ) goto error;
buf >>= 8;
if ( byteswap_ )
swap32( (unsigned char *) &buf );
if ( doNormalize )
buffer[i] = buf * gain;
else
buffer[i] = buf;
}
}
buffer.setDataRate( fileRate_ );
return;
error:
errorString_ << "FileRead: Error reading file data.";
handleError( StkError::FILE_ERROR);
}