# File lib/mp3info.rb, line 156
  def initialize(filename)
    $stderr.puts("#{self.class}::new() does not take block; use #{self.class}::open() instead") if block_given?
    raise(Mp3InfoError, "empty file") unless File.stat(filename).size? #FIXME
    @filename = filename
    @hastag1 = false
    
    @tag1 = {}
    @tag1.extend(HashKeys)

    @tag2 = ID3v2.new

    @file = File.new(filename, "rb")
    @file.extend(Mp3FileMethods)
    
    begin
      parse_tags
      @tag1_orig = @tag1.dup

      @tag = {}

      if hastag1?
        @tag = @tag1.dup
      end

      if hastag2?
        @tag = {}
      #creation of a sort of "universal" tag, regardless of the tag version
        V1_V2_TAG_MAPPING.each do |key1, key2| 
          t2 = @tag2[key2]
          next unless t2
          @tag[key1] = t2.is_a?(Array) ? t2.first : t2

          if key1 == "tracknum"
            val = @tag2[key2].is_a?(Array) ? @tag2[key2].first : @tag2[key2]
            @tag[key1] = val.to_i
          end
        end
      end

      @tag.extend(HashKeys)
      @tag_orig = @tag.dup


      ### extracts MPEG info from MPEG header and stores it in the hash @mpeg
      ###  head (fixnum) = valid 4 byte MPEG header
      
    found = false

      5.times do
        head = find_next_frame() 
        head.extend(NumericBits)
        @mpeg_version = [2, 1][head[19]]
        @layer = LAYER[head.bits(18,17)]
        next if @layer.nil?
        @bitrate = BITRATE[@mpeg_version-1][@layer-1][head.bits(15,12)-1]
        @error_protection = head[16] == 0 ? true : false
        @samplerate = SAMPLERATE[@mpeg_version-1][head.bits(11,10)]
        @padding = (head[9] == 1 ? true : false)
        @channel_mode = CHANNEL_MODE[@channel_num = head.bits(7,6)]
        @copyright = (head[3] == 1 ? true : false)
        @original = (head[2] == 1 ? true : false)
        @vbr = false
        found = true
        break
      end

      raise(Mp3InfoError, "Cannot find good frame") unless found


      seek = @mpeg_version == 1 ? 
        (@channel_num == 3 ? 17 : 32) :       
        (@channel_num == 3 ?  9 : 17)

      @file.seek(seek, IO::SEEK_CUR)
      
      vbr_head = @file.read(4)
      if vbr_head == "Xing"
        puts "Xing header (VBR) detected" if $DEBUG
        flags = @file.get32bits
        @streamsize = @frames = 0
        flags[1] == 1 and @frames = @file.get32bits
        flags[2] == 1 and @streamsize = @file.get32bits 
        puts "#{@frames} frames" if $DEBUG
        raise(Mp3InfoError, "bad VBR header") if @frames.zero?
        # currently this just skips the TOC entries if they're found
        @file.seek(100, IO::SEEK_CUR) if flags[0] == 1
        @vbr_quality = @file.get32bits if flags[3] == 1
        @length = (26/1000.0)*@frames
        @bitrate = (((@streamsize/@frames)*@samplerate)/144) >> 10
        @vbr = true
      else
        # for cbr, calculate duration with the given bitrate
        @streamsize = @file.stat.size - (@hastag1 ? TAGSIZE : 0) - (@tag2.valid? ? @tag2.io_position : 0)
        @length = ((@streamsize << 3)/1000.0)/@bitrate
        if @tag2["TLEN"]
          # but if another duration is given and it isn't close (within 5%)
          #  assume the mp3 is vbr and go with the given duration
          tlen = (@tag2["TLEN"].is_a?(Array) ? @tag2["TLEN"].last : @tag2["TLEN"]).to_i/1000
          percent_diff = ((@length.to_i-tlen)/tlen.to_f)
          if percent_diff.abs > 0.05
            # without the xing header, this is the best guess without reading
            #  every single frame
            @vbr = true
            @length = @tag2["TLEN"].to_i/1000
            @bitrate = (@streamsize / @bitrate) >> 10
          end
        end
      end
    ensure
      @file.close
    end
  end