about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2014-06-23 07:21:30 +0000
committerEric Wong <normalperson@yhbt.net>2014-06-23 08:03:21 +0000
commit34a5c2c0ae02d261191442acc3907f2346bf2f95 (patch)
tree68214c227edebf96d83f5fbb1841da861e4a068d
parenta92c8d37a094d76b2b8b691dd6cd9732011d37b3 (diff)
downloaddtas-34a5c2c0ae02d261191442acc3907f2346bf2f95.tar.gz
The names are subject to change, but the idea is to
make multiple passes over the audio if effects overlap
and combine everything afterwards.  Unedited portions
will be passed through sox (via trim and no other effects)
-rw-r--r--lib/dtas/trimfx.rb62
-rw-r--r--test/test_trimfx.rb31
2 files changed, 93 insertions, 0 deletions
diff --git a/lib/dtas/trimfx.rb b/lib/dtas/trimfx.rb
index 94ccd7a..391bbc2 100644
--- a/lib/dtas/trimfx.rb
+++ b/lib/dtas/trimfx.rb
@@ -75,4 +75,66 @@ class DTAS::TrimFX
     @tbeg = tbeg
     @tlen = tlen
   end
+
+  def <=>(other)
+    tbeg <=> other.tbeg
+  end
+
+  # for stable sorting
+  class TFXSort < Struct.new(:tfx, :idx)
+    def <=>(other)
+      cmp = tfx <=> other.tfx
+      0 == cmp ? idx <=> other.idx : cmp
+    end
+  end
+
+  # there'll be multiple epochs if ranges overlap
+  def self.schedule(ary)
+    sorted = []
+    ary.each_with_index { |tfx, i| sorted << TFXSort[tfx, i] }
+    sorted.sort!
+    rv = []
+    epoch = 0
+    prev_end = 0
+    defer = []
+    begin
+      while tfxsort = sorted.shift
+        tfx = tfxsort.tfx
+        if tfx.tbeg >= prev_end
+          prev_end = tfx.tbeg + tfx.tlen
+          (rv[epoch] ||= []) << tfx
+        else
+          defer << tfxsort
+        end
+      end
+      if defer[0]
+        epoch += 1
+        sorted = defer
+        defer = []
+        prev_end = 0
+      end
+    end while sorted[0]
+    rv
+  end
+
+  def self.expand(ary, total_len)
+    rv = []
+    schedule(ary).each_with_index do |sary, i|
+      tip = 0
+      dst = rv[i] = []
+      while tfx = sary.shift
+        if tfx.tbeg > tip
+          nfx = new(%W(trim #{tip} =#{tfx.tbeg}))
+          dst << nfx
+          dst << tfx
+          tip = tfx.tbeg + tfx.tlen
+        end
+      end
+      if tip < total_len
+        nfx = new(%W(trim #{tip} =#{total_len}))
+        dst << nfx
+      end
+    end
+    rv
+  end
 end
diff --git a/test/test_trimfx.rb b/test/test_trimfx.rb
index ff40594..3a3bdc0 100644
--- a/test/test_trimfx.rb
+++ b/test/test_trimfx.rb
@@ -47,4 +47,35 @@ class TestTrimFX < Testcase
     tfx = DTAS::TrimFX.new(%w(trim 1 sox vol -1dB))
     assert_equal %w(sox $SOXIN $SOXOUT $TRIMFX vol -1dB $FADEFX), tfx.cmd
   end
+
+  def test_schedule_simple
+    fx = [
+      DTAS::TrimFX.new(%w(trim 1 0.3)),
+      DTAS::TrimFX.new(%w(trim 2 0.2)),
+      DTAS::TrimFX.new(%w(trim 0.5 0.5)),
+    ].shuffle
+    ary = DTAS::TrimFX.schedule(fx)
+    assert_operator 1, :==, ary.size
+    assert_equal [ 0.5, 1, 2 ], ary[0].map(&:tbeg)
+    assert_equal [ 0.5, 0.3, 0.2 ], ary[0].map(&:tlen)
+  end
+
+  def test_schedule_overlaps
+    fx = [
+      DTAS::TrimFX.new(%w(trim 1 0.3 sox)),
+      DTAS::TrimFX.new(%w(trim 1.1 0.2 sox)),
+      DTAS::TrimFX.new(%w(trim 0.5 0.5 sox)),
+    ]
+    ary = DTAS::TrimFX.schedule(fx)
+    assert_equal 2, ary.size
+    assert_equal [ 0.5, 1 ], ary[0].map(&:tbeg)
+    assert_equal [ 1.1 ], ary[1].map(&:tbeg)
+
+    ex = DTAS::TrimFX.expand(fx, 10)
+    assert_equal 2, ex.size
+    assert_equal 0, ex[0][0].tbeg
+    assert_equal 3, ex[0].size
+    assert_equal 0, ex[1][0].tbeg
+    assert_equal 3, ex[1].size
+  end
 end