mp3file 0.0.2
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.
- data/.gitignore +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/Rakefile +25 -0
- data/doc/id3v2.2.0.txt +1658 -0
- data/doc/id3v2.3.0.txt +2024 -0
- data/doc/id3v2.4.0-frames.txt +1732 -0
- data/doc/id3v2.4.0-structure.txt +731 -0
- data/lib/mp3file/id3v1_tag.rb +58 -0
- data/lib/mp3file/id3v2/bit_padded_int.rb +24 -0
- data/lib/mp3file/id3v2/frame_header.rb +84 -0
- data/lib/mp3file/id3v2/header.rb +67 -0
- data/lib/mp3file/id3v2/tag.rb +25 -0
- data/lib/mp3file/id3v2/text_frame.rb +4 -0
- data/lib/mp3file/id3v2/version.rb +40 -0
- data/lib/mp3file/id3v2.rb +12 -0
- data/lib/mp3file/mp3_file.rb +182 -0
- data/lib/mp3file/mp3_header.rb +109 -0
- data/lib/mp3file/version.rb +3 -0
- data/lib/mp3file/xing_header.rb +39 -0
- data/lib/mp3file.rb +12 -0
- data/mp3file.gemspec +26 -0
- data/spec/common_helpers.rb +12 -0
- data/spec/files/bret_96.mp3 +0 -0
- data/spec/files/bret_id3v1.mp3 +0 -0
- data/spec/files/bret_id3v2.mp3 +0 -0
- data/spec/files/bret_vbr_6.mp3 +0 -0
- data/spec/mp3file/id3v1_tag_spec.rb +62 -0
- data/spec/mp3file/id3v2/bit_padded_int_spec.rb +59 -0
- data/spec/mp3file/id3v2/frame_header_spec.rb +79 -0
- data/spec/mp3file/id3v2/header_spec.rb +137 -0
- data/spec/mp3file/id3v2/tag_spec.rb +22 -0
- data/spec/mp3file/id3v2/version_spec.rb +56 -0
- data/spec/mp3file/mp3_file_spec.rb +90 -0
- data/spec/mp3file/mp3_header_spec.rb +336 -0
- data/spec/mp3file/xing_header_spec.rb +75 -0
- metadata +117 -0
@@ -0,0 +1,336 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../lib/mp3file'
|
2
|
+
require File.dirname(__FILE__) + '/../common_helpers'
|
3
|
+
|
4
|
+
include CommonHelpers
|
5
|
+
|
6
|
+
describe Mp3file::MP3Header do
|
7
|
+
it "raises an error if the first byte isn't 255" do
|
8
|
+
lambda { Mp3file::MP3Header.new(create_io([ 0xAA, 0xF8, 0x10, 0x01 ])) }.
|
9
|
+
should(raise_error(Mp3file::InvalidMP3HeaderError))
|
10
|
+
end
|
11
|
+
|
12
|
+
it "raises an error if the second sync byte is wrong" do
|
13
|
+
lambda { Mp3file::MP3Header.new(create_io([ 0xFF, 0xB8, 0x10, 0x01 ])) }.
|
14
|
+
should(raise_error(Mp3file::InvalidMP3HeaderError))
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#version" do
|
18
|
+
[ [ [ 0xFF, 0b1110_0010, 0x10, 0x01 ], 'MPEG 2.5' ],
|
19
|
+
[ [ 0xFF, 0b1111_0010, 0x10, 0x01 ], 'MPEG 2' ],
|
20
|
+
[ [ 0xFF, 0b1111_1010, 0x10, 0x01 ], 'MPEG 1' ],
|
21
|
+
].each do |bytes, version|
|
22
|
+
it "recognizes #{version}" do
|
23
|
+
h = Mp3file::MP3Header.new(create_io(bytes))
|
24
|
+
h.version.should == version
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "raises an error on an invalid version" do
|
29
|
+
lambda { Mp3file::MP3Header.new(create_io([ 0xFF, 0b1110_1010, 0x10, 0x01 ])) }.
|
30
|
+
should(raise_error(Mp3file::InvalidMP3HeaderError))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#layer" do
|
35
|
+
[ [ [ 0xFF, 0b1111_1010, 0x10, 0x01 ], 'Layer III' ],
|
36
|
+
[ [ 0xFF, 0b1111_1100, 0x10, 0x01 ], 'Layer II' ],
|
37
|
+
[ [ 0xFF, 0b1111_1110, 0x10, 0x01 ], 'Layer I' ],
|
38
|
+
].each do |bytes, layer|
|
39
|
+
it "recognizes #{layer}" do
|
40
|
+
h = Mp3file::MP3Header.new(create_io(bytes))
|
41
|
+
h.layer.should == layer
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises an error on an invalid version" do
|
46
|
+
lambda { Mp3file::MP3Header.new(create_io([ 0xFF, 0b1111_1000, 0x10, 0x01 ])) }.
|
47
|
+
should(raise_error(Mp3file::InvalidMP3HeaderError))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#has_crc" do
|
52
|
+
it "detects when a CRC is present" do
|
53
|
+
h = Mp3file::MP3Header.new(create_io([ 0xFF, 0b1111_1010, 0x10, 0x01 ]))
|
54
|
+
h.has_crc == true
|
55
|
+
end
|
56
|
+
it "detects when there is not a CRC present" do
|
57
|
+
h = Mp3file::MP3Header.new(create_io([ 0xFF, 0b1111_1011, 0x10, 0x01 ]))
|
58
|
+
h.has_crc == true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#bitrate" do
|
63
|
+
[ [ "MPEG 1 Layer I", 0xFF, [ 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 ] ],
|
64
|
+
[ "MPEG 1 Layer II", 0xFD, [ 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 ] ],
|
65
|
+
[ "MPEG 1 Layer III", 0xFB, [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 ] ],
|
66
|
+
[ "MPEG 2 Layer I", 0xF7, [ 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 ] ],
|
67
|
+
[ "MPEG 2 Layer II", 0xF5, [ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ] ],
|
68
|
+
[ "MPEG 2 Layer III", 0xF3, [ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ] ],
|
69
|
+
[ "MPEG 2.5 Layer I", 0xE7, [ 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 ] ],
|
70
|
+
[ "MPEG 2.5 Layer II", 0xE5, [ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ] ],
|
71
|
+
[ "MPEG 2.5 Layer III", 0xE3, [ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ] ],
|
72
|
+
].each do |version_layer, byte2, bitrates|
|
73
|
+
context "for #{version_layer}" do
|
74
|
+
bitrates.each_with_index do |br, i|
|
75
|
+
it "detects #{br} kbps" do
|
76
|
+
io = create_io([ 0xFF, byte2, (i + 1) << 4, 0x01 ])
|
77
|
+
h = Mp3file::MP3Header.new(io)
|
78
|
+
h.bitrate.should == br * 1000
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "rejects a free bitrate" do
|
83
|
+
io = create_io([ 0xFF, byte2, 0x00, 0x01 ])
|
84
|
+
lambda { Mp3file::MP3Header.new(io) }.should(raise_error(Mp3file::InvalidMP3HeaderError))
|
85
|
+
end
|
86
|
+
|
87
|
+
it "rejects a bad bitrate" do
|
88
|
+
io = create_io([ 0xFF, byte2, 0xF0, 0x01 ])
|
89
|
+
lambda { Mp3file::MP3Header.new(io) }.should(raise_error(Mp3file::InvalidMP3HeaderError))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#samplerate" do
|
96
|
+
[ [ "MPEG 1", 0xFF, [ 44100, 48000, 32000 ] ],
|
97
|
+
[ "MPEG 2", 0xF5, [ 22050, 24000, 16000 ] ],
|
98
|
+
[ "MPEG 2.5", 0xE3, [ 11025, 12000, 8000 ] ],
|
99
|
+
].each do |version, byte2, srs|
|
100
|
+
context "for #{version}" do
|
101
|
+
srs.each_with_index do |sr, i|
|
102
|
+
it "detects #{sr} Hz" do
|
103
|
+
io = create_io([ 0xFF, byte2, 0x10 + (i << 2), 0x01 ])
|
104
|
+
h = Mp3file::MP3Header.new(io)
|
105
|
+
h.samplerate.should == sr
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "rejects reserved samplerate values" do
|
110
|
+
io = create_io([ 0xFF, byte2, 0x1C, 0x01 ])
|
111
|
+
lambda { Mp3file::MP3Header.new(io) }.should(raise_error(Mp3file::InvalidMP3HeaderError))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#has_padding" do
|
118
|
+
it "detects if the frame is padded" do
|
119
|
+
io = create_io([ 0xFF, 0xFB, 0b0001_1010, 0x01 ])
|
120
|
+
h = Mp3file::MP3Header.new(io)
|
121
|
+
h.has_padding.should == true
|
122
|
+
end
|
123
|
+
|
124
|
+
it "detects if the frame is not padded" do
|
125
|
+
io = create_io([ 0xFF, 0xFB, 0b0001_1000, 0x01 ])
|
126
|
+
h = Mp3file::MP3Header.new(io)
|
127
|
+
h.has_padding.should == false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#mode" do
|
132
|
+
it "detects Stereo" do
|
133
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0000_0001 ])
|
134
|
+
h = Mp3file::MP3Header.new(io)
|
135
|
+
h.mode.should == 'Stereo'
|
136
|
+
end
|
137
|
+
|
138
|
+
it "detects Joint Stereo" do
|
139
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0100_0001 ])
|
140
|
+
h = Mp3file::MP3Header.new(io)
|
141
|
+
h.mode.should == 'Joint Stereo'
|
142
|
+
end
|
143
|
+
|
144
|
+
it "detects Dual Channel" do
|
145
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b1000_0001 ])
|
146
|
+
h = Mp3file::MP3Header.new(io)
|
147
|
+
h.mode.should == 'Dual Channel'
|
148
|
+
end
|
149
|
+
|
150
|
+
it "detects Mono" do
|
151
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b1100_0001 ])
|
152
|
+
h = Mp3file::MP3Header.new(io)
|
153
|
+
h.mode.should == 'Mono'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "#mode_extension" do
|
158
|
+
context "For Layers I & II" do
|
159
|
+
it "detects bands 4 to 31" do
|
160
|
+
io = create_io([ 0xFF, 0xFE, 0x92, 0b0100_0001 ])
|
161
|
+
h = Mp3file::MP3Header.new(io)
|
162
|
+
h.mode_extension.should == 'bands 4 to 31'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "detects bands 8 to 31" do
|
166
|
+
io = create_io([ 0xFF, 0xFD, 0x92, 0b0101_0001 ])
|
167
|
+
h = Mp3file::MP3Header.new(io)
|
168
|
+
h.mode_extension.should == 'bands 8 to 31'
|
169
|
+
end
|
170
|
+
|
171
|
+
it "detects bands 12 to 31" do
|
172
|
+
io = create_io([ 0xFF, 0xFE, 0x92, 0b0110_0001 ])
|
173
|
+
h = Mp3file::MP3Header.new(io)
|
174
|
+
h.mode_extension.should == 'bands 12 to 31'
|
175
|
+
end
|
176
|
+
|
177
|
+
it "detects bands 16 to 31" do
|
178
|
+
io = create_io([ 0xFF, 0xFD, 0x92, 0b0111_0001 ])
|
179
|
+
h = Mp3file::MP3Header.new(io)
|
180
|
+
h.mode_extension.should == 'bands 16 to 31'
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "For Layer III" do
|
185
|
+
it "detects neither mode extension" do
|
186
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0100_0001 ])
|
187
|
+
h = Mp3file::MP3Header.new(io)
|
188
|
+
h.mode_extension.should == nil
|
189
|
+
end
|
190
|
+
|
191
|
+
it "detects only Intensity Stereo" do
|
192
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0101_0001 ])
|
193
|
+
h = Mp3file::MP3Header.new(io)
|
194
|
+
h.mode_extension.should == 'Intensity Stereo'
|
195
|
+
end
|
196
|
+
|
197
|
+
it "detects only M/S Stereo" do
|
198
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0110_0001 ])
|
199
|
+
h = Mp3file::MP3Header.new(io)
|
200
|
+
h.mode_extension.should == 'M/S Stereo'
|
201
|
+
end
|
202
|
+
|
203
|
+
it "detects both Intensity Stereo & M/S Stereo" do
|
204
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0001 ])
|
205
|
+
h = Mp3file::MP3Header.new(io)
|
206
|
+
h.mode_extension.should == [ 'Intensity Stereo', 'M/S Stereo' ]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
context "for non-Joint-Stereo headers" do
|
211
|
+
it "should return no mode extension for Stereo" do
|
212
|
+
io = create_io([ 0xFF, 0xFE, 0x92, 0b0011_0001 ])
|
213
|
+
h = Mp3file::MP3Header.new(io)
|
214
|
+
h.mode_extension.should == nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should return no mode extension for Dual Channel" do
|
218
|
+
io = create_io([ 0xFF, 0xFD, 0x92, 0b1011_0001 ])
|
219
|
+
h = Mp3file::MP3Header.new(io)
|
220
|
+
h.mode_extension.should == nil
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should return no mode extension for Mono" do
|
224
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b1111_0001 ])
|
225
|
+
h = Mp3file::MP3Header.new(io)
|
226
|
+
h.mode_extension.should == nil
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe "#copyright" do
|
232
|
+
it "detects copyrighted material" do
|
233
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_1001 ])
|
234
|
+
h = Mp3file::MP3Header.new(io)
|
235
|
+
h.copyright.should == true
|
236
|
+
end
|
237
|
+
|
238
|
+
it "detects non-copyrighted material" do
|
239
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0001 ])
|
240
|
+
h = Mp3file::MP3Header.new(io)
|
241
|
+
h.copyright.should == false
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "#original" do
|
246
|
+
it "detects original material" do
|
247
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0101 ])
|
248
|
+
h = Mp3file::MP3Header.new(io)
|
249
|
+
h.original.should == true
|
250
|
+
end
|
251
|
+
|
252
|
+
it "detects non-original material" do
|
253
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0001 ])
|
254
|
+
h = Mp3file::MP3Header.new(io)
|
255
|
+
h.original.should == false
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe "#emphasis" do
|
260
|
+
it "detects no emphasis" do
|
261
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0000 ])
|
262
|
+
h = Mp3file::MP3Header.new(io)
|
263
|
+
h.emphasis.should == 'none'
|
264
|
+
end
|
265
|
+
|
266
|
+
it "detects 50/15 ms" do
|
267
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0001 ])
|
268
|
+
h = Mp3file::MP3Header.new(io)
|
269
|
+
h.emphasis.should == '50/15 ms'
|
270
|
+
end
|
271
|
+
|
272
|
+
it "raises an error on 2" do
|
273
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0010 ])
|
274
|
+
lambda { Mp3file::MP3Header.new(io) }.should(raise_error(Mp3file::InvalidMP3HeaderError))
|
275
|
+
end
|
276
|
+
|
277
|
+
it "detects CCIT J.17" do
|
278
|
+
io = create_io([ 0xFF, 0xFB, 0x92, 0b0111_0011 ])
|
279
|
+
h = Mp3file::MP3Header.new(io)
|
280
|
+
h.emphasis.should == 'CCIT J.17'
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe "#samples" do
|
285
|
+
combinations = [
|
286
|
+
[ "MPEG 1 Layer I", 0xFF, 384 ],
|
287
|
+
[ "MPEG 1 Layer II", 0xFD, 1152 ],
|
288
|
+
[ "MPEG 1 Layer III", 0xFB, 1152 ],
|
289
|
+
[ "MPEG 2 Layer I", 0xF7, 384 ],
|
290
|
+
[ "MPEG 2 Layer II", 0xF5, 1152 ],
|
291
|
+
[ "MPEG 2 Layer III", 0xF3, 576 ],
|
292
|
+
[ "MPEG 2.5 Layer I", 0xE7, 384 ],
|
293
|
+
[ "MPEG 2.5 Layer II", 0xE5, 1152 ],
|
294
|
+
[ "MPEG 2.5 Layer III", 0xE3, 576 ],
|
295
|
+
]
|
296
|
+
combinations.each do |name, byte2, samples|
|
297
|
+
it("for #{name}, returns %d samples" % [ samples ]) do
|
298
|
+
io = create_io([ 0xFF, byte2, 0x92, 0xC1 ])
|
299
|
+
h = Mp3file::MP3Header.new(io)
|
300
|
+
h.samples.should == samples
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe "#frame_size" do
|
306
|
+
combinations = [
|
307
|
+
[ "MPEG 1 Layer I 32 kbps 32 kHz padded", 0xFF, 0x1B, 52 ],
|
308
|
+
[ "MPEG 1 Layer II 56 kbps 48 kHz not padded", 0xFD, 0x34, 168 ],
|
309
|
+
[ "MPEG 1 Layer III 64 kbps 44.1 kHz padded", 0xFB, 0x53, 209 ],
|
310
|
+
[ "MPEG 2 Layer III 144 kbps 24 kHz not padded", 0xF3, 0xD5, 432 ],
|
311
|
+
]
|
312
|
+
combinations.each do |name, byte2, byte3, size|
|
313
|
+
it "for #{name}, returns #{size} bytes" do
|
314
|
+
io = create_io([ 0xFF, byte2, byte3, 0xC1 ])
|
315
|
+
h = Mp3file::MP3Header.new(io)
|
316
|
+
h.frame_size.should == size
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe "#side_bytes" do
|
322
|
+
combinations = [
|
323
|
+
[ "MPEG 1 Stereo", 0xFF, 0x18, 0x01, 32 ],
|
324
|
+
[ "MPEG 1 Mono", 0xFF, 0x18, 0xC1, 17 ],
|
325
|
+
[ "MPEG 2 J-Stereo", 0xF3, 0xD5, 0x41, 17 ],
|
326
|
+
[ "MPEG 2.5 Mono", 0xE3, 0xD5, 0xC1, 9 ],
|
327
|
+
]
|
328
|
+
combinations.each do |name, b2, b3, b4, side_bytes|
|
329
|
+
it "for #{name}, returns #{side_bytes} bytes" do
|
330
|
+
io = create_io([ 0xFF, b2, b3, b4 ])
|
331
|
+
h = Mp3file::MP3Header.new(io)
|
332
|
+
h.side_bytes.should == side_bytes
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../lib/mp3file'
|
2
|
+
require File.dirname(__FILE__) + '/../common_helpers'
|
3
|
+
|
4
|
+
include CommonHelpers
|
5
|
+
|
6
|
+
describe Mp3file::XingHeader do
|
7
|
+
it 'raises an error if the first 4 bytes don\'t say "Xing"' do
|
8
|
+
io = StringIO.new("Ping\x00\x00\x00\x00")
|
9
|
+
lambda { Mp3file::XingHeader.new(io) }.should(raise_error(Mp3file::InvalidXingHeaderError))
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'raises an error if the next int is more than 15' do
|
13
|
+
io = StringIO.new("Xing\x00\x00\x00\x10")
|
14
|
+
lambda { Mp3file::XingHeader.new(io) }.should(raise_error(Mp3file::InvalidXingHeaderError))
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "with no parts" do
|
18
|
+
subject { Mp3file::XingHeader.new(StringIO.new("Xing\x00\x00\x00\x00")) }
|
19
|
+
its(:frames) { should == nil }
|
20
|
+
its(:bytes) { should == nil }
|
21
|
+
its(:toc) { should == nil }
|
22
|
+
its(:quality) { should == nil }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "with only a frame count" do
|
26
|
+
subject { Mp3file::XingHeader.new(StringIO.new("Xing\x00\x00\x00\x01\x00\x00\x14\xFA")) }
|
27
|
+
its(:frames) { should == 5370 }
|
28
|
+
its(:bytes) { should == nil }
|
29
|
+
its(:toc) { should == nil }
|
30
|
+
its(:quality) { should == nil }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "with only a byte count" do
|
34
|
+
subject { Mp3file::XingHeader.new(StringIO.new("Xing\x00\x00\x00\x02\x00\x00\x14\xFA")) }
|
35
|
+
its(:frames) { should == nil }
|
36
|
+
its(:bytes) { should == 5370 }
|
37
|
+
its(:toc) { should == nil }
|
38
|
+
its(:quality) { should == nil }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "with only a TOC" do
|
42
|
+
subject { Mp3file::XingHeader.new(StringIO.new("Xing\x00\x00\x00\x04" + ("\x00" * 100))) }
|
43
|
+
its(:frames) { should == nil }
|
44
|
+
its(:bytes) { should == nil }
|
45
|
+
its(:toc) { should == [ 0 ] * 100 }
|
46
|
+
its(:quality) { should == nil }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "with only a quality" do
|
50
|
+
subject { Mp3file::XingHeader.new(StringIO.new("Xing\x00\x00\x00\x08\x00\x00\x00\x55")) }
|
51
|
+
its(:frames) { should == nil }
|
52
|
+
its(:bytes) { should == nil }
|
53
|
+
its(:toc) { should == nil }
|
54
|
+
its(:quality) { should == 85 }
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "with all four" do
|
58
|
+
subject do
|
59
|
+
str = [
|
60
|
+
'Xing', # ID
|
61
|
+
"\x00\x00\x00\x0F", # Which fields are present
|
62
|
+
"\x00\x4B\xF4\x80", # The frame count
|
63
|
+
"\x00\x1C\x7B\xB0", # The byte count
|
64
|
+
"\x00" * 100, # The TOC
|
65
|
+
"\x00\x00\x00\x55", # The quality
|
66
|
+
].join('')
|
67
|
+
Mp3file::XingHeader.new(StringIO.new(str))
|
68
|
+
end
|
69
|
+
|
70
|
+
its(:frames) { should == 4977792 }
|
71
|
+
its(:bytes) { should == 1866672 }
|
72
|
+
its(:toc) { should == [ 0 ] * 100 }
|
73
|
+
its(:quality) { should == 85 }
|
74
|
+
end
|
75
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mp3file
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Andrew Watts
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-07-01 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
requirement: &19138680 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *19138680
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: &19138260 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *19138260
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: bindata
|
39
|
+
requirement: &19137840 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *19137840
|
48
|
+
description: Reads MP3 headers and returns their information.
|
49
|
+
email:
|
50
|
+
- ahwatts@gmail.com
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- .rvmrc
|
57
|
+
- Gemfile
|
58
|
+
- Gemfile.lock
|
59
|
+
- Rakefile
|
60
|
+
- doc/id3v2.2.0.txt
|
61
|
+
- doc/id3v2.3.0.txt
|
62
|
+
- doc/id3v2.4.0-frames.txt
|
63
|
+
- doc/id3v2.4.0-structure.txt
|
64
|
+
- lib/mp3file.rb
|
65
|
+
- lib/mp3file/id3v1_tag.rb
|
66
|
+
- lib/mp3file/id3v2.rb
|
67
|
+
- lib/mp3file/id3v2/bit_padded_int.rb
|
68
|
+
- lib/mp3file/id3v2/frame_header.rb
|
69
|
+
- lib/mp3file/id3v2/header.rb
|
70
|
+
- lib/mp3file/id3v2/tag.rb
|
71
|
+
- lib/mp3file/id3v2/text_frame.rb
|
72
|
+
- lib/mp3file/id3v2/version.rb
|
73
|
+
- lib/mp3file/mp3_file.rb
|
74
|
+
- lib/mp3file/mp3_header.rb
|
75
|
+
- lib/mp3file/version.rb
|
76
|
+
- lib/mp3file/xing_header.rb
|
77
|
+
- mp3file.gemspec
|
78
|
+
- spec/common_helpers.rb
|
79
|
+
- spec/files/bret_96.mp3
|
80
|
+
- spec/files/bret_id3v1.mp3
|
81
|
+
- spec/files/bret_id3v2.mp3
|
82
|
+
- spec/files/bret_vbr_6.mp3
|
83
|
+
- spec/mp3file/id3v1_tag_spec.rb
|
84
|
+
- spec/mp3file/id3v2/bit_padded_int_spec.rb
|
85
|
+
- spec/mp3file/id3v2/frame_header_spec.rb
|
86
|
+
- spec/mp3file/id3v2/header_spec.rb
|
87
|
+
- spec/mp3file/id3v2/tag_spec.rb
|
88
|
+
- spec/mp3file/id3v2/version_spec.rb
|
89
|
+
- spec/mp3file/mp3_file_spec.rb
|
90
|
+
- spec/mp3file/mp3_header_spec.rb
|
91
|
+
- spec/mp3file/xing_header_spec.rb
|
92
|
+
has_rdoc: true
|
93
|
+
homepage: http://rubygems.org/gems/mp3file
|
94
|
+
licenses: []
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project: mp3file
|
113
|
+
rubygems_version: 1.6.2
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Reads MP3 headers and returns their information.
|
117
|
+
test_files: []
|