about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-05-19 09:14:23 +0000
committerEric Wong <e@80x24.org>2015-05-19 09:16:16 +0000
commitc02f0b8182b35df1a318418bbd0036c00be93b5c (patch)
treecf24d9e3c47ee3e3dfbe2ae697fa92b3c9f53079 /lib
parent7b47191aa4c88b3daa4c980013f0047cb7ae7f6d (diff)
downloaddtas-c02f0b8182b35df1a318418bbd0036c00be93b5c.tar.gz
Since writing nested shell commands inside YAML is subject to all
sorts of strange quoting rules, encourage users to rely on external
scripts which the YAML file refers to instead.  These scripts can be
written in any reasonable scripting language capable of executing
other commands.

This allows transparently monitoring things such as `my-script.rb'
in the below example when playing my-splitfx.yml via dtas-player:

  --------------------- my-splitfx.yml -----------------------
  infile: input.flac
  command: $INDIR/my-script.rb "$INFILE"
  ...

  --------------------- my-script.rb --------------------------
  #!/usr/bin/ruby
  require 'shellwords'
  infile = ARGV.shift
  ch = %W(sox #{infile} -p).concat((ENV['TRIMFX'] || '').shellsplit)
  fx = %W(highpass 25 gain 9)
  l = ch.dup.concat(%W(remix 1v1)).concat(fx).concat(%w(contrast 30))
  r = ch.dup.concat(%W(remix 2v1)).concat(fx).concat(%w(contrast 0))
  cmd = %W(sox -M |#{l.shelljoin} |#{r.shelljoin})
  cmd.concat((ENV['SOXFMT'] || '-p').shellsplit)
  cmd.concat(%w(- stats))
  warn cmd.inspect
  exec *cmd
Diffstat (limited to 'lib')
-rw-r--r--lib/dtas/source/splitfx.rb14
-rw-r--r--lib/dtas/splitfx.rb10
-rw-r--r--lib/dtas/watchable.rb21
3 files changed, 35 insertions, 10 deletions
diff --git a/lib/dtas/source/splitfx.rb b/lib/dtas/source/splitfx.rb
index b7b9b86..02c3a9d 100644
--- a/lib/dtas/source/splitfx.rb
+++ b/lib/dtas/source/splitfx.rb
@@ -17,6 +17,7 @@ class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc:
 
   def initialize(sox = DTAS::Source::Sox.new)
     command_init(SPLITFX_DEFAULTS)
+    @watch_extra = []
     @sox = sox
   end
 
@@ -65,6 +66,19 @@ class DTAS::Source::SplitFX < DTAS::Source::Sox # :nodoc:
     e = @env.merge!(player_format.to_env)
     @sfx.infile_env(e, @sox.infile)
 
+    # watch any scripts or files the command in the YAML file refers to
+    if c = @sfx.command
+      @sfx.expand_cmd(e, c).each do |f|
+        File.readable?(f) and @watch_extra << f
+      end
+    end
+
+    # allow users to specify explicit depdendencies to watch for edit
+    case extra = @ymlhash['deps']
+    when Array, String
+      @watch_extra.concat(Array(extra))
+    end
+
     # make sure these are visible to the "current" command...
     e["TRIMFX"] = trimfx
     e["RGFX"] = rg_state.effect(self) || nil
diff --git a/lib/dtas/splitfx.rb b/lib/dtas/splitfx.rb
index 5a1431a..cc459ae 100644
--- a/lib/dtas/splitfx.rb
+++ b/lib/dtas/splitfx.rb
@@ -14,7 +14,7 @@ class DTAS::SplitFX # :nodoc:
         '$TRIMFX $FX $RATEFX $DITHERFX'
   include DTAS::Process
   include DTAS::XS
-  attr_reader :infile, :env
+  attr_reader :infile, :env, :command
 
   class UTrim
     attr_reader :env, :comments
@@ -229,11 +229,11 @@ class DTAS::SplitFX # :nodoc:
       sub_env_s = sub_env.inject("") { |s,(k,v)| s << "#{k}=#{v} " }
       env['SOXFMT'] = '-tsox'
       sub_env['OUTFMT'] = env.delete('OUTFMT')
-      show_cmd = [ _expand_cmd(env, player_cmd), '|', '(', "#{sub_env_s};",
-                   _expand_cmd(env.merge(sub_env), command), ')' ].flatten
+      show_cmd = [ expand_cmd(env, player_cmd), '|', '(', "#{sub_env_s};",
+                   expand_cmd(env.merge(sub_env), command), ')' ].flatten
       command = "#{player_cmd} | (#{sub_env_s}; #{command})"
     else
-      show_cmd = _expand_cmd(env, command)
+      show_cmd = expand_cmd(env, command)
     end
 
     echo = "echo #{xs(show_cmd)}"
@@ -397,7 +397,7 @@ class DTAS::SplitFX # :nodoc:
     env["INBASE"] = xs(base)
   end
 
-  def _expand_cmd(env, command)
+  def expand_cmd(env, command)
     Shellwords.split(command).map do |arg|
       qx(env, "printf %s \"#{arg}\"")
     end
diff --git a/lib/dtas/watchable.rb b/lib/dtas/watchable.rb
index cc6c018..36e8644 100644
--- a/lib/dtas/watchable.rb
+++ b/lib/dtas/watchable.rb
@@ -18,7 +18,8 @@ module DTAS::Watchable
     def readable_iter
       or_call = false
       while event = take(true) # drain the buffer
-        if (event.mask & FLAGS) != 0 && @watching[1] == event.name
+        w = @watches[event.wd] or next
+        if (event.mask & FLAGS) != 0 && w[event.name]
           or_call = true
         end
       end
@@ -31,19 +32,29 @@ module DTAS::Watchable
     end
 
     # we must watch the directory, since
-    def watch_file(path, blk)
+    def watch_files(paths, blk)
+      @watches = {} # wd -> { basename -> true }
       @on_readable = blk
-      @watching = File.split(File.expand_path(path))
-      add_watch(@watching[0], FLAGS)
+      @dir2wd = {}
+      Array(paths).each do |path|
+        watchdir, watchbase = File.split(File.expand_path(path))
+        wd = @dir2wd[watchdir] ||= add_watch(watchdir, FLAGS)
+        m = @watches[wd] ||= {}
+        m[watchbase] = true
+      end
     end
   end
 
   def watch_begin(blk)
     @ino = InotifyReadableIter.new
-    @ino.watch_file(@infile, blk)
+    @ino.watch_files(@watch_extra << @infile, blk)
     @ino
   end
 
+  def watch_extra(paths)
+    @ino.watch_extra(paths)
+  end
+
   # Closing the inotify descriptor (instead of using inotify_rm_watch)
   # is cleaner because it avoids EINVAL on race conditions in case
   # a directory is deleted: https://lkml.org/lkml/2007/7/9/3