wavefile 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +1 -1
  3. data/README.markdown +71 -18
  4. data/lib/wavefile/buffer.rb +63 -39
  5. data/lib/wavefile/duration.rb +34 -0
  6. data/lib/wavefile/format.rb +42 -16
  7. data/lib/wavefile/info.rb +5 -38
  8. data/lib/wavefile/reader.rb +88 -61
  9. data/lib/wavefile/writer.rb +57 -25
  10. data/lib/wavefile.rb +6 -4
  11. data/test/buffer_test.rb +227 -37
  12. data/test/duration_test.rb +73 -0
  13. data/test/fixtures/actual_output/{valid_mono_8_44100_with_padding_byte.wav → valid_mono_pcm_8_44100_with_padding_byte.wav} +0 -0
  14. data/test/fixtures/{expected_output → valid}/no_samples.wav +0 -0
  15. data/test/fixtures/valid/valid_mono_float_32_44100.wav +0 -0
  16. data/test/fixtures/valid/valid_mono_float_64_44100.wav +0 -0
  17. data/test/fixtures/{expected_output/valid_mono_16_44100.wav → valid/valid_mono_pcm_16_44100.wav} +0 -0
  18. data/test/fixtures/{expected_output/valid_mono_32_44100.wav → valid/valid_mono_pcm_32_44100.wav} +0 -0
  19. data/test/fixtures/{expected_output/valid_mono_8_44100.wav → valid/valid_mono_pcm_8_44100.wav} +0 -0
  20. data/test/fixtures/{expected_output/valid_mono_8_44100_with_padding_byte.wav → valid/valid_mono_pcm_8_44100_with_padding_byte.wav} +0 -0
  21. data/test/fixtures/valid/valid_stereo_float_32_44100.wav +0 -0
  22. data/test/fixtures/valid/valid_stereo_float_64_44100.wav +0 -0
  23. data/test/fixtures/{expected_output/valid_stereo_16_44100.wav → valid/valid_stereo_pcm_16_44100.wav} +0 -0
  24. data/test/fixtures/{expected_output/valid_stereo_32_44100.wav → valid/valid_stereo_pcm_32_44100.wav} +0 -0
  25. data/test/fixtures/{expected_output/valid_stereo_8_44100.wav → valid/valid_stereo_pcm_8_44100.wav} +0 -0
  26. data/test/fixtures/valid/valid_tri_float_32_44100.wav +0 -0
  27. data/test/fixtures/valid/valid_tri_float_64_44100.wav +0 -0
  28. data/test/fixtures/{expected_output/valid_tri_16_44100.wav → valid/valid_tri_pcm_16_44100.wav} +0 -0
  29. data/test/fixtures/{expected_output/valid_tri_32_44100.wav → valid/valid_tri_pcm_32_44100.wav} +0 -0
  30. data/test/fixtures/{expected_output/valid_tri_8_44100.wav → valid/valid_tri_pcm_8_44100.wav} +0 -0
  31. data/test/format_test.rb +88 -58
  32. data/test/info_test.rb +9 -37
  33. data/test/reader_test.rb +160 -63
  34. data/test/wavefile_io_test_helper.rb +40 -30
  35. data/test/writer_test.rb +124 -37
  36. metadata +29 -31
  37. data/test/fixtures/valid/valid_mono_16_44100.wav +0 -0
  38. data/test/fixtures/valid/valid_mono_32_44100.wav +0 -0
  39. data/test/fixtures/valid/valid_mono_8_44100.wav +0 -0
  40. data/test/fixtures/valid/valid_mono_8_44100_with_padding_byte.wav +0 -0
  41. data/test/fixtures/valid/valid_stereo_16_44100.wav +0 -0
  42. data/test/fixtures/valid/valid_stereo_32_44100.wav +0 -0
  43. data/test/fixtures/valid/valid_stereo_8_44100.wav +0 -0
  44. data/test/fixtures/valid/valid_tri_16_44100.wav +0 -0
  45. data/test/fixtures/valid/valid_tri_32_44100.wav +0 -0
  46. data/test/fixtures/valid/valid_tri_8_44100.wav +0 -0
@@ -9,7 +9,7 @@ module WaveFile
9
9
 
10
10
 
11
11
  # Provides the ability to read sample data out of a wave file, as well as query a
12
- # wave file about its metadata (e.g. number of channels, sample rate, etc).
12
+ # wave file about its metadata (e.g. number of channels, sample rate, etc).
13
13
  class Reader
14
14
  # Returns a Reader object that is ready to start reading the specified file's sample data.
15
15
  #
@@ -26,35 +26,34 @@ module WaveFile
26
26
  @file_name = file_name
27
27
  @file = File.open(file_name, "rb")
28
28
 
29
- raw_format_chunk, sample_count = HeaderReader.new(@file, @file_name).read_until_data_chunk()
30
- @sample_count = sample_count
31
- @samples_remaining = sample_count
29
+ raw_format_chunk, sample_frame_count = HeaderReader.new(@file, @file_name).read_until_data_chunk
30
+ @current_sample_frame = 0
31
+ @total_sample_frames = sample_frame_count
32
32
 
33
33
  # Make file is in a format we can actually read
34
34
  validate_format_chunk(raw_format_chunk)
35
35
 
36
+ native_sample_format = "#{FORMAT_CODES.invert[raw_format_chunk[:audio_format]]}_#{raw_format_chunk[:bits_per_sample]}".to_sym
36
37
  @native_format = Format.new(raw_format_chunk[:channels],
37
- raw_format_chunk[:bits_per_sample],
38
+ native_sample_format,
38
39
  raw_format_chunk[:sample_rate])
39
- @pack_code = PACK_CODES[@native_format.bits_per_sample]
40
-
41
- if format == nil
42
- @format = @native_format
43
- else
44
- @format = format
45
- end
40
+ @pack_code = PACK_CODES[@native_format.sample_format][@native_format.bits_per_sample]
41
+ @format = (format == nil) ? @native_format : format
46
42
 
47
43
  if block_given?
48
- yield(self)
49
- close()
44
+ begin
45
+ yield(self)
46
+ ensure
47
+ close
48
+ end
50
49
  end
51
50
  end
52
51
 
53
52
 
54
53
  # Reads metadata from the specified wave file and returns an Info object with the results.
55
- # Metadata includes things like the number of channels, bits per sample, number of samples,
56
- # sample encoding format (i.e. PCM, IEEE float, uLaw etc). See the Info object for more
57
- # detail on exactly what metadata is available.
54
+ # Metadata includes things like the number of channels, bits per sample, number of sample
55
+ # frames, sample encoding format (i.e. PCM, IEEE float, uLaw etc). See the Info object for
56
+ # more detail on exactly what metadata is available.
58
57
  #
59
58
  # file_name - The name of the wave file to read from
60
59
  #
@@ -68,84 +67,85 @@ module WaveFile
68
67
  # that WaveFile can't read.
69
68
  def self.info(file_name)
70
69
  file = File.open(file_name, "rb")
71
- raw_format_chunk, sample_count = HeaderReader.new(file, file_name).read_until_data_chunk()
72
- file.close()
70
+ raw_format_chunk, sample_frame_count = HeaderReader.new(file, file_name).read_until_data_chunk
71
+ file.close
73
72
 
74
- return Info.new(file_name, raw_format_chunk, sample_count)
73
+ Info.new(file_name, raw_format_chunk, sample_frame_count)
75
74
  end
76
75
 
77
76
 
78
77
  # Reads sample data of the into successive Buffers of the specified size, until there is no more
79
78
  # sample data to be read. When all sample data has been read, the Reader is automatically closed.
80
- # Each Buffer is passed to the specified block.
79
+ # Each Buffer is passed to the given block.
81
80
  #
82
- # Note that the number of sames to read is for *each channel*. That is, if buffer_size is 1024, then
81
+ # Note that sample_frame_count indicates the number of sample frames to read, not number of samples.
82
+ # A sample frame include one sample for each channel. For example, if sample_frame_count is 1024, then
83
83
  # for a stereo file 1024 samples will be read from the left channel, and 1024 samples will be read from
84
84
  # the right channel.
85
85
  #
86
- # buffer_size - The number of samples to read into each Buffer from each channel. The number of
87
- # samples read into the final Buffer could be less than this size, if there are not
88
- # enough remaining samples.
86
+ # sample_frame_count - The number of sample frames to read into each Buffer from each channel. The number
87
+ # of sample frames read into the final Buffer could be less than this size, if there
88
+ # are not enough remaining.
89
89
  #
90
90
  # Returns nothing.
91
- def each_buffer(buffer_size)
91
+ def each_buffer(sample_frame_count)
92
92
  begin
93
93
  while true do
94
- yield(read(buffer_size))
94
+ yield(read(sample_frame_count))
95
95
  end
96
96
  rescue EOFError
97
- close()
97
+ close
98
98
  end
99
99
  end
100
100
 
101
101
 
102
- # Reads the specified number of samples from the wave file into a Buffer. Note that the Buffer will have
103
- # at most buffer_size samples, but could have less if the file doesn't have enough remaining samples.
102
+ # Reads the specified number of sample frames from the wave file into a Buffer. Note that the Buffer will have
103
+ # at most sample_frame_count sample frames, but could have less if the file doesn't have enough remaining.
104
104
  #
105
- # buffer_size - The number of samples to read. Note that for multi-channel files, this number of samples
106
- # will be read from each channel.
105
+ # sample_frame_count - The number of sample frames to read. Note that each sample frame includes a sample for
106
+ # each channel.
107
107
  #
108
- # Returns a Buffer containing buffer_size samples
108
+ # Returns a Buffer containing sample_frame_count sample frames
109
109
  # Raises EOFError if no samples could be read due to reaching the end of the file
110
- def read(buffer_size)
111
- if @samples_remaining == 0
110
+ def read(sample_frame_count)
111
+ if @current_sample_frame >= @total_sample_frames
112
112
  #FIXME: Do something different here, because the end of the file has not actually necessarily been reached
113
113
  raise EOFError
114
- elsif buffer_size > @samples_remaining
115
- buffer_size = @samples_remaining
114
+ elsif sample_frame_count > sample_frames_remaining
115
+ sample_frame_count = sample_frames_remaining
116
116
  end
117
117
 
118
- samples = @file.sysread(buffer_size * @native_format.block_align).unpack(@pack_code)
119
- @samples_remaining -= buffer_size
118
+ samples = @file.sysread(sample_frame_count * @native_format.block_align).unpack(@pack_code)
119
+ @current_sample_frame += sample_frame_count
120
120
 
121
121
  if @native_format.channels > 1
122
122
  num_multichannel_samples = samples.length / @native_format.channels
123
123
  multichannel_data = Array.new(num_multichannel_samples)
124
-
124
+
125
125
  if(@native_format.channels == 2)
126
126
  # Files with more than 2 channels are expected to be less common, so if there are 2 channels
127
127
  # using a faster specific algorithm instead of a general one.
128
- num_multichannel_samples.times {|i| multichannel_data[i] = [samples.pop(), samples.pop()].reverse!() }
128
+ num_multichannel_samples.times {|i| multichannel_data[i] = [samples.pop, samples.pop].reverse! }
129
129
  else
130
130
  # General algorithm that works for any number of channels, 2 or greater.
131
131
  num_multichannel_samples.times do |i|
132
132
  sample = Array.new(@native_format.channels)
133
- @native_format.channels.times {|j| sample[j] = samples.pop() }
134
- multichannel_data[i] = sample.reverse!()
133
+ @native_format.channels.times {|j| sample[j] = samples.pop }
134
+ multichannel_data[i] = sample.reverse!
135
135
  end
136
136
  end
137
137
 
138
- samples = multichannel_data.reverse!()
138
+ samples = multichannel_data.reverse!
139
139
  end
140
140
 
141
141
  buffer = Buffer.new(samples, @native_format)
142
- return buffer.convert(@format)
142
+ buffer.convert(@format)
143
143
  end
144
144
 
145
145
 
146
146
  # Returns true if the Reader is closed, and false if it is open and available for reading.
147
- def closed?()
148
- return @file.closed?
147
+ def closed?
148
+ @file.closed?
149
149
  end
150
150
 
151
151
 
@@ -153,26 +153,53 @@ module WaveFile
153
153
  #
154
154
  # Returns nothing.
155
155
  # Raises IOError if the Reader is already closed.
156
- def close()
157
- @file.close()
156
+ def close
157
+ @file.close
158
+ end
159
+
160
+ # Returns a Duration instance for the total number of sample frames in the file
161
+ def total_duration
162
+ Duration.new(total_sample_frames, @format.sample_rate)
158
163
  end
159
164
 
160
- attr_reader :file_name, :format
165
+ # Returns the name of the Wave file that is being read
166
+ attr_reader :file_name
167
+
168
+ # Returns a Format object describing how sample data is being read from the Wave file (number of
169
+ # channels, sample format and bits per sample, etc). Note that this might be different from the
170
+ # underlying format of the Wave file on disk.
171
+ attr_reader :format
172
+
173
+ # Returns the index of the sample frame which is "cued up" for reading. I.e., the index
174
+ # of the next sample frame that will be read. A sample frame contains a single sample
175
+ # for each channel. So if there are 1,000 sample frames in a stereo file, this means
176
+ # there are 1,000 left-channel samples and 1,000 right-channel samples.
177
+ attr_reader :current_sample_frame
178
+
179
+ # Returns the total number of sample frames in the file. A sample frame contains a single
180
+ # sample for each channel. So if there are 1,000 sample frames in a stereo file, this means
181
+ # there are 1,000 left-channel samples and 1,000 right-channel samples.
182
+ attr_reader :total_sample_frames
161
183
 
162
184
  private
163
185
 
186
+ # The number of sample frames in the file after the current sample frame
187
+ def sample_frames_remaining
188
+ @total_sample_frames - @current_sample_frame
189
+ end
190
+
164
191
  def validate_format_chunk(raw_format_chunk)
165
192
  # :byte_rate and :block_align are not checked to make sure that match :channels/:sample_rate/bits_per_sample
166
193
  # because this library doesn't use them.
167
194
 
168
- unless raw_format_chunk[:audio_format] == PCM
195
+ unless FORMAT_CODES.values.include? raw_format_chunk[:audio_format]
169
196
  raise UnsupportedFormatError, "Audio format is #{raw_format_chunk[:audio_format]}, " +
170
- "but only format code 1 (i.e. PCM) is supported."
197
+ "but only format code 1 (PCM) or 3 (floating point) is supported."
171
198
  end
172
199
 
173
- unless Format::SUPPORTED_BITS_PER_SAMPLE.include?(raw_format_chunk[:bits_per_sample])
200
+ unless Format::SUPPORTED_BITS_PER_SAMPLE[FORMAT_CODES.invert[raw_format_chunk[:audio_format]]].include?(raw_format_chunk[:bits_per_sample])
174
201
  raise UnsupportedFormatError, "Bits per sample is #{raw_format_chunk[:bits_per_sample]}, " +
175
- "but only #{Format::SUPPORTED_BITS_PER_SAMPLE.inspect} are supported."
202
+ "but only #{Format::SUPPORTED_BITS_PER_SAMPLE[:pcm].inspect} are supported."
176
203
  end
177
204
 
178
205
  unless raw_format_chunk[:channels] > 0
@@ -200,8 +227,8 @@ module WaveFile
200
227
  @file_name = file_name
201
228
  end
202
229
 
203
- def read_until_data_chunk()
204
- read_riff_chunk()
230
+ def read_until_data_chunk
231
+ read_riff_chunk
205
232
 
206
233
  begin
207
234
  chunk_id = @file.sysread(4)
@@ -225,14 +252,14 @@ module WaveFile
225
252
  raise_error InvalidFormatError, "The format chunk is either missing, or it comes after the data chunk."
226
253
  end
227
254
 
228
- sample_count = chunk_size / format_chunk[:block_align]
255
+ sample_frame_count = chunk_size / format_chunk[:block_align]
229
256
 
230
- return format_chunk, sample_count
257
+ return format_chunk, sample_frame_count
231
258
  end
232
259
 
233
260
  private
234
261
 
235
- def read_riff_chunk()
262
+ def read_riff_chunk
236
263
  riff_header = {}
237
264
  riff_header[:chunk_id],
238
265
  riff_header[:chunk_size],
@@ -246,7 +273,7 @@ module WaveFile
246
273
  raise_error InvalidFormatError, "Expected RIFF format of '#{WAVEFILE_FORMAT_CODE}', but was '#{riff_header[:riff_format]}'"
247
274
  end
248
275
 
249
- return riff_header
276
+ riff_header
250
277
  end
251
278
 
252
279
  def read_format_chunk(chunk_id, chunk_size)
@@ -278,7 +305,7 @@ module WaveFile
278
305
  # TODO: Parse the extension
279
306
  end
280
307
 
281
- return format_chunk
308
+ format_chunk
282
309
  end
283
310
 
284
311
  def read_chunk_body(chunk_id, chunk_size)
@@ -13,56 +13,61 @@ module WaveFile
13
13
  # starts, assuming this canonical format:
14
14
  #
15
15
  # RIFF Chunk Header (12 bytes)
16
- # Format Chunk (No Extension) (16 bytes)
16
+ # Format Chunk (16 bytes for PCM, 18 bytes for floating point)
17
+ # FACT Chunk (0 bytes for PCM, 12 bytes for floating point)
17
18
  # Data Chunk Header (8 bytes)
18
19
  #
19
20
  # All wave files written by Writer use this canonical format.
20
- CANONICAL_HEADER_BYTE_LENGTH = 36
21
+ CANONICAL_HEADER_BYTE_LENGTH = {:pcm => 36, :float => 50}
21
22
 
22
23
 
23
24
  # Returns a constructed Writer object which is available for writing sample data to the specified
24
- # file (via the write() method). When all sample data has been written, the Writer should be closed.
25
+ # file (via the write method). When all sample data has been written, the Writer should be closed.
25
26
  # Note that the wave file being written to will NOT be valid (and playable in other programs) until
26
27
  # the Writer has been closed.
27
28
  #
28
29
  # If a block is given to this method, sample data can be written inside the given block. When the
29
30
  # block terminates, the Writer will be automatically closed (and no more sample data can be written).
30
31
  #
31
- # If no block is given, then sample data can be written until the close() method is called.
32
+ # If no block is given, then sample data can be written until the close method is called.
32
33
  def initialize(file_name, format)
34
+ @file_name = file_name
33
35
  @file = File.open(file_name, "wb")
34
36
  @format = format
35
37
 
36
- @samples_written = 0
37
- @pack_code = PACK_CODES[format.bits_per_sample]
38
+ @total_sample_frames = 0
39
+ @pack_code = PACK_CODES[format.sample_format][format.bits_per_sample]
38
40
 
39
41
  # Note that the correct sizes for the RIFF and data chunks can't be determined
40
42
  # until all samples have been written, so this header as written will be incorrect.
41
- # When close() is called, the correct sizes will be re-written.
43
+ # When close is called, the correct sizes will be re-written.
42
44
  write_header(0)
43
45
 
44
46
  if block_given?
45
- yield(self)
46
- close()
47
+ begin
48
+ yield(self)
49
+ ensure
50
+ close
51
+ end
47
52
  end
48
53
  end
49
54
 
50
55
 
51
56
  # Appends the sample data in the given Buffer to the end of the wave file.
52
57
  #
53
- # Returns the number of sample that have been written to the file so far.
58
+ # Returns the number of sample frames that have been written to the file so far.
54
59
  # Raises IOError if the Writer has been closed.
55
60
  def write(buffer)
56
61
  samples = buffer.convert(@format).samples
57
62
 
58
63
  @file.syswrite(samples.flatten.pack(@pack_code))
59
- @samples_written += samples.length
64
+ @total_sample_frames += samples.length
60
65
  end
61
66
 
62
67
 
63
68
  # Returns true if the Writer is closed, and false if it is open and available for writing.
64
- def closed?()
65
- return @file.closed?
69
+ def closed?
70
+ @file.closed?
66
71
  end
67
72
 
68
73
 
@@ -70,17 +75,19 @@ module WaveFile
70
75
  #
71
76
  # Note that the wave file will NOT be valid until this method is called. The wave file
72
77
  # format requires certain information about the amount of sample data, and this can't be
73
- # determined until all samples have been written.
78
+ # determined until all samples have been written. (This method doesn't need to be called
79
+ # when passing a block to Writer.new, as this method will automatically be called when
80
+ # the block exits).
74
81
  #
75
82
  # Returns nothing.
76
83
  # Raises IOError if the Writer is already closed.
77
- def close()
84
+ def close
78
85
  # The RIFF specification requires that each chunk be aligned to an even number of bytes,
79
86
  # even if the byte count is an odd number. Therefore if an odd number of bytes has been
80
87
  # written, write an empty padding byte.
81
88
  #
82
89
  # See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf, page 11.
83
- bytes_written = @samples_written * @format.block_align
90
+ bytes_written = @total_sample_frames * @format.block_align
84
91
  if bytes_written.odd?
85
92
  @file.syswrite(EMPTY_BYTE)
86
93
  end
@@ -89,34 +96,59 @@ module WaveFile
89
96
  # samples have been written, so go back to the beginning of the file and re-write
90
97
  # those chunk headers with the correct sizes.
91
98
  @file.sysseek(0)
92
- write_header(@samples_written)
93
-
94
- @file.close()
99
+ write_header(@total_sample_frames)
100
+
101
+ @file.close
102
+ end
103
+
104
+ # Returns a Duration instance for the number of sample frames that have been written so far
105
+ def total_duration
106
+ Duration.new(@total_sample_frames, @format.sample_rate)
95
107
  end
96
108
 
97
- attr_reader :file_name, :format
109
+ # Returns the name of the Wave file that is being written to
110
+ attr_reader :file_name
111
+
112
+ # Returns a Format object describing the Wave file being written (number of channels, sample
113
+ # format and bits per sample, sample rate, etc.)
114
+ attr_reader :format
115
+
116
+ # Returns the number of samples (per channel) that have been written to the file so far.
117
+ # For example, if 1000 "left" samples and 1000 "right" samples have been written to a stereo file,
118
+ # this will return 1000.
119
+ attr_reader :total_sample_frames
98
120
 
99
121
  private
100
122
 
101
123
  # Writes the RIFF chunk header, format chunk, and the header for the data chunk. After this
102
124
  # method is called the file will be "queued up" and ready for writing actual sample data.
103
- def write_header(sample_count)
104
- sample_data_byte_count = sample_count * @format.block_align
125
+ def write_header(sample_frame_count)
126
+ sample_data_byte_count = sample_frame_count * @format.block_align
105
127
 
106
128
  # Write the header for the RIFF chunk
107
129
  header = CHUNK_IDS[:riff]
108
- header += [CANONICAL_HEADER_BYTE_LENGTH + sample_data_byte_count].pack(UNSIGNED_INT_32)
130
+ header += [CANONICAL_HEADER_BYTE_LENGTH[@format.sample_format] + sample_data_byte_count].pack(UNSIGNED_INT_32)
109
131
  header += WAVEFILE_FORMAT_CODE
110
132
 
111
133
  # Write the format chunk
112
134
  header += CHUNK_IDS[:format]
113
- header += [FORMAT_CHUNK_BYTE_LENGTH].pack(UNSIGNED_INT_32)
114
- header += [PCM].pack(UNSIGNED_INT_16)
135
+ header += [FORMAT_CHUNK_BYTE_LENGTH[@format.sample_format]].pack(UNSIGNED_INT_32)
136
+ header += [FORMAT_CODES[@format.sample_format]].pack(UNSIGNED_INT_16)
115
137
  header += [@format.channels].pack(UNSIGNED_INT_16)
116
138
  header += [@format.sample_rate].pack(UNSIGNED_INT_32)
117
139
  header += [@format.byte_rate].pack(UNSIGNED_INT_32)
118
140
  header += [@format.block_align].pack(UNSIGNED_INT_16)
119
141
  header += [@format.bits_per_sample].pack(UNSIGNED_INT_16)
142
+ if @format.sample_format == :float
143
+ header += [0].pack(UNSIGNED_INT_16)
144
+ end
145
+
146
+ # Write the FACT chunk, if necessary
147
+ unless @format.sample_format == :pcm
148
+ header += CHUNK_IDS[:fact]
149
+ header += [4].pack(UNSIGNED_INT_32)
150
+ header += [sample_frame_count].pack(UNSIGNED_INT_32)
151
+ end
120
152
 
121
153
  # Write the header for the data chunk
122
154
  header += CHUNK_IDS[:data]
data/lib/wavefile.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  require 'wavefile/buffer'
2
+ require 'wavefile/duration'
2
3
  require 'wavefile/format'
3
4
  require 'wavefile/info'
4
5
  require 'wavefile/reader'
5
6
  require 'wavefile/writer'
6
7
 
7
8
  module WaveFile
8
- VERSION = "0.4.0"
9
+ VERSION = "0.5.0"
9
10
 
10
11
  WAVEFILE_FORMAT_CODE = "WAVE"
11
- FORMAT_CHUNK_BYTE_LENGTH = 16
12
- PCM = 1
12
+ FORMAT_CHUNK_BYTE_LENGTH = {:pcm => 16, :float => 18}
13
+ FORMAT_CODES = {:pcm => 1, :float => 3}
13
14
  CHUNK_IDS = {:riff => "RIFF",
14
15
  :format => "fmt ",
15
16
  :data => "data",
@@ -24,7 +25,8 @@ module WaveFile
24
25
  :sample => "smpl",
25
26
  :instrument => "inst" }
26
27
 
27
- PACK_CODES = {8 => "C*", 16 => "s*", 32 => "l*"}
28
+ PACK_CODES = {:pcm => {8 => "C*", 16 => "s*", 32 => "l*"},
29
+ :float => { 32 => "e*", 64 => "E*"}}
28
30
 
29
31
  UNSIGNED_INT_16 = "v"
30
32
  UNSIGNED_INT_32 = "V"