wavefile 0.7.0 → 0.8.0

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/README.markdown +67 -47
  4. data/Rakefile +23 -0
  5. data/lib/wavefile.rb +4 -2
  6. data/lib/wavefile/buffer.rb +40 -25
  7. data/lib/wavefile/chunk_readers.rb +7 -1
  8. data/lib/wavefile/chunk_readers/base_chunk_reader.rb +10 -0
  9. data/lib/wavefile/chunk_readers/data_chunk_reader.rb +77 -0
  10. data/lib/wavefile/chunk_readers/format_chunk_reader.rb +59 -0
  11. data/lib/wavefile/chunk_readers/generic_chunk_reader.rb +15 -0
  12. data/lib/wavefile/chunk_readers/riff_chunk_reader.rb +19 -0
  13. data/lib/wavefile/chunk_readers/riff_reader.rb +67 -0
  14. data/lib/wavefile/duration.rb +47 -12
  15. data/lib/wavefile/format.rb +44 -23
  16. data/lib/wavefile/reader.rb +101 -111
  17. data/lib/wavefile/unvalidated_format.rb +36 -6
  18. data/lib/wavefile/writer.rb +138 -40
  19. data/test/buffer_test.rb +21 -17
  20. data/test/chunk_readers/format_chunk_reader_test.rb +130 -0
  21. data/test/duration_test.rb +42 -1
  22. data/test/fixtures/actual_output/total_duration_mono_float_32_44100.wav +0 -0
  23. data/test/fixtures/actual_output/total_duration_mono_float_64_44100.wav +0 -0
  24. data/test/fixtures/actual_output/total_duration_mono_pcm_16_44100.wav +0 -0
  25. data/test/fixtures/actual_output/total_duration_mono_pcm_24_44100.wav +0 -0
  26. data/test/fixtures/actual_output/total_duration_mono_pcm_32_44100.wav +0 -0
  27. data/test/fixtures/actual_output/total_duration_mono_pcm_8_44100.wav +0 -0
  28. data/test/fixtures/actual_output/total_duration_stereo_float_32_44100.wav +0 -0
  29. data/test/fixtures/actual_output/total_duration_stereo_float_64_44100.wav +0 -0
  30. data/test/fixtures/actual_output/total_duration_stereo_pcm_16_44100.wav +0 -0
  31. data/test/fixtures/actual_output/total_duration_stereo_pcm_24_44100.wav +0 -0
  32. data/test/fixtures/actual_output/total_duration_stereo_pcm_32_44100.wav +0 -0
  33. data/test/fixtures/actual_output/total_duration_stereo_pcm_8_44100.wav +0 -0
  34. data/test/fixtures/actual_output/total_duration_tri_float_32_44100.wav +0 -0
  35. data/test/fixtures/actual_output/total_duration_tri_float_64_44100.wav +0 -0
  36. data/test/fixtures/actual_output/total_duration_tri_pcm_16_44100.wav +0 -0
  37. data/test/fixtures/actual_output/total_duration_tri_pcm_24_44100.wav +0 -0
  38. data/test/fixtures/actual_output/total_duration_tri_pcm_32_44100.wav +0 -0
  39. data/test/fixtures/actual_output/total_duration_tri_pcm_8_44100.wav +0 -0
  40. data/test/fixtures/unsupported/README.markdown +1 -1
  41. data/test/fixtures/unsupported/bad_channel_count.wav +0 -0
  42. data/test/fixtures/unsupported/extensible_container_size_bigger_than_sample_size.wav +0 -0
  43. data/test/fixtures/unsupported/extensible_unsupported_subformat_guid.wav +0 -0
  44. data/test/fixtures/valid/valid_extensible_mono_float_32_44100.wav +0 -0
  45. data/test/fixtures/valid/valid_extensible_mono_float_64_44100.wav +0 -0
  46. data/test/fixtures/valid/valid_extensible_mono_pcm_16_44100.wav +0 -0
  47. data/test/fixtures/valid/valid_extensible_mono_pcm_24_44100.wav +0 -0
  48. data/test/fixtures/valid/valid_extensible_mono_pcm_32_44100.wav +0 -0
  49. data/test/fixtures/valid/valid_extensible_mono_pcm_8_44100.wav +0 -0
  50. data/test/fixtures/valid/valid_extensible_stereo_float_32_44100.wav +0 -0
  51. data/test/fixtures/valid/valid_extensible_stereo_float_64_44100.wav +0 -0
  52. data/test/fixtures/valid/valid_extensible_stereo_pcm_16_44100.wav +0 -0
  53. data/test/fixtures/valid/valid_extensible_stereo_pcm_24_44100.wav +0 -0
  54. data/test/fixtures/valid/valid_extensible_stereo_pcm_32_44100.wav +0 -0
  55. data/test/fixtures/valid/valid_extensible_stereo_pcm_8_44100.wav +0 -0
  56. data/test/fixtures/valid/valid_extensible_tri_float_32_44100.wav +0 -0
  57. data/test/fixtures/valid/valid_extensible_tri_float_64_44100.wav +0 -0
  58. data/test/fixtures/valid/valid_extensible_tri_pcm_16_44100.wav +0 -0
  59. data/test/fixtures/valid/valid_extensible_tri_pcm_24_44100.wav +0 -0
  60. data/test/fixtures/valid/valid_extensible_tri_pcm_32_44100.wav +0 -0
  61. data/test/fixtures/valid/valid_extensible_tri_pcm_8_44100.wav +0 -0
  62. data/test/format_test.rb +22 -48
  63. data/test/reader_test.rb +188 -93
  64. data/test/unvalidated_format_test.rb +130 -4
  65. data/test/wavefile_io_test_helper.rb +6 -4
  66. data/test/writer_test.rb +118 -95
  67. metadata +47 -4
  68. data/lib/wavefile/chunk_readers/header_reader.rb +0 -163
  69. data/test/fixtures/actual_output/no_samples.wav +0 -0
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: 0.7.0
4
+ version: 0.8.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: 2016-03-06 00:00:00.000000000 Z
11
+ date: 2017-01-29 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
@@ -25,15 +25,38 @@ files:
25
25
  - lib/wavefile.rb
26
26
  - lib/wavefile/buffer.rb
27
27
  - lib/wavefile/chunk_readers.rb
28
- - lib/wavefile/chunk_readers/header_reader.rb
28
+ - lib/wavefile/chunk_readers/base_chunk_reader.rb
29
+ - lib/wavefile/chunk_readers/data_chunk_reader.rb
30
+ - lib/wavefile/chunk_readers/format_chunk_reader.rb
31
+ - lib/wavefile/chunk_readers/generic_chunk_reader.rb
32
+ - lib/wavefile/chunk_readers/riff_chunk_reader.rb
33
+ - lib/wavefile/chunk_readers/riff_reader.rb
29
34
  - lib/wavefile/duration.rb
30
35
  - lib/wavefile/format.rb
31
36
  - lib/wavefile/reader.rb
32
37
  - lib/wavefile/unvalidated_format.rb
33
38
  - lib/wavefile/writer.rb
34
39
  - test/buffer_test.rb
40
+ - test/chunk_readers/format_chunk_reader_test.rb
35
41
  - test/duration_test.rb
36
- - test/fixtures/actual_output/no_samples.wav
42
+ - test/fixtures/actual_output/total_duration_mono_float_32_44100.wav
43
+ - test/fixtures/actual_output/total_duration_mono_float_64_44100.wav
44
+ - test/fixtures/actual_output/total_duration_mono_pcm_16_44100.wav
45
+ - test/fixtures/actual_output/total_duration_mono_pcm_24_44100.wav
46
+ - test/fixtures/actual_output/total_duration_mono_pcm_32_44100.wav
47
+ - test/fixtures/actual_output/total_duration_mono_pcm_8_44100.wav
48
+ - test/fixtures/actual_output/total_duration_stereo_float_32_44100.wav
49
+ - test/fixtures/actual_output/total_duration_stereo_float_64_44100.wav
50
+ - test/fixtures/actual_output/total_duration_stereo_pcm_16_44100.wav
51
+ - test/fixtures/actual_output/total_duration_stereo_pcm_24_44100.wav
52
+ - test/fixtures/actual_output/total_duration_stereo_pcm_32_44100.wav
53
+ - test/fixtures/actual_output/total_duration_stereo_pcm_8_44100.wav
54
+ - test/fixtures/actual_output/total_duration_tri_float_32_44100.wav
55
+ - test/fixtures/actual_output/total_duration_tri_float_64_44100.wav
56
+ - test/fixtures/actual_output/total_duration_tri_pcm_16_44100.wav
57
+ - test/fixtures/actual_output/total_duration_tri_pcm_24_44100.wav
58
+ - test/fixtures/actual_output/total_duration_tri_pcm_32_44100.wav
59
+ - test/fixtures/actual_output/total_duration_tri_pcm_8_44100.wav
37
60
  - test/fixtures/invalid/README.markdown
38
61
  - test/fixtures/invalid/bad_riff_header.wav
39
62
  - test/fixtures/invalid/bad_wavefile_format.wav
@@ -47,10 +70,30 @@ files:
47
70
  - test/fixtures/unsupported/bad_audio_format.wav
48
71
  - test/fixtures/unsupported/bad_channel_count.wav
49
72
  - test/fixtures/unsupported/bad_sample_rate.wav
73
+ - test/fixtures/unsupported/extensible_container_size_bigger_than_sample_size.wav
74
+ - test/fixtures/unsupported/extensible_unsupported_subformat_guid.wav
50
75
  - test/fixtures/unsupported/unsupported_audio_format.wav
51
76
  - test/fixtures/unsupported/unsupported_bits_per_sample.wav
52
77
  - test/fixtures/valid/README.markdown
53
78
  - test/fixtures/valid/no_samples.wav
79
+ - test/fixtures/valid/valid_extensible_mono_float_32_44100.wav
80
+ - test/fixtures/valid/valid_extensible_mono_float_64_44100.wav
81
+ - test/fixtures/valid/valid_extensible_mono_pcm_16_44100.wav
82
+ - test/fixtures/valid/valid_extensible_mono_pcm_24_44100.wav
83
+ - test/fixtures/valid/valid_extensible_mono_pcm_32_44100.wav
84
+ - test/fixtures/valid/valid_extensible_mono_pcm_8_44100.wav
85
+ - test/fixtures/valid/valid_extensible_stereo_float_32_44100.wav
86
+ - test/fixtures/valid/valid_extensible_stereo_float_64_44100.wav
87
+ - test/fixtures/valid/valid_extensible_stereo_pcm_16_44100.wav
88
+ - test/fixtures/valid/valid_extensible_stereo_pcm_24_44100.wav
89
+ - test/fixtures/valid/valid_extensible_stereo_pcm_32_44100.wav
90
+ - test/fixtures/valid/valid_extensible_stereo_pcm_8_44100.wav
91
+ - test/fixtures/valid/valid_extensible_tri_float_32_44100.wav
92
+ - test/fixtures/valid/valid_extensible_tri_float_64_44100.wav
93
+ - test/fixtures/valid/valid_extensible_tri_pcm_16_44100.wav
94
+ - test/fixtures/valid/valid_extensible_tri_pcm_24_44100.wav
95
+ - test/fixtures/valid/valid_extensible_tri_pcm_32_44100.wav
96
+ - test/fixtures/valid/valid_extensible_tri_pcm_8_44100.wav
54
97
  - test/fixtures/valid/valid_mono_float_32_44100.wav
55
98
  - test/fixtures/valid/valid_mono_float_64_44100.wav
56
99
  - test/fixtures/valid/valid_mono_pcm_16_44100.wav
@@ -1,163 +0,0 @@
1
- module WaveFile
2
- module ChunkReaders
3
- # Used to read the RIFF chunks in a wave file up until the data chunk. Thus is can be used
4
- # to open a wave file and "queue it up" to the start of the actual sample data, as well as
5
- # extract information out of pre-data chunks, such as the format chunk.
6
- class RiffReader # :nodoc:
7
- def initialize(file, file_name)
8
- @file = file
9
- @file_name = file_name
10
-
11
- read_until_data_chunk
12
- end
13
-
14
- attr_reader :native_format, :data_chunk_reader
15
-
16
- private
17
-
18
- def read_until_data_chunk
19
- begin
20
- chunk_id = @file.sysread(4)
21
- unless chunk_id == CHUNK_IDS[:riff]
22
- raise_error InvalidFormatError, "Expected chunk ID '#{CHUNK_IDS[:riff]}', but was '#{chunk_id}'"
23
- end
24
- RiffChunkReader.new(@file).read
25
-
26
- chunk_id = @file.sysread(4)
27
- while chunk_id != CHUNK_IDS[:data]
28
- if chunk_id == CHUNK_IDS[:format]
29
- @native_format = FormatChunkReader.new(@file).read
30
- else
31
- # Other chunk types besides the format chunk are ignored. This may change in the future.
32
- GenericChunkReader.new(@file).read
33
- end
34
-
35
- chunk_id = @file.sysread(4)
36
- end
37
- rescue EOFError
38
- raise_error InvalidFormatError, "It doesn't have a data chunk."
39
- end
40
-
41
- if @native_format == nil
42
- raise_error InvalidFormatError, "The format chunk is either missing, or it comes after the data chunk."
43
- end
44
-
45
- @data_chunk_reader = DataChunkReader.new(@file, @native_format)
46
- end
47
-
48
- class BaseChunkReader # :nodoc:
49
- def read_chunk_size
50
- chunk_size = @file.sysread(4).unpack(UNSIGNED_INT_32).first || 0
51
-
52
- # The RIFF specification requires that each chunk be aligned to an even number of bytes,
53
- # even if the byte count is an odd number.
54
- #
55
- # See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf, page 11.
56
- if chunk_size.odd?
57
- chunk_size += 1
58
- end
59
-
60
- chunk_size
61
- end
62
-
63
- def raise_error(exception_class, message)
64
- raise exception_class, "File '#{@file_name}' is not a supported wave file. #{message}"
65
- end
66
- end
67
-
68
- class GenericChunkReader < BaseChunkReader # :nodoc:
69
- def initialize(file)
70
- @file = file
71
- end
72
-
73
- def read
74
- chunk_size = read_chunk_size
75
- @file.sysread(chunk_size)
76
- end
77
- end
78
-
79
- class RiffChunkReader < BaseChunkReader # :nodoc:
80
- def initialize(file)
81
- @file = file
82
- end
83
-
84
- def read
85
- chunk_size = read_chunk_size
86
- riff_format = @file.sysread(4)
87
-
88
- unless riff_format == WAVEFILE_FORMAT_CODE
89
- raise_error InvalidFormatError, "Expected RIFF format of '#{WAVEFILE_FORMAT_CODE}', but was '#{riff_format}'"
90
- end
91
- end
92
- end
93
-
94
- class DataChunkReader < BaseChunkReader # :nodoc:
95
- def initialize(file, native_format)
96
- @file = file
97
- @native_format = native_format
98
-
99
- data_chunk_size = @file.sysread(4).unpack(UNSIGNED_INT_32).first
100
- @sample_frame_count = data_chunk_size / @native_format.block_align
101
- end
102
-
103
- attr_reader :sample_frame_count
104
- end
105
-
106
- class FormatChunkReader < BaseChunkReader # :nodoc:
107
- def initialize(file)
108
- @file = file
109
- end
110
-
111
- def read
112
- chunk_size = read_chunk_size
113
-
114
- if chunk_size < MINIMUM_CHUNK_SIZE
115
- raise_error InvalidFormatError, "The format chunk is incomplete."
116
- end
117
-
118
- raw_bytes = read_chunk_body(CHUNK_IDS[:format], chunk_size)
119
-
120
- format_chunk = {}
121
- format_chunk[:audio_format],
122
- format_chunk[:channels],
123
- format_chunk[:sample_rate],
124
- format_chunk[:byte_rate],
125
- format_chunk[:block_align],
126
- format_chunk[:bits_per_sample] = raw_bytes.slice!(0...MINIMUM_CHUNK_SIZE).unpack("vvVVvv")
127
-
128
- if chunk_size > MINIMUM_CHUNK_SIZE
129
- format_chunk[:extension_size] = raw_bytes.slice!(0...2).unpack(UNSIGNED_INT_16).first
130
-
131
- if format_chunk[:extension_size] == nil
132
- raise_error InvalidFormatError, "The format chunk is missing an expected extension."
133
- end
134
-
135
- if format_chunk[:extension_size] != raw_bytes.length
136
- raise_error InvalidFormatError, "The format chunk extension is shorter than expected."
137
- end
138
-
139
- # TODO: Parse the extension
140
- end
141
-
142
- UnvalidatedFormat.new(format_chunk)
143
- end
144
-
145
- private
146
-
147
- MINIMUM_CHUNK_SIZE = 16
148
-
149
- def read_chunk_body(chunk_id, chunk_size)
150
- begin
151
- return @file.sysread(chunk_size)
152
- rescue EOFError
153
- raise_error InvalidFormatError, "The #{chunk_id} chunk has incomplete data."
154
- end
155
- end
156
- end
157
-
158
- def raise_error(exception_class, message)
159
- raise exception_class, "File '#{@file_name}' is not a supported wave file. #{message}"
160
- end
161
- end
162
- end
163
- end