wavefile 0.6.0 → 0.7.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.
@@ -0,0 +1,23 @@
1
+ module WaveFile
2
+ # Represents information about the data format for a Wave file, such as number of
3
+ # channels, bits per sample, sample rate, and so forth. A Format instance is used
4
+ # by Reader to indicate what format to read samples out as, and by Writer to
5
+ # indicate what format to write samples as.
6
+ #
7
+ # This class is immutable - once a new Format is constructed, it can't be modified.
8
+ class UnvalidatedFormat < Format # :nodoc:
9
+ # Constructs a new immutable UnvalidatedFormat.
10
+ def initialize(fields)
11
+ @audio_format = fields[:audio_format]
12
+ @channels = fields[:channels]
13
+ @sample_rate = fields[:sample_rate]
14
+ @byte_rate = fields[:byte_rate]
15
+ @block_align = fields[:block_align]
16
+ @bits_per_sample = fields[:bits_per_sample]
17
+ end
18
+
19
+ # Returns a number indicating the sample format, such as 1 (PCM) or 3 (Float)
20
+ attr_reader :audio_format
21
+ end
22
+ end
23
+
@@ -16,25 +16,6 @@ module WaveFile
16
16
  # writer.close
17
17
  class Writer
18
18
 
19
- # Padding value written to the end of chunks whose payload is an odd number of bytes. The RIFF
20
- # specification requires that each chunk be aligned to an even number of bytes, even if the byte
21
- # count is an odd number.
22
- #
23
- # See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf, page 11.
24
- EMPTY_BYTE = "\000" # :nodoc:
25
-
26
- # The number of bytes at the beginning of a wave file before the sample data in the data chunk
27
- # starts, assuming this canonical format:
28
- #
29
- # RIFF Chunk Header (12 bytes)
30
- # Format Chunk (16 bytes for PCM, 18 bytes for floating point)
31
- # FACT Chunk (0 bytes for PCM, 12 bytes for floating point)
32
- # Data Chunk Header (8 bytes)
33
- #
34
- # All wave files written by Writer use this canonical format.
35
- CANONICAL_HEADER_BYTE_LENGTH = {:pcm => 36, :float => 50} # :nodoc:
36
-
37
-
38
19
  # Returns a constructed Writer object which is available for writing sample data to the specified
39
20
  # file (via the write method). When all sample data has been written, the Writer should be closed.
40
21
  # Note that the wave file being written to will NOT be valid (and playable in other programs) until
@@ -76,7 +57,7 @@ module WaveFile
76
57
 
77
58
  if @format.bits_per_sample == 24 && @format.sample_format == :pcm
78
59
  samples.flatten.each do |sample|
79
- @file.syswrite([sample].pack("lX"))
60
+ @file.syswrite([sample].pack("l<X"))
80
61
  end
81
62
  else
82
63
  @file.syswrite(samples.flatten.pack(@pack_code))
@@ -141,6 +122,26 @@ module WaveFile
141
122
 
142
123
  private
143
124
 
125
+ # Padding value written to the end of chunks whose payload is an odd number of bytes. The RIFF
126
+ # specification requires that each chunk be aligned to an even number of bytes, even if the byte
127
+ # count is an odd number.
128
+ #
129
+ # See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf, page 11.
130
+ EMPTY_BYTE = "\000" # :nodoc:
131
+
132
+ # The number of bytes at the beginning of a wave file before the sample data in the data chunk
133
+ # starts, assuming this canonical format:
134
+ #
135
+ # RIFF Chunk Header (12 bytes)
136
+ # Format Chunk (16 bytes for PCM, 18 bytes for floating point)
137
+ # FACT Chunk (0 bytes for PCM, 12 bytes for floating point)
138
+ # Data Chunk Header (8 bytes)
139
+ #
140
+ # All wave files written by Writer use this canonical format.
141
+ CANONICAL_HEADER_BYTE_LENGTH = {:pcm => 36, :float => 50} # :nodoc:
142
+
143
+ FORMAT_CHUNK_BYTE_LENGTH = {:pcm => 16, :float => 18} # :nodoc:
144
+
144
145
  # Writes the RIFF chunk header, format chunk, and the header for the data chunk. After this
145
146
  # method is called the file will be "queued up" and ready for writing actual sample data.
146
147
  def write_header(sample_frame_count)
@@ -1,9 +1,9 @@
1
- require 'test/unit'
1
+ require 'minitest/autorun'
2
2
  require 'wavefile.rb'
3
3
 
4
4
  include WaveFile
5
5
 
6
- class BufferTest < Test::Unit::TestCase
6
+ class BufferTest < MiniTest::Unit::TestCase
7
7
  def test_convert
8
8
  old_format = Format.new(:mono, :pcm_16, 44100)
9
9
  new_format = Format.new(:stereo, :pcm_16, 22050)
@@ -75,7 +75,7 @@ class BufferTest < Test::Unit::TestCase
75
75
  # Unsupported conversion (4-channel => 3-channel)
76
76
  b = Buffer.new([[-100, 200, -300, 400], [1, 2, 3, 4]],
77
77
  Format.new(4, bits_per_sample, sample_rate))
78
- assert_raise(BufferConversionError) { b.convert!(Format.new(3, bits_per_sample, sample_rate)) }
78
+ assert_raises(BufferConversionError) { b.convert!(Format.new(3, bits_per_sample, sample_rate)) }
79
79
  end
80
80
  end
81
81
  end
@@ -1,9 +1,9 @@
1
- require 'test/unit'
1
+ require 'minitest/autorun'
2
2
  require 'wavefile.rb'
3
3
 
4
4
  include WaveFile
5
5
 
6
- class DurationTest < Test::Unit::TestCase
6
+ class DurationTest < MiniTest::Unit::TestCase
7
7
  SECONDS_IN_MINUTE = 60
8
8
  SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60
9
9
 
@@ -1,9 +1,9 @@
1
- require 'test/unit'
1
+ require 'minitest/autorun'
2
2
  require 'wavefile.rb'
3
3
 
4
4
  include WaveFile
5
5
 
6
- class FormatTest < Test::Unit::TestCase
6
+ class FormatTest < MiniTest::Unit::TestCase
7
7
  def test_valid_channels
8
8
  [1, 2, 3, 4, 65535].each do |valid_channels|
9
9
  assert_equal(valid_channels, Format.new(valid_channels, :pcm_16, 44100).channels)
@@ -15,7 +15,7 @@ class FormatTest < Test::Unit::TestCase
15
15
 
16
16
  def test_invalid_channels
17
17
  ["dsfsfsdf", :foo, 0, -1, 65536].each do |invalid_channels|
18
- assert_raise(InvalidFormatError) { Format.new(invalid_channels, :pcm_16, 44100) }
18
+ assert_raises(InvalidFormatError) { Format.new(invalid_channels, :pcm_16, 44100) }
19
19
  end
20
20
  end
21
21
 
@@ -35,7 +35,7 @@ class FormatTest < Test::Unit::TestCase
35
35
 
36
36
  def test_invalid_sample_format
37
37
  ["dsfsfsdf", :foo, 12, :pcm_14, :float_20].each do |invalid_sample_format|
38
- assert_raise(InvalidFormatError) { Format.new(:mono, invalid_sample_format, 44100) }
38
+ assert_raises(InvalidFormatError) { Format.new(:mono, invalid_sample_format, 44100) }
39
39
  end
40
40
  end
41
41
 
@@ -55,7 +55,7 @@ class FormatTest < Test::Unit::TestCase
55
55
 
56
56
  def test_invalid_bits_per_sample
57
57
  ["dsfsfsdf", :foo, :pcm, 0, 12, :pcm_14, :pcm_abc, :float_40].each do |invalid_sample_format|
58
- assert_raise(InvalidFormatError) { Format.new(:mono, invalid_sample_format, 44100) }
58
+ assert_raises(InvalidFormatError) { Format.new(:mono, invalid_sample_format, 44100) }
59
59
  end
60
60
  end
61
61
 
@@ -67,7 +67,7 @@ class FormatTest < Test::Unit::TestCase
67
67
 
68
68
  def test_invalid_sample_rate
69
69
  ["dsfsfsdf", :foo, 0, -1, 4294967297].each do |invalid_sample_rate|
70
- assert_raise(InvalidFormatError) { Format.new(:mono, :pcm_16, invalid_sample_rate) }
70
+ assert_raises(InvalidFormatError) { Format.new(:mono, :pcm_16, invalid_sample_rate) }
71
71
  end
72
72
  end
73
73
 
@@ -1,19 +1,17 @@
1
- require 'test/unit'
1
+ require 'minitest/autorun'
2
2
  require 'wavefile.rb'
3
3
  require 'wavefile_io_test_helper.rb'
4
4
 
5
5
  include WaveFile
6
6
 
7
- class ReaderTest < Test::Unit::TestCase
7
+ class ReaderTest < MiniTest::Unit::TestCase
8
8
  include WaveFileIOTestHelper
9
9
 
10
10
  FIXTURE_ROOT_PATH = "test/fixtures"
11
11
 
12
12
 
13
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")) }
14
+ assert_raises(Errno::ENOENT) { Reader.new(fixture("i_do_not_exist.wav")) }
17
15
  end
18
16
 
19
17
  def test_invalid_formats
@@ -45,10 +43,8 @@ class ReaderTest < Test::Unit::TestCase
45
43
 
46
44
  # Reader.new and Reader.info should raise the same errors for invalid files,
47
45
  # so run the tests for both methods.
48
- [:new, :info].each do |method_name|
49
- invalid_fixtures.each do |fixture_name|
50
- assert_raise(InvalidFormatError) { Reader.send(method_name, fixture(fixture_name)) }
51
- end
46
+ invalid_fixtures.each do |fixture_name|
47
+ assert_raises(InvalidFormatError) { Reader.new(fixture(fixture_name)) }
52
48
  end
53
49
  end
54
50
 
@@ -68,18 +64,58 @@ class ReaderTest < Test::Unit::TestCase
68
64
  ]
69
65
 
70
66
  unsupported_fixtures.each do |fixture_name|
71
- assert_raise(UnsupportedFormatError) { Reader.new(fixture(fixture_name)) }
67
+ reader = Reader.new(fixture(fixture_name))
68
+ assert_equal(false, reader.readable_format?)
69
+ assert_raises(UnsupportedFormatError) { reader.read(1024) }
70
+ assert_raises(UnsupportedFormatError) { reader.each_buffer(1024) {|buffer| buffer } }
72
71
  end
73
72
  end
74
73
 
74
+ def test_initialize_unsupported_format
75
+ file_name = fixture("unsupported/unsupported_bits_per_sample.wav")
76
+
77
+ # Unsupported format, no read format given
78
+ reader = Reader.new(file_name)
79
+ assert_equal(2, reader.native_format.channels)
80
+ assert_equal(20, reader.native_format.bits_per_sample)
81
+ assert_equal(44100, reader.native_format.sample_rate)
82
+ assert_equal(2, reader.format.channels)
83
+ assert_equal(20, reader.format.bits_per_sample)
84
+ assert_equal(44100, reader.format.sample_rate)
85
+ assert_equal(false, reader.closed?)
86
+ assert_equal(file_name, reader.file_name)
87
+ assert_equal(0, reader.current_sample_frame)
88
+ assert_equal(2240, reader.total_sample_frames)
89
+ assert_equal(false, reader.readable_format?)
90
+ reader.close
91
+
92
+ # Unsupported format, different read format given
93
+ reader = Reader.new(file_name, Format.new(:mono, :pcm_16, 22050))
94
+ assert_equal(2, reader.native_format.channels)
95
+ assert_equal(20, reader.native_format.bits_per_sample)
96
+ assert_equal(44100, reader.native_format.sample_rate)
97
+ assert_equal(1, reader.format.channels)
98
+ assert_equal(16, reader.format.bits_per_sample)
99
+ assert_equal(22050, reader.format.sample_rate)
100
+ assert_equal(false, reader.closed?)
101
+ assert_equal(file_name, reader.file_name)
102
+ assert_equal(0, reader.current_sample_frame)
103
+ assert_equal(2240, reader.total_sample_frames)
104
+ assert_equal(false, reader.readable_format?)
105
+ reader.close
106
+ end
107
+
75
108
  def test_initialize
76
109
  format = Format.new(:stereo, :pcm_16, 22050)
77
110
 
78
111
  exhaustively_test do |channels, sample_format|
79
112
  file_name = fixture("valid/valid_#{channels}_#{sample_format}_44100.wav")
80
113
 
81
- # Read native format
114
+ # Native format
82
115
  reader = Reader.new(file_name)
116
+ assert_equal(CHANNEL_ALIAS[channels], reader.native_format.channels)
117
+ assert_equal(extract_bits_per_sample(sample_format), reader.native_format.bits_per_sample)
118
+ assert_equal(44100, reader.native_format.sample_rate)
83
119
  assert_equal(CHANNEL_ALIAS[channels], reader.format.channels)
84
120
  assert_equal(extract_bits_per_sample(sample_format), reader.format.bits_per_sample)
85
121
  assert_equal(44100, reader.format.sample_rate)
@@ -87,10 +123,14 @@ class ReaderTest < Test::Unit::TestCase
87
123
  assert_equal(file_name, reader.file_name)
88
124
  assert_equal(0, reader.current_sample_frame)
89
125
  assert_equal(2240, reader.total_sample_frames)
126
+ assert_equal(true, reader.readable_format?)
90
127
  reader.close
91
128
 
92
- # Read a non-native format
129
+ # Non-native format
93
130
  reader = Reader.new(file_name, format)
131
+ assert_equal(CHANNEL_ALIAS[channels], reader.native_format.channels)
132
+ assert_equal(extract_bits_per_sample(sample_format), reader.native_format.bits_per_sample)
133
+ assert_equal(44100, reader.native_format.sample_rate)
94
134
  assert_equal(2, reader.format.channels)
95
135
  assert_equal(16, reader.format.bits_per_sample)
96
136
  assert_equal(22050, reader.format.sample_rate)
@@ -98,10 +138,14 @@ class ReaderTest < Test::Unit::TestCase
98
138
  assert_equal(file_name, reader.file_name)
99
139
  assert_equal(0, reader.current_sample_frame)
100
140
  assert_equal(2240, reader.total_sample_frames)
141
+ assert_equal(true, reader.readable_format?)
101
142
  reader.close
102
143
 
103
144
  # Block is given.
104
145
  reader = Reader.new(file_name) {|reader| reader.read(1024) }
146
+ assert_equal(CHANNEL_ALIAS[channels], reader.native_format.channels)
147
+ assert_equal(extract_bits_per_sample(sample_format), reader.native_format.bits_per_sample)
148
+ assert_equal(44100, reader.native_format.sample_rate)
105
149
  assert_equal(CHANNEL_ALIAS[channels], reader.format.channels)
106
150
  assert_equal(extract_bits_per_sample(sample_format), reader.format.bits_per_sample)
107
151
  assert_equal(44100, reader.format.sample_rate)
@@ -109,6 +153,7 @@ class ReaderTest < Test::Unit::TestCase
109
153
  assert_equal(file_name, reader.file_name)
110
154
  assert_equal(1024, reader.current_sample_frame)
111
155
  assert_equal(2240, reader.total_sample_frames)
156
+ assert_equal(true, reader.readable_format?)
112
157
  end
113
158
  end
114
159
 
@@ -147,7 +192,7 @@ class ReaderTest < Test::Unit::TestCase
147
192
 
148
193
  def test_each_buffer_no_block_given
149
194
  reader = Reader.new(fixture("valid/valid_mono_pcm_16_44100.wav"))
150
- assert_raise(LocalJumpError) { reader.each_buffer(1024) }
195
+ assert_raises(LocalJumpError) { reader.each_buffer(1024) }
151
196
  end
152
197
 
153
198
  def test_each_buffer_native_format
@@ -231,7 +276,7 @@ class ReaderTest < Test::Unit::TestCase
231
276
  reader = Reader.new(fixture("valid/valid_mono_pcm_16_44100.wav"))
232
277
  buffer = reader.read(1024)
233
278
  reader.close
234
- assert_raise(IOError) { reader.read(1024) }
279
+ assert_raises(IOError) { reader.read(1024) }
235
280
  end
236
281
 
237
282
  def test_sample_counts_manual_reads
@@ -0,0 +1,24 @@
1
+ require 'minitest/autorun'
2
+ require 'wavefile.rb'
3
+
4
+ include WaveFile
5
+
6
+ class UnvalidatedFormatTest < MiniTest::Unit::TestCase
7
+ def test_initialize
8
+ format = UnvalidatedFormat.new({:audio_format => 1,
9
+ :channels => 2,
10
+ :sample_rate => 44100,
11
+ :byte_rate => 176400,
12
+ :block_align => 4,
13
+ :bits_per_sample => 16})
14
+
15
+ assert_equal(1, format.audio_format)
16
+ assert_equal(2, format.channels)
17
+ assert_equal(false, format.mono?)
18
+ assert_equal(true, format.stereo?)
19
+ assert_equal(44100, format.sample_rate)
20
+ assert_equal(176400, format.byte_rate)
21
+ assert_equal(4, format.block_align)
22
+ assert_equal(16, format.bits_per_sample)
23
+ end
24
+ end
@@ -1,10 +1,10 @@
1
- require 'test/unit'
1
+ require 'minitest/autorun'
2
2
  require 'wavefile.rb'
3
3
  require 'wavefile_io_test_helper.rb'
4
4
 
5
5
  include WaveFile
6
6
 
7
- class WriterTest < Test::Unit::TestCase
7
+ class WriterTest < MiniTest::Unit::TestCase
8
8
  include WaveFileIOTestHelper
9
9
 
10
10
  OUTPUT_FOLDER = "test/fixtures/actual_output"
@@ -103,7 +103,7 @@ class WriterTest < Test::Unit::TestCase
103
103
  writer.write(Buffer.new([1, 2, 3, 4], format))
104
104
  writer.close
105
105
 
106
- assert_raise(IOError) { writer.write(Buffer.new([5, 6, 7, 8], format)) }
106
+ assert_raises(IOError) { writer.write(Buffer.new([5, 6, 7, 8], format)) }
107
107
  end
108
108
 
109
109
  def test_total_duration
metadata CHANGED
@@ -1,18 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavefile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Strait
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-08 00:00:00.000000000 Z
11
+ date: 2016-03-06 00:00:00.000000000 Z
12
12
  dependencies: []
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.
13
+ description: You can use this gem to create Ruby programs that work with audio, by
14
+ reading and writing Wave sound files (*.wav). Since it is written in pure Ruby (as
15
+ opposed to wrapping an existing C library), you can use it without having to compile
16
+ a separate extension.
16
17
  email: joel dot strait at Google's popular web mail service
17
18
  executables: []
18
19
  extensions: []
@@ -21,18 +22,19 @@ files:
21
22
  - LICENSE
22
23
  - README.markdown
23
24
  - Rakefile
25
+ - lib/wavefile.rb
24
26
  - lib/wavefile/buffer.rb
27
+ - lib/wavefile/chunk_readers.rb
28
+ - lib/wavefile/chunk_readers/header_reader.rb
25
29
  - lib/wavefile/duration.rb
26
30
  - lib/wavefile/format.rb
27
- - lib/wavefile/info.rb
28
31
  - lib/wavefile/reader.rb
32
+ - lib/wavefile/unvalidated_format.rb
29
33
  - lib/wavefile/writer.rb
30
- - lib/wavefile.rb
31
34
  - test/buffer_test.rb
32
- - test/buffer_test.rbc
33
35
  - test/duration_test.rb
34
- - test/duration_test.rbc
35
- - test/fixtures/actual_output/valid_mono_pcm_8_44100_with_padding_byte.wav
36
+ - test/fixtures/actual_output/no_samples.wav
37
+ - test/fixtures/invalid/README.markdown
36
38
  - test/fixtures/invalid/bad_riff_header.wav
37
39
  - test/fixtures/invalid/bad_wavefile_format.wav
38
40
  - test/fixtures/invalid/empty.wav
@@ -41,15 +43,14 @@ files:
41
43
  - test/fixtures/invalid/insufficient_format_chunk.wav
42
44
  - test/fixtures/invalid/no_data_chunk.wav
43
45
  - test/fixtures/invalid/no_format_chunk.wav
44
- - test/fixtures/invalid/README.markdown
46
+ - test/fixtures/unsupported/README.markdown
45
47
  - test/fixtures/unsupported/bad_audio_format.wav
46
48
  - test/fixtures/unsupported/bad_channel_count.wav
47
49
  - test/fixtures/unsupported/bad_sample_rate.wav
48
- - test/fixtures/unsupported/README.markdown
49
50
  - test/fixtures/unsupported/unsupported_audio_format.wav
50
51
  - test/fixtures/unsupported/unsupported_bits_per_sample.wav
51
- - test/fixtures/valid/no_samples.wav
52
52
  - test/fixtures/valid/README.markdown
53
+ - test/fixtures/valid/no_samples.wav
53
54
  - test/fixtures/valid/valid_mono_float_32_44100.wav
54
55
  - test/fixtures/valid/valid_mono_float_64_44100.wav
55
56
  - test/fixtures/valid/valid_mono_pcm_16_44100.wav
@@ -71,17 +72,13 @@ files:
71
72
  - test/fixtures/valid/valid_tri_pcm_32_44100.wav
72
73
  - test/fixtures/valid/valid_tri_pcm_8_44100.wav
73
74
  - test/format_test.rb
74
- - test/format_test.rbc
75
- - test/info_test.rb
76
- - test/info_test.rbc
77
75
  - test/reader_test.rb
78
- - test/reader_test.rbc
76
+ - test/unvalidated_format_test.rb
79
77
  - test/wavefile_io_test_helper.rb
80
- - test/wavefile_io_test_helper.rbc
81
78
  - test/writer_test.rb
82
- - test/writer_test.rbc
83
- homepage: http://www.joelstrait.com/
84
- licenses: []
79
+ homepage: http://wavefilegem.com/
80
+ licenses:
81
+ - MIT
85
82
  metadata: {}
86
83
  post_install_message:
87
84
  rdoc_options: []
@@ -89,17 +86,17 @@ require_paths:
89
86
  - lib
90
87
  required_ruby_version: !ruby/object:Gem::Requirement
91
88
  requirements:
92
- - - '>='
89
+ - - ">="
93
90
  - !ruby/object:Gem::Version
94
- version: '0'
91
+ version: 1.9.3
95
92
  required_rubygems_version: !ruby/object:Gem::Requirement
96
93
  requirements:
97
- - - '>='
94
+ - - ">="
98
95
  - !ruby/object:Gem::Version
99
96
  version: '0'
100
97
  requirements: []
101
98
  rubyforge_project:
102
- rubygems_version: 2.1.11
99
+ rubygems_version: 2.6.1
103
100
  signing_key:
104
101
  specification_version: 4
105
102
  summary: A pure Ruby library for reading and writing Wave sound files (*.wav)