mp3file 1.1.5 → 1.2.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.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/bin/mp3info +2 -2
- data/lib/mp3file/id3v1_tag.rb +10 -10
- data/lib/mp3file/id3v2/frame_header.rb +11 -11
- data/lib/mp3file/id3v2/header.rb +3 -3
- data/lib/mp3file/mp3_file.rb +39 -12
- data/lib/mp3file/mp3_header.rb +35 -9
- data/lib/mp3file/version.rb +1 -1
- data/lib/mp3file/xing_header.rb +9 -9
- data/mp3file.gemspec +1 -1
- data/spec/files/bret_96_no_xing.mp3 +0 -0
- data/spec/files/bret_id3v1_no_xing.mp3 +0 -0
- data/spec/mp3file/id3v1_tag_spec.rb +4 -4
- data/spec/mp3file/mp3_file_spec.rb +72 -22
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9ad0218bd03684169d8f12f4bbe90a47388ea4a
|
4
|
+
data.tar.gz: 345deef9fcc2f91c5cdd0e233cc07973fdab9b49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c45bef09f17af0e2fa3f2d42329a1a3fc1267c123478182a680fc0ad696835892786f6e62464880c6f08387028fbdb7ad3ba87a14d68f58ca69c560a50a64c4
|
7
|
+
data.tar.gz: 79c80620a99932962e312a0343b4e8c090ae3ded864201b32924b91fca302758bad64c292109829e5868853e7ac954d9d9c1b810930a7347702efffb16348728
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Mp3file
|
2
2
|
|
3
3
|
This is a pure-Ruby MP3 metadata extractor. We use it to identify the
|
4
|
-
bitrate and duration of songs that people upload to
|
4
|
+
bitrate and duration of songs that people upload to http://www.reverbnation.com .
|
5
5
|
|
6
6
|
It handles a bunch of things:
|
7
7
|
* ID3v1 tags
|
@@ -12,3 +12,5 @@ It handles a bunch of things:
|
|
12
12
|
Don't think of this as an example of good code. This is some of the
|
13
13
|
most terrible, ugly, brutally hacky code I think I've ever written. I
|
14
14
|
apologize to anyone who looks at it.
|
15
|
+
|
16
|
+
[](https://travis-ci.org/ahwatts/mp3file)
|
data/bin/mp3info
CHANGED
@@ -17,7 +17,7 @@ alias :h :humanize
|
|
17
17
|
|
18
18
|
ARGV.each do |file|
|
19
19
|
begin
|
20
|
-
mp3 = Mp3file::MP3File.new(file, scan_all_headers:
|
20
|
+
mp3 = Mp3file::MP3File.new(file, scan_all_headers: false)
|
21
21
|
audio_percent = mp3.audio_size.to_f / mp3.file_size.to_f * 100.0
|
22
22
|
|
23
23
|
puts("File: #{mp3.file.path}")
|
@@ -39,7 +39,7 @@ ARGV.each do |file|
|
|
39
39
|
if mp3.xing_header
|
40
40
|
xing = mp3.xing_header
|
41
41
|
puts(" Xing header:")
|
42
|
-
print(" ")
|
42
|
+
print(" Name: #{xing.name.inspect} ")
|
43
43
|
|
44
44
|
if xing.frames
|
45
45
|
print("Frames: #{h(xing.frames)} ")
|
data/lib/mp3file/id3v1_tag.rb
CHANGED
@@ -5,12 +5,12 @@ module Mp3file
|
|
5
5
|
attr_accessor(:title, :artist, :album, :year, :comment, :track, :genre_id, :genre)
|
6
6
|
|
7
7
|
class ID3v1TagFormat < BinData::Record
|
8
|
-
string(:tag_id, :
|
9
|
-
string(:title, :
|
10
|
-
string(:artist, :
|
11
|
-
string(:album, :
|
12
|
-
string(:year, :
|
13
|
-
string(:comment, :
|
8
|
+
string(:tag_id, read_length: 3, asserted_value: "TAG")
|
9
|
+
string(:title, length: 30, trim_padding: true)
|
10
|
+
string(:artist, length: 30, trim_padding: true)
|
11
|
+
string(:album, length: 30, trim_padding: true)
|
12
|
+
string(:year, length: 4, trim_padding: true)
|
13
|
+
string(:comment, length: 30)
|
14
14
|
uint8(:genre_id)
|
15
15
|
end
|
16
16
|
|
@@ -52,12 +52,12 @@ module Mp3file
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def load_format(tag_data)
|
55
|
-
@title = tag_data.title
|
56
|
-
@artist = tag_data.artist
|
57
|
-
@album = tag_data.album
|
55
|
+
@title = tag_data.title
|
56
|
+
@artist = tag_data.artist
|
57
|
+
@album = tag_data.album
|
58
58
|
@year = tag_data.year
|
59
59
|
split_comment = tag_data.comment.split("\x00").reject { |s| s == '' }
|
60
|
-
@comment = split_comment.first
|
60
|
+
@comment = split_comment.first || ""
|
61
61
|
if split_comment.size > 1
|
62
62
|
@track = split_comment.last.bytes.first
|
63
63
|
end
|
@@ -1,38 +1,38 @@
|
|
1
1
|
module Mp3file::ID3v2
|
2
2
|
class FrameHeader
|
3
3
|
class ID3v220FrameHeaderFormat < BinData::Record
|
4
|
-
string(:frame_id, :
|
4
|
+
string(:frame_id, length: 3)
|
5
5
|
uint24be(:frame_size)
|
6
6
|
end
|
7
7
|
|
8
8
|
class ID3v230FrameHeaderFormat < BinData::Record
|
9
|
-
string(:frame_id, :
|
9
|
+
string(:frame_id, length: 4)
|
10
10
|
uint32be(:frame_size)
|
11
11
|
bit1(:tag_alter_preserve)
|
12
12
|
bit1(:file_alter_preserve)
|
13
13
|
bit1(:read_only)
|
14
|
-
bit5(:unused1)
|
14
|
+
bit5(:unused1)
|
15
15
|
bit1(:compression)
|
16
16
|
bit1(:encryption)
|
17
17
|
bit1(:has_group)
|
18
|
-
bit5(:unused2)
|
19
|
-
uint8(:encryption_type, :
|
20
|
-
uint8(:group_id, :
|
18
|
+
bit5(:unused2)
|
19
|
+
uint8(:encryption_type, onlyif: -> { encryption == 1 })
|
20
|
+
uint8(:group_id, onlyif: -> { has_group == 1 })
|
21
21
|
end
|
22
22
|
|
23
23
|
class ID3v240FrameHeaderFormat < BinData::Record
|
24
|
-
string(:frame_id, :
|
24
|
+
string(:frame_id, length: 4)
|
25
25
|
uint32be(:frame_size)
|
26
|
-
bit1(:unused1)
|
26
|
+
bit1(:unused1)
|
27
27
|
bit1(:tag_alter_preserve)
|
28
28
|
bit1(:file_alter_preserve)
|
29
29
|
bit1(:read_only)
|
30
30
|
|
31
|
-
bit4(:unused2)
|
31
|
+
bit4(:unused2)
|
32
32
|
|
33
|
-
bit1(:unused3)
|
33
|
+
bit1(:unused3)
|
34
34
|
bit1(:group)
|
35
|
-
bit2(:unused4)
|
35
|
+
bit2(:unused4)
|
36
36
|
|
37
37
|
bit1(:compression)
|
38
38
|
bit1(:encryption)
|
data/lib/mp3file/id3v2/header.rb
CHANGED
@@ -10,15 +10,15 @@ module Mp3file::ID3v2
|
|
10
10
|
:tag_size)
|
11
11
|
|
12
12
|
class ID3v2HeaderFormat < BinData::Record
|
13
|
-
string(:tag_id, :
|
14
|
-
uint8(:vmaj, :
|
13
|
+
string(:tag_id, read_length: 3, asserted_value: "ID3")
|
14
|
+
uint8(:vmaj, assert: -> { (2..4).include?(value) })
|
15
15
|
uint8(:vmin)
|
16
16
|
|
17
17
|
bit1(:unsynchronized)
|
18
18
|
bit1(:extended_header)
|
19
19
|
bit1(:experimental)
|
20
20
|
bit1(:footer)
|
21
|
-
bit4(:unused
|
21
|
+
bit4(:unused)
|
22
22
|
|
23
23
|
uint32be(:size_padded)
|
24
24
|
end
|
data/lib/mp3file/mp3_file.rb
CHANGED
@@ -125,8 +125,25 @@ module Mp3file
|
|
125
125
|
# repeat.
|
126
126
|
@extra_id3v2_tags = []
|
127
127
|
begin
|
128
|
-
# Try to find the first MP3
|
129
|
-
|
128
|
+
# Try to find the first two MP3 headers.
|
129
|
+
loop do
|
130
|
+
@first_header_offset, @first_header = get_next_header(@file)
|
131
|
+
@file.seek(@first_header_offset + @first_header.frame_size, IO::SEEK_SET)
|
132
|
+
second_header_offset = @file.tell - 4
|
133
|
+
second_header =
|
134
|
+
begin
|
135
|
+
MP3Header.new(@file)
|
136
|
+
rescue InvalidMP3HeaderError
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
|
140
|
+
# Pretend we didn't read the second header.
|
141
|
+
@file.seek(@first_header_offset + 4)
|
142
|
+
|
143
|
+
if second_header && @first_header.same_header?(second_header)
|
144
|
+
break
|
145
|
+
end
|
146
|
+
end
|
130
147
|
rescue InvalidMP3FileError
|
131
148
|
if @id3v2_tag
|
132
149
|
end_of_tags = @id3v2_tag.size + @extra_id3v2_tags.map(&:last).map(&:size).reduce(:+).to_i
|
@@ -206,22 +223,33 @@ module Mp3file
|
|
206
223
|
@vbr = !@xing_header.nil? && @xing_header.name == "Xing"
|
207
224
|
end
|
208
225
|
|
209
|
-
# puts "@num_frames = #{@num_frames.inspect}"
|
210
|
-
# puts "@
|
226
|
+
# puts "@num_frames (1) = #{@num_frames.inspect}"
|
227
|
+
# puts "@bitrate (1) = #{@bitrate.inspect}"
|
228
|
+
# puts "@vbr = #{@vbr.inspect}"
|
229
|
+
# puts "@xing_header.frames = #{@xing_header && @xing_header.frames.inspect}"
|
230
|
+
# puts "@xing_header.bytes = #{@xing_header && @xing_header.bytes.inspect}"
|
211
231
|
# puts "@audio_size = #{@audio_size.inspect}"
|
212
232
|
# puts "@first_header size = #{@first_header.frame_size.inspect}"
|
213
233
|
|
214
|
-
# Find the number of frames
|
215
|
-
#
|
216
|
-
#
|
217
|
-
|
218
|
-
|
234
|
+
# Find the number of frames, in this order:
|
235
|
+
# 1. The frame count from the Xing (or Info) header.
|
236
|
+
# 2. The number of frames we actually counted by scanning the
|
237
|
+
# whole file, which we might not have done.
|
238
|
+
# 3. Assume it's CBR and divide the file size by the frame size.
|
239
|
+
@num_frames =
|
240
|
+
(@xing_header && @xing_header.frames) ||
|
241
|
+
@num_frames ||
|
219
242
|
(@audio_size / @first_header.frame_size)
|
220
243
|
|
244
|
+
# puts "@num_frames (2) = #{@num_frames.inspect}"
|
245
|
+
|
221
246
|
# Figure out the total samples and the time duration.
|
222
247
|
@total_samples = @num_frames * @first_header.samples
|
223
248
|
@length = @total_samples.to_f / @samplerate.to_f
|
224
249
|
|
250
|
+
# puts "@total_samples = #{@total_samples.inspect}"
|
251
|
+
# puts "@length = #{@length.inspect}"
|
252
|
+
|
225
253
|
# If the file looks like it's a VBR file, do an averate bitrate
|
226
254
|
# calculation, either using the Xing header's idea of the file
|
227
255
|
# size or the one we found.
|
@@ -229,8 +257,7 @@ module Mp3file
|
|
229
257
|
@bitrate = ((@xing_header && @xing_header.bytes) || @audio_size) / @length.to_f * 8 / 1000
|
230
258
|
end
|
231
259
|
|
232
|
-
# puts "@
|
233
|
-
# puts "@bitrate = #{@bitrate.inspect}"
|
260
|
+
# puts "@bitrate (2) = #{@bitrate.inspect}"
|
234
261
|
|
235
262
|
@file.close
|
236
263
|
end
|
@@ -247,7 +274,7 @@ module Mp3file
|
|
247
274
|
while header.nil?
|
248
275
|
begin
|
249
276
|
header = MP3Header.new(file)
|
250
|
-
header_offset = file.tell - 4
|
277
|
+
header_offset = file.tell - 4
|
251
278
|
rescue InvalidMP3HeaderError
|
252
279
|
header_offset += 1
|
253
280
|
if header_offset - initial_header_offset > 4096
|
data/lib/mp3file/mp3_header.rb
CHANGED
@@ -5,18 +5,18 @@ module Mp3file
|
|
5
5
|
attr_reader(:version, :layer, :has_crc, :bitrate,
|
6
6
|
:samplerate, :has_padding, :mode, :mode_extension,
|
7
7
|
:copyright, :original, :emphasis, :samples, :frame_size,
|
8
|
-
:side_bytes)
|
8
|
+
:side_bytes, :raw)
|
9
9
|
|
10
10
|
class MP3HeaderFormat < BinData::Record
|
11
|
-
uint8(:sync1, :
|
11
|
+
uint8(:sync1, asserted_value: 255)
|
12
12
|
|
13
|
-
bit3(:sync2, :
|
14
|
-
bit2(:version, :
|
15
|
-
bit2(:layer, :
|
13
|
+
bit3(:sync2, asserted_value: 7)
|
14
|
+
bit2(:version, assert: -> { value != 1 })
|
15
|
+
bit2(:layer, assert: -> { value != 0 })
|
16
16
|
bit1(:crc)
|
17
17
|
|
18
|
-
bit4(:bitrate, :
|
19
|
-
bit2(:samplerate, :
|
18
|
+
bit4(:bitrate, assert: -> { value != 15 && value != 0 })
|
19
|
+
bit2(:samplerate, assert: -> { value != 3 })
|
20
20
|
bit1(:padding)
|
21
21
|
bit1(:private)
|
22
22
|
|
@@ -24,7 +24,7 @@ module Mp3file
|
|
24
24
|
bit2(:mode_extension)
|
25
25
|
bit1(:copyright)
|
26
26
|
bit1(:original)
|
27
|
-
bit2(:emphasis, :
|
27
|
+
bit2(:emphasis, assert: -> { value != 2 })
|
28
28
|
end
|
29
29
|
|
30
30
|
MPEG_VERSIONS = [ 'MPEG 2.5', nil, 'MPEG 2', 'MPEG 1' ]
|
@@ -78,10 +78,22 @@ module Mp3file
|
|
78
78
|
raise InvalidMP3HeaderError, ve.message
|
79
79
|
end
|
80
80
|
|
81
|
+
@raw = head
|
81
82
|
@version = MPEG_VERSIONS[head.version]
|
82
83
|
@layer = LAYERS[head.layer]
|
83
84
|
@has_crc = head.crc == 0
|
84
|
-
|
85
|
+
|
86
|
+
if @version.nil? || @layer.nil?
|
87
|
+
raise InvalidMP3HeaderError, "Bad MPEG version or layer."
|
88
|
+
end
|
89
|
+
|
90
|
+
kbitrate = BITRATES[head.version][head.layer][head.bitrate - 1]
|
91
|
+
|
92
|
+
if kbitrate.nil?
|
93
|
+
raise InvalidMP3HeaderError, "Bad bitrate."
|
94
|
+
end
|
95
|
+
|
96
|
+
@bitrate = kbitrate * 1000
|
85
97
|
@samplerate = SAMPLERATES[head.version][head.samplerate]
|
86
98
|
@has_padding = head.padding == 1
|
87
99
|
@mode = MODES[head.mode]
|
@@ -105,5 +117,19 @@ module Mp3file
|
|
105
117
|
@frame_size = (((samples.to_f * bitrate.to_f) / (8 * slot_size.to_f * samplerate.to_f)) + pad_slots).to_i * slot_size
|
106
118
|
@side_bytes = SIDE_BYTES[head.version][head.mode]
|
107
119
|
end
|
120
|
+
|
121
|
+
def to_i
|
122
|
+
@raw.to_binary_s
|
123
|
+
.reverse
|
124
|
+
.each_byte
|
125
|
+
.each_with_index
|
126
|
+
.inject(0) { |m, (b, i)| m += b << (i*8) }
|
127
|
+
end
|
128
|
+
|
129
|
+
def same_header?(other)
|
130
|
+
# Borrowed from ffmpeg.
|
131
|
+
same_header_mask = 0xffe00000 | (3 << 17) | (3 << 10) | (3 << 19)
|
132
|
+
(to_i & same_header_mask) == (other.to_i & same_header_mask)
|
133
|
+
end
|
108
134
|
end
|
109
135
|
end
|
data/lib/mp3file/version.rb
CHANGED
data/lib/mp3file/xing_header.rb
CHANGED
@@ -5,21 +5,21 @@ module Mp3file
|
|
5
5
|
attr_reader(:name, :frames, :bytes, :toc, :quality)
|
6
6
|
|
7
7
|
class XingHeaderFormat < BinData::Record
|
8
|
-
string(:vbr_id, :
|
8
|
+
string(:vbr_id, read_length: 4, assert: -> { value == 'Xing' || value == 'Info' })
|
9
9
|
|
10
|
-
uint8(:unused1, :
|
11
|
-
uint8(:unused2, :
|
12
|
-
uint8(:unused3, :
|
13
|
-
bit4(:unused4, :
|
10
|
+
uint8(:unused1, asserted_value: 0)
|
11
|
+
uint8(:unused2, asserted_value: 0)
|
12
|
+
uint8(:unused3, asserted_value: 0)
|
13
|
+
bit4(:unused4, asserted_value: 0)
|
14
14
|
bit1(:quality_present)
|
15
15
|
bit1(:toc_present)
|
16
16
|
bit1(:bytes_present)
|
17
17
|
bit1(:frames_present)
|
18
18
|
|
19
|
-
uint32be(:frames, :
|
20
|
-
uint32be(:bytes, :
|
21
|
-
array(:toc, :
|
22
|
-
uint32be(:quality, :
|
19
|
+
uint32be(:frames, onlyif: -> { frames_present == 1 })
|
20
|
+
uint32be(:bytes, onlyif: -> { bytes_present == 1 })
|
21
|
+
array(:toc, type: :uint8, read_until: -> { index == 99 }, onlyif: -> { toc_present == 1 })
|
22
|
+
uint32be(:quality, onlyif: -> { quality_present == 1 })
|
23
23
|
end
|
24
24
|
|
25
25
|
def initialize(io)
|
data/mp3file.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_development_dependency('rake')
|
20
20
|
s.add_development_dependency('pry')
|
21
21
|
|
22
|
-
s.add_dependency('bindata', '~>
|
22
|
+
s.add_dependency('bindata', '~> 2.3.0')
|
23
23
|
|
24
24
|
s.files = `git ls-files`.split("\n")
|
25
25
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
Binary file
|
Binary file
|
@@ -52,10 +52,10 @@ describe Mp3file::ID3v1Tag do
|
|
52
52
|
|
53
53
|
describe "When created with a blank ID3v1 tag" do
|
54
54
|
subject { Mp3file::ID3v1Tag.parse(StringIO.new("TAG" + ("\x00" * 125))) }
|
55
|
-
its(:title) { should ==
|
56
|
-
its(:artist) { should ==
|
57
|
-
its(:album) { should ==
|
58
|
-
its(:comment) { should ==
|
55
|
+
its(:title) { should == "" }
|
56
|
+
its(:artist) { should == "" }
|
57
|
+
its(:album) { should == "" }
|
58
|
+
its(:comment) { should == "" }
|
59
59
|
its(:track) { should == nil }
|
60
60
|
its(:genre) { should == 'Blues' }
|
61
61
|
end
|
@@ -4,47 +4,97 @@ require File.dirname(__FILE__) + '/../common_helpers'
|
|
4
4
|
include CommonHelpers
|
5
5
|
|
6
6
|
describe Mp3file::MP3File do
|
7
|
-
describe "A 96 kbps 32 kHz Joint Stereo CBR file without any ID3 tags" do
|
8
|
-
|
7
|
+
describe "A 96 kbps 32 kHz Joint Stereo CBR file without a Xing header or any ID3 tags" do
|
8
|
+
path = fixture_file("bret_96_no_xing.mp3")
|
9
|
+
subject { Mp3file::MP3File.new(path) }
|
10
|
+
|
9
11
|
its(:id3v2tag?) { should == false }
|
10
12
|
its(:id3v1tag?) { should == false }
|
11
|
-
its("file.path") { should ==
|
13
|
+
its("file.path") { should == path.to_s }
|
12
14
|
its("file.closed?") { should == true }
|
13
|
-
its(:file_size) { should ==
|
14
|
-
its(:audio_size) { should ==
|
15
|
+
its(:file_size) { should == path.size }
|
16
|
+
its(:audio_size) { should == path.size }
|
15
17
|
its(:first_header_offset) { should == 0 }
|
16
18
|
its(:mpeg_version) { should == 'MPEG 1' }
|
17
19
|
its(:layer) { should == 'Layer III' }
|
18
20
|
its(:bitrate) { should == 96 }
|
19
21
|
its(:samplerate) { should == 32000 }
|
20
22
|
its(:mode) { should == 'Joint Stereo' }
|
21
|
-
its(:num_frames) { should ==
|
22
|
-
its(:total_samples) { should ==
|
23
|
-
its(:length) { should == 5 }
|
23
|
+
its(:num_frames) { should == 140 }
|
24
|
+
its(:total_samples) { should == 161280 }
|
25
|
+
its(:length) { should == 5.04 }
|
24
26
|
its(:vbr?) { should == false }
|
25
27
|
end
|
26
28
|
|
27
|
-
describe "
|
28
|
-
|
29
|
+
describe "A 96 kbps 32 kHz Joint Stereo CBR file with a Xing \"Info\" header and no ID3 tags" do
|
30
|
+
path = fixture_file("bret_96.mp3")
|
31
|
+
subject { Mp3file::MP3File.new(path) }
|
32
|
+
|
29
33
|
its(:id3v2tag?) { should == false }
|
30
34
|
its(:id3v1tag?) { should == false }
|
31
|
-
its("file.path") { should ==
|
35
|
+
its("file.path") { should == path.to_s }
|
32
36
|
its("file.closed?") { should == true }
|
33
|
-
its(:file_size) { should ==
|
37
|
+
its(:file_size) { should == path.size }
|
38
|
+
its(:audio_size) { should == path.size }
|
39
|
+
its(:first_header_offset) { should == 0 }
|
40
|
+
its(:mpeg_version) { should == 'MPEG 1' }
|
41
|
+
its(:layer) { should == 'Layer III' }
|
42
|
+
its(:bitrate) { should == 96 }
|
43
|
+
its(:samplerate) { should == 32000 }
|
44
|
+
its(:mode) { should == 'Joint Stereo' }
|
45
|
+
its(:num_frames) { should == 140 }
|
46
|
+
its(:total_samples) { should == 161280 }
|
47
|
+
its(:length) { should == 5.04 }
|
48
|
+
its(:vbr?) { should == false }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "a 44.1 kHz Stereo VBR file with an average bitrate of 130 kbps without any ID3 tags" do
|
52
|
+
path = fixture_file("bret_vbr_6.mp3")
|
53
|
+
subject { Mp3file::MP3File.new(path) }
|
54
|
+
|
55
|
+
its(:id3v2tag?) { should == false }
|
56
|
+
its(:id3v1tag?) { should == false }
|
57
|
+
its("file.path") { should == path.to_s }
|
58
|
+
its("file.closed?") { should == true }
|
59
|
+
its(:file_size) { should == path.size }
|
34
60
|
its(:audio_size) { should == 81853 }
|
35
61
|
its(:first_header_offset) { should == 0 }
|
36
62
|
its(:mpeg_version) { should == 'MPEG 1' }
|
37
63
|
its(:layer) { should == 'Layer III' }
|
38
|
-
its(:bitrate) { should
|
64
|
+
its(:bitrate) { should be_within(0.005).of(129.88) }
|
39
65
|
its(:samplerate) { should == 44100 }
|
40
66
|
its(:mode) { should == 'Stereo' }
|
41
67
|
its(:num_frames) { should == 193 }
|
42
68
|
its(:total_samples) { should == 222336 }
|
43
|
-
its(:length) { should
|
69
|
+
its(:length) { should be_within(0.005).of(5.04) }
|
44
70
|
its(:vbr?) { should == true }
|
45
71
|
end
|
46
72
|
|
47
|
-
describe "A 96 kbps 32 kHz CBR file with only an ID3v1 tag" do
|
73
|
+
describe "A 96 kbps 32 kHz CBR file with no Xing header and only an ID3v1 tag" do
|
74
|
+
subject { Mp3file::MP3File.new(fixture_file('bret_id3v1_no_xing.mp3')) }
|
75
|
+
its(:id3v2tag?) { should == false }
|
76
|
+
its(:id3v1tag?) { should == true }
|
77
|
+
its(:audio_size) { should == 60480 }
|
78
|
+
its(:first_header_offset) { should == 0 }
|
79
|
+
its(:mpeg_version) { should == 'MPEG 1' }
|
80
|
+
its(:layer) { should == 'Layer III' }
|
81
|
+
its(:bitrate) { should == 96 }
|
82
|
+
its(:samplerate) { should == 32000 }
|
83
|
+
its(:mode) { should == 'Joint Stereo' }
|
84
|
+
its(:num_frames) { should == 140 }
|
85
|
+
its(:total_samples) { should == 161280 }
|
86
|
+
its(:length) { should be_within(0.005).of(5.04) }
|
87
|
+
its(:vbr?) { should == false }
|
88
|
+
its('id3v1_tag.artist') { should == 'Cracker' }
|
89
|
+
its(:title) { should == 'Hey Bret (You Know What Time I' }
|
90
|
+
its(:album) { should == 'Sunrise in the Land of Milk an' }
|
91
|
+
its(:comment) { should == 'For testing the mp3file gem' }
|
92
|
+
its(:year) { should == '2009' }
|
93
|
+
its(:track) { should == 9 }
|
94
|
+
its(:genre) { should == 'Rock' }
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "A 96 kbps 32 kHz CBR file with a Xing \"Info\" header and only an ID3v1 tag" do
|
48
98
|
subject { Mp3file::MP3File.new(fixture_file('bret_id3v1.mp3')) }
|
49
99
|
its(:id3v2tag?) { should == false }
|
50
100
|
its(:id3v1tag?) { should == true }
|
@@ -55,9 +105,9 @@ describe Mp3file::MP3File do
|
|
55
105
|
its(:bitrate) { should == 96 }
|
56
106
|
its(:samplerate) { should == 32000 }
|
57
107
|
its(:mode) { should == 'Joint Stereo' }
|
58
|
-
its(:num_frames) { should ==
|
59
|
-
its(:total_samples) { should ==
|
60
|
-
its(:length) { should
|
108
|
+
its(:num_frames) { should == 140 }
|
109
|
+
its(:total_samples) { should == 161280 }
|
110
|
+
its(:length) { should be_within(0.005).of(5.04) }
|
61
111
|
its(:vbr?) { should == false }
|
62
112
|
its('id3v1_tag.artist') { should == 'Cracker' }
|
63
113
|
its(:title) { should == 'Hey Bret (You Know What Time I' }
|
@@ -68,7 +118,7 @@ describe Mp3file::MP3File do
|
|
68
118
|
its(:genre) { should == 'Rock' }
|
69
119
|
end
|
70
120
|
|
71
|
-
describe "A 96 kbps 34 kHz Joint Stereo CBR file with an ID3v2 tag" do
|
121
|
+
describe "A 96 kbps 34 kHz Joint Stereo CBR file with a Xing \"Info\" header and an ID3v2 tag" do
|
72
122
|
subject { Mp3file::MP3File.new(fixture_file('bret_id3v2.mp3')) }
|
73
123
|
its(:id3v2tag?) { should == true }
|
74
124
|
its(:id3v1tag?) { should == false }
|
@@ -82,9 +132,9 @@ describe Mp3file::MP3File do
|
|
82
132
|
its(:bitrate) { should == 96 }
|
83
133
|
its(:samplerate) { should == 32000 }
|
84
134
|
its(:mode) { should == 'Joint Stereo' }
|
85
|
-
its(:num_frames) { should ==
|
86
|
-
its(:total_samples) { should ==
|
87
|
-
its(:length) { should == 5 }
|
135
|
+
its(:num_frames) { should == 140 }
|
136
|
+
its(:total_samples) { should == 161280 }
|
137
|
+
its(:length) { should == be_within(0.001).of(5.04) }
|
88
138
|
its(:vbr?) { should == false }
|
89
139
|
end
|
90
140
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mp3file
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Watts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 2.3.0
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: 2.3.0
|
75
75
|
description: Reads MP3 headers and returns their information.
|
76
76
|
email:
|
77
77
|
- ahwatts@gmail.com
|
@@ -107,7 +107,9 @@ files:
|
|
107
107
|
- mp3file.gemspec
|
108
108
|
- spec/common_helpers.rb
|
109
109
|
- spec/files/bret_96.mp3
|
110
|
+
- spec/files/bret_96_no_xing.mp3
|
110
111
|
- spec/files/bret_id3v1.mp3
|
112
|
+
- spec/files/bret_id3v1_no_xing.mp3
|
111
113
|
- spec/files/bret_id3v2.mp3
|
112
114
|
- spec/files/bret_vbr_6.mp3
|
113
115
|
- spec/files/zeroes.mp3
|
@@ -146,7 +148,9 @@ summary: Reads MP3 headers and returns their information.
|
|
146
148
|
test_files:
|
147
149
|
- spec/common_helpers.rb
|
148
150
|
- spec/files/bret_96.mp3
|
151
|
+
- spec/files/bret_96_no_xing.mp3
|
149
152
|
- spec/files/bret_id3v1.mp3
|
153
|
+
- spec/files/bret_id3v1_no_xing.mp3
|
150
154
|
- spec/files/bret_id3v2.mp3
|
151
155
|
- spec/files/bret_vbr_6.mp3
|
152
156
|
- spec/files/zeroes.mp3
|