about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-08-25 09:25:07 +0000
committerEric Wong <normalperson@yhbt.net>2013-08-25 09:29:46 +0000
commit68ffa097e187da663fa3f537b430428ea5e8de2e (patch)
treebe7d441b68ab8c77a7ebc062c129b5701bf2a5b1
parent9cd8e2776edc246950d2c7ebdea833489efb1d1f (diff)
downloaddtas-68ffa097e187da663fa3f537b430428ea5e8de2e.tar.gz
We should've done this at the start, but we didn't.
-rw-r--r--lib/dtas/format.rb1
-rw-r--r--lib/dtas/player.rb11
-rw-r--r--lib/dtas/player/client_handler.rb4
-rw-r--r--lib/dtas/source.rb145
-rw-r--r--lib/dtas/source/cmd.rb (renamed from lib/dtas/source/command.rb)2
-rw-r--r--lib/dtas/source/file.rb63
-rw-r--r--lib/dtas/source/mp3gain.rb (renamed from lib/dtas/source/mp3.rb)2
-rw-r--r--lib/dtas/source/sox.rb100
-rw-r--r--test/test_rg_integration.rb2
-rw-r--r--test/test_source_sox.rb (renamed from test/test_source.rb)20
10 files changed, 186 insertions, 164 deletions
diff --git a/lib/dtas/format.rb b/lib/dtas/format.rb
index 83a541a..a6e424b 100644
--- a/lib/dtas/format.rb
+++ b/lib/dtas/format.rb
@@ -75,6 +75,7 @@ class DTAS::Format # :nodoc:
     ivars_to_hash(SIVS)
   end
 
+  # FIXME, move to per-source (sox/avconv/ffmpeg)
   def from_file(path)
     @channels = qx(%W(soxi -c #{path})).to_i
     @type = qx(%W(soxi -t #{path})).strip
diff --git a/lib/dtas/player.rb b/lib/dtas/player.rb
index c6d6027..57976c2 100644
--- a/lib/dtas/player.rb
+++ b/lib/dtas/player.rb
@@ -5,7 +5,8 @@ require 'yaml'
 require 'shellwords'
 require_relative '../dtas'
 require_relative 'source'
-require_relative 'source/command'
+require_relative 'source/sox'
+require_relative 'source/cmd'
 require_relative 'sink'
 require_relative 'unix_server'
 require_relative 'buffer'
@@ -304,17 +305,17 @@ class DTAS::Player # :nodoc:
 
       case source_spec
       when String
-        @current = DTAS::Source.new(source_spec)
+        @current = DTAS::Source::Sox.new(source_spec)
         echo(%W(file #{@current.infile}))
       when Array
-        @current = DTAS::Source.new(*source_spec)
+        @current = DTAS::Source::Sox.new(*source_spec)
         echo(%W(file #{@current.infile} #{@current.offset_samples}s))
       else
-        @current = DTAS::Source::Command.new(source_spec["command"])
+        @current = DTAS::Source::Cmd.new(source_spec["command"])
         echo(%W(command #{@current.command_string}))
       end
 
-      if DTAS::Source === @current
+      if DTAS::Source::Sox === @current
         @current.command = @srccmd if @srccmd
         @current.env = @srcenv.dup unless @srcenv.empty?
       end
diff --git a/lib/dtas/player/client_handler.rb b/lib/dtas/player/client_handler.rb
index cddbe4c..44f0b57 100644
--- a/lib/dtas/player/client_handler.rb
+++ b/lib/dtas/player/client_handler.rb
@@ -204,7 +204,7 @@ module DTAS::Player::ClientHandler # :nodoc:
       # this offset in the @current.format (not player @format)
       @queue.unshift([ @current.infile, "#{__current_decoded_samples}s" ])
     else
-      # DTAS::Source::Command (hash), just rerun it
+      # DTAS::Source::Cmd (hash), just rerun it
       @queue.unshift(@current.to_hsh)
     end
     # We also want to hard drop the buffer so we do not get repeated audio.
@@ -424,7 +424,7 @@ module DTAS::Player::ClientHandler # :nodoc:
     case msg.shift
     when "cat"
       io.emit({
-        "command" => @srccmd || DTAS::Source::SOURCE_DEFAULTS["command"],
+        "command" => @srccmd || DTAS::Source::Sox::SOX_DEFAULTS["command"],
         "env" => @srcenv,
       }.to_yaml)
     when "ed"
diff --git a/lib/dtas/source.rb b/lib/dtas/source.rb
index 747fa9f..1093b18 100644
--- a/lib/dtas/source.rb
+++ b/lib/dtas/source.rb
@@ -2,149 +2,6 @@
 # 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 'command'
-require_relative 'format'
-require_relative 'replaygain'
-require_relative 'process'
-require_relative 'serialize'
 
-# this is usually one input file
-class DTAS::Source # :nodoc:
-  attr_reader :infile
-  attr_reader :offset
-  require_relative 'source/common'
-  require_relative 'source/mp3'
-
-  include DTAS::Command
-  include DTAS::Process
-  include DTAS::Source::Common
-  include DTAS::Source::Mp3
-
-  SOURCE_DEFAULTS = COMMAND_DEFAULTS.merge(
-    "command" => 'exec sox "$INFILE" $SOXFMT - $TRIMFX $RGFX',
-    "comments" => nil,
-  )
-
-  SIVS = %w(infile comments command env)
-
-  def initialize(infile, offset = nil)
-    command_init(SOURCE_DEFAULTS)
-    @format = nil
-    @infile = infile
-    @offset = offset
-    @comments = nil
-    @samples = 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
-
-  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
-
-  def format
-    @format ||= begin
-      fmt = DTAS::Format.new
-      fmt.from_file(@infile)
-      fmt.bits ||= precision
-      fmt
-    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
-
-  # This is the number of samples according to the samples in the source
-  # file itself, not the decoded output
-  def samples
-    @samples ||= qx(%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
-      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
-
-  def comments
-    @comments ||= __load_comments
-  end
-
-  def replaygain
-    @rg = DTAS::ReplayGain.new(comments) ||
-          DTAS::ReplayGain.new(mp3gain_comments)
-  end
-
-  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
-    e.merge!(@rg.to_env) if @rg
-
-    @pid = dtas_spawn(e.merge!(@env), command_string, opts)
-  end
-
-  def to_hsh
-    to_hash.delete_if { |k,v| v == SOURCE_DEFAULTS[k] }
-  end
-
-  def to_hash
-    rv = ivars_to_hash(SIVS)
-    rv["samples"] = samples
-    rv
-  end
+module DTAS::Source # :nodoc:
 end
diff --git a/lib/dtas/source/command.rb b/lib/dtas/source/cmd.rb
index 930c5cf..2507101 100644
--- a/lib/dtas/source/command.rb
+++ b/lib/dtas/source/cmd.rb
@@ -6,7 +6,7 @@ require_relative '../source'
 require_relative '../command'
 require_relative '../serialize'
 
-class DTAS::Source::Command # :nodoc:
+class DTAS::Source::Cmd # :nodoc:
   require_relative '../source/common'
 
   include DTAS::Command
diff --git a/lib/dtas/source/file.rb b/lib/dtas/source/file.rb
new file mode 100644
index 0000000..472cb3d
--- /dev/null
+++ b/lib/dtas/source/file.rb
@@ -0,0 +1,63 @@
+# -*- 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 '../command'
+require_relative '../format'
+require_relative '../process'
+
+module DTAS::Source::File # :nodoc:
+  attr_reader :infile
+  attr_reader :offset
+  require_relative 'common' # dtas/source/common
+  include DTAS::Command
+  include DTAS::Process
+  include DTAS::Source::Common
+
+  FILE_SIVS = %w(infile comments command env)
+
+  def source_file_init(infile, offset)
+    @format = nil
+    @infile = infile
+    @offset = offset
+    @comments = nil
+    @samples = 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
+end
diff --git a/lib/dtas/source/mp3.rb b/lib/dtas/source/mp3gain.rb
index 7ceaf8a..03bc37a 100644
--- a/lib/dtas/source/mp3.rb
+++ b/lib/dtas/source/mp3gain.rb
@@ -3,7 +3,7 @@
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../process'
 
-module DTAS::Source::Mp3 # :nodoc:
+module DTAS::Source::Mp3gain # :nodoc:
   include DTAS::Process
   # we use dBFS = 1.0 as scale (not 32768)
   def __mp3gain_peak(str)
diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb
new file mode 100644
index 0000000..44b5f17
--- /dev/null
+++ b/lib/dtas/source/sox.rb
@@ -0,0 +1,100 @@
+# -*- 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'
+  require_relative 'mp3gain'
+
+  include DTAS::Source::File
+  include DTAS::Source::Mp3gain
+
+  SOX_DEFAULTS = COMMAND_DEFAULTS.merge(
+    "command" => 'exec sox "$INFILE" $SOXFMT - $TRIMFX $RGFX',
+    "comments" => nil,
+  )
+
+  def initialize(infile, offset = nil)
+    command_init(SOX_DEFAULTS)
+    source_file_init(infile, offset)
+  end
+
+  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
+
+  def format
+    @format ||= begin
+      fmt = DTAS::Format.new
+      fmt.from_file(@infile)
+      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(%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
+      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
+      end
+    end
+    tmp
+  end
+
+  def replaygain
+    @rg = DTAS::ReplayGain.new(comments) ||
+          DTAS::ReplayGain.new(mp3gain_comments)
+  end
+
+  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
+    e.merge!(@rg.to_env) if @rg
+
+    @pid = dtas_spawn(e.merge!(@env), command_string, opts)
+  end
+
+  def to_hsh
+    to_hash.delete_if { |k,v| v == SOX_DEFAULTS[k] }
+  end
+end
diff --git a/test/test_rg_integration.rb b/test/test_rg_integration.rb
index 0d2ac09..79a6563 100644
--- a/test/test_rg_integration.rb
+++ b/test/test_rg_integration.rb
@@ -103,7 +103,7 @@ class TestRgIntegration < Minitest::Unit::TestCase
     s = client_socket
     s.req_ok("rg mode=album_gain")
     pluck, _ = tmp_pluck
-    cmd = DTAS::Source::SOURCE_DEFAULTS["command"]
+    cmd = DTAS::Source::Sox::SOX_DEFAULTS["command"]
     fifo = tmpfifo
     s.req_ok("source ed command='env > #{fifo}; #{cmd}'")
     s.req_ok("sink ed default command='cat >/dev/null' active=true")
diff --git a/test/test_source.rb b/test/test_source_sox.rb
index 21a56ac..6bf5071 100644
--- a/test/test_source.rb
+++ b/test/test_source_sox.rb
@@ -2,7 +2,7 @@
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require './test/helper'
-require 'dtas/source'
+require 'dtas/source/sox'
 require 'tempfile'
 
 class TestSource < Minitest::Unit::TestCase
@@ -31,7 +31,7 @@ class TestSource < Minitest::Unit::TestCase
     return if `which metaflac`.strip.size == 0
     tmp = new_file('flac') or return
 
-    source = DTAS::Source.new(tmp.path)
+    source = DTAS::Source::Sox.new(tmp.path)
     x(%W(metaflac --set-tag=FOO=BAR #{tmp.path}))
     x(%W(metaflac --add-replay-gain #{tmp.path}))
     assert_equal source.comments["FOO"], "BAR"
@@ -48,7 +48,7 @@ class TestSource < Minitest::Unit::TestCase
     a = new_file('mp3') or return
     b = new_file('mp3') or return
 
-    source = DTAS::Source.new(a.path)
+    source = DTAS::Source::Sox.new(a.path)
 
     # redirect stdout to /dev/null temporarily, mp3gain is noisy
     File.open("/dev/null", "w") do |null|
@@ -72,31 +72,31 @@ class TestSource < Minitest::Unit::TestCase
 
   def test_offset
     tmp = new_file('sox') or return
-    source = DTAS::Source.new(*%W(#{tmp.path} 5s))
+    source = DTAS::Source::Sox.new(*%W(#{tmp.path} 5s))
     assert_equal 5, source.offset_samples
 
-    source = DTAS::Source.new(*%W(#{tmp.path} 1:00:00.5))
+    source = DTAS::Source::Sox.new(*%W(#{tmp.path} 1:00:00.5))
     expect = 1 * 60 * 60 * 44100 + (44100/2)
     assert_equal expect, source.offset_samples
 
-    source = DTAS::Source.new(*%W(#{tmp.path} 1:10.5))
+    source = DTAS::Source::Sox.new(*%W(#{tmp.path} 1:10.5))
     expect = 1 * 60 * 44100 + (10 * 44100) + (44100/2)
     assert_equal expect, source.offset_samples
 
-    source = DTAS::Source.new(*%W(#{tmp.path} 10.03))
+    source = DTAS::Source::Sox.new(*%W(#{tmp.path} 10.03))
     expect = (10 * 44100) + (44100 * 3/100.0)
     assert_equal expect, source.offset_samples
   end
 
   def test_offset_us
     tmp = new_file('sox') or return
-    source = DTAS::Source.new(*%W(#{tmp.path} 441s))
+    source = DTAS::Source::Sox.new(*%W(#{tmp.path} 441s))
     assert_equal 10000.0, source.offset_us
 
-    source = DTAS::Source.new(*%W(#{tmp.path} 22050s))
+    source = DTAS::Source::Sox.new(*%W(#{tmp.path} 22050s))
     assert_equal 500000.0, source.offset_us
 
-    source = DTAS::Source.new(tmp.path, '1')
+    source = DTAS::Source::Sox.new(tmp.path, '1')
     assert_equal 1000000.0, source.offset_us
   end
 end