dtas.git  about / heads / tags
duct tape audio suite for *nix
blob 8ac75731017d8edfb3b4cd24608bb1fbc41a894a 3013 bytes (raw)
$ git show v0.1.I:lib/dtas/source/sox.rb	# shows this blob on the CLI

  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
 
# -*- encoding: binary -*-
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
require_relative '../../dtas'
require_relative '../source'
require_relative '../replaygain'

# this is usually one input file
class DTAS::Source::Sox # :nodoc:
  require_relative 'file'

  include DTAS::Source::File

  SOX_DEFAULTS = COMMAND_DEFAULTS.merge(
    "command" => 'exec sox "$INFILE" $SOXFMT - $TRIMFX $RGFX',
    "tryorder" => 0,
  )

  # we use this to be less noisy when seeking a file
  @last_failed = nil
  def self.try_to_fail_harder(infile, s, cmd)
    msg = nil
    case s
    when %r{\A0\s*\z} then msg = "detected zero samples"
    when Process::Status then msg = "failed with #{s.exitstatus}"
    end
    if msg
      return if @last_failed == infile
      @last_failed = infile
      return warn("`#{Shellwords.join(cmd)}' #{msg}")
    end
    true
  end

  def initialize
    command_init(SOX_DEFAULTS)
  end

  def try(infile, offset = nil)
    err = ""
    cmd = %W(soxi -s #{infile})
    s = qx(@env, cmd, err_str: err, no_raise: true)
    return if err =~ /soxi FAIL formats:/
    self.class.try_to_fail_harder(infile, s, cmd) or return
    source_file_dup(infile, offset)
  end

  def precision
    qx(@env, %W(soxi -p #@infile), err: "/dev/null").to_i # sox.git f4562efd0aa3
  rescue # fallback to parsing the whole output
    s = qx(@env, %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

  def format
    @format ||= begin
      fmt = DTAS::Format.new
      path = @infile
      fmt.channels = qx(@env, %W(soxi -c #{path})).to_i
      fmt.type = qx(@env, %W(soxi -t #{path})).strip
      fmt.rate = qx(@env, %W(soxi -r #{path})).to_i
      fmt.bits ||= precision
      fmt
    end
  end

  # This is the number of samples according to the samples in the source
  # file itself, not the decoded output
  def samples
    @samples ||= qx(@env, %W(soxi -s #@infile)).to_i
  rescue => e
    warn e.message
    0
  end

  # just run soxi -a
  def __load_comments
    tmp = {}
    case @infile
    when String
      qx(@env, %W(soxi -a #@infile)).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
    end
    tmp
  end

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

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

    @pid = dtas_spawn(e, command_string, opts)
  end

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

  def source_defaults
    SOX_DEFAULTS
  end
end

git clone git://80x24.org/dtas.git
git clone https://80x24.org/dtas.git