mp3file 1.1.5 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cea56455b0c3fcd4691734fd996aa92b2e70c5bc
4
- data.tar.gz: 577dad17813c5d17ff6f23db687ea98857f60e45
3
+ metadata.gz: b9ad0218bd03684169d8f12f4bbe90a47388ea4a
4
+ data.tar.gz: 345deef9fcc2f91c5cdd0e233cc07973fdab9b49
5
5
  SHA512:
6
- metadata.gz: d06cbe98cbb7c9b86c13e3e0dc2ec2de5dabec8907145f9bf6860d35dcdaca0517e57a8d56d5596bf32f18c98fc535ca6e0b9c47e45de79173c80581efcd38fb
7
- data.tar.gz: fcb827f6846adbac1a2f98186906875e30a8a44023baa01e0bb50018493a9a52e03bcd89490212cf3302cb4b2cdbaae0be2e0dac605ed740302f7601561f5315
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 [http://www.reverbnation.com].
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
+ [![Build Status](https://travis-ci.org/ahwatts/mp3file.svg?branch=master)](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: true)
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)} ")
@@ -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, :length => 3, :check_value => lambda { value == 'TAG' })
9
- string(:title, :length => 30)
10
- string(:artist, :length => 30)
11
- string(:album, :length => 30)
12
- string(:year, :length => 4)
13
- string(:comment, :length => 30)
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.split("\x00").first
56
- @artist = tag_data.artist.split("\x00").first
57
- @album = tag_data.album.split("\x00").first
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, :length => 3)
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, :length => 4)
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) # , :check_value => lambda { value == 0 })
14
+ bit5(:unused1)
15
15
  bit1(:compression)
16
16
  bit1(:encryption)
17
17
  bit1(:has_group)
18
- bit5(:unused2) # , :check_value => lambda { value == 0 })
19
- uint8(:encryption_type, :onlyif => lambda { encryption == 1 })
20
- uint8(:group_id, :onlyif => lambda { has_group == 1 })
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, :length => 4)
24
+ string(:frame_id, length: 4)
25
25
  uint32be(:frame_size)
26
- bit1(:unused1) # , :check_value => lambda { value == 0 })
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) # , :check_value => lambda { value == 0 })
31
+ bit4(:unused2)
32
32
 
33
- bit1(:unused3) # , :check_value => lambda { value == 0 })
33
+ bit1(:unused3)
34
34
  bit1(:group)
35
- bit2(:unused4) # , :check_value => lambda { value == 0 })
35
+ bit2(:unused4)
36
36
 
37
37
  bit1(:compression)
38
38
  bit1(:encryption)
@@ -10,15 +10,15 @@ module Mp3file::ID3v2
10
10
  :tag_size)
11
11
 
12
12
  class ID3v2HeaderFormat < BinData::Record
13
- string(:tag_id, :length => 3, :check_value => lambda { value == 'ID3' })
14
- uint8(:vmaj, :check_value => lambda { value >= 2 && value <= 4 })
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, :check_value => lambda { value == 0 })
21
+ bit4(:unused)
22
22
 
23
23
  uint32be(:size_padded)
24
24
  end
@@ -125,8 +125,25 @@ module Mp3file
125
125
  # repeat.
126
126
  @extra_id3v2_tags = []
127
127
  begin
128
- # Try to find the first MP3 header.
129
- @first_header_offset, @first_header = get_next_header(@file)
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 "@xing_header = #{@xing_header.inspect}"
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. Prefer the actual frame count we
215
- # did (if we scanned all the frames) over the Xing
216
- # header. Prefer the Xing header over file size math.
217
- @num_frames = @num_frames ||
218
- (@xing_header && (@xing_header.frames + 1)) ||
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 "@vbr = #{@vbr.inspect}"
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
@@ -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, :value => 255, :check_value => lambda { value == 255 })
11
+ uint8(:sync1, asserted_value: 255)
12
12
 
13
- bit3(:sync2, :value => 7, :check_value => lambda { value == 7 })
14
- bit2(:version, :check_value => lambda { value != 1 })
15
- bit2(:layer, :check_value => lambda { value != 0 })
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, :check_value => lambda { value != 15 && value != 0 })
19
- bit2(:samplerate, :check_value => lambda { value != 3 })
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, :check_value => lambda { value != 2 })
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
- @bitrate = BITRATES[head.version][head.layer][head.bitrate - 1] * 1000
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
@@ -1,3 +1,3 @@
1
1
  module Mp3file
2
- VERSION = "1.1.5"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -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, :length => 4, :check_value => lambda { value == 'Xing' || value == 'Info' })
8
+ string(:vbr_id, read_length: 4, assert: -> { value == 'Xing' || value == 'Info' })
9
9
 
10
- uint8(:unused1, :check_value => lambda { value == 0 })
11
- uint8(:unused2, :check_value => lambda { value == 0 })
12
- uint8(:unused3, :check_value => lambda { value == 0 })
13
- bit4(:unused4, :check_value => lambda { value == 0 })
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, :onlyif => lambda { frames_present == 1 })
20
- uint32be(:bytes, :onlyif => lambda { bytes_present == 1 })
21
- array(:toc, :type => :uint8, :read_until => lambda { index == 99 }, :onlyif => lambda { toc_present == 1 })
22
- uint32be(:quality, :onlyif => lambda { quality_present == 1 })
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', '~> 1.5.0')
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 == nil }
56
- its(:artist) { should == nil }
57
- its(:album) { should == nil }
58
- its(:comment) { should == nil }
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
- subject { Mp3file::MP3File.new(fixture_file('bret_96.mp3')) }
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 == fixture_file('bret_96.mp3').to_s }
13
+ its("file.path") { should == path.to_s }
12
14
  its("file.closed?") { should == true }
13
- its(:file_size) { should == fixture_file('bret_96.mp3').size }
14
- its(:audio_size) { should == fixture_file('bret_96.mp3').size }
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 == 141 }
22
- its(:total_samples) { should == 162432 }
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 "a 44.1 kHz Stereo VBR file with an average bitrate of 13 kbps without any ID3 tags" do
28
- subject { Mp3file::MP3File.new(fixture_file('bret_vbr_6.mp3')) }
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 == fixture_file('bret_vbr_6.mp3').to_s }
35
+ its("file.path") { should == path.to_s }
32
36
  its("file.closed?") { should == true }
33
- its(:file_size) { should == fixture_file('bret_vbr_6.mp3').size }
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 == 130 }
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 == 5 }
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 == 141 }
59
- its(:total_samples) { should == 162432 }
60
- its(:length) { should == 5 }
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 == 141 }
86
- its(:total_samples) { should == 162432 }
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.1.5
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-05-05 00:00:00.000000000 Z
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: 1.5.0
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: 1.5.0
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