wavefile 0.7.0 → 0.8.0

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