wavefile 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)