From 37eae22446feb5a805d9cd59f6ad54362829189f Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 28 Jan 2015 07:44:05 +0000 Subject: player: support the "trim" parameter This feature is intended to allow users to "zoom-in" on a particular portion of a track to tweak parameters (either with dtas-sourceedit(1) or via playback of splitfx YAML files). This may be combined with looping the tracklist (via "tl repeat"). --- lib/dtas/source/av.rb | 2 +- lib/dtas/source/av_ff_common.rb | 25 ++++++++++++++++++------- lib/dtas/source/ff.rb | 2 +- lib/dtas/source/file.rb | 24 +++++++++++++++++++++--- lib/dtas/source/sox.rb | 6 +++--- lib/dtas/source/splitfx.rb | 8 ++++---- 6 files changed, 48 insertions(+), 19 deletions(-) (limited to 'lib/dtas/source') diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb index 722c798..c86b5d2 100644 --- a/lib/dtas/source/av.rb +++ b/lib/dtas/source/av.rb @@ -10,7 +10,7 @@ class DTAS::Source::Av # :nodoc: AV_DEFAULTS = COMMAND_DEFAULTS.merge( "command" => 'avconv -v error $SSPOS $PROBE -i "$INFILE" $AMAP -f sox - |' \ - 'sox -p $SOXFMT - $RGFX', + 'sox -p $SOXFMT - $TRIMFX $RGFX', # this is above ffmpeg because this av is the Debian default and # it's easier for me to test av than ff diff --git a/lib/dtas/source/av_ff_common.rb b/lib/dtas/source/av_ff_common.rb index 03526d2..189e135 100644 --- a/lib/dtas/source/av_ff_common.rb +++ b/lib/dtas/source/av_ff_common.rb @@ -19,8 +19,8 @@ module DTAS::Source::AvFfCommon # :nodoc: attr_reader :precision # always 32 attr_reader :format - def try(infile, offset = nil) - rv = source_file_dup(infile, offset) + def try(infile, offset = nil, trim = nil) + rv = source_file_dup(infile, offset, trim) rv.av_ff_ok? or return rv end @@ -101,10 +101,20 @@ module DTAS::Source::AvFfCommon # :nodoc: ! @astreams.compact.empty? end - def sspos(offset) - offset =~ /\A(\d+)s\z/ or return "-ss #{offset}" - samples = $1.to_f - sprintf("-ss %0.9g", samples / @format.rate) + def sspos + return unless @offset || @trim + off = offset_samples / @format.rate.to_f + sprintf('-ss %0.9g', off) + end + + def av_ff_trimfx # for sox + return unless @trim + tbeg, tlen = @trim # Floats + tend = tbeg + tlen + off = offset_samples / @format.rate.to_f + tlen = tend - off + tlen = 0 if tlen < 0 + sprintf('trim 0 %0.9g', tlen) end def select_astream(as) @@ -150,8 +160,9 @@ module DTAS::Source::AvFfCommon # :nodoc: # make sure these are visible to the source command... e["INFILE"] = @infile e["AMAP"] = amap - e["SSPOS"] = @offset ? sspos(@offset) : nil + e["SSPOS"] = sspos e["RGFX"] = rg_state.effect(self) || nil + e["TRIMFX"] = av_ff_trimfx e.merge!(@rg.to_env) if @rg @pid = dtas_spawn(e, command_string, opts) diff --git a/lib/dtas/source/ff.rb b/lib/dtas/source/ff.rb index c59de40..d5e744c 100644 --- a/lib/dtas/source/ff.rb +++ b/lib/dtas/source/ff.rb @@ -12,7 +12,7 @@ class DTAS::Source::Ff # :nodoc: FF_DEFAULTS = COMMAND_DEFAULTS.merge( "command" => 'ffmpeg -v error $SSPOS $PROBE -i "$INFILE" $AMAP -f sox - |' \ - 'sox -p $SOXFMT - $RGFX', + 'sox -p $SOXFMT - $TRIMFX $RGFX', # I haven't tested this much since av is in Debian stable and ff is not "tryorder" => 2, diff --git a/lib/dtas/source/file.rb b/lib/dtas/source/file.rb index 8a9fa34..75b4a43 100644 --- a/lib/dtas/source/file.rb +++ b/lib/dtas/source/file.rb @@ -21,17 +21,18 @@ module DTAS::Source::File # :nodoc: FILE_SIVS = %w(infile comments command env) # for the "current" command SRC_SIVS = %w(command env tryorder) - def source_file_dup(infile, offset) + def source_file_dup(infile, offset, trim) rv = dup - rv.__file_init(infile, offset) + rv.__file_init(infile, offset, trim) rv end - def __file_init(infile, offset) + def __file_init(infile, offset, trim) @env = @env.dup @format = nil @infile = infile @offset = offset + @trim = trim @comments = nil @samples = nil @cuebp = nil @@ -47,6 +48,13 @@ module DTAS::Source::File # :nodoc: # returns any offset in samples (relative to the original source file), # likely zero unless seek was used def offset_samples + off = __offset_samples + return off unless @trim + tbeg = @trim[0] * format.rate + tbeg < off ? off : tbeg + end + + def __offset_samples return 0 unless @offset case @offset when /\A\d+s\z/ @@ -56,6 +64,16 @@ module DTAS::Source::File # :nodoc: end end + # creates the effect to fill the TRIMFX env + def trimfx + return unless @offset || @trim + fx = "trim #{offset_samples}s" + if @trim && @trim[1] + fx << sprintf(' =%0.9gs', (@trim[0] + @trim[1]) * format.rate) + end + fx + end + # A user may be downloading the file and start playing # it before the download completes, this refreshes def samples! diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb index 99dfe35..91a3c40 100644 --- a/lib/dtas/source/sox.rb +++ b/lib/dtas/source/sox.rb @@ -38,13 +38,13 @@ class DTAS::Source::Sox # :nodoc: command_init(SOX_DEFAULTS) end - def try(infile, offset = nil) + def try(infile, offset = nil, trim = nil) err = "" cmd = %W(soxi -s #{infile}) s = qx(@env.dup, 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) + source_file_dup(infile, offset, trim) end def format @@ -81,7 +81,7 @@ class DTAS::Source::Sox # :nodoc: e["INFILE"] = @infile # make sure these are visible to the "current" command... - e["TRIMFX"] = @offset ? "trim #@offset" : nil + e["TRIMFX"] = trimfx e["RGFX"] = rg_state.effect(self) || nil e.merge!(@rg.to_env) if @rg diff --git a/lib/dtas/source/splitfx.rb b/lib/dtas/source/splitfx.rb index 680ad8b..b7b9b86 100644 --- a/lib/dtas/source/splitfx.rb +++ b/lib/dtas/source/splitfx.rb @@ -20,7 +20,7 @@ class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc: @sox = sox end - def try(ymlfile, offset = nil) + def try(ymlfile, offset = nil, trim = nil) @splitfx = @ymlhash = nil st = File.stat(ymlfile) return false if !st.file? || st.size > MAX_YAML_SIZE @@ -41,8 +41,8 @@ class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc: end @splitfx = sfx @infile = ymlfile - sox = @sox.try(sfx.infile, offset) or return false - rv = source_file_dup(ymlfile, offset) + sox = @sox.try(sfx.infile, offset, trim) or return false + rv = source_file_dup(ymlfile, offset, trim) rv.sox = sox rv.env = sfx.env rv.sfx = sfx @@ -66,7 +66,7 @@ class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc: @sfx.infile_env(e, @sox.infile) # make sure these are visible to the "current" command... - e["TRIMFX"] = @offset ? "trim #@offset" : nil + e["TRIMFX"] = trimfx e["RGFX"] = rg_state.effect(self) || nil e.merge!(@rg.to_env) if @rg -- cgit v1.2.3-24-ge0c7