wavefile 0.3.0 → 0.4.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.
- data/LICENSE +1 -1
- data/README.markdown +29 -56
- data/Rakefile +6 -0
- data/lib/wavefile.rb +28 -452
- data/lib/wavefile/buffer.rb +147 -0
- data/lib/wavefile/format.rb +69 -0
- data/lib/wavefile/info.rb +53 -0
- data/lib/wavefile/reader.rb +296 -0
- data/lib/wavefile/writer.rb +128 -0
- data/test/buffer_test.rb +121 -0
- data/test/fixtures/actual_output/valid_mono_8_44100_with_padding_byte.wav +0 -0
- data/test/fixtures/expected_output/no_samples.wav +0 -0
- data/test/fixtures/expected_output/valid_mono_16_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_mono_32_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_mono_8_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_mono_8_44100_with_padding_byte.wav +0 -0
- data/test/fixtures/expected_output/valid_stereo_16_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_stereo_32_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_stereo_8_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_tri_16_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_tri_32_44100.wav +0 -0
- data/test/fixtures/expected_output/valid_tri_8_44100.wav +0 -0
- data/test/fixtures/invalid/README.markdown +10 -0
- data/test/fixtures/invalid/bad_riff_header.wav +1 -0
- data/test/fixtures/invalid/bad_wavefile_format.wav +0 -0
- data/test/fixtures/invalid/empty.wav +0 -0
- data/test/fixtures/invalid/empty_format_chunk.wav +0 -0
- data/test/fixtures/invalid/incomplete_riff_header.wav +1 -0
- data/test/fixtures/invalid/insufficient_format_chunk.wav +0 -0
- data/test/fixtures/invalid/no_data_chunk.wav +0 -0
- data/test/fixtures/invalid/no_format_chunk.wav +0 -0
- data/test/fixtures/unsupported/README.markdown +6 -0
- data/test/fixtures/unsupported/bad_audio_format.wav +0 -0
- data/test/fixtures/unsupported/bad_channel_count.wav +0 -0
- data/test/fixtures/unsupported/bad_sample_rate.wav +0 -0
- data/test/fixtures/unsupported/unsupported_audio_format.wav +0 -0
- data/test/fixtures/unsupported/unsupported_bits_per_sample.wav +0 -0
- data/test/fixtures/valid/README.markdown +3 -0
- data/test/fixtures/valid/valid_mono_16_44100.wav +0 -0
- data/test/fixtures/valid/valid_mono_32_44100.wav +0 -0
- data/test/fixtures/valid/valid_mono_8_44100.wav +0 -0
- data/test/fixtures/valid/valid_mono_8_44100_with_padding_byte.wav +0 -0
- data/test/fixtures/valid/valid_stereo_16_44100.wav +0 -0
- data/test/fixtures/valid/valid_stereo_32_44100.wav +0 -0
- data/test/fixtures/valid/valid_stereo_8_44100.wav +0 -0
- data/test/fixtures/valid/valid_tri_16_44100.wav +0 -0
- data/test/fixtures/valid/valid_tri_32_44100.wav +0 -0
- data/test/fixtures/valid/valid_tri_8_44100.wav +0 -0
- data/test/format_test.rb +105 -0
- data/test/info_test.rb +60 -0
- data/test/reader_test.rb +222 -0
- data/test/wavefile_io_test_helper.rb +47 -0
- data/test/writer_test.rb +118 -0
- metadata +72 -33
- data/test/wavefile_test.rb +0 -339
data/test/info_test.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'wavefile.rb'
|
3
|
+
|
4
|
+
include WaveFile
|
5
|
+
|
6
|
+
class InfoTest < Test::Unit::TestCase
|
7
|
+
FILE_NAME = "foo.wav"
|
8
|
+
SECONDS_IN_MINUTE = 60
|
9
|
+
SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60
|
10
|
+
|
11
|
+
def test_basic
|
12
|
+
format_chunk = { :audio_format => 1, :channels => 2, :sample_rate => 44100,
|
13
|
+
:byte_rate => 176400, :block_align => 4, :bits_per_sample => 16 }
|
14
|
+
info = Info.new(FILE_NAME, format_chunk, 44100)
|
15
|
+
|
16
|
+
assert_equal(FILE_NAME, info.file_name)
|
17
|
+
assert_equal(1, info.audio_format)
|
18
|
+
assert_equal(2, info.channels)
|
19
|
+
assert_equal(44100, info.sample_rate)
|
20
|
+
assert_equal(176400, info.byte_rate)
|
21
|
+
assert_equal(4, info.block_align)
|
22
|
+
assert_equal(16, info.bits_per_sample)
|
23
|
+
assert_equal(44100, info.sample_count)
|
24
|
+
assert_equal({:hours => 0, :minutes => 0, :seconds => 1, :milliseconds => 0}, info.duration)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_duration
|
28
|
+
format_chunk = { :audio_format => 1, :channels => 2, :byte_rate => 176400, :block_align => 4, :bits_per_sample => 16 }
|
29
|
+
|
30
|
+
# Test common sample rates (22050 and 44100), and some crazy arbitrary sample rate (12346)
|
31
|
+
[22050, 44100, 12346].each do |sample_rate|
|
32
|
+
format_chunk[:sample_rate] = sample_rate
|
33
|
+
|
34
|
+
info = Info.new(FILE_NAME, format_chunk, 0)
|
35
|
+
assert_equal({:hours => 0, :minutes => 0, :seconds => 0, :milliseconds => 0}, info.duration)
|
36
|
+
|
37
|
+
info = Info.new(FILE_NAME, format_chunk, sample_rate / 2)
|
38
|
+
assert_equal({:hours => 0, :minutes => 0, :seconds => 0, :milliseconds => 500}, info.duration)
|
39
|
+
|
40
|
+
info = Info.new(FILE_NAME, format_chunk, sample_rate)
|
41
|
+
assert_equal({:hours => 0, :minutes => 0, :seconds => 1, :milliseconds => 0}, info.duration)
|
42
|
+
|
43
|
+
info = Info.new(FILE_NAME, format_chunk, sample_rate * SECONDS_IN_MINUTE)
|
44
|
+
assert_equal({:hours => 0, :minutes => 1, :seconds => 0, :milliseconds => 0}, info.duration)
|
45
|
+
|
46
|
+
info = Info.new(FILE_NAME, format_chunk, sample_rate * SECONDS_IN_HOUR)
|
47
|
+
assert_equal({:hours => 1, :minutes => 0, :seconds => 0, :milliseconds => 0}, info.duration)
|
48
|
+
|
49
|
+
info = Info.new(FILE_NAME, format_chunk, (sample_rate * SECONDS_IN_MINUTE) + sample_rate + (sample_rate / 2))
|
50
|
+
assert_equal({:hours => 0, :minutes => 1, :seconds => 1, :milliseconds => 500}, info.duration)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Test for when the number of hours is more than a day.
|
54
|
+
format_chunk[:sample_rate] = 44100
|
55
|
+
samples_per_hour = 44100 * 60 * 60
|
56
|
+
info = Info.new(FILE_NAME, format_chunk, samples_per_hour * 25)
|
57
|
+
assert_equal({:hours => 25, :minutes => 0, :seconds => 0, :milliseconds => 0}, info.duration)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
data/test/reader_test.rb
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'wavefile.rb'
|
3
|
+
require 'wavefile_io_test_helper.rb'
|
4
|
+
|
5
|
+
include WaveFile
|
6
|
+
|
7
|
+
class ReaderTest < Test::Unit::TestCase
|
8
|
+
include WaveFileIOTestHelper
|
9
|
+
|
10
|
+
FIXTURE_ROOT_PATH = "test/fixtures"
|
11
|
+
|
12
|
+
|
13
|
+
def test_nonexistent_file
|
14
|
+
assert_raise(Errno::ENOENT) { Reader.new(fixture("i_do_not_exist.wav")) }
|
15
|
+
|
16
|
+
assert_raise(Errno::ENOENT) { Reader.info(fixture("i_do_not_exist.wav")) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_invalid_formats
|
20
|
+
# Reader.new() and Reader.info() should raise the same errors for invalid files,
|
21
|
+
# so run the tests for both methods.
|
22
|
+
[:new, :info].each do |method_name|
|
23
|
+
# File contains 0 bytes
|
24
|
+
assert_raise(InvalidFormatError) { Reader.send(method_name, fixture("invalid/empty.wav")) }
|
25
|
+
|
26
|
+
# File consists of "RIFF" and nothing else
|
27
|
+
assert_raise(InvalidFormatError) { Reader.send(method_name, fixture("invalid/incomplete_riff_header.wav")) }
|
28
|
+
|
29
|
+
# First 4 bytes in the file are not "RIFF"
|
30
|
+
assert_raise(InvalidFormatError) { Reader.send(method_name, fixture("invalid/bad_riff_header.wav")) }
|
31
|
+
|
32
|
+
# The format code in the RIFF header is not "WAVE"
|
33
|
+
assert_raise(InvalidFormatError) { Reader.new(fixture("invalid/bad_wavefile_format.wav")) }
|
34
|
+
|
35
|
+
# The file consists of just a valid RIFF header
|
36
|
+
assert_raise(InvalidFormatError) { Reader.new(fixture("invalid/no_format_chunk.wav")) }
|
37
|
+
|
38
|
+
# The format chunk has 0 bytes in it (despite the chunk size being 16)
|
39
|
+
assert_raise(InvalidFormatError) { Reader.new(fixture("invalid/empty_format_chunk.wav")) }
|
40
|
+
|
41
|
+
# The format chunk has some data, but not all of the minimum required.
|
42
|
+
assert_raise(InvalidFormatError) { Reader.new(fixture("invalid/insufficient_format_chunk.wav")) }
|
43
|
+
|
44
|
+
# The RIFF header and format chunk are OK, but there is no data chunk
|
45
|
+
assert_raise(InvalidFormatError) { Reader.new(fixture("invalid/no_data_chunk.wav")) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_unsupported_formats
|
50
|
+
# Audio format is 2, which is not supported
|
51
|
+
assert_raise(UnsupportedFormatError) { Reader.new(fixture("unsupported/unsupported_audio_format.wav")) }
|
52
|
+
|
53
|
+
# Bits per sample is 24, which is not supported
|
54
|
+
assert_raise(UnsupportedFormatError) { Reader.new(fixture("unsupported/unsupported_bits_per_sample.wav")) }
|
55
|
+
|
56
|
+
# Channel count is 0
|
57
|
+
assert_raise(UnsupportedFormatError) { Reader.new(fixture("unsupported/bad_channel_count.wav")) }
|
58
|
+
|
59
|
+
# Sample rate is 0
|
60
|
+
assert_raise(UnsupportedFormatError) { Reader.new(fixture("unsupported/bad_sample_rate.wav")) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_initialize
|
64
|
+
format = Format.new(:stereo, 16, 22050)
|
65
|
+
|
66
|
+
exhaustively_test do |channels, bits_per_sample|
|
67
|
+
file_name = fixture("valid/valid_#{channels}_#{bits_per_sample}_44100.wav")
|
68
|
+
|
69
|
+
# Read native format
|
70
|
+
reader = Reader.new(file_name)
|
71
|
+
assert_equal(CHANNEL_ALIAS[channels], reader.format.channels)
|
72
|
+
assert_equal(bits_per_sample, reader.format.bits_per_sample)
|
73
|
+
assert_equal(44100, reader.format.sample_rate)
|
74
|
+
assert_equal(false, reader.closed?)
|
75
|
+
assert_equal(file_name, reader.file_name)
|
76
|
+
reader.close()
|
77
|
+
|
78
|
+
# Read a non-native format
|
79
|
+
reader = Reader.new(file_name, format)
|
80
|
+
assert_equal(2, reader.format.channels)
|
81
|
+
assert_equal(16, reader.format.bits_per_sample)
|
82
|
+
assert_equal(22050, reader.format.sample_rate)
|
83
|
+
assert_equal(false, reader.closed?)
|
84
|
+
assert_equal(file_name, reader.file_name)
|
85
|
+
reader.close()
|
86
|
+
|
87
|
+
# Block is given.
|
88
|
+
reader = Reader.new(file_name) {|reader| reader.read(1024) }
|
89
|
+
assert_equal(CHANNEL_ALIAS[channels], reader.format.channels)
|
90
|
+
assert_equal(bits_per_sample, reader.format.bits_per_sample)
|
91
|
+
assert_equal(44100, reader.format.sample_rate)
|
92
|
+
assert(reader.closed?)
|
93
|
+
assert_equal(file_name, reader.file_name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_read_native_format
|
98
|
+
exhaustively_test do |channels, bits_per_sample|
|
99
|
+
buffers = read_file("valid/valid_#{channels}_#{bits_per_sample}_44100.wav", 1024)
|
100
|
+
|
101
|
+
assert_equal(3, buffers.length)
|
102
|
+
assert_equal([1024, 1024, 192], buffers.map {|buffer| buffer.samples.length })
|
103
|
+
assert_equal(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 128, buffers[0].samples)
|
104
|
+
assert_equal(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 128, buffers[1].samples)
|
105
|
+
assert_equal(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 24, buffers[2].samples)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_read_with_format_conversion
|
110
|
+
buffers = read_file("valid/valid_mono_16_44100.wav", 1024, Format.new(:stereo, 8, 22100))
|
111
|
+
|
112
|
+
assert_equal(3, buffers.length)
|
113
|
+
assert_equal([1024, 1024, 192], buffers.map {|buffer| buffer.samples.length })
|
114
|
+
assert_equal(SQUARE_WAVE_CYCLE[:stereo][8] * 128, buffers[0].samples)
|
115
|
+
assert_equal(SQUARE_WAVE_CYCLE[:stereo][8] * 128, buffers[1].samples)
|
116
|
+
assert_equal(SQUARE_WAVE_CYCLE[:stereo][8] * 24, buffers[2].samples)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_read_with_padding_byte
|
120
|
+
buffers = read_file("valid/valid_mono_8_44100_with_padding_byte.wav", 1024)
|
121
|
+
|
122
|
+
assert_equal(3, buffers.length)
|
123
|
+
assert_equal([1024, 1024, 191], buffers.map {|buffer| buffer.samples.length })
|
124
|
+
assert_equal(SQUARE_WAVE_CYCLE[:mono][8] * 128, buffers[0].samples)
|
125
|
+
assert_equal(SQUARE_WAVE_CYCLE[:mono][8] * 128, buffers[1].samples)
|
126
|
+
assert_equal((SQUARE_WAVE_CYCLE[:mono][8] * 23) + [88, 88, 88, 88, 167, 167, 167],
|
127
|
+
buffers[2].samples)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_each_buffer_no_block_given
|
131
|
+
reader = Reader.new(fixture("valid/valid_mono_16_44100.wav"))
|
132
|
+
assert_raise(LocalJumpError) { reader.each_buffer(1024) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_each_buffer_native_format
|
136
|
+
exhaustively_test do |channels, bits_per_sample|
|
137
|
+
reader = Reader.new(fixture("valid/valid_#{channels}_#{bits_per_sample}_44100.wav"))
|
138
|
+
|
139
|
+
buffers = []
|
140
|
+
reader.each_buffer(1024) {|buffer| buffers << buffer }
|
141
|
+
|
142
|
+
assert(reader.closed?)
|
143
|
+
assert_equal(3, buffers.length)
|
144
|
+
assert_equal([1024, 1024, 192], buffers.map {|buffer| buffer.samples.length })
|
145
|
+
assert_equal(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 128, buffers[0].samples)
|
146
|
+
assert_equal(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 128, buffers[1].samples)
|
147
|
+
assert_equal(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 24, buffers[2].samples)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_each_buffer_with_format_conversion
|
152
|
+
reader = Reader.new(fixture("valid/valid_mono_16_44100.wav"), Format.new(:stereo, 8, 22050))
|
153
|
+
assert_equal(2, reader.format.channels)
|
154
|
+
assert_equal(8, reader.format.bits_per_sample)
|
155
|
+
assert_equal(22050, reader.format.sample_rate)
|
156
|
+
|
157
|
+
buffers = []
|
158
|
+
reader.each_buffer(1024) {|buffer| buffers << buffer }
|
159
|
+
|
160
|
+
assert_equal(3, buffers.length)
|
161
|
+
assert_equal([1024, 1024, 192], buffers.map {|buffer| buffer.samples.length })
|
162
|
+
assert_equal(SQUARE_WAVE_CYCLE[:stereo][8] * 128, buffers[0].samples)
|
163
|
+
assert_equal(SQUARE_WAVE_CYCLE[:stereo][8] * 128, buffers[1].samples)
|
164
|
+
assert_equal(SQUARE_WAVE_CYCLE[:stereo][8] * 24, buffers[2].samples)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_each_buffer_with_padding_byte
|
168
|
+
buffers = []
|
169
|
+
reader = Reader.new(fixture("valid/valid_mono_8_44100_with_padding_byte.wav"))
|
170
|
+
reader.each_buffer(1024) {|buffer| buffers << buffer }
|
171
|
+
|
172
|
+
assert_equal(3, buffers.length)
|
173
|
+
assert_equal([1024, 1024, 191], buffers.map {|buffer| buffer.samples.length })
|
174
|
+
assert_equal(SQUARE_WAVE_CYCLE[:mono][8] * 128, buffers[0].samples)
|
175
|
+
assert_equal(SQUARE_WAVE_CYCLE[:mono][8] * 128, buffers[1].samples)
|
176
|
+
assert_equal((SQUARE_WAVE_CYCLE[:mono][8] * 23) + [88, 88, 88, 88, 167, 167, 167],
|
177
|
+
buffers[2].samples)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_closed?
|
181
|
+
reader = Reader.new(fixture("valid/valid_mono_16_44100.wav"))
|
182
|
+
assert_equal(false, reader.closed?)
|
183
|
+
reader.close()
|
184
|
+
assert(reader.closed?)
|
185
|
+
|
186
|
+
# For Reader.each_buffer()
|
187
|
+
reader = Reader.new(fixture("valid/valid_mono_16_44100.wav"))
|
188
|
+
assert_equal(false, reader.closed?)
|
189
|
+
reader.each_buffer(1024) do |buffer|
|
190
|
+
# No-op
|
191
|
+
end
|
192
|
+
assert_equal(true, reader.closed?)
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_read_after_close
|
196
|
+
reader = Reader.new(fixture("valid/valid_mono_16_44100.wav"))
|
197
|
+
buffer = reader.read(1024)
|
198
|
+
reader.close()
|
199
|
+
assert_raise(IOError) { reader.read(1024) }
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
def read_file(file_name, buffer_size, format=nil)
|
205
|
+
buffers = []
|
206
|
+
reader = Reader.new(fixture(file_name), format)
|
207
|
+
|
208
|
+
begin
|
209
|
+
while true do
|
210
|
+
buffers << reader.read(buffer_size)
|
211
|
+
end
|
212
|
+
rescue EOFError
|
213
|
+
reader.close()
|
214
|
+
end
|
215
|
+
|
216
|
+
return buffers
|
217
|
+
end
|
218
|
+
|
219
|
+
def fixture(fixture_name)
|
220
|
+
return "#{FIXTURE_ROOT_PATH}/#{fixture_name}"
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module WaveFileIOTestHelper
|
2
|
+
CHANNEL_ALIAS = { :mono => 1, :stereo => 2, :tri => 3}
|
3
|
+
|
4
|
+
SQUARE_WAVE_CYCLE = {}
|
5
|
+
SQUARE_WAVE_CYCLE[:mono] = {}
|
6
|
+
|
7
|
+
SQUARE_WAVE_CYCLE[:mono][8] = [88, 88, 88, 88, 167, 167, 167, 167]
|
8
|
+
SQUARE_WAVE_CYCLE[:mono][16] = [-10000, -10000, -10000, -10000, 10000, 10000, 10000, 10000]
|
9
|
+
SQUARE_WAVE_CYCLE[:mono][32] = [-1000000000, -1000000000, -1000000000, -1000000000,
|
10
|
+
1000000000, 1000000000, 1000000000, 1000000000]
|
11
|
+
|
12
|
+
SQUARE_WAVE_CYCLE[:stereo] = {}
|
13
|
+
SQUARE_WAVE_CYCLE[:stereo][8] = [[88, 88], [88, 88], [88, 88], [88, 88],
|
14
|
+
[167, 167], [167, 167], [167, 167], [167, 167]]
|
15
|
+
SQUARE_WAVE_CYCLE[:stereo][16] = [[-10000, -10000], [-10000, -10000], [-10000, -10000], [-10000, -10000],
|
16
|
+
[10000, 10000], [10000, 10000], [10000, 10000], [10000, 10000]]
|
17
|
+
SQUARE_WAVE_CYCLE[:stereo][32] = [[-1000000000, -1000000000], [-1000000000, -1000000000],
|
18
|
+
[-1000000000, -1000000000], [-1000000000, -1000000000],
|
19
|
+
[ 1000000000, 1000000000], [ 1000000000, 1000000000],
|
20
|
+
[ 1000000000, 1000000000], [ 1000000000, 1000000000]]
|
21
|
+
|
22
|
+
SQUARE_WAVE_CYCLE[:tri] = {}
|
23
|
+
SQUARE_WAVE_CYCLE[:tri][8] = [[88, 88, 88], [88, 88, 88], [88, 88, 88], [88, 88, 88],
|
24
|
+
[167, 167, 167], [167, 167, 167], [167, 167, 167], [167, 167, 167]]
|
25
|
+
SQUARE_WAVE_CYCLE[:tri][16] = [[-10000, -10000, -10000], [-10000, -10000, -10000],
|
26
|
+
[-10000, -10000, -10000], [-10000, -10000, -10000],
|
27
|
+
[ 10000, 10000, 10000], [ 10000, 10000, 10000],
|
28
|
+
[ 10000, 10000, 10000], [ 10000, 10000, 10000]]
|
29
|
+
SQUARE_WAVE_CYCLE[:tri][32] = [[-1000000000, -1000000000, -1000000000],
|
30
|
+
[-1000000000, -1000000000, -1000000000],
|
31
|
+
[-1000000000, -1000000000, -1000000000],
|
32
|
+
[-1000000000, -1000000000, -1000000000],
|
33
|
+
[ 1000000000, 1000000000, 1000000000],
|
34
|
+
[ 1000000000, 1000000000, 1000000000],
|
35
|
+
[ 1000000000, 1000000000, 1000000000],
|
36
|
+
[ 1000000000, 1000000000, 1000000000]]
|
37
|
+
|
38
|
+
|
39
|
+
# Executes the given block against different combinations of number of channels and bits per sample.
|
40
|
+
def exhaustively_test
|
41
|
+
[:mono, :stereo, :tri].each do |channels|
|
42
|
+
Format::SUPPORTED_BITS_PER_SAMPLE.each do |bits_per_sample|
|
43
|
+
yield(channels, bits_per_sample)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/writer_test.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'wavefile.rb'
|
3
|
+
require 'wavefile_io_test_helper.rb'
|
4
|
+
|
5
|
+
include WaveFile
|
6
|
+
|
7
|
+
class WriterTest < Test::Unit::TestCase
|
8
|
+
include WaveFileIOTestHelper
|
9
|
+
|
10
|
+
OUTPUT_FOLDER = "test/fixtures/actual_output"
|
11
|
+
|
12
|
+
def setup
|
13
|
+
clean_output_folder()
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_write_file_with_no_sample_data
|
17
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/no_samples.wav", Format.new(1, 8, 44100))
|
18
|
+
writer.close()
|
19
|
+
|
20
|
+
assert_equal(read_file(:expected, "no_samples.wav"), read_file(:actual, "no_samples.wav"))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_write_basic_file
|
24
|
+
exhaustively_test do |channels, bits_per_sample|
|
25
|
+
file_name = "valid_#{channels}_#{bits_per_sample}_44100.wav"
|
26
|
+
format = Format.new(CHANNEL_ALIAS[channels], bits_per_sample, 44100)
|
27
|
+
|
28
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/#{file_name}", format)
|
29
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 128, format))
|
30
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 128, format))
|
31
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 24, format))
|
32
|
+
writer.close()
|
33
|
+
|
34
|
+
assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_write_basic_file_with_a_block
|
39
|
+
exhaustively_test do |channels, bits_per_sample|
|
40
|
+
file_name = "valid_#{channels}_#{bits_per_sample}_44100.wav"
|
41
|
+
format = Format.new(CHANNEL_ALIAS[channels], bits_per_sample, 44100)
|
42
|
+
|
43
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/#{file_name}", format) do |writer|
|
44
|
+
4.times do
|
45
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 70, format))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
|
50
|
+
assert(writer.closed?)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_write_buffers_of_different_formats
|
55
|
+
file_name = "valid_mono_8_44100.wav"
|
56
|
+
format_8bit_mono = Format.new(:mono, 8, 44100)
|
57
|
+
format_16_bit_mono = Format.new(:mono, 16, 22050)
|
58
|
+
format_16bit_stereo = Format.new(:stereo, 16, 44100)
|
59
|
+
|
60
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/#{file_name}", format_8bit_mono)
|
61
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:stereo][16] * 128, format_16bit_stereo))
|
62
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][16] * 128, format_16_bit_mono))
|
63
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:stereo][16] * 24, format_16bit_stereo))
|
64
|
+
writer.close()
|
65
|
+
|
66
|
+
assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_write_file_with_padding_byte
|
70
|
+
file_name = "valid_mono_8_44100_with_padding_byte.wav"
|
71
|
+
format = Format.new(1, 8, 44100)
|
72
|
+
|
73
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/#{file_name}", format)
|
74
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][8] * 128, format))
|
75
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][8] * 128, format))
|
76
|
+
writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][8] * 23 + [88, 88, 88, 88, 167, 167, 167], format))
|
77
|
+
writer.close()
|
78
|
+
|
79
|
+
assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_closed?
|
83
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/closed_test.wav", Format.new(1, 16, 44100))
|
84
|
+
assert_equal(false, writer.closed?)
|
85
|
+
writer.close()
|
86
|
+
assert(writer.closed?)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_attempt_to_write_after_close
|
90
|
+
format = Format.new(1, 8, 44100)
|
91
|
+
|
92
|
+
writer = Writer.new("#{OUTPUT_FOLDER}/write_after_close.wav", format)
|
93
|
+
writer.write(Buffer.new([1, 2, 3, 4], format))
|
94
|
+
writer.close()
|
95
|
+
|
96
|
+
assert_raise(IOError) { writer.write(Buffer.new([5, 6, 7, 8], format)) }
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def read_file(type, file_name)
|
102
|
+
# For Windows compatibility with binary files, File.read() is not directly used
|
103
|
+
return File.open("test/fixtures/#{type}_output/#{file_name}", "rb") {|f| f.read() }
|
104
|
+
end
|
105
|
+
|
106
|
+
def clean_output_folder()
|
107
|
+
# Make the folder if it doesn't already exist
|
108
|
+
Dir.mkdir(OUTPUT_FOLDER) unless File.exists?(OUTPUT_FOLDER)
|
109
|
+
|
110
|
+
dir = Dir.new(OUTPUT_FOLDER)
|
111
|
+
file_names = dir.entries
|
112
|
+
file_names.each do |file_name|
|
113
|
+
if(file_name != "." && file_name != "..")
|
114
|
+
File.delete("#{OUTPUT_FOLDER}/#{file_name}")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|