wavefile 0.4.0 → 0.5.0

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 (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"