Version 4.4.3

This commit is contained in:
Gary Scavone
2013-09-29 23:21:29 +02:00
committed by Stephen Sinclair
parent baca57040b
commit 0aec39260a
223 changed files with 26190 additions and 11130 deletions

View File

@@ -10,20 +10,21 @@
FileWrite 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. STK RAW files use 16-bit integers by
(8-, 16-, 24-, and 32-bit) and floating- point (32- and 64-bit)
data types are supported. STK RAW files use 16-bit integers by
definition. MAT-files will always be written as 64-bit floats.
If a data type specification does not match the specified file
type, the data type will automatically be modified. Compressed
data types are not supported.
by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
by Perry R. Cook and Gary P. Scavone, 1995-2011.
*/
/***************************************************/
#include "FileWrite.h"
#include <cstring>
#include <string>
#include <cstdio>
#include <cstring>
#include <cmath>
namespace stk {
@@ -36,58 +37,64 @@ const FileWrite::FILE_TYPE FileWrite :: FILE_MAT = 5;
// WAV header structure. See ftp://ftp.isi.edu/in-notes/rfc2361.txt
// for information regarding format codes.
struct wavhdr {
struct WaveHeader {
char riff[4]; // "RIFF"
SINT32 file_size; // in bytes
SINT32 fileSize; // in bytes
char wave[4]; // "WAVE"
char fmt[4]; // "fmt "
SINT32 chunk_size; // in bytes (16 for PCM)
SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
SINT16 num_chans; // 1=mono, 2=stereo
SINT32 sample_rate;
SINT32 bytes_per_sec;
SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo
SINT16 bits_per_samp;
char data[4]; // "data"
SINT32 data_length; // in bytes
SINT32 chunkSize; // in bytes (16 for PCM)
SINT16 formatCode; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
SINT16 nChannels; // 1=mono, 2=stereo
SINT32 sampleRate;
SINT32 bytesPerSecond;
SINT16 bytesPerSample; // 2=16-bit mono, 4=16-bit stereo
SINT16 bitsPerSample;
SINT16 cbSize; // size of extension
SINT16 validBits; // valid bits per sample
SINT32 channelMask; // speaker position mask
char subformat[16]; // format code and GUID
char fact[4]; // "fact"
SINT32 factSize; // fact chunk size
SINT32 frames; // sample frames
};
// SND (AU) header structure (NeXT and Sun).
struct sndhdr {
struct SndHeader {
char pref[4];
SINT32 hdr_length;
SINT32 data_length;
SINT32 headerBytes;
SINT32 dataBytes;
SINT32 format;
SINT32 sample_rate;
SINT32 num_channels;
SINT32 sampleRate;
SINT32 nChannels;
char comment[16];
};
// AIFF/AIFC header structure ... only the part common to both
// formats.
struct aifhdr {
struct AifHeader {
char form[4]; // "FORM"
SINT32 form_size; // in bytes
SINT32 formSize; // in bytes
char aiff[4]; // "AIFF" or "AIFC"
char comm[4]; // "COMM"
SINT32 comm_size; // "COMM" chunk size (18 for AIFF, 24 for AIFC)
SINT16 num_chans; // number of channels
unsigned long sample_frames; // sample frames of audio data
SINT16 sample_size; // in bits
SINT32 commSize; // "COMM" chunk size (18 for AIFF, 24 for AIFC)
SINT16 nChannels; // number of channels
unsigned long sampleFrames; // sample frames of audio data
SINT16 sampleSize; // in bits
unsigned char srate[10]; // IEEE 754 floating point format
};
struct aifssnd {
struct AifSsnd {
char ssnd[4]; // "SSND"
SINT32 ssnd_size; // "SSND" chunk size
SINT32 ssndSize; // "SSND" chunk size
unsigned long offset; // data offset in data block (should be 0)
unsigned long block_size; // not used by STK (should be 0)
unsigned long blockSize; // not used by STK (should be 0)
};
// MAT-file 5 header structure.
struct mathdr {
struct MatHeader {
char heading[124]; // Header text field
SINT16 hff[2]; // Header flag fields
SINT32 fs[16]; // Sample rate data element
SINT32 adf[11]; // Array data format fields
// There's more, but it's of variable length
};
@@ -138,7 +145,7 @@ void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite:
this->close();
if ( nChannels < 1 ) {
errorString_ << "FileWrite::open: then channels argument must be greater than zero!";
oStream_ << "FileWrite::open: then channels argument must be greater than zero!";
handleError( StkError::FUNCTION_ARGUMENT );
}
@@ -146,9 +153,9 @@ void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite:
fileType_ = type;
if ( format != STK_SINT8 && format != STK_SINT16 &&
format != STK_SINT32 && format != STK_FLOAT32 &&
format != STK_FLOAT64 ) {
errorString_ << "FileWrite::open: unknown data type (" << format << ") specified!";
format != STK_SINT24 && format != STK_SINT32 &&
format != STK_FLOAT32 && format != STK_FLOAT64 ) {
oStream_ << "FileWrite::open: unknown data type (" << format << ") specified!";
handleError( StkError::FUNCTION_ARGUMENT );
}
dataType_ = format;
@@ -156,21 +163,21 @@ void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite:
bool result = false;
if ( fileType_ == FILE_RAW ) {
if ( channels_ != 1 ) {
errorString_ << "FileWrite::open: STK RAW files are, by definition, always monaural (channels = " << nChannels << " not supported)!";
oStream_ << "FileWrite::open: STK RAW files are, by definition, always monaural (channels = " << nChannels << " not supported)!";
handleError( StkError::FUNCTION_ARGUMENT );
}
result = setRawFile( fileName.c_str() );
result = setRawFile( fileName );
}
else if ( fileType_ == FILE_WAV )
result = setWavFile( fileName.c_str() );
result = setWavFile( fileName );
else if ( fileType_ == FILE_SND )
result = setSndFile( fileName.c_str() );
result = setSndFile( fileName );
else if ( fileType_ == FILE_AIF )
result = setAifFile( fileName.c_str() );
result = setAifFile( fileName );
else if ( fileType_ == FILE_MAT )
result = setMatFile( fileName.c_str() );
result = setMatFile( fileName );
else {
errorString_ << "FileWrite::open: unknown file type (" << fileType_ << ") specified!";
oStream_ << "FileWrite::open: unknown file type (" << fileType_ << ") specified!";
handleError( StkError::FUNCTION_ARGUMENT );
}
@@ -180,21 +187,19 @@ void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite:
frameCounter_ = 0;
}
bool FileWrite :: setRawFile( const char *fileName )
bool FileWrite :: setRawFile( std::string fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".raw") == NULL) strcat(name, ".raw");
fd_ = fopen(name, "wb");
if ( fileName.find( ".raw" ) == std::string::npos ) fileName += ".raw";
fd_ = fopen( fileName.c_str(), "wb" );
if ( !fd_ ) {
errorString_ << "FileWrite: could not create RAW file: " << name << '.';
oStream_ << "FileWrite: could not create RAW file: " << fileName << '.';
return false;
}
if ( dataType_ != STK_SINT16 ) {
dataType_ = STK_SINT16;
errorString_ << "FileWrite: using 16-bit signed integer data format for file " << name << '.';
handleError( StkError::DEBUG_WARNING );
oStream_ << "FileWrite: using 16-bit signed integer data format for file " << fileName << '.';
handleError( StkError::WARNING );
}
byteswap_ = false;
@@ -202,113 +207,160 @@ bool FileWrite :: setRawFile( const char *fileName )
byteswap_ = true;
#endif
errorString_ << "FileWrite: creating RAW file: " << name;
oStream_ << "FileWrite: creating RAW file: " << fileName;
handleError( StkError::STATUS );
return true;
}
bool FileWrite :: setWavFile( const char *fileName )
bool FileWrite :: setWavFile( std::string fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".wav") == NULL) strcat(name, ".wav");
fd_ = fopen(name, "wb");
std::string name( fileName );
if ( fileName.find( ".wav" ) == std::string::npos ) fileName += ".wav";
fd_ = fopen( fileName.c_str(), "wb" );
if ( !fd_ ) {
errorString_ << "FileWrite: could not create WAV file: " << name;
oStream_ << "FileWrite: could not create WAV file: " << fileName;
return false;
}
struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1,
(SINT32) Stk::sampleRate(), 0, 2, 16, "dat", 0};
hdr.riff[3] = 'F';
hdr.wave[3] = 'E';
hdr.fmt[3] = ' ';
hdr.data[3] = 'a';
hdr.num_chans = (SINT16) channels_;
struct WaveHeader hdr = { {'R','I','F','F'}, 44, {'W','A','V','E'}, {'f','m','t',' '}, 16, 1, 1,
(SINT32) Stk::sampleRate(), 0, 2, 16, 0, 0, 0,
{'\x01','\x00','\x00','\x00','\x00','\x00','\x10','\x00','\x80','\x00','\x00','\xAA','\x00','\x38','\x9B','\x71'},
{'f','a','c','t'}, 4, 0 };
hdr.nChannels = (SINT16) channels_;
if ( dataType_ == STK_SINT8 )
hdr.bits_per_samp = 8;
hdr.bitsPerSample = 8;
else if ( dataType_ == STK_SINT16 )
hdr.bits_per_samp = 16;
hdr.bitsPerSample = 16;
else if ( dataType_ == STK_SINT24 )
hdr.bitsPerSample = 24;
else if ( dataType_ == STK_SINT32 )
hdr.bits_per_samp = 32;
hdr.bitsPerSample = 32;
else if ( dataType_ == STK_FLOAT32 ) {
hdr.format_tag = 3;
hdr.bits_per_samp = 32;
hdr.formatCode = 3;
hdr.bitsPerSample = 32;
}
else if ( dataType_ == STK_FLOAT64 ) {
hdr.format_tag = 3;
hdr.bits_per_samp = 64;
hdr.formatCode = 3;
hdr.bitsPerSample = 64;
}
hdr.bytesPerSample = (SINT16) (channels_ * hdr.bitsPerSample / 8);
hdr.bytesPerSecond = (SINT32) (hdr.sampleRate * hdr.bytesPerSample);
unsigned int bytesToWrite = 36;
bool useExtensible = false;
if ( channels_ > 2 || hdr.bitsPerSample > 16 ) { // use extensible format
useExtensible = true;
bytesToWrite = 72;
hdr.chunkSize += 24;
hdr.formatCode = 0xFFFE;
hdr.cbSize = 22;
hdr.validBits = hdr.bitsPerSample;
SINT16 *subFormat = (SINT16 *)&hdr.subformat[0];
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 )
*subFormat = 3;
else *subFormat = 1;
}
hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8);
hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp);
byteswap_ = false;
#ifndef __LITTLE_ENDIAN__
byteswap_ = true;
swap32((unsigned char *)&hdr.file_size);
swap32((unsigned char *)&hdr.chunk_size);
swap16((unsigned char *)&hdr.format_tag);
swap16((unsigned char *)&hdr.num_chans);
swap32((unsigned char *)&hdr.sample_rate);
swap32((unsigned char *)&hdr.bytes_per_sec);
swap16((unsigned char *)&hdr.bytes_per_samp);
swap16((unsigned char *)&hdr.bits_per_samp);
swap32((unsigned char *)&hdr.chunkSize);
swap16((unsigned char *)&hdr.formatCode);
swap16((unsigned char *)&hdr.nChannels);
swap32((unsigned char *)&hdr.sampleRate);
swap32((unsigned char *)&hdr.bytesPerSecond);
swap16((unsigned char *)&hdr.bytesPerSample);
swap16((unsigned char *)&hdr.bitsPerSample);
swap16((unsigned char *)&hdr.cbSize);
swap16((unsigned char *)&hdr.validBits);
swap16((unsigned char *)&hdr.subformat[0]);
swap32((unsigned char *)&hdr.factSize);
#endif
if ( fwrite(&hdr, 4, 11, fd_) != 11 ) {
errorString_ << "FileWrite: could not write WAV header for file " << name << '.';
return false;
}
char data[4] = {'d','a','t','a'};
SINT32 dataSize = 0;
if ( fwrite(&hdr, 1, bytesToWrite, fd_) != bytesToWrite ) goto error;
if ( fwrite(&data, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&dataSize, 4, 1, fd_) != 1 ) goto error;
errorString_ << "FileWrite: creating WAV file: " << name;
oStream_ << "FileWrite: creating WAV file: " << fileName;
handleError( StkError::STATUS );
return true;
error:
oStream_ << "FileWrite: could not write WAV header for file: " << fileName;
return false;
}
void FileWrite :: closeWavFile( void )
{
int bytes_per_sample = 1;
int bytesPerSample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
bytesPerSample = 2;
else if ( dataType_ == STK_SINT24 )
bytesPerSample = 3;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
bytesPerSample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
bytesPerSample = 8;
SINT32 bytes = frameCounter_ * channels_ * bytes_per_sample;
bool useExtensible = false;
int dataLocation = 40;
if ( bytesPerSample > 2 || channels_ > 2 ) {
useExtensible = true;
dataLocation = 76;
}
SINT32 bytes = frameCounter_ * channels_ * bytesPerSample;
if ( bytes % 2 ) { // pad extra byte if odd
signed char sample = 0;
fwrite( &sample, 1, 1, fd_ );
}
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 40, SEEK_SET); // jump to data length
fwrite(&bytes, 4, 1, fd_);
fseek( fd_, dataLocation, SEEK_SET ); // jump to data length
fwrite( &bytes, 4, 1, fd_ );
bytes = frameCounter_ * channels_ * bytes_per_sample + 44;
bytes = frameCounter_ * channels_ * bytesPerSample + 44;
if ( useExtensible ) bytes += 36;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 4, SEEK_SET); // jump to file size
fwrite(&bytes, 4, 1, fd_);
fseek( fd_, 4, SEEK_SET ); // jump to file size
fwrite( &bytes, 4, 1, fd_ );
if ( useExtensible ) { // fill in the "fact" chunk frames value
bytes = frameCounter_;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek( fd_, 68, SEEK_SET );
fwrite( &bytes, 4, 1, fd_ );
}
fclose( fd_ );
}
bool FileWrite :: setSndFile( const char *fileName )
bool FileWrite :: setSndFile( std::string fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".snd") == NULL) strcat(name, ".snd");
fd_ = fopen(name, "wb");
std::string name( fileName );
if ( fileName.find( ".snd" ) == std::string::npos ) fileName += ".snd";
fd_ = fopen( fileName.c_str(), "wb" );
if ( !fd_ ) {
errorString_ << "FileWrite: could not create SND file: " << name;
oStream_ << "FileWrite: could not create SND file: " << fileName;
return false;
}
struct sndhdr hdr = {".sn", 40, 0, 3, (SINT32) Stk::sampleRate(), 1, "Created by STK"};
struct SndHeader hdr = {".sn", 40, 0, 3, (SINT32) Stk::sampleRate(), 1, "Created by STK"};
hdr.pref[3] = 'd';
hdr.num_channels = channels_;
hdr.nChannels = channels_;
if ( dataType_ == STK_SINT8 )
hdr.format = 2;
else if ( dataType_ == STK_SINT16 )
hdr.format = 3;
else if ( dataType_ == STK_SINT24 )
hdr.format = 4;
else if ( dataType_ == STK_SINT32 )
hdr.format = 5;
else if ( dataType_ == STK_FLOAT32 )
@@ -319,35 +371,37 @@ bool FileWrite :: setSndFile( const char *fileName )
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
swap32 ((unsigned char *)&hdr.hdr_length);
swap32 ((unsigned char *)&hdr.headerBytes);
swap32 ((unsigned char *)&hdr.format);
swap32 ((unsigned char *)&hdr.sample_rate);
swap32 ((unsigned char *)&hdr.num_channels);
swap32 ((unsigned char *)&hdr.sampleRate);
swap32 ((unsigned char *)&hdr.nChannels);
#endif
if ( fwrite(&hdr, 4, 10, fd_) != 10 ) {
errorString_ << "FileWrite: Could not write SND header for file " << name << '.';
oStream_ << "FileWrite: Could not write SND header for file " << fileName << '.';
return false;
}
errorString_ << "FileWrite: creating SND file: " << name;
oStream_ << "FileWrite: creating SND file: " << fileName;
handleError( StkError::STATUS );
return true;
}
void FileWrite :: closeSndFile( void )
{
int bytes_per_sample = 1;
int bytesPerSample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
bytesPerSample = 2;
else if ( dataType_ == STK_SINT24 )
bytesPerSample = 3;
else if ( dataType_ == STK_SINT32 )
bytes_per_sample = 4;
bytesPerSample = 4;
else if ( dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
bytesPerSample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
bytesPerSample = 8;
SINT32 bytes = frameCounter_ * bytes_per_sample * channels_;
SINT32 bytes = frameCounter_ * bytesPerSample * channels_;
#ifdef __LITTLE_ENDIAN__
swap32 ((unsigned char *)&bytes);
#endif
@@ -356,40 +410,37 @@ void FileWrite :: closeSndFile( void )
fclose(fd_);
}
bool FileWrite :: setAifFile( const char *fileName )
bool FileWrite :: setAifFile( std::string fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".aif") == NULL) strcat(name, ".aif");
fd_ = fopen(name, "wb");
std::string name( fileName );
if ( fileName.find( ".aif" ) == std::string::npos ) fileName += ".aif";
fd_ = fopen( fileName.c_str(), "wb" );
if ( !fd_ ) {
errorString_ << "FileWrite: could not create AIF file: " << name;
oStream_ << "FileWrite: could not create AIF file: " << fileName;
return false;
}
// Common parts of AIFF/AIFC header.
struct aifhdr hdr = {"FOR", 46, "AIF", "COM", 18, 0, 0, 16, "0"};
struct aifssnd ssnd = {"SSN", 8, 0, 0};
hdr.form[3] = 'M';
hdr.aiff[3] = 'F';
hdr.comm[3] = 'M';
ssnd.ssnd[3] = 'D';
hdr.num_chans = channels_;
struct AifHeader hdr = {{'F','O','R','M'}, 46, {'A','I','F','F'}, {'C','O','M','M'}, 18, 0, 0, 16, "0"};
struct AifSsnd ssnd = {{'S','S','N','D'}, 8, 0, 0};
hdr.nChannels = channels_;
if ( dataType_ == STK_SINT8 )
hdr.sample_size = 8;
hdr.sampleSize = 8;
else if ( dataType_ == STK_SINT16 )
hdr.sample_size = 16;
hdr.sampleSize = 16;
else if ( dataType_ == STK_SINT24 )
hdr.sampleSize = 24;
else if ( dataType_ == STK_SINT32 )
hdr.sample_size = 32;
hdr.sampleSize = 32;
else if ( dataType_ == STK_FLOAT32 ) {
hdr.aiff[3] = 'C';
hdr.sample_size = 32;
hdr.comm_size = 24;
hdr.sampleSize = 32;
hdr.commSize = 24;
}
else if ( dataType_ == STK_FLOAT64 ) {
hdr.aiff[3] = 'C';
hdr.sample_size = 64;
hdr.comm_size = 24;
hdr.sampleSize = 64;
hdr.commSize = 24;
}
// For AIFF files, the sample rate is stored in a 10-byte,
@@ -398,11 +449,11 @@ bool FileWrite :: setAifFile( const char *fileName )
SINT16 i;
unsigned long exp;
unsigned long rate = (unsigned long) Stk::sampleRate();
memset(hdr.srate, 0, 10);
memset( hdr.srate, 0, 10 );
exp = rate;
for (i=0; i<32; i++) {
for ( i=0; i<32; i++ ) {
exp >>= 1;
if (!exp) break;
if ( !exp ) break;
}
i += 16383;
#ifdef __LITTLE_ENDIAN__
@@ -410,8 +461,8 @@ bool FileWrite :: setAifFile( const char *fileName )
#endif
*(SINT16 *)(hdr.srate) = (SINT16) i;
for (i=32; i; i--) {
if (rate & 0x80000000) break;
for ( i=32; i; i-- ) {
if ( rate & 0x80000000 ) break;
rate <<= 1;
}
@@ -423,20 +474,20 @@ bool FileWrite :: setAifFile( const char *fileName )
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
swap32((unsigned char *)&hdr.form_size);
swap32((unsigned char *)&hdr.comm_size);
swap16((unsigned char *)&hdr.num_chans);
swap16((unsigned char *)&hdr.sample_size);
swap32((unsigned char *)&ssnd.ssnd_size);
swap32((unsigned char *)&hdr.formSize);
swap32((unsigned char *)&hdr.commSize);
swap16((unsigned char *)&hdr.nChannels);
swap16((unsigned char *)&hdr.sampleSize);
swap32((unsigned char *)&ssnd.ssndSize);
swap32((unsigned char *)&ssnd.offset);
swap32((unsigned char *)&ssnd.block_size);
swap32((unsigned char *)&ssnd.blockSize);
#endif
// The structure boundaries don't allow a single write of 54 bytes.
if ( fwrite(&hdr, 4, 5, fd_) != 5 ) goto error;
if ( fwrite(&hdr.num_chans, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sample_frames, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sample_size, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.nChannels, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sampleFrames, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sampleSize, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.srate, 10, 1, fd_) != 1 ) goto error;
if ( dataType_ == STK_FLOAT32 ) {
@@ -454,12 +505,12 @@ bool FileWrite :: setAifFile( const char *fileName )
if ( fwrite(&ssnd, 4, 4, fd_) != 4 ) goto error;
errorString_ << "FileWrite: creating AIF file: " << name;
oStream_ << "FileWrite: creating AIF file: " << fileName;
handleError( StkError::STATUS );
return true;
error:
errorString_ << "FileWrite: could not write AIF header for file: " << name;
oStream_ << "FileWrite: could not write AIF header for file: " << fileName;
return false;
}
@@ -469,18 +520,20 @@ void FileWrite :: closeAifFile( void )
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&frames);
#endif
fseek(fd_, 22, SEEK_SET); // jump to "COMM" sample_frames
fseek(fd_, 22, SEEK_SET); // jump to "COMM" sampleFrames
fwrite(&frames, 4, 1, fd_);
int bytes_per_sample = 1;
int bytesPerSample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
bytesPerSample = 2;
if ( dataType_ == STK_SINT24 )
bytesPerSample = 3;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
bytesPerSample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
bytesPerSample = 8;
unsigned long bytes = frameCounter_ * bytes_per_sample * channels_ + 46;
unsigned long bytes = frameCounter_ * bytesPerSample * channels_ + 46;
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
@@ -488,7 +541,7 @@ void FileWrite :: closeAifFile( void )
fseek(fd_, 4, SEEK_SET); // jump to file size
fwrite(&bytes, 4, 1, fd_);
bytes = frameCounter_ * bytes_per_sample * channels_ + 8;
bytes = frameCounter_ * bytesPerSample * channels_ + 8;
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
@@ -502,28 +555,24 @@ void FileWrite :: closeAifFile( void )
fclose( fd_ );
}
bool FileWrite :: setMatFile( const char *fileName )
bool FileWrite :: setMatFile( std::string fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".mat") == NULL) strcat(name, ".mat");
fd_ = fopen(name, "w+b");
if ( fileName.find( ".mat" ) == std::string::npos ) fileName += ".mat";
fd_ = fopen( fileName.c_str(), "w+b" );
if ( !fd_ ) {
errorString_ << "FileWrite: could not create MAT file: " << name;
oStream_ << "FileWrite: could not create MAT file: " << fileName;
return false;
}
if ( dataType_ != STK_FLOAT64 ) {
dataType_ = STK_FLOAT64;
errorString_ << "FileWrite: using 64-bit floating-point data format for file " << name << '.';
handleError( StkError::DEBUG_WARNING );
oStream_ << "FileWrite: using 64-bit floating-point data format for file " << fileName << '.';
handleError( StkError::DEBUG_PRINT );
}
struct mathdr hdr;
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit in C++ (STK). By Perry R. Cook and Gary P. Scavone.");
int i;
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
struct MatHeader hdr;
strcpy( hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit in C++ (STK). By Perry R. Cook and Gary P. Scavone." );
for ( int i=strlen(hdr.heading); i<124; i++ ) hdr.heading[i] = ' ';
// Header Flag Fields
hdr.hff[0] = (SINT16) 0x0100; // Version field
@@ -531,9 +580,34 @@ bool FileWrite :: setMatFile( const char *fileName )
hdr.hff[1] <<= 8;
hdr.hff[1] += 'I';
// Write sample rate in array data element
hdr.fs[0] = (SINT32) 14; // Matlab array data type value
hdr.fs[1] = (SINT32) 56; // Size of data element to follow (in bytes)
// Numeric Array Subelements (4):
// 1. Array Flags
hdr.fs[2] = (SINT32) 6; // Matlab 32-bit unsigned integer data type value
hdr.fs[3] = (SINT32) 8; // 8 bytes of data to follow
hdr.fs[4] = (SINT32) 6; // Double-precision array, no array flags set
hdr.fs[5] = (SINT32) 0; // 4 bytes undefined
// 2. Array Dimensions
hdr.fs[6] = (SINT32) 5; // Matlab 32-bit signed integer data type value
hdr.fs[7] = (SINT32) 8; // 8 bytes of data to follow (2D array)
hdr.fs[8] = (SINT32) 1; // 1 row
hdr.fs[9] = (SINT32) 1; // 1 column
// 3. Array Name (small data format element)
hdr.fs[10] = 0x00020001;
hdr.fs[11] = 's' << 8;
hdr.fs[11] += 'f';
// 4. Real Part
hdr.fs[12] = 9; // Matlab IEEE 754 double data type
hdr.fs[13] = 8; // 8 bytes of data to follow
FLOAT64 *sampleRate = (FLOAT64 *)&hdr.fs[14];
*sampleRate = (FLOAT64) Stk::sampleRate();
// Write audio samples in array data element
hdr.adf[0] = (SINT32) 14; // Matlab array data type value
hdr.adf[1] = (SINT32) 0; // Size of file after this point to end (in bytes)
// Don't know size yet.
// Numeric Array Subelements (4):
// 1. Array Flags
@@ -547,82 +621,83 @@ bool FileWrite :: setMatFile( const char *fileName )
hdr.adf[8] = (SINT32) channels_; // This is the number of rows
hdr.adf[9] = (SINT32) 0; // This is the number of columns
// 3. Array Name
// We'll use fileName for the matlab array name (as well as the file name).
// If fileName is 4 characters or less, we have to use a compressed data element
// format for the array name data element. Otherwise, the array name must
// be formatted in 8-byte increments (up to 31 characters + NULL).
SINT32 namelength = (SINT32) strlen(fileName);
if (strstr(fileName, ".mat")) namelength -= 4;
if (namelength > 31) namelength = 31; // Truncate name to 31 characters.
char arrayName[64];
strncpy(arrayName, fileName, namelength);
arrayName[namelength] = '\0';
if (namelength > 4) {
// 3. Array Name We'll use fileName for the matlab array name (as
// well as the file name), though we might need to strip off a
// leading directory path. If fileName is 4 characters or less, we
// have to use a small data format element for the array name data
// element. Otherwise, the array name must be formatted in 8-byte
// increments (up to 31 characters + NULL).
std::string name = fileName;
size_t found;
found = name.find_last_of("/\\");
name = name.substr(found+1);
SINT32 namelength = (SINT32) name.size() - 4; // strip off the ".mat" extension
if ( namelength > 31 ) namelength = 31; // Truncate name to 31 characters.
if ( namelength > 4 ) {
hdr.adf[10] = (SINT32) 1; // Matlab 8-bit signed integer data type value
}
else { // Compressed data element format
hdr.adf[10] = namelength;
hdr.adf[10] <<= 16;
hdr.adf[10] += 1;
hdr.adf[10] = (namelength << 16) + 1;
}
SINT32 headsize = 40; // Number of bytes in data element so far.
SINT32 headsize = 40; // Number of bytes in audio data element so far.
// Write the fixed portion of the header
if ( fwrite(&hdr, 172, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr, 236, 1, fd_) != 1 ) goto error;
// Write MATLAB array name
SINT32 tmp;
if (namelength > 4) {
if ( namelength > 4 ) {
if ( fwrite(&namelength, 4, 1, fd_) != 1) goto error;
if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
if ( fwrite(name.c_str(), namelength, 1, fd_) != 1 ) goto error;
tmp = (SINT32) ceil((float)namelength / 8);
if ( fseek(fd_, tmp*8-namelength, SEEK_CUR) == -1 ) goto error;
headsize += tmp * 8;
}
else { // Compressed data element format
if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
if ( fwrite(name.c_str(), namelength, 1, fd_) != 1 ) goto error;
tmp = 4 - namelength;
if ( fseek(fd_, tmp, SEEK_CUR) == -1 ) goto error;
}
// Finish writing known header information
//4. Real Part
tmp = 9; // Matlab IEEE 754 double data type
if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
tmp = 0; // Size of real part subelement in bytes (8 per sample)
if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
headsize += 8; // Total number of bytes in data element so far
if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
if ( fseek(fd_, 196, SEEK_SET) == -1 ) goto error;
if ( fwrite(&headsize, 4, 1, fd_) != 1 ) goto error; // Write header size ... will update at end
if ( fseek(fd_, 0, SEEK_END) == -1 ) goto error;
byteswap_ = false;
errorString_ << "FileWrite: creating MAT-file (" << name << ") containing MATLAB array: " << arrayName;
oStream_ << "FileWrite: creating MAT-file: " << fileName;
handleError( StkError::STATUS );
return true;
error:
errorString_ << "FileWrite: could not write MAT-file header for file " << name << '.';
oStream_ << "FileWrite: could not write MAT-file header for file " << fileName << '.';
return false;
}
void FileWrite :: closeMatFile( void )
{
fseek(fd_, 164, SEEK_SET); // jump to number of columns
fseek(fd_, 228, SEEK_SET); // jump to number of columns
fwrite(&frameCounter_, 4, 1, fd_);
SINT32 headsize, temp;
fseek(fd_, 132, SEEK_SET); // jump to header size
fseek(fd_, 196, SEEK_SET); // jump to header size
fread(&headsize, 4, 1, fd_);
temp = headsize;
headsize += (SINT32) (frameCounter_ * 8 * channels_);
fseek(fd_, 132, SEEK_SET);
fseek(fd_, 196, SEEK_SET);
// Write file size (minus some header info)
fwrite(&headsize, 4, 1, fd_);
fseek(fd_, temp+132, SEEK_SET); // jumpt to data size (in bytes)
fseek(fd_, temp+196, SEEK_SET); // jumpt to data size (in bytes)
temp = frameCounter_ * 8 * channels_;
fwrite(&temp, 4, 1, fd_);
@@ -632,13 +707,13 @@ void FileWrite :: closeMatFile( void )
void FileWrite :: write( StkFrames& buffer )
{
if ( fd_ == 0 ) {
errorString_ << "FileWrite::write(): a file has not yet been opened!";
oStream_ << "FileWrite::write(): a file has not yet been opened!";
handleError( StkError::WARNING );
return;
}
if ( buffer.channels() != channels_ ) {
errorString_ << "FileWrite::write(): number of channels in the StkFrames argument does not match that specified to open() function!";
oStream_ << "FileWrite::write(): number of channels in the StkFrames argument does not match that specified to open() function!";
handleError( StkError::FUNCTION_ARGUMENT );
return;
}
@@ -695,12 +770,25 @@ void FileWrite :: write( StkFrames& buffer )
if ( fwrite(&sample, 8, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_SINT24 ) {
SINT32 sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (SINT32) (buffer[k] * 8388607.0);
if ( byteswap_ ) {
swap32( (unsigned char *)&sample );
unsigned char *ptr = (unsigned char *) &sample;
if ( fwrite(ptr+1, 3, 1, fd_) != 1 ) goto error;
}
else
if ( fwrite(&sample, 3, 1, fd_) != 1 ) goto error;
}
}
frameCounter_ += buffer.frames();
return;
error:
errorString_ << "FileWrite::write(): error writing data to file!";
oStream_ << "FileWrite::write(): error writing data to file!";
handleError( StkError::FILE_ERROR );
}