Class: DTAS::Source

Inherits:
Object
  • Object
show all
Includes:
Command, Process, Common, Mp3
Defined in:
lib/dtas/source.rb

Overview

this is usually one input file

Defined Under Namespace

Modules: Common, Mp3 Classes: Command

Constant Summary collapse

SOURCE_DEFAULTS =
COMMAND_DEFAULTS.merge(
  "command" => 'exec sox "$INFILE" $SOXFMT - $TRIMFX $RGFX',
  "comments" => nil,
)
SIVS =
%w(infile comments command env)

Constants included from Process

Process::PIDS

Constants included from Command

Command::COMMAND_DEFAULTS

Instance Attribute Summary collapse

Attributes included from Common

#dst, #dst_zero_byte, #requeued

Attributes included from Command

#command, #env, #pid, #spawn_at, #to_io

Instance Method Summary collapse

Methods included from Mp3

#__mp3gain_peak, #mp3gain_comments

Methods included from Process

#dtas_spawn, #qx, reaper, #xs

Methods included from Common

#dst_assoc

Methods included from Command

#command_init, #command_string, #kill, #on_death

Methods included from Serialize

#ivars_to_hash

Constructor Details

#initialize(infile, offset = nil) ⇒ Source

Returns a new instance of Source.



30
31
32
33
34
35
36
37
# File 'lib/dtas/source.rb', line 30

def initialize(infile, offset = nil)
  command_init(SOURCE_DEFAULTS)
  @format = nil
  @infile = infile
  @offset = offset
  @comments = nil
  @samples = nil
end

Instance Attribute Details

#infileObject (readonly)

:nodoc:



13
14
15
# File 'lib/dtas/source.rb', line 13

def infile
  @infile
end

#offsetObject (readonly)

Returns the value of attribute offset.



14
15
16
# File 'lib/dtas/source.rb', line 14

def offset
  @offset
end

Instance Method Details

#__load_commentsObject

just run soxi -a



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/dtas/source.rb', line 93

def __load_comments
  tmp = {}
  case @infile
  when String
    err = ""
    cmd = %W(soxi -a #@infile)
    begin
      qx(cmd, err: err).split(/\n/).each do |line|
        key, value = line.split(/=/, 2)
        key && value or next
        # TODO: multi-line/multi-value/repeated tags
        tmp[key.upcase] = value
      end
    rescue => e
      if /FAIL formats: no handler for file extension/ =~ err
        warn("#{xs(cmd)}: #{err}")
      else
        warn("#{e.message} (#{e.class})")
      end
      # TODO: fallbacks
    end
  end
  tmp
end

#commentsObject



118
119
120
# File 'lib/dtas/source.rb', line 118

def comments
  @comments ||= __load_comments
end

#formatObject



67
68
69
70
71
72
73
74
# File 'lib/dtas/source.rb', line 67

def format
  @format ||= begin
    fmt = DTAS::Format.new
    fmt.from_file(@infile)
    fmt.bits ||= precision
    fmt
  end
end

#offset_samplesObject

returns any offset in samples (relative to the original source file), likely zero unless seek was used



47
48
49
50
51
52
53
54
55
# File 'lib/dtas/source.rb', line 47

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

#offset_usObject

this exists mainly to make the mpris interface easier, but it’s not necessary, the mpris interface also knows the sample rate



41
42
43
# File 'lib/dtas/source.rb', line 41

def offset_us
  (offset_samples / format.rate.to_f) * 1000000
end

#precisionObject



57
58
59
60
61
62
63
64
65
# File 'lib/dtas/source.rb', line 57

def precision
  qx(%W(soxi -p #@infile), err: "/dev/null").to_i # sox.git f4562efd0aa3
rescue # fallback to parsing the whole output
  s = qx(%W(soxi #@infile), err: "/dev/null")
  s =~ /Precision\s+:\s*(\d+)-bit/
  v = $1.to_i
  return v if v > 0
  raise TypeError, "could not determine precision for #@infile"
end

#replaygainObject



122
123
124
# File 'lib/dtas/source.rb', line 122

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

#samplesObject

This is the number of samples according to the samples in the source file itself, not the decoded output



85
86
87
88
89
90
# File 'lib/dtas/source.rb', line 85

def samples
  @samples ||= qx(%W(soxi -s #@infile)).to_i
rescue => e
  warn e.message
  0
end

#samples!Object

A user may be downloading the file and start playing it before the download completes, this refreshes



78
79
80
81
# File 'lib/dtas/source.rb', line 78

def samples!
  @samples = nil
  samples
end

#spawn(format, rg_state, opts) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
# File 'lib/dtas/source.rb', line 126

def spawn(format, rg_state, opts)
  raise "BUG: #{self.inspect}#spawn called twice" if @to_io
  e = format.to_env
  e["INFILE"] = @infile

  # make sure these are visible to the "current" command...
  @env["TRIMFX"] = @offset ? "trim #@offset" : nil
  @env["RGFX"] = rg_state.effect(self) || nil

  @pid = dtas_spawn(e.merge!(@env), command_string, opts)
end

#to_hashObject



142
143
144
145
146
# File 'lib/dtas/source.rb', line 142

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

#to_hshObject



138
139
140
# File 'lib/dtas/source.rb', line 138

def to_hsh
  to_hash.delete_if { |k,v| v == SOURCE_DEFAULTS[k] }
end