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.
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