fallback.liq 4.26 KB
Newer Older
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# Custom crossfade to deal with jingles.
def smart_crossfade (~start_next=5.,~fade_in=3.,~fade_out=3.,
                     ~default=(fun (a,b) -> sequence([a, b])),
                     ~high=-15., ~medium=-32., ~margin=4.,
                     ~width=2.,~conservative=false,s)
  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 ma["type"] == "jingles" or mb["type"] == "jingles" then
      log("Old or new file is a jingle: sequenced transition.")
      sequence([sa, sb])
    elsif
      # If A and B are not too loud and close, fully cross-fade them.
      a <= medium and b <= medium and abs(a - b) <= margin
    then
      log("Old <= medium, new <= medium and |old-new| <= margin.")
      log("Old and new source are not too loud and close.")
      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("new >= old + margin, old >= medium and new <= high.")
      log("New source is significantly louder than old one.")
      log("Transition: crossed, fade-out.")
      add(fade.out(sa),sb)

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

    elsif
      # Do not fade if it's already very low.
      b >= a + margin and a <= medium and b <= high
    then
      log("new >= old + margin, old <= medium and new <= high.")
      log("Do not fade if it's already very low.")
      log("Transition: crossed, no fade.")
      add(sa,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: using default.")
      default(sa, sb)
    end
  end

  smart_cross(width=width, duration=start_next, conservative=conservative, transition, s)
end

# create a pool
def fallback_create(~skip=true, name, requestor)
  log("Creating channel #{name}")

  # Create the request.dynamic source
  # Set conservative to true to queue
  # several songs in advance
79
80
  #source = request.dynamic(conservative=true, length=50., id="pool_"^name, requestor, timeout=60.)
  source = request.dynamic(length=50., id="pool_"^name, requestor, timeout=60.)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

  # Apply normalization using replaygain information
  source = amplify(1., override="replay_gain", source)

  # Skip blank when asked to
  source =
    if skip then
      skip_blank(source, max_blank=10., threshold=-40.)
    else
      source
    end

  # Tell the system when a new track
  # is played
  source = on_metadata(fun (meta) ->
    system('#{list.assoc("install_dir", ini)}/modules/liquidsoap/helpers/message.py -c aura -t liquid_startup'), source)

  # Finally apply a smart crossfading
  smart_crossfade(source)
end

def create_dynamic_playlist(next)
  log("next song is: #{next}")
  request.create(list.hd(next))
end

def create_station_fallback() =
  log("requesting next song for STATION fallback")
  result = get_process_lines('#{list.assoc("install_dir", ini)}/guru.py --get-next-for-fallback-file "station"')
  create_dynamic_playlist(result)
end

def create_show_fallback() =
  log("requesting next song for SHOW fallback")
  result = get_process_lines('#{list.assoc("install_dir", ini)}/guru.py --get-next-for-fallback-file "show"')
  create_dynamic_playlist(result)
end

def create_timeslot_fallback() =
  log("requesting next song for TIMESLOT fallback")
  result = get_process_lines('#{list.assoc("install_dir", ini)}/guru.py --get-next-for-fallback-file "timeslot"')
  create_dynamic_playlist(result)
end