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 +4 -4
- data/README.markdown +6 -1
- data/lib/wavefile.rb +1 -1
- data/lib/wavefile/buffer.rb +14 -2
- data/lib/wavefile/duration.rb +0 -2
- data/lib/wavefile/format.rb +0 -2
- data/lib/wavefile/reader.rb +6 -6
- data/lib/wavefile/unvalidated_format.rb +0 -2
- data/lib/wavefile/writer.rb +10 -6
- data/test/writer_test.rb +32 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ee407af48a824f261cca687280e449d0cf8a865e9eb5b17c7b707d0f2df0b691
|
|
4
|
+
data.tar.gz: f5dae672a110107b4b572d47ed08a16c1a1cb87b913686b6d3c1a0aa100892a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
data/lib/wavefile/buffer.rb
CHANGED
|
@@ -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
|
#
|
data/lib/wavefile/duration.rb
CHANGED
|
@@ -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
|
#
|
data/lib/wavefile/format.rb
CHANGED
|
@@ -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.
|
data/lib/wavefile/reader.rb
CHANGED
|
@@ -18,7 +18,7 @@ module WaveFile
|
|
|
18
18
|
# # Read sample data here
|
|
19
19
|
# reader.close
|
|
20
20
|
class Reader
|
|
21
|
-
# Public:
|
|
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)
|
data/lib/wavefile/writer.rb
CHANGED
|
@@ -19,10 +19,10 @@ module WaveFile
|
|
|
19
19
|
# writer.close
|
|
20
20
|
class Writer
|
|
21
21
|
|
|
22
|
-
# Public:
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
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(
|
|
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.
|
|
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-
|
|
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
|