beeps 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.doc/ext/beeps/beeps.cpp +46 -0
  3. data/.doc/ext/beeps/file_in.cpp +59 -0
  4. data/.doc/ext/beeps/native.cpp +41 -0
  5. data/.doc/ext/beeps/processor.cpp +49 -0
  6. data/.doc/ext/beeps/sawtooth_wave.cpp +66 -0
  7. data/.doc/ext/beeps/sine_wave.cpp +66 -0
  8. data/.doc/ext/beeps/sound.cpp +69 -0
  9. data/.doc/ext/beeps/square_wave.cpp +66 -0
  10. data/README.md +4 -0
  11. data/Rakefile +27 -0
  12. data/VERSION +1 -0
  13. data/beeps.gemspec +43 -0
  14. data/ext/beeps/beeps.cpp +48 -0
  15. data/ext/beeps/defs.h +13 -0
  16. data/ext/beeps/extconf.rb +25 -0
  17. data/ext/beeps/file_in.cpp +61 -0
  18. data/ext/beeps/native.cpp +41 -0
  19. data/ext/beeps/processor.cpp +50 -0
  20. data/ext/beeps/sawtooth_wave.cpp +69 -0
  21. data/ext/beeps/sine_wave.cpp +69 -0
  22. data/ext/beeps/sound.cpp +72 -0
  23. data/ext/beeps/square_wave.cpp +69 -0
  24. data/include/beeps.h +12 -0
  25. data/include/beeps/beeps.h +25 -0
  26. data/include/beeps/defs.h +23 -0
  27. data/include/beeps/exception.h +47 -0
  28. data/include/beeps/openal.h +34 -0
  29. data/include/beeps/processor.h +132 -0
  30. data/include/beeps/ruby.h +10 -0
  31. data/include/beeps/ruby/beeps.h +21 -0
  32. data/include/beeps/ruby/processor.h +86 -0
  33. data/include/beeps/ruby/sound.h +42 -0
  34. data/include/beeps/signals.h +53 -0
  35. data/include/beeps/sound.h +44 -0
  36. data/lib/beeps.rb +9 -0
  37. data/lib/beeps/autoinit.rb +10 -0
  38. data/lib/beeps/beeps.rb +49 -0
  39. data/lib/beeps/ext.rb +4 -0
  40. data/lib/beeps/module.rb +49 -0
  41. data/lib/beeps/processor.rb +60 -0
  42. data/lib/beeps/sound.rb +19 -0
  43. data/src/beeps.cpp +93 -0
  44. data/src/exception.cpp +43 -0
  45. data/src/openal.cpp +216 -0
  46. data/src/openal.h +25 -0
  47. data/src/processor.cpp +201 -0
  48. data/src/signals.cpp +90 -0
  49. data/src/sound.cpp +125 -0
  50. data/src/stk/include/Blit.h +151 -0
  51. data/src/stk/include/BlitSaw.h +148 -0
  52. data/src/stk/include/BlitSquare.h +170 -0
  53. data/src/stk/include/FileRead.h +141 -0
  54. data/src/stk/include/FileWvIn.h +195 -0
  55. data/src/stk/include/Generator.h +50 -0
  56. data/src/stk/include/SineWave.h +159 -0
  57. data/src/stk/include/Stk.h +589 -0
  58. data/src/stk/include/WvIn.h +46 -0
  59. data/src/stk/src/Blit.cpp +78 -0
  60. data/src/stk/src/BlitSaw.cpp +91 -0
  61. data/src/stk/src/BlitSquare.cpp +95 -0
  62. data/src/stk/src/FileRead.cpp +903 -0
  63. data/src/stk/src/FileWvIn.cpp +260 -0
  64. data/src/stk/src/SineWave.cpp +78 -0
  65. data/src/stk/src/Stk.cpp +395 -0
  66. data/test/helper.rb +17 -0
  67. data/test/test_beeps.rb +18 -0
  68. data/test/test_sound.rb +26 -0
  69. 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