-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathCHANGELOG
337 lines (309 loc) · 18.9 KB
/
CHANGELOG
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
1.1.2
===============================================================================
* **Bug Fix:** Files that have extra bytes at the end of the `"fmt "` chunk can
now be read. If the format code is `1`, the `"fmt "` chunk has extra bytes if
the chunk body size is greater than 16 bytes. Otherwise, "extra bytes" means
the chunk contains bytes after the chunk extension (not including the
required padding byte for an odd-sized chunk). Previously, attempting to open
certain files like this via `Reader.new` would result in `InvalidFormatError`
being raised with a misleading `"Not a supported wave file. The format chunk
extension is shorter than expected."` message. This was misleading because if
the format code is `1`, the `"fmt "` chunk won't actually have a chunk
extension, and for other format codes the chunk extension might actually be
the expected size or larger. When reading a file like this, any extra data in
the `"fmt "` chunk beyond what is expected based on the relevant format code
will now be ignored.
* There was a special case where a file like this _could_ be opened
correctly. If the format code was `1`, and the value of bytes 16 and 17
(0-based), when interpreted as a 16-bit unsigned little-endian integer,
happened to be the same as the number of subsequent bytes in the chunk, the
file could be opened without issue. For example, if the `"fmt "` chunk size
was `22`, the format code was `1`, and the value of bytes 16 and 17 was `4`
(when interpreted as a 16-bit unsigned little-endian integer), the file
could be opened correctly.
* There was another special case where `InvalidFormatError` would be
incorrectly raised, but the error message would be different (and also
misleading). If the format code was `1`, and there was exactly 1 extra byte
in the `"fmt "` chunk (i.e. the chunk size was 17 bytes), the error message
would be `"Not a supported wave file. The format chunk is missing an
expected extension."` This was misleading because when the format code is
`1`, the `"fmt "` chunk doesn't have a chunk extension.
* Thanks to [@CromonMS](https://github.com/CromonMS) for reporting this as an
issue.
* **Bug Fix:** Files in WAVE_FORMAT_EXTENSIBLE format with a missing or
incomplete `"fmt "` chunk extension can no longer be opened using
`Reader.new`. Previously, a `Reader` instance could be constructed for a file
like this, but the relevant fields on the object returned by
`Reader#native_format` would contain `nil` or `""` values for these fields,
and no sample data could be read from the file. Since files like this are
missing required fields that don't necessarily have sensible default values,
it seems like it shouldn't be possible to create a `Reader` instance from
them. After this fix, attempting to do so will cause `InvalidFormatError` to
be raised.
* **Bug Fix:** Files in WAVE_FORMAT_EXTENSIBLE format that have extra bytes at
the end of the `"fmt "` chunk extension can now be read. This is similar but
different from the first bug above; that bug refers to extra bytes _after_
the chunk extension, while this bug refers to extra bytes _inside_ the chunk
extension. A WAVE_FORMAT_EXTENSIBLE `"fmt "` chunk extension has extra bytes
if it is larger than 22 bytes. Previously, a `Reader` instance could be
constructed for a file like this, but
`Reader#native_format#sub_audio_format_guid` would have an incorrect value,
and sample data could not be read from the file. After this fix, this field
will have the correct value, and if it is one of the supported values then
sample data can be read. Any extra data at the end of the chunk extension
will be ignored. Implicit in this scenario is that the `"fmt "` chunk has a
stated size large enough to fit the oversized chunk extension. For cases
where it doesn't, see the next bug fix below.
* **Bug Fix:** More accurate message on the `InvalidFormatError` raised when
reading a file whose `"fmt "` chunk extension is too large to fit in the
chunk. The message will now correctly state that the chunk extension is too
large, rather than `"Not a supported wave file. The format chunk extension is
shorter than expected."`. As an example of what "too large" means, if a
`"fmt "` chunk has a size of 50 bytes, then any chunk extension larger than
32 bytes will be too large and overflow out of the chunk, since a chunk
extension's content always starts at byte 18 (0-based).
1.1.1
===============================================================================
* Removes `warning: Using the last argument as keyword parameters is
deprecated; maybe ** should be added to the call` output when reading a
file with a `smpl` chunk using Ruby 2.7.0. (And presumably, higher Ruby
versions as well, but Ruby 2.7.0 is the most recent Ruby version at the
time of this release).
1.1.0
===============================================================================
* **Can read `smpl` chunk data from files that contain this kind of chunk.**
If a *.wav file contains a `smpl` chunk, then `Reader.sampler_info` will
return a `SamplerInfo` instance with the relevant data (or `nil` otherwise).
Thanks to [@henrikj242](https://github.com/henrikj242) for suggesting this
feature and providing the base implementation.
* **More informative errors raised by `Reader.new`**. When attempting to read
an invalid file, the error message now provides more detail about why the
file is invalid.
* **Bug Fix**: The master RIFF chunk size for files written by the gem will
now take into account padding bytes written for child chunks. For example,
when writing a file with a `data` chunk whose body has an odd number of
bytes, the master RIFF chunk's size will be 1 byte larger (to take the empty
padding byte at the end of the `data` chunk into account).
* **Bug Fix**: If the stated `data` chunk size is larger than the actual number
of bytes in the file, `Reader.current_sample_frame` will be correct when
attempting to read past the end of the chunk. For example, if a `data` chunk
says it has 2000 sample frames, but there are only 1000 sample frames
remaining in the file, then after calling `Reader.read(1500)`,
`Reader.current_sample_frame` will have a value of `1000`, not `1500`. (This
bug did not occur for files in which the data chunk listed the correct size).
* **Bug Fix**: Fixed off-by-one error in the maximum allowed value for
`Format#sample rate`. The correct maximum sample rate is now 4_294_967_295;
previously it allowed a maximum of 4_294_967_296.
1.0.1
===============================================================================
* Bug fix: The file(s) written to an arbitrary `IO` instance are no longer
corrupt if the initial seek position is greater than 0.
1.0.0
===============================================================================
* Ruby 2.0 or greater is now required - the gem no longer works in Ruby 1.9.3.
* **Backwards incompatible change:** Calling `Reader.close` on a `Reader`
instance that is already closed no longer raises `ReaderClosedError`.
Instead, it does nothing. Similarly, calling `Writer.close` on a `Writer`
instance that is already closed no longer raises `WriterClosedError`. Thanks
to [@kylekyle](https://github.com/kylekyle) for raising this as an issue.
* Better compatibility when writing Wave files. `Writer` will now write files
using a format called WAVE_FORMAT_EXTENSIBLE where appropriate. This is a
behind-the-scenes improvement - for most use cases it won't affect how you
use the gem, but can result in better compatibility with other programs.
* A file will automatically be written using WAVE_FORMAT_EXTENSIBLE format
if any of the following are true:
* It has more than 2 channels
* It uses integer PCM sample format and the bits per sample is not 8 or 16
(in other words, if the sample format is `:pcm_24` or `:pcm_32`).
* A specific channel->speaker mapping is given (see below).
* The channel->speaker mapping field can now be read from files that have it
defined. For example, if a file indicates that the first sound channel
should be mapped to the back right speaker, the second channel to the top
center speaker, etc., this can be read using the
`Reader.format.speaker_mapping` field.
* Example:
* ~~~
reader = Reader.new("4_channel_file.wav")
# [:front_left, :front_right, :front_center, :back_center]
puts reader.format.speaker_mapping.inspect
~~~
* The channel->speaker mapping field isn't present in all Wave files.
(Specifically, it's only present if the file uses WAVE_FORMAT_EXTENSIBLE
format). For a non-WAVE_FORMAT_EXTENSIBLE file,
`Reader.native_format.speaker_mapping` will be `nil`, to reflect that the
channel->speaker mapping is undefined. `Reader.format.speaker_mapping`
will use a "sensible" default value for the given number of channels.
* A channel->speaker mapping array can optionally be given when constructing
a `Format` instance. If not given, a default value will be set for the
given number of channels.
* Example:
* `Format.new(4, :pcm_16, 44100, speaker_mapping: [:front_left,
:front_right,
:front_center,
:low_frequency])`
* Errors raised by `Format.new` are improved to provide more detail.
0.8.1
===============================================================================
* Fixes an error when frozen string literals are enabled in Ruby 2.3 or higher.
(At the time of this release, that means Ruby 2.3 or 2.4). The gem should now
work properly when the --enable-frozen-string-literal Ruby option is
enabled. Thanks to [@samaaron](https://github.com/samaaron) for finding and
fixing this!
0.8.0
===============================================================================
* Wave files using WAVEFORMATEXTENSIBLE format (format code 65534) can now
be read.
* Notes/Limitations
* The same formats supported in "vanilla" Wave files are supported when
reading WAVEFORMATEXTENSIBLE files. That is, PCM (8/16/24/32 bits per
sample) or IEEE_FLOAT (32/64 bits per sample).
* The channel speaker mapping field is not exposed.
* The number of valid bits per sample must match the sample container size.
For example, if a file has a sample container size of 24 bits and each
sample is 24 bits, then it can be read. If the container size is 32 bits
and each sample is 24 bits, it _can't_ be read.
* Writing files using WAVEFORMATEXTENSIBLE format is not supported - all
files will be written as a "vanilla" file regardless of the number of
channels or sample format.
* Reader and Writer can now be constructed using with an open IO instance,
to allow reading/writing using an arbitrary IO-like object (File, StringIO,
etc). Previously, they could only be constructed from a file name (given by
a String). Thanks to [@taf2](https://github.com/taf2) for suggesting this
feature and providing an example pull request.
* The buffer size in Reader.each_buffer() is now optional. If not given, a
default buffer size will be used.
* Two Duration objects will now evaluate to equal if they represent the same
amount of time, due to an overridden definition of ==. Thanks to
[Christopher Smith](https://github.com/chrylis) for suggesting this improvement.
* A ReaderClosedError is now raised (instead of IOError) when attempting to
read from a closed Reader instance. However, ReaderClosedError extends
IOError.
* A WriterClosedError is now raised (instead of IOError) when attempting to
read from a closed Writer instance. However, WriterClosedError extends
IOError.
* **Backwards Incompatible Changes**
* Reader.file_name and Writer.file_name have been removed. When a Reader
or Writer instance is constructed from an IO instance, this field
wouldn't necessarily have a sensible value. Since I don't know of an obvious
use-case for these fields, going ahead and removing them altogether.
* The long deprecated ability to provide the sample format for a Format
instance as an integer (implying PCM format) has been removed. For example,
this is no longer valid: Format.new(:mono, 16, 44100). Instead, use
Format.new(:mono, :pcm_16, 44100).
0.7.0
===============================================================================
* The minimum supported Ruby version is now 1.9.3 - earlier versions are no
longer supported.
* New method: Reader.native_format. Returns a Format instance with information
about the underlaying format of the Wave file being read, which is not
necessarily the same format the sample data is being converted to as it's
being read.
* Reader.info() has been removed. Instead, construct a new Reader instance and
use Reader.native_format() - this will return a Format instance with the same
info that would have been returned by Reader.info().
* Similarly, the Info class has been removed, due to Reader.info() being removed.
* Constructing a Reader instance will no longer raise an exception if the file
is valid Wave file, but in a format unsupported by this gem. The purpose of
this is to allow calling Reader.native_format() on this instance, to get
format information for files not supported by this gem.
* New method: Reader.readable_format? returns true if the file is a valid
format that the gem can read, false otherwise.
* Reader.read() and Reader.each_buffer() will now raise an exception if the
file is a valid Wave file, but not a format that the gem can read. Or put
differently, if Reader.readable_format? returns false, any subsequent calls
to Reader.read() or Reader.each_buffer() will raise an exception.
* Some constants have been made private since they are intended for internal use.
* Bug fix: Files will now be read/written correctly on big-endian platforms.
Or in other words, sample data is always read as little-endian, regardless
of the native endianness of the platform.
0.6.0
===============================================================================
* Support for reading and writing Wave files containing 24-bit PCM sample data,
and the ability to convert buffers containing 24-bit PCM sample data to/from
other formats. (Thanks to Rich Orton (https://github.com/richorton) for
suggesting this).
* Reading files with 2 or more channels is now faster.
* Converting buffers from one format to another is now faster in certain cases.
* Bug fix: Files containing certain chunks with an odd size are now read properly.
According to the Wave file spec, all chunks should be aligned to an even
number of bytes. If the chunk has an odd size, a padding byte should be
appended to bring the chunk to an even size. The Reader class now properly
takes this expected padding byte into account for all chunks when reading
files. (Previously it just took this into account for the main 'data' chunk).
(Thanks to [Andrew Kuklewicz](https://github.com/kookster) for reporting
this).
0.5.0
===============================================================================
* Added support for reading and writing Wave files containing 32 and 64-bit
floating point sample data.
* Added support for buffers that contain floating point data (i.e., samples
between -1.0 and 1.0), including the ability to convert to and from
PCM buffers.
* Added a new Duration object which can be used to calculate the playback
time given a sample rate and number of sample frames.
* New attributes: Reader.current_sample_frame, Reader.total_sample_frames,
and Writer.total_sample_frames.
* Ability to get these attributes as a Duration object as well:
Reader.total_duration, Writer.total_duration.
* The 2nd argument to Format.new now indicates the sample format, not the
bits per sample. For example, :pcm_16 or :float_32 instead of 8 or 16.
For backwards compatibility, 8, 16, and 32 can still be given and will be
interpreted as :pcm_8, :pcm_16, and :pcm_32, but this support might be
removed in the future.
* Bug fix: Wave files are no longer corrupted when an unhandled exception
occurs inside a Writer block. (Thanks to James Tunnell
(https://github.com/jamestunnell) for reporting and fixing this).
* Bug fix: Writer.file_name now returns the file name, instead of always
returning nil (Thanks to James Tunnell (https://github.com/jamestunnell)
for reporting this).
* Info.duration now returns a Duration object, instead of a hash.
* Info.sample_count has been renamed sample_frame_count.
0.4.0
===============================================================================
* A brand new API, based on streaming. (The old API has been removed).
Improvements due to the new API include:
** Reduced memory consumption, due to not having to load the entire file
into memory. In practice, this allows the gem to read/write files that
previously would have been prohibitively large.
** Better performance for large files, for the same reason as above.
** Ability to progressively append data to the end of a file, instead of
writing the entire file at once.
** Ability to easily read and write data in an arbitrary format, regardless of
the file's native format. For example, you can transparently read data out
of a 16-bit stereo file as 8-bit mono.
** Automatic file management, similar to how IO.open() works.
* Ability to query format metadata of files without opening them, even for
formats that this gem can't read or write.
* Support for reading and writing 32-bit PCM files.
* No longer supported: Reading PCM data as floating point and writing floating
point as PCM.
0.3.0
===============================================================================
* New method bits_per_sample=(). Allows converting a file from 8-bit to 16-bit
and vice-versa.
* New method num_channels=(). Allows converting a mono file to stereo, and
vice-versa.
* New method sample_rate=(). Allows changing the sample rate of a file.
* New method duration(). Returns a hash listing the playback time of the file.
* New method inspect(). Returns a pretty-printed string listing metadata
about the file.
* More descriptive error messages are displayed when a file with an invalid
format can't be opened.
* Files that have more than just a format and data chunk can now be opened.
0.2.1
===============================================================================
* Fixed bug which prevented stereo files from being opened, due to refactoring
gone bad.
0.2.0
===============================================================================
* Added support for properly reading and writing stereo files. Files with more
than 2 channels (such as surround sound) are supported as well.
* Added convenience methods mono?() and stereo?().
* Can now pass :mono and :stereo into the num_channels argument of the
constructor, to allow for more readable code.
* Added method reverse().
* Conversion of raw samples to normalized samples, and vice versa, is more
accurate.
0.1.0
===============================================================================
* Initial version.