wavefile 1.0.0 → 1.0.1

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