wavefile 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 345be2bed4e76c59bfb0163cc844399ff54bc7ca2643b82ba555c4bf167d5b5e
4
- data.tar.gz: 1923c71c3af5438319425709de665acd6bf6be53f67058f7bf4b99c43d7a2493
3
+ metadata.gz: ee407af48a824f261cca687280e449d0cf8a865e9eb5b17c7b707d0f2df0b691
4
+ data.tar.gz: f5dae672a110107b4b572d47ed08a16c1a1cb87b913686b6d3c1a0aa100892a8
5
5
  SHA512:
6
- metadata.gz: 3134a277c3c239e41e0dc60dda461223664a316e2ea16b299b61d137deee8cb545ccde99bac35566a8834571da2538aa973551d6f27b0521be9f78c0c8d88765
7
- data.tar.gz: '069c9654d04eabb25c5125983b658ff468697de5eb551b7673be42fe6775a470899d20ba19e7e44c9fcd280377866ade72b1bf1aa672523065155e75c17c0604'
6
+ metadata.gz: 9ebaf573b2e015968616acac11c333f0a1a98bdcdaa9baf85d67987251eb649aaa31a8fb5f7c8a079e652e6ece7ebeae39fccbc079b61c51c2c6696109bcdbd1
7
+ data.tar.gz: 5d481c271766b50114450bf483189bd7038b0989a87c813af0d2f3b0d57f6eb4cda3ba95a3d62caff441e1ec97e9575c53c9517f5ff5cc2df3e01e85c310dbea
data/README.markdown CHANGED
@@ -37,7 +37,12 @@ This gem lets you read and write audio data! You can use it to create Ruby progr
37
37
  * Written in pure Ruby, so it's easy to include in your program. There's no need to compile a separate extension in order to use it.
38
38
 
39
39
 
40
- # Current Release: v1.0.0
40
+ # Current Release: v1.0.1
41
+
42
+ Released on August 2, 2018, this version contains a bug fix: the file(s) written to an arbitrary `IO` instance are no longer corrupt if the initial seek position is greater than 0.
43
+
44
+
45
+ # Previous Release: v1.0.0
41
46
 
42
47
  Released on June 10, 2018, this version has these changes:
43
48
 
data/lib/wavefile.rb CHANGED
@@ -7,7 +7,7 @@ require 'wavefile/unvalidated_format'
7
7
  require 'wavefile/writer'
8
8
 
9
9
  module WaveFile
10
- VERSION = "1.0.0"
10
+ VERSION = "1.0.1"
11
11
 
12
12
  WAVEFILE_FORMAT_CODE = "WAVE" # :nodoc:
13
13
  FORMAT_CODES = {:pcm => 1, :float => 3, :extensible => 65534}.freeze # :nodoc:
@@ -57,7 +57,17 @@ module WaveFile
57
57
  # Public: Creates a new Buffer containing the sample data of this Buffer, but converted
58
58
  # to a different format.
59
59
  #
60
- # new_format - The format that the sample data should be converted to
60
+ # new_format - The format that the sample data should be converted to. If the new format
61
+ # has a different number of channels than the original buffer format, the sample data
62
+ # will be converted in the following way:
63
+ #
64
+ # 1 -> n: Each mono sample will be duplicated into the new number of channels.
65
+ #
66
+ # n -> 1: Each sample in each sample frame will be averaged into a single sample.
67
+ #
68
+ # (n > 2) -> 2: The first two channels will be kept, all other channels discarded.
69
+ #
70
+ # other: Unsupported, will cause BufferConversionError to be raised.
61
71
  #
62
72
  # Examples
63
73
  #
@@ -75,7 +85,9 @@ module WaveFile
75
85
  # Public: Converts the sample data contained in the Buffer to a new format. The sample
76
86
  # data is converted in place, so the existing Buffer is modified.
77
87
  #
78
- # new_format - The format that the sample data should be converted to
88
+ # new_format - The format that the sample data should be converted to. See Buffer#create
89
+ # for how samples will be mapped if the new number of channels differs from
90
+ # the original number of channels.
79
91
  #
80
92
  # Examples
81
93
  #
@@ -7,8 +7,6 @@ module WaveFile
7
7
  # stopwatch running for exactly 2 hours would show something like "2:00:00.000".
8
8
  # Accordingly, if the given sample frame count and sample rate add up to exactly
9
9
  # 2 hours, then hours will be 2, and minutes, seconds, and milliseconds will all be 0.
10
- #
11
- # This class is immutable - once a new Duration is constructed, it can't be modified.
12
10
  class Duration
13
11
  # Public: Constructs a new immutable Duration.
14
12
  #
@@ -17,8 +17,6 @@ module WaveFile
17
17
  # channels, bits per sample, sample rate, and so forth. A Format instance is used
18
18
  # by Reader to indicate what format to read samples out as, and by Writer to
19
19
  # indicate what format to write samples as.
20
- #
21
- # This class is immutable - once a new Format is constructed, it can't be modified.
22
20
  class Format
23
21
 
24
22
  # Public: Constructs a new immutable Format.
@@ -18,7 +18,7 @@ module WaveFile
18
18
  # # Read sample data here
19
19
  # reader.close
20
20
  class Reader
21
- # Public: Returns a Reader object that is ready to start reading the specified file's
21
+ # Public: Constructs a Reader object that is ready to start reading the specified file's
22
22
  # sample data.
23
23
  #
24
24
  # io_or_file_name - The name of the wave file to read from,
@@ -27,8 +27,8 @@ module WaveFile
27
27
  # (default: the wave file's internal format).
28
28
  #
29
29
  # Returns a Reader object that is ready to start reading the specified file's sample data.
30
- # Raises +Errno::ENOENT+ if the specified file can't be found
31
- # Raises InvalidFormatError if the specified file isn't a valid wave file
30
+ # Raises +Errno::ENOENT+ if the specified file can't be found.
31
+ # Raises InvalidFormatError if the specified file isn't a valid wave file.
32
32
  def initialize(io_or_file_name, format=nil)
33
33
  if io_or_file_name.is_a?(String)
34
34
  @io = File.open(io_or_file_name, "rb")
@@ -114,10 +114,10 @@ module WaveFile
114
114
  # sample_frame_count - The number of sample frames to read. Note that each sample frame includes a sample for
115
115
  # each channel.
116
116
  #
117
- # Returns a Buffer containing sample_frame_count sample frames
118
- # Raises UnsupportedFormatError if file is in a format that can't be read by this gem
117
+ # Returns a Buffer containing sample_frame_count sample frames.
118
+ # Raises UnsupportedFormatError if file is in a format that can't be read by this gem.
119
119
  # Raises ReaderClosedError if the Writer has been closed.
120
- # Raises EOFError if no samples could be read due to reaching the end of the file
120
+ # Raises EOFError if no samples could be read due to reaching the end of the file.
121
121
  def read(sample_frame_count)
122
122
  if @closed
123
123
  raise ReaderClosedError
@@ -3,8 +3,6 @@ module WaveFile
3
3
  # channels, bits per sample, sample rate, and so forth. A Format instance is used
4
4
  # by Reader to indicate what format to read samples out as, and by Writer to
5
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
6
  class UnvalidatedFormat < Format # :nodoc:
9
7
  # Constructs a new immutable UnvalidatedFormat.
10
8
  def initialize(fields)
@@ -19,10 +19,10 @@ module WaveFile
19
19
  # writer.close
20
20
  class Writer
21
21
 
22
- # Public: Returns a constructed Writer object which is available for writing sample data to the
23
- # specified file (via the write method). When all sample data has been written, the Writer should
24
- # be closed. Note that the wave file being written to will NOT be valid (and playable in other programs)
25
- # until the Writer has been closed.
22
+ # Public: Constructs a Writer object which is available for writing sample data to the specified file
23
+ # (via the write method). When all sample data has been written, the Writer should be closed. Note
24
+ # that the wave file being written to will NOT be valid (and playable in other programs) until the
25
+ # Writer has been closed.
26
26
  #
27
27
  # If a block is given to this method, sample data can be written inside the given block. When the
28
28
  # block terminates, the Writer will be automatically closed (and no more sample data can be written).
@@ -44,6 +44,10 @@ module WaveFile
44
44
  @io = io_or_file_name
45
45
  @io_source = :io
46
46
  end
47
+
48
+ # The position to seek back to when re-writing the header on close
49
+ @start_pos = @io.pos
50
+
47
51
  @format = format
48
52
 
49
53
  @closed = false
@@ -90,7 +94,7 @@ module WaveFile
90
94
  #
91
95
  # Returns the number of sample frames that have been written to the file so far.
92
96
  # Raises WriterClosedError if the Writer has been closed.
93
- # Raises BufferConversionError if the Buffer can't be converted to the Writer's format
97
+ # Raises BufferConversionError if the Buffer can't be converted to the Writer's format.
94
98
  def write(buffer)
95
99
  if @closed
96
100
  raise WriterClosedError
@@ -187,7 +191,7 @@ module WaveFile
187
191
  # We can't know what chunk sizes to write for the RIFF and data chunks until all
188
192
  # samples have been written, so go back to the beginning of the file and re-write
189
193
  # those chunk headers with the correct sizes.
190
- @io.seek(0)
194
+ @io.seek(@start_pos)
191
195
  write_header(@total_sample_frames)
192
196
 
193
197
  if @io_source == :file_name
data/test/writer_test.rb CHANGED
@@ -252,6 +252,8 @@ class WriterTest < Minitest::Test
252
252
  assert_equal(false, io.closed?)
253
253
  assert_equal(0, io.pos)
254
254
 
255
+
256
+ # Write first file
255
257
  writer = Writer.new(io, Format.new(:mono, :pcm_16, 44100))
256
258
  assert_equal(false, writer.closed?)
257
259
 
@@ -262,6 +264,36 @@ class WriterTest < Minitest::Test
262
264
 
263
265
  assert_equal(false, io.closed?)
264
266
  assert_equal(2092, io.pos) # 44 bytes for header, plus 2 bytes per sample, with 8 * 128 samples
267
+
268
+ # Verify the first file header was written correctly
269
+ io.seek(0)
270
+ header = io.read(44).unpack("a4Va4a4VvvVVvva4V")
271
+ assert_equal(["RIFF", 2084, "WAVE", "fmt ", 16, 1, 1, 44100, 88200, 2, 16, "data", 2048], header)
272
+ io.seek(2092)
273
+
274
+
275
+ # Write 2nd file to same IO
276
+ writer = Writer.new(io, Format.new(:stereo, :float, 22050))
277
+ assert_equal(false, writer.closed?)
278
+
279
+ writer.write(Buffer.new(SQUARE_WAVE_CYCLE[:stereo][:float_32] * 10, Format.new(:stereo, :float_32, 44100)))
280
+
281
+ writer.close
282
+ assert(writer.closed?)
283
+
284
+ assert_equal(false, io.closed?)
285
+ assert_equal(2790, io.pos) # 44 bytes for header, plus 2 bytes per sample, with 8 * 128 samples
286
+
287
+ # Verify the first file header was not over-written
288
+ io.seek(0)
289
+ header = io.read(44).unpack("a4Va4a4VvvVVvva4V")
290
+ assert_equal(["RIFF", 2084, "WAVE", "fmt ", 16, 1, 1, 44100, 88200, 2, 16, "data", 2048], header)
291
+
292
+ # Verify the 2nd file header was written in the correct location
293
+ io.seek(2092)
294
+ header = io.read(58).unpack("a4Va4a4VvvVVvvva4VVa4V")
295
+ assert_equal(["RIFF", 690, "WAVE", "fmt ", 18, 3, 2, 22050, 176400, 8, 32, 0, "fact", 4, 80, "data", 640], header)
296
+
265
297
  io.close
266
298
  end
267
299
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavefile
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Strait
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-10 00:00:00.000000000 Z
11
+ date: 2018-08-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: You can use this gem to create Ruby programs that work with audio, by
14
14
  reading and writing Wave sound files (*.wav). Since it is written in pure Ruby (as