about summary refs log tree commit homepage
diff options
context:
space:
mode:
-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