beeps 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.doc/ext/beeps/beeps.cpp +46 -0
- data/.doc/ext/beeps/file_in.cpp +59 -0
- data/.doc/ext/beeps/native.cpp +41 -0
- data/.doc/ext/beeps/processor.cpp +49 -0
- data/.doc/ext/beeps/sawtooth_wave.cpp +66 -0
- data/.doc/ext/beeps/sine_wave.cpp +66 -0
- data/.doc/ext/beeps/sound.cpp +69 -0
- data/.doc/ext/beeps/square_wave.cpp +66 -0
- data/README.md +4 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/beeps.gemspec +43 -0
- data/ext/beeps/beeps.cpp +48 -0
- data/ext/beeps/defs.h +13 -0
- data/ext/beeps/extconf.rb +25 -0
- data/ext/beeps/file_in.cpp +61 -0
- data/ext/beeps/native.cpp +41 -0
- data/ext/beeps/processor.cpp +50 -0
- data/ext/beeps/sawtooth_wave.cpp +69 -0
- data/ext/beeps/sine_wave.cpp +69 -0
- data/ext/beeps/sound.cpp +72 -0
- data/ext/beeps/square_wave.cpp +69 -0
- data/include/beeps.h +12 -0
- data/include/beeps/beeps.h +25 -0
- data/include/beeps/defs.h +23 -0
- data/include/beeps/exception.h +47 -0
- data/include/beeps/openal.h +34 -0
- data/include/beeps/processor.h +132 -0
- data/include/beeps/ruby.h +10 -0
- data/include/beeps/ruby/beeps.h +21 -0
- data/include/beeps/ruby/processor.h +86 -0
- data/include/beeps/ruby/sound.h +42 -0
- data/include/beeps/signals.h +53 -0
- data/include/beeps/sound.h +44 -0
- data/lib/beeps.rb +9 -0
- data/lib/beeps/autoinit.rb +10 -0
- data/lib/beeps/beeps.rb +49 -0
- data/lib/beeps/ext.rb +4 -0
- data/lib/beeps/module.rb +49 -0
- data/lib/beeps/processor.rb +60 -0
- data/lib/beeps/sound.rb +19 -0
- data/src/beeps.cpp +93 -0
- data/src/exception.cpp +43 -0
- data/src/openal.cpp +216 -0
- data/src/openal.h +25 -0
- data/src/processor.cpp +201 -0
- data/src/signals.cpp +90 -0
- data/src/sound.cpp +125 -0
- data/src/stk/include/Blit.h +151 -0
- data/src/stk/include/BlitSaw.h +148 -0
- data/src/stk/include/BlitSquare.h +170 -0
- data/src/stk/include/FileRead.h +141 -0
- data/src/stk/include/FileWvIn.h +195 -0
- data/src/stk/include/Generator.h +50 -0
- data/src/stk/include/SineWave.h +159 -0
- data/src/stk/include/Stk.h +589 -0
- data/src/stk/include/WvIn.h +46 -0
- data/src/stk/src/Blit.cpp +78 -0
- data/src/stk/src/BlitSaw.cpp +91 -0
- data/src/stk/src/BlitSquare.cpp +95 -0
- data/src/stk/src/FileRead.cpp +903 -0
- data/src/stk/src/FileWvIn.cpp +260 -0
- data/src/stk/src/SineWave.cpp +78 -0
- data/src/stk/src/Stk.cpp +395 -0
- data/test/helper.rb +17 -0
- data/test/test_beeps.rb +18 -0
- data/test/test_sound.rb +26 -0
- metadata +177 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
#ifndef STK_WVIN_H
|
2
|
+
#define STK_WVIN_H
|
3
|
+
|
4
|
+
#include "Stk.h"
|
5
|
+
|
6
|
+
namespace stk {
|
7
|
+
|
8
|
+
/***************************************************/
|
9
|
+
/*! \class WvIn
|
10
|
+
\brief STK audio input abstract base class.
|
11
|
+
|
12
|
+
This class provides common functionality for a variety of audio
|
13
|
+
data input subclasses.
|
14
|
+
|
15
|
+
by Perry R. Cook and Gary P. Scavone, 1995--2014.
|
16
|
+
*/
|
17
|
+
/***************************************************/
|
18
|
+
|
19
|
+
class WvIn : public Stk
|
20
|
+
{
|
21
|
+
public:
|
22
|
+
//! Return the number of audio channels in the data or stream.
|
23
|
+
unsigned int channelsOut( void ) const { return data_.channels(); };
|
24
|
+
|
25
|
+
//! Return an StkFrames reference to the last computed sample frame.
|
26
|
+
/*!
|
27
|
+
If no file data is loaded, an empty container is returned.
|
28
|
+
*/
|
29
|
+
const StkFrames& lastFrame( void ) const { return lastFrame_; };
|
30
|
+
|
31
|
+
//! Compute one sample frame and return the specified \c channel value.
|
32
|
+
virtual StkFloat tick( unsigned int channel = 0 ) = 0;
|
33
|
+
|
34
|
+
//! Fill the StkFrames object with computed sample frames, starting at the specified channel and return the same reference.
|
35
|
+
virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ) = 0;
|
36
|
+
|
37
|
+
protected:
|
38
|
+
|
39
|
+
StkFrames data_;
|
40
|
+
StkFrames lastFrame_;
|
41
|
+
|
42
|
+
};
|
43
|
+
|
44
|
+
} // stk namespace
|
45
|
+
|
46
|
+
#endif
|
@@ -0,0 +1,78 @@
|
|
1
|
+
/***************************************************/
|
2
|
+
/*! \class Blit
|
3
|
+
\brief STK band-limited impulse train class.
|
4
|
+
|
5
|
+
This class generates a band-limited impulse train using a
|
6
|
+
closed-form algorithm reported by Stilson and Smith in "Alias-Free
|
7
|
+
Digital Synthesis of Classic Analog Waveforms", 1996. The user
|
8
|
+
can specify both the fundamental frequency of the impulse train
|
9
|
+
and the number of harmonics contained in the resulting signal.
|
10
|
+
|
11
|
+
The signal is normalized so that the peak value is +/-1.0.
|
12
|
+
|
13
|
+
If nHarmonics is 0, then the signal will contain all harmonics up
|
14
|
+
to half the sample rate. Note, however, that this setting may
|
15
|
+
produce aliasing in the signal when the frequency is changing (no
|
16
|
+
automatic modification of the number of harmonics is performed by
|
17
|
+
the setFrequency() function).
|
18
|
+
|
19
|
+
Original code by Robin Davies, 2005.
|
20
|
+
Revisions by Gary Scavone for STK, 2005.
|
21
|
+
*/
|
22
|
+
/***************************************************/
|
23
|
+
|
24
|
+
#include "Blit.h"
|
25
|
+
|
26
|
+
namespace stk {
|
27
|
+
|
28
|
+
Blit:: Blit( StkFloat frequency )
|
29
|
+
{
|
30
|
+
if ( frequency <= 0.0 ) {
|
31
|
+
oStream_ << "Blit::Blit: argument (" << frequency << ") must be positive!";
|
32
|
+
handleError( StkError::FUNCTION_ARGUMENT );
|
33
|
+
}
|
34
|
+
|
35
|
+
nHarmonics_ = 0;
|
36
|
+
this->setFrequency( frequency );
|
37
|
+
this->reset();
|
38
|
+
}
|
39
|
+
|
40
|
+
Blit :: ~Blit()
|
41
|
+
{
|
42
|
+
}
|
43
|
+
|
44
|
+
void Blit :: reset()
|
45
|
+
{
|
46
|
+
phase_ = 0.0;
|
47
|
+
lastFrame_[0] = 0.0;
|
48
|
+
}
|
49
|
+
|
50
|
+
void Blit :: setFrequency( StkFloat frequency )
|
51
|
+
{
|
52
|
+
if ( frequency <= 0.0 ) {
|
53
|
+
oStream_ << "Blit::setFrequency: argument (" << frequency << ") must be positive!";
|
54
|
+
handleError( StkError::WARNING ); return;
|
55
|
+
}
|
56
|
+
|
57
|
+
p_ = Stk::sampleRate() / frequency;
|
58
|
+
rate_ = PI / p_;
|
59
|
+
this->updateHarmonics();
|
60
|
+
}
|
61
|
+
|
62
|
+
void Blit :: setHarmonics( unsigned int nHarmonics )
|
63
|
+
{
|
64
|
+
nHarmonics_ = nHarmonics;
|
65
|
+
this->updateHarmonics();
|
66
|
+
}
|
67
|
+
|
68
|
+
void Blit :: updateHarmonics( void )
|
69
|
+
{
|
70
|
+
if ( nHarmonics_ <= 0 ) {
|
71
|
+
unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );
|
72
|
+
m_ = 2 * maxHarmonics + 1;
|
73
|
+
}
|
74
|
+
else
|
75
|
+
m_ = 2 * nHarmonics_ + 1;
|
76
|
+
}
|
77
|
+
|
78
|
+
} // stk namespace
|
@@ -0,0 +1,91 @@
|
|
1
|
+
/***************************************************/
|
2
|
+
/*! \class BlitSaw
|
3
|
+
\brief STK band-limited sawtooth wave class.
|
4
|
+
|
5
|
+
This class generates a band-limited sawtooth waveform using a
|
6
|
+
closed-form algorithm reported by Stilson and Smith in "Alias-Free
|
7
|
+
Digital Synthesis of Classic Analog Waveforms", 1996. The user
|
8
|
+
can specify both the fundamental frequency of the sawtooth and the
|
9
|
+
number of harmonics contained in the resulting signal.
|
10
|
+
|
11
|
+
If nHarmonics is 0, then the signal will contain all harmonics up
|
12
|
+
to half the sample rate. Note, however, that this setting may
|
13
|
+
produce aliasing in the signal when the frequency is changing (no
|
14
|
+
automatic modification of the number of harmonics is performed by
|
15
|
+
the setFrequency() function).
|
16
|
+
|
17
|
+
Based on initial code of Robin Davies, 2005.
|
18
|
+
Modified algorithm code by Gary Scavone, 2005.
|
19
|
+
*/
|
20
|
+
/***************************************************/
|
21
|
+
|
22
|
+
#include "BlitSaw.h"
|
23
|
+
|
24
|
+
namespace stk {
|
25
|
+
|
26
|
+
BlitSaw:: BlitSaw( StkFloat frequency )
|
27
|
+
{
|
28
|
+
if ( frequency <= 0.0 ) {
|
29
|
+
oStream_ << "BlitSaw::BlitSaw: argument (" << frequency << ") must be positive!";
|
30
|
+
handleError( StkError::FUNCTION_ARGUMENT );
|
31
|
+
}
|
32
|
+
|
33
|
+
nHarmonics_ = 0;
|
34
|
+
this->reset();
|
35
|
+
this->setFrequency( frequency );
|
36
|
+
}
|
37
|
+
|
38
|
+
BlitSaw :: ~BlitSaw()
|
39
|
+
{
|
40
|
+
}
|
41
|
+
|
42
|
+
void BlitSaw :: reset()
|
43
|
+
{
|
44
|
+
phase_ = 0.0f;
|
45
|
+
state_ = 0.0;
|
46
|
+
lastFrame_[0] = 0.0;
|
47
|
+
}
|
48
|
+
|
49
|
+
void BlitSaw :: setFrequency( StkFloat frequency )
|
50
|
+
{
|
51
|
+
if ( frequency <= 0.0 ) {
|
52
|
+
oStream_ << "BlitSaw::setFrequency: argument (" << frequency << ") must be positive!";
|
53
|
+
handleError( StkError::WARNING ); return;
|
54
|
+
}
|
55
|
+
|
56
|
+
p_ = Stk::sampleRate() / frequency;
|
57
|
+
C2_ = 1 / p_;
|
58
|
+
rate_ = PI * C2_;
|
59
|
+
this->updateHarmonics();
|
60
|
+
}
|
61
|
+
|
62
|
+
void BlitSaw :: setHarmonics( unsigned int nHarmonics )
|
63
|
+
{
|
64
|
+
nHarmonics_ = nHarmonics;
|
65
|
+
this->updateHarmonics();
|
66
|
+
|
67
|
+
// I found that the initial DC offset could be minimized with an
|
68
|
+
// initial state setting as given below. This initialization should
|
69
|
+
// only happen before starting the oscillator for the first time
|
70
|
+
// (but after setting the frequency and number of harmonics). I
|
71
|
+
// struggled a bit to decide where best to put this and finally
|
72
|
+
// settled on here. In general, the user shouldn't be messing with
|
73
|
+
// the number of harmonics once the oscillator is running because
|
74
|
+
// this is automatically taken care of in the setFrequency()
|
75
|
+
// function. (GPS - 1 October 2005)
|
76
|
+
state_ = -0.5 * a_;
|
77
|
+
}
|
78
|
+
|
79
|
+
void BlitSaw :: updateHarmonics( void )
|
80
|
+
{
|
81
|
+
if ( nHarmonics_ <= 0 ) {
|
82
|
+
unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );
|
83
|
+
m_ = 2 * maxHarmonics + 1;
|
84
|
+
}
|
85
|
+
else
|
86
|
+
m_ = 2 * nHarmonics_ + 1;
|
87
|
+
|
88
|
+
a_ = m_ / p_;
|
89
|
+
}
|
90
|
+
|
91
|
+
} // stk namespace
|
@@ -0,0 +1,95 @@
|
|
1
|
+
/***************************************************/
|
2
|
+
/*! \class BlitSquare
|
3
|
+
\brief STK band-limited square wave class.
|
4
|
+
|
5
|
+
This class generates a band-limited square wave signal. It is
|
6
|
+
derived in part from the approach reported by Stilson and Smith in
|
7
|
+
"Alias-Free Digital Synthesis of Classic Analog Waveforms", 1996.
|
8
|
+
The algorithm implemented in this class uses a SincM function with
|
9
|
+
an even M value to achieve a bipolar bandlimited impulse train.
|
10
|
+
This signal is then integrated to achieve a square waveform. The
|
11
|
+
integration process has an associated DC offset so a DC blocking
|
12
|
+
filter is applied at the output.
|
13
|
+
|
14
|
+
The user can specify both the fundamental frequency of the
|
15
|
+
waveform and the number of harmonics contained in the resulting
|
16
|
+
signal.
|
17
|
+
|
18
|
+
If nHarmonics is 0, then the signal will contain all harmonics up
|
19
|
+
to half the sample rate. Note, however, that this setting may
|
20
|
+
produce aliasing in the signal when the frequency is changing (no
|
21
|
+
automatic modification of the number of harmonics is performed by
|
22
|
+
the setFrequency() function). Also note that the harmonics of a
|
23
|
+
square wave fall at odd integer multiples of the fundamental, so
|
24
|
+
aliasing will happen with a lower fundamental than with the other
|
25
|
+
Blit waveforms. This class is not guaranteed to be well behaved
|
26
|
+
in the presence of significant aliasing.
|
27
|
+
|
28
|
+
Based on initial code of Robin Davies, 2005
|
29
|
+
Modified algorithm code by Gary Scavone, 2005 - 2010.
|
30
|
+
*/
|
31
|
+
/***************************************************/
|
32
|
+
|
33
|
+
#include "BlitSquare.h"
|
34
|
+
|
35
|
+
namespace stk {
|
36
|
+
|
37
|
+
BlitSquare:: BlitSquare( StkFloat frequency )
|
38
|
+
{
|
39
|
+
if ( frequency <= 0.0 ) {
|
40
|
+
oStream_ << "BlitSquare::BlitSquare: argument (" << frequency << ") must be positive!";
|
41
|
+
handleError( StkError::FUNCTION_ARGUMENT );
|
42
|
+
}
|
43
|
+
|
44
|
+
nHarmonics_ = 0;
|
45
|
+
this->setFrequency( frequency );
|
46
|
+
this->reset();
|
47
|
+
}
|
48
|
+
|
49
|
+
BlitSquare :: ~BlitSquare()
|
50
|
+
{
|
51
|
+
}
|
52
|
+
|
53
|
+
void BlitSquare :: reset()
|
54
|
+
{
|
55
|
+
phase_ = 0.0;
|
56
|
+
lastFrame_[0] = 0.0;
|
57
|
+
dcbState_ = 0.0;
|
58
|
+
lastBlitOutput_ = 0;
|
59
|
+
}
|
60
|
+
|
61
|
+
void BlitSquare :: setFrequency( StkFloat frequency )
|
62
|
+
{
|
63
|
+
if ( frequency <= 0.0 ) {
|
64
|
+
oStream_ << "BlitSquare::setFrequency: argument (" << frequency << ") must be positive!";
|
65
|
+
handleError( StkError::WARNING ); return;
|
66
|
+
}
|
67
|
+
|
68
|
+
// By using an even value of the parameter M, we get a bipolar blit
|
69
|
+
// waveform at half the blit frequency. Thus, we need to scale the
|
70
|
+
// frequency value here by 0.5. (GPS, 2006).
|
71
|
+
p_ = 0.5 * Stk::sampleRate() / frequency;
|
72
|
+
rate_ = PI / p_;
|
73
|
+
this->updateHarmonics();
|
74
|
+
}
|
75
|
+
|
76
|
+
void BlitSquare :: setHarmonics( unsigned int nHarmonics )
|
77
|
+
{
|
78
|
+
nHarmonics_ = nHarmonics;
|
79
|
+
this->updateHarmonics();
|
80
|
+
}
|
81
|
+
|
82
|
+
void BlitSquare :: updateHarmonics( void )
|
83
|
+
{
|
84
|
+
// Make sure we end up with an even value of the parameter M here.
|
85
|
+
if ( nHarmonics_ <= 0 ) {
|
86
|
+
unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );
|
87
|
+
m_ = 2 * (maxHarmonics + 1);
|
88
|
+
}
|
89
|
+
else
|
90
|
+
m_ = 2 * (nHarmonics_ + 1);
|
91
|
+
|
92
|
+
a_ = m_ / p_;
|
93
|
+
}
|
94
|
+
|
95
|
+
} // stk namespace
|
@@ -0,0 +1,903 @@
|
|
1
|
+
/***************************************************/
|
2
|
+
/*! \class FileRead
|
3
|
+
\brief STK audio file input class.
|
4
|
+
|
5
|
+
This class provides input support for various
|
6
|
+
audio file formats. Multi-channel (>2)
|
7
|
+
soundfiles are supported. The file data is
|
8
|
+
returned via an external StkFrames object
|
9
|
+
passed to the read() function. This class
|
10
|
+
does not store its own copy of the file data,
|
11
|
+
rather the data is read directly from disk.
|
12
|
+
|
13
|
+
FileRead currently supports uncompressed WAV,
|
14
|
+
AIFF/AIFC, SND (AU), MAT-file (Matlab), and
|
15
|
+
STK RAW file formats. Signed integer (8-,
|
16
|
+
16-, 24- and 32-bit) and floating-point (32- and
|
17
|
+
64-bit) data types are supported. Compressed
|
18
|
+
data types are not supported.
|
19
|
+
|
20
|
+
STK RAW files have no header and are assumed to
|
21
|
+
contain a monophonic stream of 16-bit signed
|
22
|
+
integers in big-endian byte order at a sample
|
23
|
+
rate of 22050 Hz. MAT-file data should be saved
|
24
|
+
in an array with each data channel filling a
|
25
|
+
matrix row. The sample rate for MAT-files should
|
26
|
+
be specified in a variable named "fs". If no
|
27
|
+
such variable is found, the sample rate is
|
28
|
+
assumed to be 44100 Hz.
|
29
|
+
|
30
|
+
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
|
31
|
+
*/
|
32
|
+
/***************************************************/
|
33
|
+
|
34
|
+
#include "FileRead.h"
|
35
|
+
#include <sys/stat.h>
|
36
|
+
#include <sys/types.h>
|
37
|
+
#include <cstring>
|
38
|
+
#include <cmath>
|
39
|
+
#include <cstdio>
|
40
|
+
|
41
|
+
namespace stk {
|
42
|
+
|
43
|
+
FileRead :: FileRead()
|
44
|
+
: fd_(0), fileSize_(0), channels_(0), dataType_(0), fileRate_(0.0)
|
45
|
+
{
|
46
|
+
}
|
47
|
+
|
48
|
+
FileRead :: FileRead( std::string fileName, bool typeRaw, unsigned int nChannels,
|
49
|
+
StkFormat format, StkFloat rate )
|
50
|
+
: fd_(0)
|
51
|
+
{
|
52
|
+
open( fileName, typeRaw, nChannels, format, rate );
|
53
|
+
}
|
54
|
+
|
55
|
+
FileRead :: ~FileRead()
|
56
|
+
{
|
57
|
+
if ( fd_ )
|
58
|
+
fclose( fd_ );
|
59
|
+
}
|
60
|
+
|
61
|
+
void FileRead :: close( void )
|
62
|
+
{
|
63
|
+
if ( fd_ ) fclose( fd_ );
|
64
|
+
fd_ = 0;
|
65
|
+
wavFile_ = false;
|
66
|
+
fileSize_ = 0;
|
67
|
+
channels_ = 0;
|
68
|
+
dataType_ = 0;
|
69
|
+
fileRate_ = 0.0;
|
70
|
+
}
|
71
|
+
|
72
|
+
bool FileRead :: isOpen( void )
|
73
|
+
{
|
74
|
+
if ( fd_ ) return true;
|
75
|
+
else return false;
|
76
|
+
}
|
77
|
+
|
78
|
+
void FileRead :: open( std::string fileName, bool typeRaw, unsigned int nChannels,
|
79
|
+
StkFormat format, StkFloat rate )
|
80
|
+
{
|
81
|
+
// If another file is open, close it.
|
82
|
+
close();
|
83
|
+
|
84
|
+
// Try to open the file.
|
85
|
+
fd_ = fopen( fileName.c_str(), "rb" );
|
86
|
+
if ( !fd_ ) {
|
87
|
+
oStream_ << "FileRead::open: could not open or find file (" << fileName << ")!";
|
88
|
+
handleError( StkError::FILE_NOT_FOUND );
|
89
|
+
}
|
90
|
+
|
91
|
+
// Attempt to determine file type from header (unless RAW).
|
92
|
+
bool result = false;
|
93
|
+
if ( typeRaw )
|
94
|
+
result = getRawInfo( fileName.c_str(), nChannels, format, rate );
|
95
|
+
else {
|
96
|
+
char header[12];
|
97
|
+
if ( fread( &header, 4, 3, fd_ ) != 3 ) goto error;
|
98
|
+
if ( !strncmp( header, "RIFF", 4 ) &&
|
99
|
+
!strncmp( &header[8], "WAVE", 4 ) )
|
100
|
+
result = getWavInfo( fileName.c_str() );
|
101
|
+
else if ( !strncmp( header, ".snd", 4 ) )
|
102
|
+
result = getSndInfo( fileName.c_str() );
|
103
|
+
else if ( !strncmp( header, "FORM", 4 ) &&
|
104
|
+
( !strncmp( &header[8], "AIFF", 4 ) || !strncmp(&header[8], "AIFC", 4) ) )
|
105
|
+
result = getAifInfo( fileName.c_str() );
|
106
|
+
else {
|
107
|
+
if ( fseek( fd_, 126, SEEK_SET ) == -1 ) goto error;
|
108
|
+
if ( fread( &header, 2, 1, fd_ ) != 1 ) goto error;
|
109
|
+
if ( !strncmp( header, "MI", 2 ) ||
|
110
|
+
!strncmp( header, "IM", 2 ) )
|
111
|
+
result = getMatInfo( fileName.c_str() );
|
112
|
+
else {
|
113
|
+
oStream_ << "FileRead::open: file (" << fileName << ") format unknown.";
|
114
|
+
handleError( StkError::FILE_UNKNOWN_FORMAT );
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
// If here, we had a file type candidate but something else went wrong.
|
120
|
+
if ( result == false )
|
121
|
+
handleError( StkError::FILE_ERROR );
|
122
|
+
|
123
|
+
// Check for empty files.
|
124
|
+
if ( fileSize_ == 0 ) {
|
125
|
+
oStream_ << "FileRead::open: file (" << fileName << ") data size is zero!";
|
126
|
+
handleError( StkError::FILE_ERROR );
|
127
|
+
}
|
128
|
+
|
129
|
+
return;
|
130
|
+
|
131
|
+
error:
|
132
|
+
oStream_ << "FileRead::open: error reading file (" << fileName << ")!";
|
133
|
+
handleError( StkError::FILE_ERROR );
|
134
|
+
}
|
135
|
+
|
136
|
+
bool FileRead :: getRawInfo( const char *fileName, unsigned int nChannels, StkFormat format, StkFloat rate )
|
137
|
+
{
|
138
|
+
// Use the system call "stat" to determine the file length.
|
139
|
+
struct stat filestat;
|
140
|
+
if ( stat(fileName, &filestat) == -1 ) {
|
141
|
+
oStream_ << "FileRead: Could not stat RAW file (" << fileName << ").";
|
142
|
+
return false;
|
143
|
+
}
|
144
|
+
if ( nChannels == 0 ) {
|
145
|
+
oStream_ << "FileRead: number of channels can't be 0 (" << fileName << ").";
|
146
|
+
return false;
|
147
|
+
}
|
148
|
+
|
149
|
+
// Rawwave files have no header and by default, are assumed to
|
150
|
+
// contain a monophonic stream of 16-bit signed integers in
|
151
|
+
// big-endian byte order at a sample rate of 22050 Hz. However,
|
152
|
+
// different parameters can be specified if desired.
|
153
|
+
dataOffset_ = 0;
|
154
|
+
channels_ = nChannels;
|
155
|
+
dataType_ = format;
|
156
|
+
fileRate_ = rate;
|
157
|
+
int sampleBytes = 0;
|
158
|
+
if ( format == STK_SINT8 ) sampleBytes = 1;
|
159
|
+
else if ( format == STK_SINT16 ) sampleBytes = 2;
|
160
|
+
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) sampleBytes = 4;
|
161
|
+
else if ( format == STK_FLOAT64 ) sampleBytes = 8;
|
162
|
+
else {
|
163
|
+
oStream_ << "FileRead: StkFormat " << format << " is invalid (" << fileName << ").";
|
164
|
+
return false;
|
165
|
+
}
|
166
|
+
|
167
|
+
fileSize_ = (long) filestat.st_size / sampleBytes / channels_; // length in frames
|
168
|
+
|
169
|
+
byteswap_ = false;
|
170
|
+
#ifdef __LITTLE_ENDIAN__
|
171
|
+
byteswap_ = true;
|
172
|
+
#endif
|
173
|
+
|
174
|
+
return true;
|
175
|
+
}
|
176
|
+
|
177
|
+
bool FileRead :: getWavInfo( const char *fileName )
|
178
|
+
{
|
179
|
+
// Find "format" chunk ... it must come before the "data" chunk.
|
180
|
+
char id[4];
|
181
|
+
SINT32 chunkSize;
|
182
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
183
|
+
while ( strncmp(id, "fmt ", 4) ) {
|
184
|
+
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
|
185
|
+
#ifndef __LITTLE_ENDIAN__
|
186
|
+
swap32((unsigned char *)&chunkSize);
|
187
|
+
#endif
|
188
|
+
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
|
189
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
190
|
+
}
|
191
|
+
|
192
|
+
// Check that the data is not compressed.
|
193
|
+
unsigned short format_tag;
|
194
|
+
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; // Read fmt chunk size.
|
195
|
+
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
|
196
|
+
#ifndef __LITTLE_ENDIAN__
|
197
|
+
swap16((unsigned char *)&format_tag);
|
198
|
+
swap32((unsigned char *)&chunkSize);
|
199
|
+
#endif
|
200
|
+
if ( format_tag == 0xFFFE ) { // WAVE_FORMAT_EXTENSIBLE
|
201
|
+
dataOffset_ = ftell(fd_);
|
202
|
+
if ( fseek(fd_, 14, SEEK_CUR) == -1 ) goto error;
|
203
|
+
unsigned short extSize;
|
204
|
+
if ( fread(&extSize, 2, 1, fd_) != 1 ) goto error;
|
205
|
+
#ifndef __LITTLE_ENDIAN__
|
206
|
+
swap16((unsigned char *)&extSize);
|
207
|
+
#endif
|
208
|
+
if ( extSize == 0 ) goto error;
|
209
|
+
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error;
|
210
|
+
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
|
211
|
+
#ifndef __LITTLE_ENDIAN__
|
212
|
+
swap16((unsigned char *)&format_tag);
|
213
|
+
#endif
|
214
|
+
if ( fseek(fd_, dataOffset_, SEEK_SET) == -1 ) goto error;
|
215
|
+
}
|
216
|
+
if ( format_tag != 1 && format_tag != 3 ) { // PCM = 1, FLOAT = 3
|
217
|
+
oStream_ << "FileRead: "<< fileName << " contains an unsupported data format type (" << format_tag << ").";
|
218
|
+
return false;
|
219
|
+
}
|
220
|
+
|
221
|
+
// Get number of channels from the header.
|
222
|
+
SINT16 temp;
|
223
|
+
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
|
224
|
+
#ifndef __LITTLE_ENDIAN__
|
225
|
+
swap16((unsigned char *)&temp);
|
226
|
+
#endif
|
227
|
+
channels_ = (unsigned int ) temp;
|
228
|
+
|
229
|
+
// Get file sample rate from the header.
|
230
|
+
SINT32 srate;
|
231
|
+
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
|
232
|
+
#ifndef __LITTLE_ENDIAN__
|
233
|
+
swap32((unsigned char *)&srate);
|
234
|
+
#endif
|
235
|
+
fileRate_ = (StkFloat) srate;
|
236
|
+
|
237
|
+
// Determine the data type.
|
238
|
+
dataType_ = 0;
|
239
|
+
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; // Locate bits_per_sample info.
|
240
|
+
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
|
241
|
+
#ifndef __LITTLE_ENDIAN__
|
242
|
+
swap16((unsigned char *)&temp);
|
243
|
+
#endif
|
244
|
+
if ( format_tag == 1 ) {
|
245
|
+
if ( temp == 8 )
|
246
|
+
dataType_ = STK_SINT8;
|
247
|
+
else if ( temp == 16 )
|
248
|
+
dataType_ = STK_SINT16;
|
249
|
+
else if ( temp == 24 )
|
250
|
+
dataType_ = STK_SINT24;
|
251
|
+
else if ( temp == 32 )
|
252
|
+
dataType_ = STK_SINT32;
|
253
|
+
}
|
254
|
+
else if ( format_tag == 3 ) {
|
255
|
+
if ( temp == 32 )
|
256
|
+
dataType_ = STK_FLOAT32;
|
257
|
+
else if ( temp == 64 )
|
258
|
+
dataType_ = STK_FLOAT64;
|
259
|
+
}
|
260
|
+
if ( dataType_ == 0 ) {
|
261
|
+
oStream_ << "FileRead: " << temp << " bits per sample with data format " << format_tag << " are not supported (" << fileName << ").";
|
262
|
+
return false;
|
263
|
+
}
|
264
|
+
|
265
|
+
// Jump over any remaining part of the "fmt" chunk.
|
266
|
+
if ( fseek(fd_, chunkSize-16, SEEK_CUR) == -1 ) goto error;
|
267
|
+
|
268
|
+
// Find "data" chunk ... it must come after the "fmt" chunk.
|
269
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
270
|
+
|
271
|
+
while ( strncmp(id, "data", 4) ) {
|
272
|
+
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
|
273
|
+
#ifndef __LITTLE_ENDIAN__
|
274
|
+
swap32((unsigned char *)&chunkSize);
|
275
|
+
#endif
|
276
|
+
chunkSize += chunkSize % 2; // chunk sizes must be even
|
277
|
+
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
|
278
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
279
|
+
}
|
280
|
+
|
281
|
+
// Get length of data from the header.
|
282
|
+
SINT32 bytes;
|
283
|
+
if ( fread(&bytes, 4, 1, fd_) != 1 ) goto error;
|
284
|
+
#ifndef __LITTLE_ENDIAN__
|
285
|
+
swap32((unsigned char *)&bytes);
|
286
|
+
#endif
|
287
|
+
fileSize_ = bytes / temp / channels_; // sample frames
|
288
|
+
fileSize_ *= 8; // sample frames
|
289
|
+
|
290
|
+
dataOffset_ = ftell(fd_);
|
291
|
+
byteswap_ = false;
|
292
|
+
#ifndef __LITTLE_ENDIAN__
|
293
|
+
byteswap_ = true;
|
294
|
+
#endif
|
295
|
+
|
296
|
+
wavFile_ = true;
|
297
|
+
return true;
|
298
|
+
|
299
|
+
error:
|
300
|
+
oStream_ << "FileRead: error reading WAV file (" << fileName << ").";
|
301
|
+
return false;
|
302
|
+
}
|
303
|
+
|
304
|
+
bool FileRead :: getSndInfo( const char *fileName )
|
305
|
+
{
|
306
|
+
// Determine the data type.
|
307
|
+
UINT32 format;
|
308
|
+
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Locate format
|
309
|
+
if ( fread(&format, 4, 1, fd_) != 1 ) goto error;
|
310
|
+
#ifdef __LITTLE_ENDIAN__
|
311
|
+
swap32((unsigned char *)&format);
|
312
|
+
#endif
|
313
|
+
|
314
|
+
if (format == 2) dataType_ = STK_SINT8;
|
315
|
+
else if (format == 3) dataType_ = STK_SINT16;
|
316
|
+
else if (format == 4) dataType_ = STK_SINT24;
|
317
|
+
else if (format == 5) dataType_ = STK_SINT32;
|
318
|
+
else if (format == 6) dataType_ = STK_FLOAT32;
|
319
|
+
else if (format == 7) dataType_ = STK_FLOAT64;
|
320
|
+
else {
|
321
|
+
oStream_ << "FileRead: data format in file " << fileName << " is not supported.";
|
322
|
+
return false;
|
323
|
+
}
|
324
|
+
|
325
|
+
// Get file sample rate from the header.
|
326
|
+
UINT32 srate;
|
327
|
+
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
|
328
|
+
#ifdef __LITTLE_ENDIAN__
|
329
|
+
swap32((unsigned char *)&srate);
|
330
|
+
#endif
|
331
|
+
fileRate_ = (StkFloat) srate;
|
332
|
+
|
333
|
+
// Get number of channels from the header.
|
334
|
+
UINT32 chans;
|
335
|
+
if ( fread(&chans, 4, 1, fd_) != 1 ) goto error;
|
336
|
+
#ifdef __LITTLE_ENDIAN__
|
337
|
+
swap32((unsigned char *)&chans);
|
338
|
+
#endif
|
339
|
+
channels_ = chans;
|
340
|
+
|
341
|
+
UINT32 offset;
|
342
|
+
if ( fseek(fd_, 4, SEEK_SET) == -1 ) goto error;
|
343
|
+
if ( fread(&offset, 4, 1, fd_) != 1 ) goto error;
|
344
|
+
#ifdef __LITTLE_ENDIAN__
|
345
|
+
swap32((unsigned char *)&offset);
|
346
|
+
#endif
|
347
|
+
dataOffset_ = offset;
|
348
|
+
|
349
|
+
// Get length of data from the header.
|
350
|
+
if ( fread(&fileSize_, 4, 1, fd_) != 1 ) goto error;
|
351
|
+
#ifdef __LITTLE_ENDIAN__
|
352
|
+
swap32((unsigned char *)&fileSize_);
|
353
|
+
#endif
|
354
|
+
// Convert to sample frames.
|
355
|
+
if ( dataType_ == STK_SINT8 )
|
356
|
+
fileSize_ /= channels_;
|
357
|
+
if ( dataType_ == STK_SINT16 )
|
358
|
+
fileSize_ /= 2 * channels_;
|
359
|
+
else if ( dataType_ == STK_SINT24 )
|
360
|
+
fileSize_ /= 3 * channels_;
|
361
|
+
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
|
362
|
+
fileSize_ /= 4 * channels_;
|
363
|
+
else if ( dataType_ == STK_FLOAT64 )
|
364
|
+
fileSize_ /= 8 * channels_;
|
365
|
+
|
366
|
+
byteswap_ = false;
|
367
|
+
#ifdef __LITTLE_ENDIAN__
|
368
|
+
byteswap_ = true;
|
369
|
+
#endif
|
370
|
+
|
371
|
+
return true;
|
372
|
+
|
373
|
+
error:
|
374
|
+
oStream_ << "FileRead: Error reading SND file (" << fileName << ").";
|
375
|
+
return false;
|
376
|
+
}
|
377
|
+
|
378
|
+
bool FileRead :: getAifInfo( const char *fileName )
|
379
|
+
{
|
380
|
+
bool aifc = false;
|
381
|
+
char id[4];
|
382
|
+
|
383
|
+
// Determine whether this is AIFF or AIFC.
|
384
|
+
if ( fseek(fd_, 8, SEEK_SET) == -1 ) goto error;
|
385
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
386
|
+
if ( !strncmp(id, "AIFC", 4) ) aifc = true;
|
387
|
+
|
388
|
+
// Find "common" chunk
|
389
|
+
SINT32 chunkSize;
|
390
|
+
if ( fread(&id, 4, 1, fd_) != 1) goto error;
|
391
|
+
while ( strncmp(id, "COMM", 4) ) {
|
392
|
+
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
|
393
|
+
#ifdef __LITTLE_ENDIAN__
|
394
|
+
swap32((unsigned char *)&chunkSize);
|
395
|
+
#endif
|
396
|
+
chunkSize += chunkSize % 2; // chunk sizes must be even
|
397
|
+
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
|
398
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
399
|
+
}
|
400
|
+
|
401
|
+
// Get number of channels from the header.
|
402
|
+
SINT16 temp;
|
403
|
+
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; // Jump over chunk size
|
404
|
+
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
|
405
|
+
#ifdef __LITTLE_ENDIAN__
|
406
|
+
swap16((unsigned char *)&temp);
|
407
|
+
#endif
|
408
|
+
channels_ = temp;
|
409
|
+
|
410
|
+
// Get length of data from the header.
|
411
|
+
SINT32 frames;
|
412
|
+
if ( fread(&frames, 4, 1, fd_) != 1 ) goto error;
|
413
|
+
#ifdef __LITTLE_ENDIAN__
|
414
|
+
swap32((unsigned char *)&frames);
|
415
|
+
#endif
|
416
|
+
fileSize_ = frames; // sample frames
|
417
|
+
|
418
|
+
// Read the number of bits per sample.
|
419
|
+
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
|
420
|
+
#ifdef __LITTLE_ENDIAN__
|
421
|
+
swap16((unsigned char *)&temp);
|
422
|
+
#endif
|
423
|
+
|
424
|
+
// Get file sample rate from the header. For AIFF files, this value
|
425
|
+
// is stored in a 10-byte, IEEE Standard 754 floating point number,
|
426
|
+
// so we need to convert it first.
|
427
|
+
unsigned char srate[10];
|
428
|
+
unsigned char exp;
|
429
|
+
unsigned long mantissa;
|
430
|
+
unsigned long last;
|
431
|
+
if ( fread(&srate, 10, 1, fd_) != 1 ) goto error;
|
432
|
+
mantissa = (unsigned long) *(unsigned long *)(srate+2);
|
433
|
+
#ifdef __LITTLE_ENDIAN__
|
434
|
+
swap32((unsigned char *)&mantissa);
|
435
|
+
#endif
|
436
|
+
exp = 30 - *(srate+1);
|
437
|
+
last = 0;
|
438
|
+
while (exp--) {
|
439
|
+
last = mantissa;
|
440
|
+
mantissa >>= 1;
|
441
|
+
}
|
442
|
+
if (last & 0x00000001) mantissa++;
|
443
|
+
fileRate_ = (StkFloat) mantissa;
|
444
|
+
|
445
|
+
byteswap_ = false;
|
446
|
+
#ifdef __LITTLE_ENDIAN__
|
447
|
+
byteswap_ = true;
|
448
|
+
#endif
|
449
|
+
|
450
|
+
// Determine the data format.
|
451
|
+
dataType_ = 0;
|
452
|
+
if ( aifc == false ) {
|
453
|
+
if ( temp <= 8 ) dataType_ = STK_SINT8;
|
454
|
+
else if ( temp <= 16 ) dataType_ = STK_SINT16;
|
455
|
+
else if ( temp <= 24 ) dataType_ = STK_SINT24;
|
456
|
+
else if ( temp <= 32 ) dataType_ = STK_SINT32;
|
457
|
+
}
|
458
|
+
else {
|
459
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
460
|
+
if ( !strncmp(id, "sowt", 4) ) { // uncompressed little-endian
|
461
|
+
if ( byteswap_ == false ) byteswap_ = true;
|
462
|
+
else byteswap_ = false;
|
463
|
+
}
|
464
|
+
if ( !strncmp(id, "NONE", 4) || !strncmp(id, "sowt", 4) ) {
|
465
|
+
if ( temp <= 8 ) dataType_ = STK_SINT8;
|
466
|
+
else if ( temp <= 16 ) dataType_ = STK_SINT16;
|
467
|
+
else if ( temp <= 24 ) dataType_ = STK_SINT24;
|
468
|
+
else if ( temp <= 32 ) dataType_ = STK_SINT32;
|
469
|
+
}
|
470
|
+
else if ( (!strncmp(id, "fl32", 4) || !strncmp(id, "FL32", 4)) && temp == 32 ) dataType_ = STK_FLOAT32;
|
471
|
+
else if ( (!strncmp(id, "fl64", 4) || !strncmp(id, "FL64", 4)) && temp == 64 ) dataType_ = STK_FLOAT64;
|
472
|
+
}
|
473
|
+
if ( dataType_ == 0 ) {
|
474
|
+
oStream_ << "FileRead: AIFF/AIFC file (" << fileName << ") has unsupported data type (" << id << ").";
|
475
|
+
return false;
|
476
|
+
}
|
477
|
+
|
478
|
+
// Start at top to find data (SSND) chunk ... chunk order is undefined.
|
479
|
+
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error;
|
480
|
+
|
481
|
+
// Find data (SSND) chunk
|
482
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
483
|
+
while ( strncmp(id, "SSND", 4) ) {
|
484
|
+
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
|
485
|
+
#ifdef __LITTLE_ENDIAN__
|
486
|
+
swap32((unsigned char *)&chunkSize);
|
487
|
+
#endif
|
488
|
+
chunkSize += chunkSize % 2; // chunk sizes must be even
|
489
|
+
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
|
490
|
+
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
|
491
|
+
}
|
492
|
+
|
493
|
+
// Skip over chunk size, offset, and blocksize fields
|
494
|
+
if ( fseek(fd_, 12, SEEK_CUR) == -1 ) goto error;
|
495
|
+
|
496
|
+
dataOffset_ = ftell(fd_);
|
497
|
+
return true;
|
498
|
+
|
499
|
+
error:
|
500
|
+
oStream_ << "FileRead: Error reading AIFF file (" << fileName << ").";
|
501
|
+
return false;
|
502
|
+
}
|
503
|
+
|
504
|
+
bool FileRead :: findNextMatArray( SINT32 *chunkSize, SINT32 *rows, SINT32 *columns, SINT32 *nametype )
|
505
|
+
{
|
506
|
+
// Look for the next data array element. The file pointer should be
|
507
|
+
// at the data element type when this function is called.
|
508
|
+
SINT32 datatype;
|
509
|
+
*chunkSize = 0;
|
510
|
+
do {
|
511
|
+
if ( fseek(fd_, *chunkSize, SEEK_CUR) == -1 ) return false;
|
512
|
+
if ( fread(&datatype, 4, 1, fd_) != 1 ) return false;
|
513
|
+
if ( byteswap_ ) swap32((unsigned char *)&datatype);
|
514
|
+
if ( fread(chunkSize, 4, 1, fd_) != 1 ) return false;
|
515
|
+
if ( byteswap_ ) swap32((unsigned char *)chunkSize);
|
516
|
+
} while ( datatype != 14 );
|
517
|
+
|
518
|
+
// Check dimension subelement size to make sure 2D
|
519
|
+
if ( fseek(fd_, 20, SEEK_CUR) == -1 ) return false;
|
520
|
+
SINT32 size;
|
521
|
+
if ( fread(&size, 4, 1, fd_) != 1 ) return false;
|
522
|
+
if ( byteswap_ ) swap32((unsigned char *)&size);
|
523
|
+
if ( size != 8 ) return false;
|
524
|
+
|
525
|
+
// Read dimensions data
|
526
|
+
if ( fread(rows, 4, 1, fd_) != 1 ) return false;
|
527
|
+
if ( byteswap_ ) swap32((unsigned char *)rows);
|
528
|
+
if ( fread(columns, 4, 1, fd_) != 1 ) return false;
|
529
|
+
if ( byteswap_ ) swap32((unsigned char *)columns);
|
530
|
+
|
531
|
+
// Read array name subelement type
|
532
|
+
if ( fread(nametype, 4, 1, fd_) != 1 ) return false;
|
533
|
+
if ( byteswap_ ) swap32((unsigned char *)nametype);
|
534
|
+
|
535
|
+
return true;
|
536
|
+
}
|
537
|
+
|
538
|
+
bool FileRead :: getMatInfo( const char *fileName )
|
539
|
+
{
|
540
|
+
// MAT-file formatting information is available at:
|
541
|
+
// http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf
|
542
|
+
|
543
|
+
// Verify this is a version 5 MAT-file format.
|
544
|
+
char head[5];
|
545
|
+
if ( fseek(fd_, 0, SEEK_SET) == -1 ) goto error;
|
546
|
+
if ( fread(&head, 4, 1, fd_) != 1 ) goto error;
|
547
|
+
// If any of the first 4 characters of the header = 0, then this is
|
548
|
+
// a Version 4 MAT-file.
|
549
|
+
head[4] = '\0';
|
550
|
+
if ( strstr(head, "0") ) {
|
551
|
+
oStream_ << "FileRead: " << fileName << " appears to be a Version 4 MAT-file, which is not currently supported.";
|
552
|
+
return false;
|
553
|
+
}
|
554
|
+
|
555
|
+
// Determine the endian-ness of the file.
|
556
|
+
char mi[2];
|
557
|
+
byteswap_ = false;
|
558
|
+
// Locate "M" and "I" characters in header.
|
559
|
+
if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error;
|
560
|
+
if ( fread(&mi, 2, 1, fd_) != 1) goto error;
|
561
|
+
#ifdef __LITTLE_ENDIAN__
|
562
|
+
if ( !strncmp(mi, "MI", 2) )
|
563
|
+
byteswap_ = true;
|
564
|
+
else if ( strncmp(mi, "IM", 2) ) goto error;
|
565
|
+
#else
|
566
|
+
if ( !strncmp(mi, "IM", 2))
|
567
|
+
byteswap_ = true;
|
568
|
+
else if ( strncmp(mi, "MI", 2) ) goto error;
|
569
|
+
#endif
|
570
|
+
|
571
|
+
// We are expecting a data element containing the audio data and an
|
572
|
+
// optional data element containing the sample rate (with an array
|
573
|
+
// name of "fs"). Both elements should be stored as a Matlab array
|
574
|
+
// type (14).
|
575
|
+
|
576
|
+
bool doneParsing, haveData, haveSampleRate;
|
577
|
+
SINT32 chunkSize, rows, columns, nametype;
|
578
|
+
long dataoffset;
|
579
|
+
doneParsing = false;
|
580
|
+
haveData = false;
|
581
|
+
haveSampleRate = false;
|
582
|
+
while ( !doneParsing ) {
|
583
|
+
|
584
|
+
dataoffset = ftell( fd_ ); // save location in file
|
585
|
+
if ( findNextMatArray( &chunkSize, &rows, &columns, &nametype ) == false ) {
|
586
|
+
// No more Matlab array type chunks found.
|
587
|
+
if ( !haveData ) {
|
588
|
+
oStream_ << "FileRead: No audio data found in MAT-file (" << fileName << ").";
|
589
|
+
return false;
|
590
|
+
}
|
591
|
+
else if ( !haveSampleRate ) {
|
592
|
+
fileRate_ = 44100.0;
|
593
|
+
oStream_ << "FileRead: No sample rate found ... assuming 44100.0";
|
594
|
+
handleError( StkError::WARNING );
|
595
|
+
return true;
|
596
|
+
}
|
597
|
+
else return true;
|
598
|
+
}
|
599
|
+
|
600
|
+
if ( !haveSampleRate && rows == 1 && columns == 1 ) { // Parse for sample rate.
|
601
|
+
|
602
|
+
SINT32 namesize = 4;
|
603
|
+
if ( nametype == 1 ) { // array name > 4 characters
|
604
|
+
if ( fread(&namesize, 4, 1, fd_) != 1 ) goto error;
|
605
|
+
if ( byteswap_ ) swap32((unsigned char *)&namesize);
|
606
|
+
if ( namesize != 2 ) goto tryagain; // expecting name = "fs"
|
607
|
+
namesize = 8; // field must be padded to multiple of 8 bytes
|
608
|
+
}
|
609
|
+
char name[3]; name[2] = '\0';
|
610
|
+
if ( fread(&name, 2, 1, fd_) != 1) goto error;
|
611
|
+
if ( strncmp(name, "fs", 2) ) goto tryagain;
|
612
|
+
|
613
|
+
// Jump to real part data subelement, which is likely to be in a
|
614
|
+
// small data format.
|
615
|
+
if ( fseek(fd_, namesize-2, SEEK_CUR) == -1 ) goto error;
|
616
|
+
UINT32 type;
|
617
|
+
StkFloat srate;
|
618
|
+
if ( fread(&type, 4, 1, fd_) != 1 ) goto error;
|
619
|
+
if ( byteswap_ ) swap32((unsigned char *)&type);
|
620
|
+
if ( (type & 0xffff0000) != 0 ) // small data format
|
621
|
+
type = (type & 0x0000ffff);
|
622
|
+
else
|
623
|
+
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error;
|
624
|
+
if ( type == 1 ) { // SINT8
|
625
|
+
signed char rate;
|
626
|
+
if ( fread(&rate, 1, 1, fd_) != 1 ) goto error;
|
627
|
+
srate = (StkFloat) rate;
|
628
|
+
}
|
629
|
+
else if ( type == 2 ) { // UINT8
|
630
|
+
unsigned char rate;
|
631
|
+
if ( fread(&rate, 1, 1, fd_) != 1 ) goto error;
|
632
|
+
srate = (StkFloat) rate;
|
633
|
+
}
|
634
|
+
else if ( type == 3 ) { // SINT16
|
635
|
+
SINT16 rate;
|
636
|
+
if ( fread(&rate, 2, 1, fd_) != 1 ) goto error;
|
637
|
+
if ( byteswap_ ) swap16((unsigned char *)&rate);
|
638
|
+
srate = (StkFloat) rate;
|
639
|
+
}
|
640
|
+
else if ( type == 4 ) { // UINT16
|
641
|
+
UINT16 rate;
|
642
|
+
if ( fread(&rate, 2, 1, fd_) != 1 ) goto error;
|
643
|
+
if ( byteswap_ ) swap16((unsigned char *)&rate);
|
644
|
+
srate = (StkFloat) rate;
|
645
|
+
}
|
646
|
+
else if ( type == 5 ) { // SINT32
|
647
|
+
SINT32 rate;
|
648
|
+
if ( fread(&rate, 4, 1, fd_) != 1 ) goto error;
|
649
|
+
if ( byteswap_ ) swap32((unsigned char *)&rate);
|
650
|
+
srate = (StkFloat) rate;
|
651
|
+
}
|
652
|
+
else if ( type == 6 ) { // UINT32
|
653
|
+
UINT32 rate;
|
654
|
+
if ( fread(&rate, 4, 1, fd_) != 1 ) goto error;
|
655
|
+
if ( byteswap_ ) swap32((unsigned char *)&rate);
|
656
|
+
srate = (StkFloat) rate;
|
657
|
+
}
|
658
|
+
else if ( type == 7 ) { // FLOAT32
|
659
|
+
FLOAT32 rate;
|
660
|
+
if ( fread(&rate, 4, 1, fd_) != 1 ) goto error;
|
661
|
+
if ( byteswap_ ) swap32((unsigned char *)&rate);
|
662
|
+
srate = (StkFloat) rate;
|
663
|
+
}
|
664
|
+
else if ( type == 9 ) { // FLOAT64
|
665
|
+
FLOAT64 rate;
|
666
|
+
if ( fread(&rate, 8, 1, fd_) != 1 ) goto error;
|
667
|
+
if ( byteswap_ ) swap64((unsigned char *)&rate);
|
668
|
+
srate = (StkFloat) rate;
|
669
|
+
}
|
670
|
+
else
|
671
|
+
goto tryagain;
|
672
|
+
|
673
|
+
if ( srate > 0 ) fileRate_ = srate;
|
674
|
+
haveSampleRate = true;
|
675
|
+
}
|
676
|
+
else if ( !haveData ) { // Parse for data.
|
677
|
+
|
678
|
+
// Assume channels = smaller of rows or columns.
|
679
|
+
if ( rows < columns ) {
|
680
|
+
channels_ = rows;
|
681
|
+
fileSize_ = columns;
|
682
|
+
}
|
683
|
+
else {
|
684
|
+
oStream_ << "FileRead: Transpose the MAT-file array so that audio channels fill matrix rows (not columns).";
|
685
|
+
return false;
|
686
|
+
}
|
687
|
+
|
688
|
+
SINT32 namesize = 4;
|
689
|
+
if ( nametype == 1 ) { // array name > 4 characters
|
690
|
+
if ( fread(&namesize, 4, 1, fd_) != 1 ) goto error;
|
691
|
+
if ( byteswap_ ) swap32((unsigned char *)&namesize);
|
692
|
+
namesize = (SINT32) ceil((float)namesize / 8);
|
693
|
+
if ( fseek( fd_, namesize*8, SEEK_CUR) == -1 ) goto error; // jump over array name
|
694
|
+
}
|
695
|
+
else {
|
696
|
+
if ( fseek( fd_, 4, SEEK_CUR ) == -1 ) goto error;
|
697
|
+
}
|
698
|
+
|
699
|
+
// Now at real part data subelement
|
700
|
+
SINT32 type;
|
701
|
+
if ( fread(&type, 4, 1, fd_) != 1 ) goto error;
|
702
|
+
if ( byteswap_ ) swap32((unsigned char *)&type);
|
703
|
+
if ( type == 1 ) dataType_ = STK_SINT8;
|
704
|
+
else if ( type == 3 ) dataType_ = STK_SINT16;
|
705
|
+
else if ( type == 5 ) dataType_ = STK_SINT32;
|
706
|
+
else if ( type == 7 ) dataType_ = STK_FLOAT32;
|
707
|
+
else if ( type == 9 ) dataType_ = STK_FLOAT64;
|
708
|
+
else {
|
709
|
+
oStream_ << "FileRead: The MAT-file array data format (" << type << ") is not supported.";
|
710
|
+
return false;
|
711
|
+
}
|
712
|
+
|
713
|
+
// Jump to the data.
|
714
|
+
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error;
|
715
|
+
dataOffset_ = ftell(fd_);
|
716
|
+
haveData = true;
|
717
|
+
}
|
718
|
+
|
719
|
+
tryagain:
|
720
|
+
if ( haveData && haveSampleRate ) doneParsing = true;
|
721
|
+
else // jump to end of data element and keep trying
|
722
|
+
if ( fseek( fd_, dataoffset+chunkSize+8, SEEK_SET) == -1 ) goto error;
|
723
|
+
}
|
724
|
+
|
725
|
+
return true;
|
726
|
+
|
727
|
+
error:
|
728
|
+
oStream_ << "FileRead: Error reading MAT-file (" << fileName << ") header.";
|
729
|
+
return false;
|
730
|
+
}
|
731
|
+
|
732
|
+
void FileRead :: read( StkFrames& buffer, unsigned long startFrame, bool doNormalize )
|
733
|
+
{
|
734
|
+
// Make sure we have an open file.
|
735
|
+
if ( fd_ == 0 ) {
|
736
|
+
oStream_ << "FileRead::read: a file is not open!";
|
737
|
+
Stk::handleError( StkError::WARNING ); return;
|
738
|
+
}
|
739
|
+
|
740
|
+
// Check the buffer size.
|
741
|
+
unsigned long nFrames = buffer.frames();
|
742
|
+
if ( nFrames == 0 ) {
|
743
|
+
oStream_ << "FileRead::read: StkFrames buffer size is zero ... no data read!";
|
744
|
+
Stk::handleError( StkError::WARNING ); return;
|
745
|
+
}
|
746
|
+
|
747
|
+
if ( buffer.channels() != channels_ ) {
|
748
|
+
oStream_ << "FileRead::read: StkFrames argument has incompatible number of channels!";
|
749
|
+
Stk::handleError( StkError::FUNCTION_ARGUMENT );
|
750
|
+
}
|
751
|
+
|
752
|
+
if ( startFrame >= fileSize_ ) {
|
753
|
+
oStream_ << "FileRead::read: startFrame argument is greater than or equal to the file size!";
|
754
|
+
Stk::handleError( StkError::FUNCTION_ARGUMENT );
|
755
|
+
}
|
756
|
+
|
757
|
+
// Check for file end.
|
758
|
+
if ( startFrame + nFrames > fileSize_ )
|
759
|
+
nFrames = fileSize_ - startFrame;
|
760
|
+
|
761
|
+
long i, nSamples = (long) ( nFrames * channels_ );
|
762
|
+
unsigned long offset = startFrame * channels_;
|
763
|
+
|
764
|
+
// Read samples into StkFrames data buffer.
|
765
|
+
if ( dataType_ == STK_SINT16 ) {
|
766
|
+
SINT16 *buf = (SINT16 *) &buffer[0];
|
767
|
+
if ( fseek( fd_, dataOffset_+(offset*2), SEEK_SET ) == -1 ) goto error;
|
768
|
+
if ( fread( buf, nSamples * 2, 1, fd_ ) != 1 ) goto error;
|
769
|
+
if ( byteswap_ ) {
|
770
|
+
SINT16 *ptr = buf;
|
771
|
+
for ( i=nSamples-1; i>=0; i-- )
|
772
|
+
swap16( (unsigned char *) ptr++ );
|
773
|
+
}
|
774
|
+
if ( doNormalize ) {
|
775
|
+
StkFloat gain = 1.0 / 32768.0;
|
776
|
+
for ( i=nSamples-1; i>=0; i-- )
|
777
|
+
buffer[i] = buf[i] * gain;
|
778
|
+
}
|
779
|
+
else {
|
780
|
+
for ( i=nSamples-1; i>=0; i-- )
|
781
|
+
buffer[i] = buf[i];
|
782
|
+
}
|
783
|
+
}
|
784
|
+
else if ( dataType_ == STK_SINT32 ) {
|
785
|
+
SINT32 *buf = (SINT32 *) &buffer[0];
|
786
|
+
if ( fseek( fd_, dataOffset_+(offset*4 ), SEEK_SET ) == -1 ) goto error;
|
787
|
+
if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
|
788
|
+
if ( byteswap_ ) {
|
789
|
+
SINT32 *ptr = buf;
|
790
|
+
for ( i=nSamples-1; i>=0; i-- )
|
791
|
+
swap32( (unsigned char *) ptr++ );
|
792
|
+
}
|
793
|
+
if ( doNormalize ) {
|
794
|
+
StkFloat gain = 1.0 / 2147483648.0;
|
795
|
+
for ( i=nSamples-1; i>=0; i-- )
|
796
|
+
buffer[i] = buf[i] * gain;
|
797
|
+
}
|
798
|
+
else {
|
799
|
+
for ( i=nSamples-1; i>=0; i-- )
|
800
|
+
buffer[i] = buf[i];
|
801
|
+
}
|
802
|
+
}
|
803
|
+
else if ( dataType_ == STK_FLOAT32 ) {
|
804
|
+
FLOAT32 *buf = (FLOAT32 *) &buffer[0];
|
805
|
+
if ( fseek( fd_, dataOffset_+(offset*4), SEEK_SET ) == -1 ) goto error;
|
806
|
+
if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
|
807
|
+
if ( byteswap_ ) {
|
808
|
+
FLOAT32 *ptr = buf;
|
809
|
+
for ( i=nSamples-1; i>=0; i-- )
|
810
|
+
swap32( (unsigned char *) ptr++ );
|
811
|
+
}
|
812
|
+
for ( i=nSamples-1; i>=0; i-- )
|
813
|
+
buffer[i] = buf[i];
|
814
|
+
}
|
815
|
+
else if ( dataType_ == STK_FLOAT64 ) {
|
816
|
+
FLOAT64 *buf = (FLOAT64 *) &buffer[0];
|
817
|
+
if ( fseek( fd_, dataOffset_+(offset*8), SEEK_SET ) == -1 ) goto error;
|
818
|
+
if ( fread( buf, nSamples * 8, 1, fd_ ) != 1 ) goto error;
|
819
|
+
if ( byteswap_ ) {
|
820
|
+
FLOAT64 *ptr = buf;
|
821
|
+
for ( i=nSamples-1; i>=0; i-- )
|
822
|
+
swap64( (unsigned char *) ptr++ );
|
823
|
+
}
|
824
|
+
for ( i=nSamples-1; i>=0; i-- )
|
825
|
+
buffer[i] = buf[i];
|
826
|
+
}
|
827
|
+
else if ( dataType_ == STK_SINT8 && wavFile_ ) { // 8-bit WAV data is unsigned!
|
828
|
+
unsigned char *buf = (unsigned char *) &buffer[0];
|
829
|
+
if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
|
830
|
+
if ( fread( buf, nSamples, 1, fd_) != 1 ) goto error;
|
831
|
+
if ( doNormalize ) {
|
832
|
+
StkFloat gain = 1.0 / 128.0;
|
833
|
+
for ( i=nSamples-1; i>=0; i-- )
|
834
|
+
buffer[i] = ( buf[i] - 128 ) * gain;
|
835
|
+
}
|
836
|
+
else {
|
837
|
+
for ( i=nSamples-1; i>=0; i-- )
|
838
|
+
buffer[i] = buf[i] - 128.0;
|
839
|
+
}
|
840
|
+
}
|
841
|
+
else if ( dataType_ == STK_SINT8 ) { // signed 8-bit data
|
842
|
+
char *buf = (char *) &buffer[0];
|
843
|
+
if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
|
844
|
+
if ( fread( buf, nSamples, 1, fd_ ) != 1 ) goto error;
|
845
|
+
if ( doNormalize ) {
|
846
|
+
StkFloat gain = 1.0 / 128.0;
|
847
|
+
for ( i=nSamples-1; i>=0; i-- )
|
848
|
+
buffer[i] = buf[i] * gain;
|
849
|
+
}
|
850
|
+
else {
|
851
|
+
for ( i=nSamples-1; i>=0; i-- )
|
852
|
+
buffer[i] = buf[i];
|
853
|
+
}
|
854
|
+
}
|
855
|
+
else if ( dataType_ == STK_SINT24 ) {
|
856
|
+
// 24-bit values are harder to import efficiently since there is
|
857
|
+
// no native 24-bit type. The following routine works but is much
|
858
|
+
// less efficient than that used for the other data types.
|
859
|
+
SINT32 temp;
|
860
|
+
unsigned char *ptr = (unsigned char *) &temp;
|
861
|
+
StkFloat gain = 1.0 / 2147483648.0;
|
862
|
+
if ( fseek(fd_, dataOffset_+(offset*3), SEEK_SET ) == -1 ) goto error;
|
863
|
+
for ( i=0; i<nSamples; i++ ) {
|
864
|
+
#ifdef __LITTLE_ENDIAN__
|
865
|
+
if ( byteswap_ ) {
|
866
|
+
if ( fread( ptr, 3, 1, fd_ ) != 1 ) goto error;
|
867
|
+
temp &= 0x00ffffff;
|
868
|
+
swap32( (unsigned char *) ptr );
|
869
|
+
}
|
870
|
+
else {
|
871
|
+
if ( fread( ptr+1, 3, 1, fd_ ) != 1 ) goto error;
|
872
|
+
temp &= 0xffffff00;
|
873
|
+
}
|
874
|
+
#else
|
875
|
+
if ( byteswap_ ) {
|
876
|
+
if ( fread( ptr+1, 3, 1, fd_ ) != 1 ) goto error;
|
877
|
+
temp &= 0xffffff00;
|
878
|
+
swap32( (unsigned char *) ptr );
|
879
|
+
}
|
880
|
+
else {
|
881
|
+
if ( fread( ptr, 3, 1, fd_ ) != 1 ) goto error;
|
882
|
+
temp &= 0x00ffffff;
|
883
|
+
}
|
884
|
+
#endif
|
885
|
+
|
886
|
+
if ( doNormalize ) {
|
887
|
+
buffer[i] = (StkFloat) temp * gain; // "gain" also includes 1 / 256 factor.
|
888
|
+
}
|
889
|
+
else
|
890
|
+
buffer[i] = (StkFloat) temp / 256; // right shift without affecting the sign bit
|
891
|
+
}
|
892
|
+
}
|
893
|
+
|
894
|
+
buffer.setDataRate( fileRate_ );
|
895
|
+
|
896
|
+
return;
|
897
|
+
|
898
|
+
error:
|
899
|
+
oStream_ << "FileRead: Error reading file data.";
|
900
|
+
handleError( StkError::FILE_ERROR);
|
901
|
+
}
|
902
|
+
|
903
|
+
} // stk namespace
|