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
data/test/writer_test.rb CHANGED
@@ -10,39 +10,39 @@ class WriterTest < Test::Unit::TestCase
10
10
  OUTPUT_FOLDER = "test/fixtures/actual_output"
11
11
 
12
12
  def setup
13
- clean_output_folder()
13
+ clean_output_folder
14
14
  end
15
15
 
16
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
-
17
+ writer = Writer.new("#{OUTPUT_FOLDER}/no_samples.wav", Format.new(:mono, :pcm_8, 44100))
18
+ writer.close
19
+
20
20
  assert_equal(read_file(:expected, "no_samples.wav"), read_file(:actual, "no_samples.wav"))
21
21
  end
22
22
 
23
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)
24
+ exhaustively_test do |channels, sample_format|
25
+ file_name = "valid_#{channels}_#{sample_format}_44100.wav"
26
+ format = Format.new(CHANNEL_ALIAS[channels], sample_format, 44100)
27
27
 
28
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()
29
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 128, format))
30
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 128, format))
31
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 24, format))
32
+ writer.close
33
33
 
34
34
  assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
35
35
  end
36
36
  end
37
37
 
38
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)
39
+ exhaustively_test do |channels, sample_format|
40
+ file_name = "valid_#{channels}_#{sample_format}_44100.wav"
41
+ format = Format.new(CHANNEL_ALIAS[channels], sample_format, 44100)
42
42
 
43
43
  writer = Writer.new("#{OUTPUT_FOLDER}/#{file_name}", format) do |writer|
44
44
  4.times do
45
- writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][bits_per_sample] * 70, format))
45
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 70, format))
46
46
  end
47
47
  end
48
48
 
@@ -52,58 +52,145 @@ class WriterTest < Test::Unit::TestCase
52
52
  end
53
53
 
54
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)
55
+ file_name = "valid_mono_pcm_8_44100.wav"
56
+ format_8bit_mono = Format.new(:mono, :pcm_8, 44100)
57
+ format_16_bit_mono = Format.new(:mono, :pcm_16, 22050)
58
+ format_16bit_stereo = Format.new(:stereo, :pcm_16, 44100)
59
59
 
60
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()
61
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:stereo][:pcm_16] * 128, format_16bit_stereo))
62
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][:pcm_16] * 128, format_16_bit_mono))
63
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:stereo][:pcm_16] * 24, format_16bit_stereo))
64
+ writer.close
65
65
 
66
66
  assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
67
67
  end
68
68
 
69
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)
70
+ file_name = "valid_mono_pcm_8_44100_with_padding_byte.wav"
71
+ format = Format.new(:mono, :pcm_8, 44100)
72
72
 
73
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()
74
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 128, format))
75
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 128, format))
76
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:mono][:pcm_8] * 23 + [88, 88, 88, 88, 167, 167, 167], format))
77
+ writer.close
78
78
 
79
79
  assert_equal(read_file(:expected, file_name), read_file(:actual, file_name))
80
80
  end
81
-
81
+
82
+ def test_file_name
83
+ file_name = "#{OUTPUT_FOLDER}/example.wav"
84
+
85
+ writer = Writer.new(file_name, Format.new(:mono, :pcm_8, 44100))
86
+ assert_equal("#{OUTPUT_FOLDER}/example.wav", writer.file_name)
87
+
88
+ writer.close
89
+ assert_equal("#{OUTPUT_FOLDER}/example.wav", writer.file_name)
90
+ end
91
+
82
92
  def test_closed?
83
- writer = Writer.new("#{OUTPUT_FOLDER}/closed_test.wav", Format.new(1, 16, 44100))
93
+ writer = Writer.new("#{OUTPUT_FOLDER}/closed_test.wav", Format.new(:mono, :pcm_16, 44100))
84
94
  assert_equal(false, writer.closed?)
85
- writer.close()
95
+ writer.close
86
96
  assert(writer.closed?)
87
97
  end
88
98
 
89
99
  def test_attempt_to_write_after_close
90
- format = Format.new(1, 8, 44100)
100
+ format = Format.new(:mono, :pcm_8, 44100)
91
101
 
92
102
  writer = Writer.new("#{OUTPUT_FOLDER}/write_after_close.wav", format)
93
103
  writer.write(Buffer.new([1, 2, 3, 4], format))
94
- writer.close()
104
+ writer.close
95
105
 
96
106
  assert_raise(IOError) { writer.write(Buffer.new([5, 6, 7, 8], format)) }
97
107
  end
98
108
 
109
+ def test_total_duration
110
+ exhaustively_test do |channels, sample_format|
111
+ format = Format.new(CHANNEL_ALIAS[channels], sample_format, 44100)
112
+
113
+ writer = Writer.new("#{OUTPUT_FOLDER}/total_duration_#{channels}_#{sample_format}_44100.wav", format)
114
+
115
+ assert_equal(0, writer.total_sample_frames)
116
+ duration = writer.total_duration
117
+ assert_equal(0, duration.sample_frame_count)
118
+ assert_equal(44100, duration.sample_rate)
119
+ assert_equal(0, duration.hours)
120
+ assert_equal(0, duration.minutes)
121
+ assert_equal(0, duration.seconds)
122
+ assert_equal(0, duration.milliseconds)
123
+
124
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 2756, format))
125
+
126
+ assert_equal(8 * 2756, writer.total_sample_frames)
127
+ duration = writer.total_duration
128
+ assert_equal(8 * 2756, duration.sample_frame_count)
129
+ assert_equal(44100, duration.sample_rate)
130
+ assert_equal(0, duration.hours)
131
+ assert_equal(0, duration.minutes)
132
+ assert_equal(0, duration.seconds)
133
+ assert_equal(499, duration.milliseconds)
134
+
135
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 2756, format))
136
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[channels][sample_format] * 2756, format))
137
+
138
+ assert_equal(8 * 2756 * 3, writer.total_sample_frames)
139
+ duration = writer.total_duration
140
+ assert_equal(8 * 2756 * 3, duration.sample_frame_count)
141
+ assert_equal(44100, duration.sample_rate)
142
+ assert_equal(0, duration.hours)
143
+ assert_equal(0, duration.minutes)
144
+ assert_equal(1, duration.seconds)
145
+ assert_equal(499, duration.milliseconds)
146
+
147
+ writer.close
148
+
149
+ assert_equal(8 * 2756 * 3, writer.total_sample_frames)
150
+ duration = writer.total_duration
151
+ assert_equal(8 * 2756 * 3, duration.sample_frame_count)
152
+ assert_equal(44100, duration.sample_rate)
153
+ assert_equal(0, duration.hours)
154
+ assert_equal(0, duration.minutes)
155
+ assert_equal(1, duration.seconds)
156
+ assert_equal(499, duration.milliseconds)
157
+ end
158
+ end
159
+
160
+ # Cause an exception within the block passed to Writer.new, to prove
161
+ # that close is still called (due to an ensure statement in Writer.new).
162
+ def test_exception_with_block
163
+ format = Format.new(:mono, :pcm_8, 44100)
164
+ samples = [1, 2, 3, 4, 5, 6]
165
+ Writer.new("#{OUTPUT_FOLDER}/exception_with_block.wav", format) do |writer|
166
+ begin
167
+ writer.write(Buffer.new(samples, format))
168
+ 1 / 0 # cause divide-by-zero exception
169
+ rescue
170
+ # catch the exception and ignore, so test passes OK
171
+ end
172
+ end
173
+
174
+ reader = Reader.new("#{OUTPUT_FOLDER}/exception_with_block.wav")
175
+ assert_equal(samples.size, reader.total_sample_frames)
176
+ end
177
+
99
178
  private
100
179
 
101
180
  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() }
181
+ if type == :expected
182
+ fixture_folder = 'valid'
183
+ elsif type == :actual
184
+ fixture_folder = 'actual_output'
185
+ else
186
+ raise 'Invalid fixture type'
187
+ end
188
+
189
+ # For Windows compatibility with binary files, File.read is not directly used
190
+ File.open("test/fixtures/#{fixture_folder}/#{file_name}", "rb") {|f| f.read }
104
191
  end
105
192
 
106
- def clean_output_folder()
193
+ def clean_output_folder
107
194
  # Make the folder if it doesn't already exist
108
195
  Dir.mkdir(OUTPUT_FOLDER) unless File.exists?(OUTPUT_FOLDER)
109
196
 
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavefile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
5
- prerelease:
4
+ version: 0.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Joel Strait
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-01-01 00:00:00.000000000 Z
11
+ date: 2013-02-25 00:00:00.000000000 Z
13
12
  dependencies: []
14
- description:
13
+ description: You can use this gem to create Ruby programs that produce audio. Since
14
+ it is written in pure Ruby (as opposed to wrapping an existing C library), you can
15
+ use it without having to compile a separate extension.
15
16
  email: joel dot strait at Google's popular web mail service
16
17
  executables: []
17
18
  extensions: []
@@ -21,24 +22,15 @@ files:
21
22
  - README.markdown
22
23
  - Rakefile
23
24
  - lib/wavefile/buffer.rb
25
+ - lib/wavefile/duration.rb
24
26
  - lib/wavefile/format.rb
25
27
  - lib/wavefile/info.rb
26
28
  - lib/wavefile/reader.rb
27
29
  - lib/wavefile/writer.rb
28
30
  - lib/wavefile.rb
29
31
  - test/buffer_test.rb
30
- - test/fixtures/actual_output/valid_mono_8_44100_with_padding_byte.wav
31
- - test/fixtures/expected_output/no_samples.wav
32
- - test/fixtures/expected_output/valid_mono_16_44100.wav
33
- - test/fixtures/expected_output/valid_mono_32_44100.wav
34
- - test/fixtures/expected_output/valid_mono_8_44100.wav
35
- - test/fixtures/expected_output/valid_mono_8_44100_with_padding_byte.wav
36
- - test/fixtures/expected_output/valid_stereo_16_44100.wav
37
- - test/fixtures/expected_output/valid_stereo_32_44100.wav
38
- - test/fixtures/expected_output/valid_stereo_8_44100.wav
39
- - test/fixtures/expected_output/valid_tri_16_44100.wav
40
- - test/fixtures/expected_output/valid_tri_32_44100.wav
41
- - test/fixtures/expected_output/valid_tri_8_44100.wav
32
+ - test/duration_test.rb
33
+ - test/fixtures/actual_output/valid_mono_pcm_8_44100_with_padding_byte.wav
42
34
  - test/fixtures/invalid/bad_riff_header.wav
43
35
  - test/fixtures/invalid/bad_wavefile_format.wav
44
36
  - test/fixtures/invalid/empty.wav
@@ -54,17 +46,24 @@ files:
54
46
  - test/fixtures/unsupported/README.markdown
55
47
  - test/fixtures/unsupported/unsupported_audio_format.wav
56
48
  - test/fixtures/unsupported/unsupported_bits_per_sample.wav
49
+ - test/fixtures/valid/no_samples.wav
57
50
  - test/fixtures/valid/README.markdown
58
- - test/fixtures/valid/valid_mono_16_44100.wav
59
- - test/fixtures/valid/valid_mono_32_44100.wav
60
- - test/fixtures/valid/valid_mono_8_44100.wav
61
- - test/fixtures/valid/valid_mono_8_44100_with_padding_byte.wav
62
- - test/fixtures/valid/valid_stereo_16_44100.wav
63
- - test/fixtures/valid/valid_stereo_32_44100.wav
64
- - test/fixtures/valid/valid_stereo_8_44100.wav
65
- - test/fixtures/valid/valid_tri_16_44100.wav
66
- - test/fixtures/valid/valid_tri_32_44100.wav
67
- - test/fixtures/valid/valid_tri_8_44100.wav
51
+ - test/fixtures/valid/valid_mono_float_32_44100.wav
52
+ - test/fixtures/valid/valid_mono_float_64_44100.wav
53
+ - test/fixtures/valid/valid_mono_pcm_16_44100.wav
54
+ - test/fixtures/valid/valid_mono_pcm_32_44100.wav
55
+ - test/fixtures/valid/valid_mono_pcm_8_44100.wav
56
+ - test/fixtures/valid/valid_mono_pcm_8_44100_with_padding_byte.wav
57
+ - test/fixtures/valid/valid_stereo_float_32_44100.wav
58
+ - test/fixtures/valid/valid_stereo_float_64_44100.wav
59
+ - test/fixtures/valid/valid_stereo_pcm_16_44100.wav
60
+ - test/fixtures/valid/valid_stereo_pcm_32_44100.wav
61
+ - test/fixtures/valid/valid_stereo_pcm_8_44100.wav
62
+ - test/fixtures/valid/valid_tri_float_32_44100.wav
63
+ - test/fixtures/valid/valid_tri_float_64_44100.wav
64
+ - test/fixtures/valid/valid_tri_pcm_16_44100.wav
65
+ - test/fixtures/valid/valid_tri_pcm_32_44100.wav
66
+ - test/fixtures/valid/valid_tri_pcm_8_44100.wav
68
67
  - test/format_test.rb
69
68
  - test/info_test.rb
70
69
  - test/reader_test.rb
@@ -72,26 +71,25 @@ files:
72
71
  - test/writer_test.rb
73
72
  homepage: http://www.joelstrait.com/
74
73
  licenses: []
74
+ metadata: {}
75
75
  post_install_message:
76
76
  rdoc_options: []
77
77
  require_paths:
78
78
  - lib
79
79
  required_ruby_version: !ruby/object:Gem::Requirement
80
- none: false
81
80
  requirements:
82
81
  - - ! '>='
83
82
  - !ruby/object:Gem::Version
84
83
  version: '0'
85
84
  required_rubygems_version: !ruby/object:Gem::Requirement
86
- none: false
87
85
  requirements:
88
86
  - - ! '>='
89
87
  - !ruby/object:Gem::Version
90
88
  version: '0'
91
89
  requirements: []
92
90
  rubyforge_project:
93
- rubygems_version: 1.8.10
91
+ rubygems_version: 2.0.0
94
92
  signing_key:
95
- specification_version: 3
96
- summary: A class for reading and writing Wave sound files (*.wav)
93
+ specification_version: 4
94
+ summary: A pure Ruby library for reading and writing Wave sound files (*.wav)
97
95
  test_files: []