smart_crossfade.liq

# Crossfade between tracks, 
# taking the respective volume levels 
# into account in the choice of the 
# transition.
# @category Source / Track Processing
# @param ~start_next   Crossing duration, if any.
# @param ~fade_in      Fade-in duration, if any.
# @param ~fade_out     Fade-out duration, if any.
# @param ~width        Width of the volume analysis window.
# @param ~conservative Always prepare for
#                      a premature end-of-track.
# @param s             The input source.
def smart_crossfade (~start_next=5.,~fade_in=3.,
                     ~fade_out=3., ~width=2.,
		     ~conservative=false,s)
  high   = -20.
  medium = -32.
  margin = 4.
  fade.out = fade.out(type="sin",duration=fade_out)
  fade.in  = fade.in(type="sin",duration=fade_in)
  add = fun (a,b) -> add(normalize=false,[b,a])
  log = log(label="smart_crossfade")

  def transition(a,b,ma,mb,sa,sb)

    list.iter(fun(x)-> 
       log(level=4,"Before: #{x}"),ma)
    list.iter(fun(x)-> 
       log(level=4,"After : #{x}"),mb)

    if
      # If A and B and not too loud and close, 
      # fully cross-fade them.
      a <= medium and 
      b <= medium and 
      abs(a - b) <= margin
    then
      log("Transition: crossed, fade-in, fade-out.")
      add(fade.out(sa),fade.in(sb))

    elsif
      # If B is significantly louder than A, 
      # only fade-out A.
      # We don't want to fade almost silent things, 
      # ask for >medium.
      b >= a + margin and a >= medium and b <= high
    then
      log("Transition: crossed, fade-out.")
      add(fade.out(sa),sb)

    elsif
      # Do not fade if it's already very low.
      b >= a + margin and a <= medium and b <= high
    then
      log("Transition: crossed, no fade-out.")
      add(sa,sb)

    elsif
      # Opposite as the previous one.
      a >= b + margin and b >= medium and a <= high
    then
      log("Transition: crossed, fade-in.")
      add(sa,fade.in(sb))

    # What to do with a loud end and 
    # a quiet beginning ?
    # A good idea is to use a jingle to separate 
    # the two tracks, but that's another story.

    else
      # Otherwise, A and B are just too loud 
      # to overlap nicely, or the difference 
      # between them is too large and 
      # overlapping would completely mask one 
      # of them.
      log("No transition: just sequencing.")
      sequence([sa, sb])
    end
  end

  smart_cross(width=width, duration=start_next, 
              conservative=conservative,
              transition,s)
end
Grab the code!