about summary refs log tree commit homepage
path: root/lib/dtas/source/file.rb
blob: 8657b0cfa612224cf3f6016b81826f06d702508b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
require_relative '../../dtas'
require_relative '../source'
require_relative '../command'
require_relative '../format'
require_relative '../process'
require_relative '../cue_index'

module DTAS::Source::File # :nodoc:
  attr_reader :infile
  attr_reader :offset
  attr_accessor :tryorder
  require_relative 'common' # dtas/source/common
  require_relative 'mp3gain'
  include DTAS::Command
  include DTAS::Process
  include DTAS::Source::Common
  include DTAS::Source::Mp3gain

  FILE_SIVS = %w(infile comments command env) # for the "current" command
  SRC_SIVS = %w(command env tryorder)

  def source_file_dup(infile, offset)
    rv = dup
    rv.__file_init(infile, offset)
    rv
  end

  def __file_init(infile, offset)
    @env = @env.dup
    @format = nil
    @infile = infile
    @offset = offset
    @comments = nil
    @samples = nil
    @cuebp = nil
    @rg = nil
  end

  # this exists mainly to make the mpris interface easier, but it's not
  # necessary, the mpris interface also knows the sample rate
  def offset_us
    (offset_samples / format.rate.to_f) * 1000000
  end

  # returns any offset in samples (relative to the original source file),
  # likely zero unless seek was used
  def offset_samples
    return 0 unless @offset
    case @offset
    when /\A\d+s\z/
      @offset.to_i
    else
      format.hhmmss_to_samples(@offset)
    end
  end

  # A user may be downloading the file and start playing
  # it before the download completes, this refreshes
  def samples!
    @samples = nil
    samples
  end

  def comments
    @comments ||= __load_comments
  end

  def to_hash
    rv = ivars_to_hash(FILE_SIVS)
    rv["samples"] = samples
    rv
  end

  def replaygain
    @rg ||= DTAS::ReplayGain.new(comments) ||
            DTAS::ReplayGain.new(mp3gain_comments)
  end

  def to_source_cat
    ivars_to_hash(SRC_SIVS)
  end

  def load!(src_hsh)
    SRC_SIVS.each do |field|
      val = src_hsh[field] and instance_variable_set("@#{field}", val)
    end
  end

  def to_state_hash
    defaults = source_defaults # see dtas/source/{av,sox}.rb
    to_source_cat.delete_if { |k,v| v == defaults[k] }
  end

  def cuebreakpoints
    rv = @cuebp and return rv
    rv = []
    begin
      str = qx(@env, %W(metaflac --export-cuesheet-to=- #@infile))
    rescue
      return rv
    end
    str.scan(/^    INDEX (\d+) (\S+)/) do |m|
      index = m[0]
      time = m[1].dup
      case time
      when /\A\d+\z/
        time << "s" # sample count (flac 1.3.0)
      else # HH:MM:SS:FF
        # FF/75 CDDA frames per second, convert to fractional seconds
        time.sub!(/:(\d+)\z/, "")
        frames = $1.to_f
        if frames > 0
          time = sprintf("#{time}.%0.6g", frames / 75.0)
        end
      end
      rv << DTAS::CueIndex.new(index, time)
    end
    @cuebp = rv
  end
end