wavefile 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -23
- data/README.markdown +27 -43
- data/lib/wavefile.rb +4 -1
- data/lib/wavefile/buffer.rb +7 -5
- data/lib/wavefile/chunk_readers.rb +1 -2
- data/lib/wavefile/chunk_readers/base_chunk_reader.rb +13 -0
- data/lib/wavefile/chunk_readers/data_chunk_reader.rb +12 -3
- data/lib/wavefile/chunk_readers/format_chunk_reader.rb +2 -10
- data/lib/wavefile/chunk_readers/riff_reader.rb +73 -26
- data/lib/wavefile/chunk_readers/sample_chunk_reader.rb +74 -0
- data/lib/wavefile/format.rb +13 -9
- data/lib/wavefile/reader.rb +15 -7
- data/lib/wavefile/sampler_info.rb +162 -0
- data/lib/wavefile/sampler_loop.rb +142 -0
- data/lib/wavefile/smpte_timecode.rb +61 -0
- data/lib/wavefile/writer.rb +7 -1
- data/test/fixtures/wave/invalid/data_chunk_ends_after_chunk_id.wav +0 -0
- data/test/fixtures/wave/invalid/data_chunk_has_incomplete_chunk_size.wav +0 -0
- data/test/fixtures/wave/invalid/data_chunk_truncated.wav +0 -0
- data/test/fixtures/wave/invalid/format_chunk_after_data_chunk.wav +0 -0
- data/test/fixtures/wave/invalid/incomplete_riff_format.wav +0 -0
- data/test/fixtures/wave/invalid/incomplete_riff_header.wav +1 -1
- data/test/fixtures/wave/invalid/no_format_chunk_size.wav +0 -0
- data/test/fixtures/wave/invalid/no_riff_format.wav +0 -0
- data/test/fixtures/wave/invalid/riff_chunk_has_incomplete_chunk_size.wav +1 -0
- data/test/fixtures/wave/invalid/smpl_chunk_empty.wav +0 -0
- data/test/fixtures/wave/invalid/smpl_chunk_fields_out_of_range.wav +0 -0
- data/test/fixtures/wave/invalid/smpl_chunk_loop_count_too_high.wav +0 -0
- data/test/fixtures/wave/invalid/smpl_chunk_truncated_sampler_specific_data.wav +0 -0
- data/test/fixtures/wave/invalid/truncated_smpl_chunk.wav +0 -0
- data/test/fixtures/wave/unsupported/bad_audio_format.wav +0 -0
- data/test/fixtures/wave/unsupported/bad_sample_rate.wav +0 -0
- data/test/fixtures/wave/unsupported/extensible_unsupported_subformat_guid.wav +0 -0
- data/test/fixtures/wave/unsupported/unsupported_audio_format.wav +0 -0
- data/test/fixtures/wave/unsupported/unsupported_bits_per_sample.wav +0 -0
- data/test/fixtures/wave/valid/valid_mono_pcm_16_44100_junk_chunk_final_chunk_missing_padding_byte.wav +0 -0
- data/test/fixtures/wave/valid/valid_mono_pcm_16_44100_junk_chunk_with_padding_byte.wav +0 -0
- data/test/fixtures/wave/valid/valid_mono_pcm_8_44100_with_padding_byte.wav +0 -0
- data/test/fixtures/wave/valid/valid_with_sample_chunk_after_data_chunk.wav +0 -0
- data/test/fixtures/wave/valid/valid_with_sample_chunk_after_data_chunk_and_data_chunk_has_padding_byte.wav +0 -0
- data/test/fixtures/wave/valid/valid_with_sample_chunk_before_data_chunk.wav +0 -0
- data/test/fixtures/wave/valid/valid_with_sample_chunk_no_loops.wav +0 -0
- data/test/fixtures/wave/valid/valid_with_sample_chunk_with_extra_unused_bytes.wav +0 -0
- data/test/fixtures/wave/valid/valid_with_sample_chunk_with_sampler_specific_data.wav +0 -0
- data/test/format_test.rb +4 -4
- data/test/reader_test.rb +266 -8
- data/test/sampler_info_test.rb +314 -0
- data/test/sampler_loop_test.rb +215 -0
- data/test/smpte_timecode_test.rb +103 -0
- data/test/writer_test.rb +1 -1
- metadata +30 -6
- data/lib/wavefile/chunk_readers/generic_chunk_reader.rb +0 -15
- data/lib/wavefile/chunk_readers/riff_chunk_reader.rb +0 -19
data/lib/wavefile/writer.rb
CHANGED
@@ -93,7 +93,9 @@ module WaveFile
|
|
93
93
|
# writer.write(buffer)
|
94
94
|
#
|
95
95
|
# Returns the number of sample frames that have been written to the file so far.
|
96
|
+
#
|
96
97
|
# Raises WriterClosedError if the Writer has been closed.
|
98
|
+
#
|
97
99
|
# Raises BufferConversionError if the Buffer can't be converted to the Writer's format.
|
98
100
|
def write(buffer)
|
99
101
|
if @closed
|
@@ -287,10 +289,14 @@ module WaveFile
|
|
287
289
|
requires_fact_chunk = (format_code != :pcm)
|
288
290
|
|
289
291
|
sample_data_byte_count = sample_frame_count * @format.block_align
|
292
|
+
riff_chunk_size = CANONICAL_HEADER_BYTE_LENGTH[format_code] + sample_data_byte_count
|
293
|
+
if sample_data_byte_count.odd?
|
294
|
+
riff_chunk_size += 1
|
295
|
+
end
|
290
296
|
|
291
297
|
# Write the header for the RIFF chunk
|
292
298
|
header = CHUNK_IDS[:riff]
|
293
|
-
header += [
|
299
|
+
header += [riff_chunk_size].pack(UNSIGNED_INT_32)
|
294
300
|
header += WAVEFILE_FORMAT_CODE
|
295
301
|
|
296
302
|
# Write the format chunk
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1 +1 @@
|
|
1
|
-
RIFF
|
1
|
+
RIFF
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
RIFFaa
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/test/format_test.rb
CHANGED
@@ -14,7 +14,7 @@ class FormatTest < Minitest::Test
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_invalid_channels
|
17
|
-
["dsfsfsdf", :foo, 0, -1, 65536, 2.5, 2.0].each do |invalid_channels|
|
17
|
+
["dsfsfsdf", "1", :foo, 0, -1, 65536, 2.5, 2.0].each do |invalid_channels|
|
18
18
|
assert_raises(InvalidFormatError) { Format.new(invalid_channels, :pcm_16, 44100) }
|
19
19
|
end
|
20
20
|
end
|
@@ -30,7 +30,7 @@ class FormatTest < Minitest::Test
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_invalid_sample_format
|
33
|
-
["dsfsfsdf", :foo, :pcm, 0, 12, :pcm_14, :pcm_abc, :float_40].each do |invalid_sample_format|
|
33
|
+
["dsfsfsdf", "pcm_16", :foo, :pcm, 0, 12, :pcm_14, :pcm_abc, :float_40].each do |invalid_sample_format|
|
34
34
|
assert_raises(InvalidFormatError) { Format.new(:mono, invalid_sample_format, 44100) }
|
35
35
|
end
|
36
36
|
end
|
@@ -46,13 +46,13 @@ class FormatTest < Minitest::Test
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_valid_sample_rate
|
49
|
-
[1, 44100,
|
49
|
+
[1, 44100, 4294967295].each do |valid_sample_rate|
|
50
50
|
assert_equal(valid_sample_rate, Format.new(:mono, :pcm_16, valid_sample_rate).sample_rate)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_invalid_sample_rate
|
55
|
-
["dsfsfsdf", :foo, 0, -1,
|
55
|
+
["dsfsfsdf", "44100", :foo, 0, -1, 4294967296, 44100.5, 44100.0].each do |invalid_sample_rate|
|
56
56
|
assert_raises(InvalidFormatError) { Format.new(:mono, :pcm_16, invalid_sample_rate) }
|
57
57
|
end
|
58
58
|
end
|
data/test/reader_test.rb
CHANGED
@@ -22,15 +22,27 @@ class ReaderTest < Minitest::Test
|
|
22
22
|
# File consists of "RIFF" and nothing else
|
23
23
|
"invalid/incomplete_riff_header.wav",
|
24
24
|
|
25
|
+
# The RIFF header chunk size field ends prematurely
|
26
|
+
"invalid/riff_chunk_has_incomplete_chunk_size.wav",
|
27
|
+
|
25
28
|
# First 4 bytes in the file are not "RIFF"
|
26
29
|
"invalid/bad_riff_header.wav",
|
27
30
|
|
31
|
+
# The format code in the RIFF header is missing
|
32
|
+
"invalid/no_riff_format.wav",
|
33
|
+
|
34
|
+
# The format code in the RIFF header is truncated; i.e. not a full 4 bytes
|
35
|
+
"invalid/incomplete_riff_format.wav",
|
36
|
+
|
28
37
|
# The format code in the RIFF header is not "WAVE"
|
29
38
|
"invalid/bad_wavefile_format.wav",
|
30
39
|
|
31
40
|
# The file consists of just a valid RIFF header
|
32
41
|
"invalid/no_format_chunk.wav",
|
33
42
|
|
43
|
+
# The format chunk only includes the chunk ID
|
44
|
+
"invalid/no_format_chunk_size.wav",
|
45
|
+
|
34
46
|
# The format chunk has 0 bytes in it (despite the chunk size being 16)
|
35
47
|
"invalid/empty_format_chunk.wav",
|
36
48
|
|
@@ -39,6 +51,27 @@ class ReaderTest < Minitest::Test
|
|
39
51
|
|
40
52
|
# The RIFF header and format chunk are OK, but there is no data chunk
|
41
53
|
"invalid/no_data_chunk.wav",
|
54
|
+
|
55
|
+
# The data chunk only contains the chunk ID, nothing else
|
56
|
+
"invalid/data_chunk_ends_after_chunk_id.wav",
|
57
|
+
|
58
|
+
# The data chunk size field ends prematurely
|
59
|
+
"invalid/data_chunk_has_incomplete_chunk_size.wav",
|
60
|
+
|
61
|
+
# The format chunk comes after the data chunk; it must come before
|
62
|
+
"invalid/format_chunk_after_data_chunk.wav",
|
63
|
+
|
64
|
+
# Contains a `smpl` chunk that has a size of 0 and no data
|
65
|
+
"invalid/smpl_chunk_empty.wav",
|
66
|
+
|
67
|
+
# Contains a `smpl` chunk that doesn't have enough bytes to match the chunk's size
|
68
|
+
"invalid/truncated_smpl_chunk.wav",
|
69
|
+
|
70
|
+
# `smpl` chunk does not contain as many loops as the 'loop count' field indicates
|
71
|
+
"invalid/smpl_chunk_loop_count_too_high.wav",
|
72
|
+
|
73
|
+
# `smpl` chunk does not contain as bytes as 'sampler specific data size' field indicates
|
74
|
+
"invalid/smpl_chunk_truncated_sampler_specific_data.wav",
|
42
75
|
]
|
43
76
|
|
44
77
|
invalid_fixtures.each do |fixture_name|
|
@@ -66,8 +99,9 @@ class ReaderTest < Minitest::Test
|
|
66
99
|
assert_nil(reader.format.speaker_mapping)
|
67
100
|
assert_equal(false, reader.closed?)
|
68
101
|
assert_equal(0, reader.current_sample_frame)
|
69
|
-
assert_equal(
|
102
|
+
assert_equal(0, reader.total_sample_frames)
|
70
103
|
assert_equal(false, reader.readable_format?)
|
104
|
+
assert_nil(reader.sampler_info)
|
71
105
|
reader.close
|
72
106
|
end
|
73
107
|
|
@@ -84,8 +118,9 @@ class ReaderTest < Minitest::Test
|
|
84
118
|
assert_equal([:front_center], reader.format.speaker_mapping)
|
85
119
|
assert_equal(false, reader.closed?)
|
86
120
|
assert_equal(0, reader.current_sample_frame)
|
87
|
-
assert_equal(
|
121
|
+
assert_equal(0, reader.total_sample_frames)
|
88
122
|
assert_equal(false, reader.readable_format?)
|
123
|
+
assert_nil(reader.sampler_info)
|
89
124
|
reader.close
|
90
125
|
end
|
91
126
|
end
|
@@ -146,6 +181,7 @@ class ReaderTest < Minitest::Test
|
|
146
181
|
assert_equal(0, reader.current_sample_frame)
|
147
182
|
assert_equal(2240, reader.total_sample_frames)
|
148
183
|
assert_equal(true, reader.readable_format?)
|
184
|
+
assert_nil(reader.sampler_info)
|
149
185
|
reader.close
|
150
186
|
end
|
151
187
|
|
@@ -162,6 +198,7 @@ class ReaderTest < Minitest::Test
|
|
162
198
|
assert_equal(0, reader.current_sample_frame)
|
163
199
|
assert_equal(2240, reader.total_sample_frames)
|
164
200
|
assert_equal(true, reader.readable_format?)
|
201
|
+
assert_nil(reader.sampler_info)
|
165
202
|
reader.close
|
166
203
|
end
|
167
204
|
|
@@ -178,6 +215,7 @@ class ReaderTest < Minitest::Test
|
|
178
215
|
assert_equal(1024, reader.current_sample_frame)
|
179
216
|
assert_equal(2240, reader.total_sample_frames)
|
180
217
|
assert_equal(true, reader.readable_format?)
|
218
|
+
assert_nil(reader.sampler_info)
|
181
219
|
end
|
182
220
|
end
|
183
221
|
end
|
@@ -211,6 +249,7 @@ class ReaderTest < Minitest::Test
|
|
211
249
|
assert_equal(0, reader.current_sample_frame)
|
212
250
|
assert_equal(2240, reader.total_sample_frames)
|
213
251
|
assert_equal(true, reader.readable_format?)
|
252
|
+
assert_nil(reader.sampler_info)
|
214
253
|
reader.close
|
215
254
|
|
216
255
|
buffers = read_file("valid/valid_extensible_stereo_pcm_16_44100.wav", 1024)
|
@@ -237,6 +276,7 @@ class ReaderTest < Minitest::Test
|
|
237
276
|
assert_equal(0, reader.current_sample_frame)
|
238
277
|
assert_equal(2240, reader.total_sample_frames)
|
239
278
|
assert_equal(true, reader.readable_format?)
|
279
|
+
assert_nil(reader.sampler_info)
|
240
280
|
reader.close
|
241
281
|
|
242
282
|
buffers = read_file("valid/valid_extensible_stereo_pcm_24_44100_no_speaker_mapping.wav", 1024)
|
@@ -263,6 +303,7 @@ class ReaderTest < Minitest::Test
|
|
263
303
|
assert_equal(0, reader.current_sample_frame)
|
264
304
|
assert_equal(2240, reader.total_sample_frames)
|
265
305
|
assert_equal(true, reader.readable_format?)
|
306
|
+
assert_nil(reader.sampler_info)
|
266
307
|
reader.close
|
267
308
|
|
268
309
|
buffers = read_file("valid/valid_extensible_stereo_pcm_16_44100_more_speakers_than_channels.wav", 1024)
|
@@ -307,6 +348,7 @@ class ReaderTest < Minitest::Test
|
|
307
348
|
assert_equal(0, reader.current_sample_frame)
|
308
349
|
assert_equal(2240, reader.total_sample_frames)
|
309
350
|
assert_equal(true, reader.readable_format?)
|
351
|
+
assert_nil(reader.sampler_info)
|
310
352
|
reader.close
|
311
353
|
|
312
354
|
buffers = read_file("valid/valid_extensible_stereo_pcm_16_44100_more_speakers_than_defined_by_spec.wav", 1024)
|
@@ -333,6 +375,7 @@ class ReaderTest < Minitest::Test
|
|
333
375
|
assert_equal(0, reader.current_sample_frame)
|
334
376
|
assert_equal(2240, reader.total_sample_frames)
|
335
377
|
assert_equal(true, reader.readable_format?)
|
378
|
+
assert_nil(reader.sampler_info)
|
336
379
|
reader.close
|
337
380
|
|
338
381
|
buffers = read_file("valid/valid_extensible_stereo_pcm_16_44100_only_undefined_high_bit_speakers.wav", 1024)
|
@@ -362,6 +405,7 @@ class ReaderTest < Minitest::Test
|
|
362
405
|
assert_equal(0, reader.current_sample_frame)
|
363
406
|
assert_equal(2240, reader.total_sample_frames)
|
364
407
|
assert_equal(true, reader.readable_format?)
|
408
|
+
assert_nil(reader.sampler_info)
|
365
409
|
reader.close
|
366
410
|
|
367
411
|
buffers = read_file("valid/valid_mono_pcm_16_44100_with_extension.wav", 1024)
|
@@ -387,13 +431,34 @@ class ReaderTest < Minitest::Test
|
|
387
431
|
buffers = read_file("valid/valid_mono_pcm_8_44100_with_padding_byte.wav", 1024)
|
388
432
|
|
389
433
|
assert_equal(3, buffers.length)
|
390
|
-
assert_equal([1024, 1024,
|
434
|
+
assert_equal([1024, 1024, 193], buffers.map {|buffer| buffer.samples.length })
|
391
435
|
assert_equal(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 128, buffers[0].samples)
|
392
436
|
assert_equal(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 128, buffers[1].samples)
|
393
|
-
assert_equal((SQUARE_WAVE_CYCLE[:mono][:pcm_8] *
|
437
|
+
assert_equal((SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 24) + [88],
|
394
438
|
buffers[2].samples)
|
395
439
|
end
|
396
440
|
|
441
|
+
def test_read_truncated_file
|
442
|
+
reader = Reader.new(fixture("invalid/data_chunk_truncated.wav"), Format.new(:mono, :pcm_8, 44100))
|
443
|
+
|
444
|
+
# The chunk does not actually contain this many sample frames, it actually has 2240
|
445
|
+
assert_equal(100000, reader.total_sample_frames)
|
446
|
+
assert_equal(0, reader.current_sample_frame)
|
447
|
+
|
448
|
+
# First set of requested sample frames should be read correctly
|
449
|
+
buffer = reader.read(2000)
|
450
|
+
assert_equal(2000, buffer.samples.length)
|
451
|
+
assert_equal(2000, reader.current_sample_frame)
|
452
|
+
|
453
|
+
# All of the remaining sample frames are returned, which is fewer than were requested.
|
454
|
+
buffer = reader.read(2000)
|
455
|
+
assert_equal(240, buffer.samples.length)
|
456
|
+
assert_equal(2240, reader.current_sample_frame)
|
457
|
+
|
458
|
+
# Since there are no more sample frames, an end-of-file error should be raised
|
459
|
+
assert_raises(EOFError) { reader.read(2000) }
|
460
|
+
end
|
461
|
+
|
397
462
|
def test_each_buffer_no_block_given
|
398
463
|
reader = Reader.new(fixture("valid/valid_mono_pcm_16_44100.wav"))
|
399
464
|
assert_raises(LocalJumpError) { reader.each_buffer(1024) }
|
@@ -457,13 +522,13 @@ class ReaderTest < Minitest::Test
|
|
457
522
|
reader.each_buffer(1024) {|buffer| buffers << buffer }
|
458
523
|
|
459
524
|
assert_equal(3, buffers.length)
|
460
|
-
assert_equal([1024, 1024,
|
525
|
+
assert_equal([1024, 1024, 193], buffers.map {|buffer| buffer.samples.length })
|
461
526
|
assert_equal(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 128, buffers[0].samples)
|
462
527
|
assert_equal(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 128, buffers[1].samples)
|
463
|
-
assert_equal((SQUARE_WAVE_CYCLE[:mono][:pcm_8] *
|
528
|
+
assert_equal((SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 24) + [88],
|
464
529
|
buffers[2].samples)
|
465
|
-
assert_equal(
|
466
|
-
assert_equal(
|
530
|
+
assert_equal(2241, reader.current_sample_frame)
|
531
|
+
assert_equal(2241, reader.total_sample_frames)
|
467
532
|
end
|
468
533
|
|
469
534
|
def test_each_buffer_inside_reader_block
|
@@ -492,6 +557,17 @@ class ReaderTest < Minitest::Test
|
|
492
557
|
assert_equal(2240, reader.total_sample_frames)
|
493
558
|
end
|
494
559
|
|
560
|
+
def test_read_non_data_chunk_is_final_chunk_without_padding_byte
|
561
|
+
# This fixture file contains a JUNK chunk with an odd size, but no padding byte. When a chunk
|
562
|
+
# is the final chunk in the file, a missing padding byte won't cause an error as long as the
|
563
|
+
# RIFF chunk size field matches the actual number of bytes in the file.
|
564
|
+
reader = Reader.new(fixture("valid/valid_mono_pcm_16_44100_junk_chunk_final_chunk_missing_padding_byte.wav"))
|
565
|
+
buffer = reader.read(1024)
|
566
|
+
assert_equal(buffer.samples, SQUARE_WAVE_CYCLE[:mono][:pcm_16] * 128)
|
567
|
+
assert_equal(1024, reader.current_sample_frame)
|
568
|
+
assert_equal(2240, reader.total_sample_frames)
|
569
|
+
end
|
570
|
+
|
495
571
|
def test_closed?
|
496
572
|
reader = Reader.new(fixture("valid/valid_mono_pcm_16_44100.wav"))
|
497
573
|
assert_equal(false, reader.closed?)
|
@@ -600,6 +676,188 @@ class ReaderTest < Minitest::Test
|
|
600
676
|
end
|
601
677
|
end
|
602
678
|
|
679
|
+
def test_smpl_chunk
|
680
|
+
file_name = fixture("valid/valid_with_sample_chunk_before_data_chunk.wav")
|
681
|
+
sampler_info = Reader.new(file_name).sampler_info
|
682
|
+
|
683
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
684
|
+
assert_equal(0, sampler_info.product_id)
|
685
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
686
|
+
assert_equal(60, sampler_info.midi_note)
|
687
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
688
|
+
assert_equal(0, sampler_info.smpte_format)
|
689
|
+
assert_equal(0, sampler_info.smpte_offset.hours)
|
690
|
+
assert_equal(0, sampler_info.smpte_offset.minutes)
|
691
|
+
assert_equal(0, sampler_info.smpte_offset.seconds)
|
692
|
+
assert_equal(0, sampler_info.smpte_offset.frames)
|
693
|
+
assert_equal(1, sampler_info.loops.length)
|
694
|
+
assert_equal(0, sampler_info.loops[0].id)
|
695
|
+
assert_equal(:backward, sampler_info.loops[0].type)
|
696
|
+
assert_equal(0, sampler_info.loops[0].start_sample_frame)
|
697
|
+
assert_equal(0, sampler_info.loops[0].end_sample_frame)
|
698
|
+
assert_equal(0.5, sampler_info.loops[0].fraction)
|
699
|
+
assert_equal(1, sampler_info.loops[0].play_count)
|
700
|
+
assert_equal("", sampler_info.sampler_specific_data)
|
701
|
+
end
|
702
|
+
|
703
|
+
# Several field values are out of the expected range, but the file should be successfully
|
704
|
+
# read anyway because the sample chunk has the correct structure
|
705
|
+
def test_smpl_chunk_field_values_out_of_range
|
706
|
+
file_name = fixture("invalid/smpl_chunk_fields_out_of_range.wav")
|
707
|
+
sampler_info = Reader.new(file_name).sampler_info
|
708
|
+
|
709
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
710
|
+
assert_equal(0, sampler_info.product_id)
|
711
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
712
|
+
assert_equal(10000, sampler_info.midi_note)
|
713
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
714
|
+
assert_equal(99999, sampler_info.smpte_format)
|
715
|
+
assert_equal(-128, sampler_info.smpte_offset.hours)
|
716
|
+
assert_equal(128, sampler_info.smpte_offset.minutes)
|
717
|
+
assert_equal(8, sampler_info.smpte_offset.seconds)
|
718
|
+
assert_equal(1, sampler_info.smpte_offset.frames)
|
719
|
+
assert_equal(1, sampler_info.loops.length)
|
720
|
+
assert_equal(0, sampler_info.loops[0].id)
|
721
|
+
assert_equal(88888, sampler_info.loops[0].type)
|
722
|
+
assert_equal(9999999, sampler_info.loops[0].start_sample_frame)
|
723
|
+
assert_equal(9999999, sampler_info.loops[0].end_sample_frame)
|
724
|
+
assert_equal(0.5, sampler_info.loops[0].fraction)
|
725
|
+
assert_equal(1, sampler_info.loops[0].play_count)
|
726
|
+
assert_equal("", sampler_info.sampler_specific_data)
|
727
|
+
end
|
728
|
+
|
729
|
+
def test_smpl_chunk_after_data_chunk
|
730
|
+
file_name = fixture("valid/valid_with_sample_chunk_after_data_chunk.wav")
|
731
|
+
sampler_info = Reader.new(file_name).sampler_info
|
732
|
+
|
733
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
734
|
+
assert_equal(0, sampler_info.product_id)
|
735
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
736
|
+
assert_equal(60, sampler_info.midi_note)
|
737
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
738
|
+
assert_equal(0, sampler_info.smpte_format)
|
739
|
+
assert_equal(0, sampler_info.smpte_offset.hours)
|
740
|
+
assert_equal(0, sampler_info.smpte_offset.minutes)
|
741
|
+
assert_equal(0, sampler_info.smpte_offset.seconds)
|
742
|
+
assert_equal(0, sampler_info.smpte_offset.frames)
|
743
|
+
assert_equal(1, sampler_info.loops.length)
|
744
|
+
assert_equal(0, sampler_info.loops[0].id)
|
745
|
+
assert_equal(:backward, sampler_info.loops[0].type)
|
746
|
+
assert_equal(0, sampler_info.loops[0].start_sample_frame)
|
747
|
+
assert_equal(0, sampler_info.loops[0].end_sample_frame)
|
748
|
+
assert_equal(0.5, sampler_info.loops[0].fraction)
|
749
|
+
assert_equal(1, sampler_info.loops[0].play_count)
|
750
|
+
assert_equal("", sampler_info.sampler_specific_data)
|
751
|
+
end
|
752
|
+
|
753
|
+
def test_smpl_chunk_after_data_chunk_and_data_chunk_has_padding_byte
|
754
|
+
file_name = fixture("valid/valid_with_sample_chunk_after_data_chunk_and_data_chunk_has_padding_byte.wav")
|
755
|
+
|
756
|
+
reader = Reader.new(file_name)
|
757
|
+
sampler_info = reader.sampler_info
|
758
|
+
|
759
|
+
# Should correctly deal with data chunk with odd number of bytes, followed
|
760
|
+
# by a padding byte.
|
761
|
+
assert_equal(2241, reader.total_sample_frames)
|
762
|
+
# Test that data chunk read is correctly queued up to start of data chunk
|
763
|
+
assert_equal([88, 88, 88, 88, 167, 167, 167, 167], reader.read(8).samples)
|
764
|
+
|
765
|
+
# Sample chunk should be correctly located despite the padding byte following
|
766
|
+
# the data chunk.
|
767
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
768
|
+
assert_equal(0, sampler_info.product_id)
|
769
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
770
|
+
assert_equal(60, sampler_info.midi_note)
|
771
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
772
|
+
assert_equal(0, sampler_info.smpte_format)
|
773
|
+
assert_equal(0, sampler_info.smpte_offset.hours)
|
774
|
+
assert_equal(0, sampler_info.smpte_offset.minutes)
|
775
|
+
assert_equal(0, sampler_info.smpte_offset.seconds)
|
776
|
+
assert_equal(0, sampler_info.smpte_offset.frames)
|
777
|
+
assert_equal(1, sampler_info.loops.length)
|
778
|
+
assert_equal(0, sampler_info.loops[0].id)
|
779
|
+
assert_equal(:backward, sampler_info.loops[0].type)
|
780
|
+
assert_equal(0, sampler_info.loops[0].start_sample_frame)
|
781
|
+
assert_equal(0, sampler_info.loops[0].end_sample_frame)
|
782
|
+
assert_equal(0.5, sampler_info.loops[0].fraction)
|
783
|
+
assert_equal(1, sampler_info.loops[0].play_count)
|
784
|
+
assert_equal("", sampler_info.sampler_specific_data)
|
785
|
+
end
|
786
|
+
|
787
|
+
def test_smpl_chunk_with_sampler_specific_data
|
788
|
+
file_name = fixture("valid/valid_with_sample_chunk_with_sampler_specific_data.wav")
|
789
|
+
sampler_info = Reader.new(file_name).sampler_info
|
790
|
+
|
791
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
792
|
+
assert_equal(0, sampler_info.product_id)
|
793
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
794
|
+
assert_equal(60, sampler_info.midi_note)
|
795
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
796
|
+
assert_equal(0, sampler_info.smpte_format)
|
797
|
+
assert_equal(0, sampler_info.smpte_offset.hours)
|
798
|
+
assert_equal(0, sampler_info.smpte_offset.minutes)
|
799
|
+
assert_equal(0, sampler_info.smpte_offset.seconds)
|
800
|
+
assert_equal(0, sampler_info.smpte_offset.frames)
|
801
|
+
assert_equal(1, sampler_info.loops.length)
|
802
|
+
assert_equal(0, sampler_info.loops[0].id)
|
803
|
+
assert_equal(:backward, sampler_info.loops[0].type)
|
804
|
+
assert_equal(0, sampler_info.loops[0].start_sample_frame)
|
805
|
+
assert_equal(0, sampler_info.loops[0].end_sample_frame)
|
806
|
+
assert_equal(0.5, sampler_info.loops[0].fraction)
|
807
|
+
assert_equal(Float::INFINITY, sampler_info.loops[0].play_count)
|
808
|
+
assert_equal("\x04\x01\x03\x02", sampler_info.sampler_specific_data)
|
809
|
+
assert_equal(Encoding::ASCII_8BIT, sampler_info.sampler_specific_data.encoding)
|
810
|
+
end
|
811
|
+
|
812
|
+
def test_smpl_chunk_with_extra_unused_bytes
|
813
|
+
file_name = fixture("valid/valid_with_sample_chunk_with_extra_unused_bytes.wav")
|
814
|
+
reader = Reader.new(file_name)
|
815
|
+
sampler_info = reader.sampler_info
|
816
|
+
|
817
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
818
|
+
assert_equal(0, sampler_info.product_id)
|
819
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
820
|
+
assert_equal(60, sampler_info.midi_note)
|
821
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
822
|
+
assert_equal(0, sampler_info.smpte_format)
|
823
|
+
assert_equal(0, sampler_info.smpte_offset.hours)
|
824
|
+
assert_equal(0, sampler_info.smpte_offset.minutes)
|
825
|
+
assert_equal(0, sampler_info.smpte_offset.seconds)
|
826
|
+
assert_equal(0, sampler_info.smpte_offset.frames)
|
827
|
+
assert_equal(1, sampler_info.loops.length)
|
828
|
+
assert_equal(0, sampler_info.loops[0].id)
|
829
|
+
assert_equal(:backward, sampler_info.loops[0].type)
|
830
|
+
assert_equal(0, sampler_info.loops[0].start_sample_frame)
|
831
|
+
assert_equal(0, sampler_info.loops[0].end_sample_frame)
|
832
|
+
assert_equal(0.5, sampler_info.loops[0].fraction)
|
833
|
+
assert_equal(1, sampler_info.loops[0].play_count)
|
834
|
+
assert_equal("\x04\x01\x05", sampler_info.sampler_specific_data)
|
835
|
+
assert_equal(Encoding::ASCII_8BIT, sampler_info.sampler_specific_data.encoding)
|
836
|
+
|
837
|
+
# Data chunk should be queued correctly and not raise an error, despite extra bytes
|
838
|
+
# at end of `smpl` chunk.
|
839
|
+
buffer = reader.read(1)
|
840
|
+
assert_equal([[-10000, -10000]], buffer.samples)
|
841
|
+
end
|
842
|
+
|
843
|
+
def test_smpl_chunk_no_loops
|
844
|
+
file_name = fixture("valid/valid_with_sample_chunk_no_loops.wav")
|
845
|
+
sampler_info = Reader.new(file_name).sampler_info
|
846
|
+
|
847
|
+
assert_equal(0, sampler_info.manufacturer_id)
|
848
|
+
assert_equal(0, sampler_info.product_id)
|
849
|
+
assert_equal(0, sampler_info.sample_nanoseconds)
|
850
|
+
assert_equal(60, sampler_info.midi_note)
|
851
|
+
assert_equal(50.0, sampler_info.fine_tuning_cents)
|
852
|
+
assert_equal(0, sampler_info.smpte_format)
|
853
|
+
assert_equal(0, sampler_info.smpte_offset.hours)
|
854
|
+
assert_equal(0, sampler_info.smpte_offset.minutes)
|
855
|
+
assert_equal(0, sampler_info.smpte_offset.seconds)
|
856
|
+
assert_equal(0, sampler_info.smpte_offset.frames)
|
857
|
+
assert_equal([], sampler_info.loops)
|
858
|
+
assert_equal("", sampler_info.sampler_specific_data)
|
859
|
+
end
|
860
|
+
|
603
861
|
private
|
604
862
|
|
605
863
|
def read_file(file_name, buffer_size, format=nil)
|