diff options
-rw-r--r-- | lib/dtas/trimfx.rb | 62 | ||||
-rw-r--r-- | test/test_trimfx.rb | 31 |
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 |