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 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