autocue ⇧
On-the-fly JSON song cue-in, cue-out, overlay, replaygain calculation for Liquidsoap, AzuraCast and other AutoDJ software.
Work in progress.
Note: This documentation describes the standalone cue_file
and the autocue2
Liquidsoap protocol. Documentation for the integrated version in the integrate-with-liquidsoap
branch will follow later.
Requires Python3 and ffmpeg
with the ebur128 filter. (The AzuraCast Docker already has these.)
Tested on Linux and Mac, with several ffmpeg
versions ranging from 4.4.2–6.1.1, and running on several stations since a few weeks.
Basically, autocue
consists of two parts:
cue_file
, a Python3 script, that returns JSON cueing, loudness and overlay data for an audio file. This can be used standalone, as part of some pre-processing or AutoDJ software, or in conjunction with below.- The Liquidsoap
autocue2:
protocol, for full integration into Liquidsoap, which in turn can be used standalone or as part of a larger playout system like AzuraCast or others.
Note: Liquidsoap recently introduced a bultin autocue:
protocol. I had to rename my autocue:
protocol to autocue2:
so it doesn’t clash with the other one.
Both standalone Liquidsoap operation and integrated playout systems like AzuraCast (and others) are supported. cue_file
, the central part of autocue2
, is available as CLI executable and can be used to integrate into other applications, for example to get the autocue2
results into a database, or pre-tag your audio files.
Table of Contents ⇧
- autocue
Install ⇧
Install cue_file
⇧
Put cue_file
in your path locally (i.e., into ~/bin
, ~/.local/bin
or /usr/local/bin
) and chmod+x
it.
If you wish, you can now play around with it a bit (use cue_file --help
for help), or follow our examples below and analyze some of your audio files. Audacity and spec can be helpful in checking.
Local testing with Liquidsoap ⇧
Use the code in test_autocue2.liq
for some local testing, if you have Liquidsoap installed on your machine.
Adjust the settings near the beginning of the fie, then look for
# --- Use YOUR (playlist/single) here! ---
and put in your song and jingle playlist, and a single
for testing.
Then run
$ liquidsoap test_autocue2.liq
Depending on your settings, you’ll get some result files for further study:
test_autocue2.log
— Log file, usetail -f test_autocue2.liq
in another terminal to followtest_autocue2.mp3
— an MP3 recording, to see how well the track transitions worked outtest_autocue2.cue
— a.cue
file to go with the MP3 recording, for finding tracks easier (open this in your audio player)
Install on AzuraCast ⇧
cue_file
⇧
On your AzuraCast host, you can put it into /var/azuracast/bin
and overlay it into the Docker by adding a line to your docker-compose.override.yml
, like so:
services:
web:
volumes:
- /var/azuracast/bin/cue_file:/usr/local/bin/cue_file
Use Plugin or not? ⇧
With AzuraCast, you now have two options for installing:
- Without modifying the generated AzuraCast Liquidsoap config. Use
enable_autocue2_metadata()
for that. Drawback: You can’t usesettings.autocue2.blankskip := true
and expect "hidden" jingles to be automatically exempted from finding silent parts in the tracks. - You can modify the AzuraCast Liquidsoap config by installing @RM-FM’s
ls-config-replace
plugin, and copying over thels-config-replace/liq/10_audodj_next_song_add_autocue
folder into your/var/azuracast/plugins/ls-config-replace/liq
folder after installing the plugin. This will allow using all features.
If you wish to disable AzuraCast’s built-in liq_amplify
handling and rather use your tagged ReplayGain data, also copy over the 12_remove_amplify
folder.
Add the autocue2
protocol code ⇧
Then copy-paste the contents of the autocue2.liq
file into the second input box in your station’s Liquidsoap Config.
If you want to enable skipping silence within tracks, add the following line at the end of this input box:
settings.autocue2.blankskip := true
Note: This should only be used with installation variant 2 (plugin/modify config).
For installation variant 1 (enable_autocue2_metadata()
), this command also goes here, second input box, just after the settings:
enable_autocue2_metadata()
Custom crossfading code ⇧
Use the example in test_autocue2.liq
and add your custom amplify
and live_aware_crossfade
code in the third input box of AzuraCast’s Liquidsoap Config. You might already have modified this in your local testing above.
To find the relevant parts, look out for
# --- Copy-paste ...
Note: If you had used ReplayGain adjustment before like so (third input box)
# Be sure to have ReplayGain applied before crossing.
radio = amplify(1.,override="replaygain_track_gain",radio)
you might want to delete or comment out these lines. The autocue2:
protocol already calculates a liq_amplify
value that is recognized by AzuraCast and roughly equals a ReplayGain "track gain". If you would leave both in, you’d get a much too quiet playout.
ReplayGain vs. liq_amplify
⇧
If you have disabled AzuraCast’s built-in liq_amplify
handler (by copying 12_remove_amplify
above), you have the choice. But you must define your own adjustment (start of third input box).
Example, to use your own tagged ReplayGain Track Gain instead:
# Be sure to have ReplayGain or "liq_amplify" applied before crossing.
radio = amplify(1.,override="replaygain_track_gain",radio)
#radio = amplify(1.,override="liq_amplify",radio)
Pros & Cons:
- ReplayGain can be more exact (and prevent clipping) if pre-tagged with a tool like
loudgain
. - ReplayGain values should exist as tags in your audio files. If not, and
settings.autocue2.unify_loudness_correction := true
,autocue2
will insert an (internal)replaygain_track_gain
value. cue_file
(and thus theautocue2:
protocol) will always calculate aliq_amplify
value on the fly, so it can be used with any audio file (even when not pre-tagged)liq_amplify
has no means of clipping prevention or EBU-recommended -1 dB/LU margin. The value still resembles a ReplayGain Track Gain closely, in most cases.- Both can be used with
autocue2:
.
Save and Restart Broadcasting.
Command-line interface ⇧
usage: cue_file [-h]
[-t {-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0}]
[-s SILENCE] [-o OVERLAY] [-l LONGTAIL] [-x EXTRA] [-b] [-w]
[-f]
file
Return cue-in, cue-out, overlay and replaygain data for an audio file as JSON.
To be used with my Liquidsoap "autocue:" protocol.
positional arguments:
file File to be processed
options:
-h, --help show this help message and exit
-t {-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0}, --target {-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0}
LUFS reference target (default: -18.0)
-s SILENCE, --silence SILENCE
LU/dB below integrated track loudness for cue-in &
cue-out points (silence removal at beginning & end of
a track) (default: -42.0)
-o OVERLAY, --overlay OVERLAY
LU/dB below integrated track loudness to trigger next
track (default: -8.0)
-l LONGTAIL, --longtail LONGTAIL
More than so many seconds of calculated overlay
duration are considered a long tail, and will force a
recalculation using --extra, thus keeping long song
endings intact (default: 15.0)
-x EXTRA, --extra EXTRA
Extra LU/dB below overlay loudness to trigger next
track for songs with long tail (default: -15.0)
-b, --blankskip Skip blank (silence) within song (get rid of "hidden
tracks"). Sets the cue-out point to where the silence
begins. Don't use this with spoken or TTS-generated
text, as it will often cut the message short.
(default: False)
-w, --write Write Liquidsoap liq_* tags to file. Use with care, as
ffmpeg can't write all tags to all file types! Ensure
you have enough free space to hold a copy of the
original file. (default: False)
-f, --force Force re-calculation, even if tags exist (default:
False)
Please report any issues to https://github.com/Moonbase59/autocue/issues
Examples ⇧
Hidden track ⇧
The well-known Nirvana song Something in the Way / Endless, Nameless from their 1991 album Nevermind:
It contains the 3:48 song Something in the Way, followed by 10:03 of silence, followed by the "hidden track" Endless, Nameless.
Normal mode (no blank detection):
$ cue_file "Nirvana - Something in the Way _ Endless, Nameless.mp3"
{"duration": 1235.1, "liq_cue_duration": 1231.8, "liq_cue_in": 0.4, "liq_cue_out": 1232.2, "liq_cross_start_next": 1222.3, "liq_longtail": false, "liq_cross_duration": 9.900000000000091, "liq_loudness": "-10.47 dB", "liq_amplify": "-7.53 dB", "liq_blank_skipped": false}
With blank detection (cue-out at start of silence):
$ cue_file -b "Nirvana - Something in the Way _ Endless, Nameless.mp3"
{"duration": 1235.1, "liq_cue_duration": 227.1, "liq_cue_in": 0.4, "liq_cue_out": 227.5, "liq_cross_start_next": 224.1, "liq_longtail": false, "liq_cross_duration": 3.4000000000000057, "liq_loudness": "-10.47 dB", "liq_amplify": "-7.53 dB", "liq_blank_skipped": true}
where
- duration — the real file duration (including silence at start/end of song), in seconds
- liq_cue_duration — the actual playout duration (cue-in to cue-out), in seconds
- liq_cue_in — cue-in point, in seconds
- liq_cue_out — cue-out point, in seconds
- liq_cross_start_next — suggested start point of next song, in seconds (counting from beginning of file)
- liq_longtail — flag to show if song has a "long tail", i.e. a very long fade-out (true/false)
- liq_cross_duration — suggested crossing duration for next song, in seconds backwards from cue-out point
- liq_loudness — song’s EBU R128 loudness, in dB (=LU)
- liq_amplify — simple "ReplayGain" value, offset to desired loudness target (i.e., -18 LUFS). This is intentionally not called replaygain_track_gain, since that tag might already exist and have been calculated using more exact tools like
loudgain
. - liq_blank_skipped — flag to show that we have an early cue-out, caused by silence in the song (true/false)
Long tail handling ⇧
Bohemian Rhapsody by Queen has a rather long ending, which we don’t want to destroy by overlaying the next song too early. This is where cue_file
’s automatic "long tail" handling comes into play. Let’s see how the end of the song looks like:
Here are the values we get from cue_file
:
$ cue_file "Queen - Bohemian Rhapsody.flac"
{"duration": 355.1, "liq_cue_duration": 353.0, "liq_cue_in": 0.0, "liq_cue_out": 353.0, "liq_cross_start_next": 348.5, "liq_longtail": true, "liq_cross_duration": 4.5, "liq_loudness": "-15.50 dB", "liq_amplify": "-2.50 dB", "liq_blank_skipped": false}
We notice the liq_longtail
flag is true
, and the liq_cross_duration
is 4.5
seconds.
Let’s follow the steps cue_file
took to arrive at this result.
Cue-out point ⇧
cue_file
uses the -s
/--silence
parameter value (-42 LU default) to scan backwards from the end for something that is louder than -42 LU below the average (integrated) song loudness, using the EBU R128 momentary loudness algorithm. This is not a simple "level check"! Using the default (playout) reference loudness target of -18 LUFS
(-t
/--target
parameter), we thus arrive at a noise floor of -60 LU, which is a good silence level to use.
cue_file
has determined the cue-out point at 353.0
seconds (5:53).
Cross duration (where the next track could start and be overlaid) ⇧
Liquidsoap uses a liq_cross_duration
concept instead of an abolute "start next" point, since that could be ambiguous (start counting at the beginning of the file or at the cue-in point?). The cross duration is measured in seconds backwards from the cue-out point.
cue_file
uses the -o
/--overlay
parameter value (-8 LU default) to scan backwards from the cue-out point for something that is louder than -8 LU below the average (integrated) song loudness, thus finding a good point where the next song could start and be overlaid.
cue_file
has determined a cross duration of 16.5
seconds, starting at 336.5 seconds (5:36.5).
We can see this would destroy an important part of the song’s end.
A long tail! ⇧
Finding that the calculated cross duration of 16.5
seconds is longer than 15 seconds (the -l
/--longtail
parameter), cue_file
now recalculates the cross duration automatically, using an extra -15 LU loudness offset (-x
/--extra
parameter), and arrives at this:
cue_file
has now set liq_cross_duration
to 4.5
seconds and liq_longtail
to true
so we know this song has a "long tail" and been calculated differently.
Much better!
Avoiding too much overlap ⇧
We possibly don’t want the previous song to play "too much" into the next song, so we can set a default fade-out in our custom crossfading. This will ensure a limit in case no user-defined fade-out has been set. We use 2.5
seconds in the example below (under AzuraCast Notes, in live_aware_crossfade
):
add(normalize=false, [fade.in(duration=.1, delay=delay, new.source), fade.out(duration=2.5, delay=delay, old.source)])
Fading area, using above settings. The rest of the ending won’t be heard.
Blank (silence) detection ⇧
Note: Blank detection within a song is experimental. It will most certainly fail on spoken or TTS-generated messages (since spoken text has long pauses), and it can fail on some songs with very smooth beginnings, like Sarah McLachlan’s Fallen:
This song works fine in "normal mode", but only a 0.5 second portion (marked) of the beginning is played in "blank detection" mode when using the default settings:
$ cue_file -b "McLachlan, Sarah - Fallen (radio mix).flac"
{"duration": 229.0, "liq_cue_duration": 0.5, "liq_cue_in": 2.3, "liq_cue_out": 2.8, "liq_cross_start_next": 2.8, "liq_longtail": false, "liq_cross_duration": 0.0, "liq_loudness": "-8.97 dB", "liq_amplify": "-9.03 dB", "liq_blank_skipped": true}
You can avoid such issues in several ways:
- Don’t use the
-b
/--blankstrip
option (default). - Lower the silence level:
-s -50
/--silence -50
. - Manually assign later cue-in/cue-out points in the AzuraCast UI (user settings here overrule the automatic values).
Example result when reducing the silence level to -50 LU below average:
$ cue_file -b -s -50 "McLachlan, Sarah - Fallen (radio mix).flac"
{"duration": 229.0, "liq_cue_duration": 221.79999999999998, "liq_cue_in": 1.9, "liq_cue_out": 223.7, "liq_cross_start_next": 215.6, "liq_longtail": false, "liq_cross_duration": 8.099999999999994, "liq_loudness": "-8.97 dB", "liq_amplify": "-9.03 dB", "liq_blank_skipped": false}
Notice the new cue-in and cue-out times as well as the long cross duration with this change! Additionally, liq_blank_skipped
is false
, showing us that no silent (blank) parts have been skipped in this case.
Liquidsoap protocol ⇧
Note: The autocue2:
protocol is meant to be used with Liquidsoap 2.2.5 or newer.
The protocol is invoked by prefixing a playlist or request with autocue2:
like so:
radio = playlist(prefix="autocue2:", "/home/matthias/Musik/Playlists/Radio/Classic Rock.m3u")
Alternatively, you can set enable_autocue2_metadata()
and it will process all files Liquidsoap handles. Use either—or, but not both variants together. If running video streams, you might also want to exclude the video files from processing, by annotating liq_autocue2=false
for them, for instance as a playlist prefix. autocue2
can handle multi-gigabyte video files, but that will eat up lots of CPU (and bandwidth) and might bring your station down.
autocue2
offers the following settings (defaults shown):
settings.autocue2.path := "cue_file"
settings.autocue2.timeout := 60.
settings.autocue2.target := -18
settings.autocue2.silence := -42
settings.autocue2.overlay := -8
settings.autocue2.longtail := 15.0
settings.autocue2.overlay_longtail := -15
# The following can be overridden by the `liq_blankskip` annotation
# on a per-request or per-playlist basis
settings.autocue2.blankskip := false
# Unify can only work correctly if your files have been replaygained
# to the same LUFS target as your `settings.autocue2.target`,
# usually -23 or -18 LUFS (-18 corresponds to the now obsolete `mp3gain` value "89 dB").
settings.autocue2.unify_loudness_correction := true
Minimal working example ⇧
This minimal example enables autocue2
for all tracks, using default settings, and plays a nicely crossfaded playlist to your sound card, so you can get a first impression. Just change the playlist to one of your own!
# minimal_example_autocue2.liq
# 2024-04-09 - Moonbase59
# 2024-04-19 - Moonbase59 - rename to "minimal_example_autocue2.liq"
# Minimal example for the `autocue2` protocol.
# Uses one playlist and outputs to sound card.
%include "autocue2.liq"
enable_autocue2_metadata()
# --- Use YOUR playlist here! ---
radio = playlist("/home/matthias/Musik/Playlists/Radio/Classic Rock.m3u")
# Use calculated `liq_amplify` for loudness correction
radio = amplify(1.,override="liq_amplify",radio)
# simplest crossfade possible, using `autocue2` calculated data
# set fades to your preference
radio = crossfade(radio, fade_in=0.1, fade_out=2.5)
radio = mksafe(radio)
output(radio)
Next track and short jingle handling ⇧
With Liquidsoap 2.2.5+git@cadd05596 and newer:
If you have a long liq_cross_duration
and a jingle following that is shorter than the computed crossing duration, Liquidsoap will now try to ensure the jingle still starts at the right position, and simply cut off the "overhang" from the previous track.
autocue2
, if used, sets settings.request.prefetch := 2
to ensure there is always one more track ready. This is also new functionality. It helps "bridging the time" until autocue2
has calculated data for the next track, which might take a while.
Tags/Annotations that influence autocue2
’s behaviour ⇧
There are three possible annotations (or tags from a file) that can influence autocue2
’s behaviour. In an annotation string, these must occur to the right of the protcol, i.e. autocue2:annotate:...
to work as intended. Think of these as "switches" to enable or disable features.
liq_autocue2
(true
/false
) ⇧
Note: I had to rename my original liq_autocue
to liq_autocue2
, because Liquidsoap now also uses liq_autocue
, for another purpose. Sigh.
You can disable autocueing for selected sources, like maybe a playlist of large video files, even when autocue2
is globally enabled.
So if you’ve used
enable_autocue2_metadata()
to globally enable autocue2
, and want to exclude a playlist from processing, use:
p = playlist(prefix='annotate:liq_autocue2="false":', '/path/to/playlist.ext')
If a track has been skipped, it will be shown in the logs like this:
2024/04/01 10:47:00 [autocue2_metadata:2] Skipping autocue2 for file "/home/matthias/Musik/Other/Jingles/Short/Magenta - How sentimental.flac" because liq_autocue2=false forbids it.
Note: Using this makes only sense if you used enable_autocue2_metadata()
. When using the autocue2:
protocol in your annotations, you’d simply leave the autocue2:
part off the annotation instead.
liq_blankskip
(true
/false
) ⇧
You can override the "blankskip" behaviour (early cue-out of a song when silence is detected) on a per-request or per-playlist basis using a special liq_blankskip
annotation. This is an "ultimate override" which overrides both settings.autocue2.blankskip
and jingle_mode
.
For a playlist
, you could use its prefix
, like in
p = playlist(prefix='autocue2:annotate:liq_blankskip="false":', '/path/to/playlist.ext')
For a single
, this would look like
s = single('autocue2:annotate:liq_blankskip="false":/path/to/file.ext')
Or for a request
like
r = request.create('autocue2:annotate:liq_blankskip="false":/path/to/file.ext')
This allows for a general protocol-wide setting, but exceptions for special content, like a playlist containing spoken content that would otherwise be cut.
The logs will show if blank skipping has been used on a track:
2024/04/01 06:43:40 [autocue2.compute:3] Blank (silence) skipping active: true
In the returned metadata, in liq_blank_skipped
, you’ll also receive information if something actually has been skipped. So for the Nirvana song above, it would show:
2024/04/01 11:00:47 [autocue2.metadata:3] ("liq_blank_skipped", "true")
liq_blankskip
is the switch that controls autocue2
’s behaviour, while liq_blank_skipped
is the result of the operation.
AzuraCast: jingle_mode
("true"
) ⇧
This is a convenience feature for AzuraCast users. If you set Hide Metadata from Listeners ("Jingle Mode") to ON for a playlist in AzuraCast, it will annotate requests for this playlist with jingle_mode="true"
. Even if blank skipping for songs is globally enabled, we would not want this to happen for jingles. They might contain pauses in speech that could cut them off early.
So if autocue2
sees this annotation (or tag in a file), it will automatically disable "blankskip" for this track.
Note this setting is superceded by liq_blankskip
, the "ultimate blankskip switch". So if both are there, the setting from liq_blankskip
will "win".
Effect of settings.autocue2.unify_loudness_correction
(true
/false
) ⇧
Unify replaygain_track_gain
and liq_amplify
. If enabled, this will ensure both have the same value, with replaygain_track_gain
taking precedence if we can see it. Allows scripts to amplify on either value, without getting loudness jumps.
Note: This can only work correctly if your files have been replaygained to the same LUFS target as your settings.autocue2.target
!
ReplayGain inserted ⇧
Here is an example of an inserted replaygain_track_gain
value (taken from the calculated liq_amplify
):
2024/04/02 09:07:57 [autocue2.metadata:3] Inserted replaygain_track_gain: -8.36 dB
ReplayGain overriding liq_amplify
⇧
Here liq_amplify
has been corrected, because we have seen a different replaygain_track_gain
(coming from a pre-tagged file where loudgain was used to ensure clipping prevention):
2024/04/02 08:54:48 [autocue2.metadata:3] Replaced liq_amplify=-8.72 dB with -9.71 dB from replaygain_track_gain
AzuraCast Notes ⇧
media:
URIs will be resolved.- Works well with smart crossfades. (But these are definitely not needed, see code below!)
- Even when
settings.autocue2.blankskip := true
, hidden jingles (those with ajingle_mode="true"
annotation) will be excluded from blank detection within the track, because the chance is too high that spoken text gets cut. - User settings in the AzuraCast UI ("Edit Song") always "win" over the calculated values.
- Currently needs a patch to the AzuraCast-generated Liquidsoap code to enable all features, but you can also opt to use
enable_autocue2_metadata()
instead, not usesettings.autocue2.blankskip := true
and skip all the plugin-related things. - Currently generates lots of log data, for debugging. This will eventually change. But hey, you can see what it does!
Typical log sample (level 3; level 4 gives much more details):
2024/04/13 14:24:12 [autocue2.metadata:3] jingle_mode=, liq_blankskip=
2024/04/13 14:24:12 [autocue2:3] Now autocueing: "/home/matthias/Musik/Playlists/Radio/../../Tagged/Blackfoot/Blackfoot - Marauder/Blackfoot - Diary Of A Workingman.mp3"
2024/04/13 14:24:12 [autocue2:3] Blank (silence) skipping active: true
...
2024/04/13 14:24:16 [autocue2:3] Autocue2 result for "/home/matthias/Musik/Playlists/Radio/../../Tagged/Blackfoot/Blackfoot - Marauder/Blackfoot - Diary Of A Workingman.mp3": {"duration": 336.40000000000003, "liq_cue_duration": 333.8, "liq_cue_in": 0.7, "liq_cue_out": 334.5, "liq_cross_start_next": 323.5, "liq_longtail": false, "liq_cross_duration": 11.0, "liq_loudness": "-13.35 dB", "liq_amplify": "-4.65 dB", "liq_blank_skipped": false}
2024/04/13 14:24:16 [autocue2.metadata:3] Replaced liq_amplify=-4.65 dB with -4.66 dB from replaygain_track_gain
2024/04/13 14:24:16 [autocue2.metadata:3] Metadata added/corrected:
2024/04/13 14:24:16 [autocue2.metadata:3] ("duration", "336.4")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_amplify", "-4.66 dB")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_blank_skipped", "false")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_cross_duration", "11.")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_cross_start_next", "323.5")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_cue_duration", "333.80")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_cue_in", "0.7")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_cue_out", "334.5")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_longtail", "false")
2024/04/13 14:24:16 [autocue2.metadata:3] ("liq_loudness", "-13.35 dB")
2024/04/13 14:24:16 [autocue2.metadata:3] ("replaygain_track_gain", "-4.66 dB")
Custom crossfading ⇧
I currently1 use these crossfade settings (third input box in AzuraCast; lots of debugging info here, could be much shorter).
Be sure to check the copy-paste sections in test_autocue2.liq
, which always holds the most current code.
# Fading/crossing/segueing
def live_aware_crossfade(old, new) =
label = "live_aware_crossfade"
if to_live() then
# If going to the live show, play a simple sequence
# fade out AutoDJ, do (almost) not fade in streamer
sequence([fade.out(duration=2.5,old.source),fade.in(duration=0.1,new.source)])
else
# Otherwise, use the simple transition
log.important(label=label, "Using custom crossfade")
if (old.metadata["jingle_mode"] == "true")
and (new.metadata["jingle_mode"] == "true") then
log.important(label=label, "Jingle → Jingle transition")
end
if (old.metadata["jingle_mode"] == "true")
and (new.metadata["jingle_mode"] == "") then
log.important(label=label, "Jingle → Song transition")
end
if (old.metadata["jingle_mode"] == "")
and (new.metadata["jingle_mode"] == "true") then
log.important(label=label, "Song → Jingle transition")
end
if (old.metadata["jingle_mode"] == "")
and (new.metadata["jingle_mode"] == "") then
log.important(label=label, "Song → Song transition")
end
nd = float_of_string(default=0.1, list.assoc(default="0.1", "liq_cue_duration", new.metadata))
xd = float_of_string(default=0.1, list.assoc(default="0.1", "liq_cross_duration", old.metadata))
delay = max(0., xd - nd)
log.important(label=label, "Cross/new/delay: #{xd} / #{nd} / #{delay} s")
if (xd > nd) then
log.severe(label=label, "Cross duration #{xd} s longer than next track (#{nd} s)!")
#log.severe(label=label, "Delaying fade-out & next track fade-in by #{delay} s.")
end
# Starting with LS 2.2.5+git@cadd05596, we don’t need the delay anymore
add(normalize=false, [fade.in(initial_metadata=new.metadata, duration=.1, new.source), fade.out(initial_metadata=old.metadata, duration=2.5, old.source)])
#cross.simple(old.source, new.source, fade_in=0.1, fade_out=2.5)
#cross.smart(old, new, fade_in=0.1, fade_out=2.5, margin=8.)
end
end
radio = cross(duration=3.0, width=2.0, live_aware_crossfade, radio)
The 2.5 s fade-out helps tuning long overlap durations down, so they won’t distract the listener by overlaying songs and possibly jingles too long. If using cross.smart
, the increased margin (8 dB/LU) helps making the smart crossfades sound much better.
Footnotes
-
As of 2024-04-07, using Liquidsoap 2.2.5+git@317f191c0. Liquidsoap has a very active development, so things might change. ↩