blog.rastageeks.org
Home page > Liquidsoap > DJ mix using liquidsoap

DJ mix using liquidsoap

Monday 8 June 2009, by Toots

Recently, I wanted to generate a single audio file containing the mix of several others, in order to publish it as a podcast.

The purpose of this is, based on an playlist of songs, to generate a single audio file containing an enhanced sequence of these songs. We would also like to normalize the volumes between the songs and have nice crossfaded transitions.

As you can imagine, I used my tool of choice for that purpose: liquidsoap !

In the following is presented the script that performs that. It takes a playlist, located at ./playlist.m3u, and introductory jingle, located at ./intro.mp3 and generates mix.mp3, mix.ogg and mix.aac.

The script is commented. There were minor issues with the playlist parsing not preserving the ordering, so it should be run with a recent SVN code.

Also, the script uses a perl handler to extract replay gain information. This script is:

#!/usr/bin/perl -w
# A perl script that get the replay gain
# from either a vorbis or an mp3 file
# and returns it.

use strict ;

my $file = $ARGV[0] || die ;

if ($file =~ /\.mp3$/i) {

 my $out = `nice -n 20 mp3gain "$file" 2> /dev/null` ;
 $out =~ /Recommended "Track" dB change: (.*)$/m || die ;
 print "$1 dB\n" ;

} elsif ($file =~ /\.ogg$/i) {

 system("nice -n 20 vorbisgain -f \"$file\" \
         2>/dev/null >/dev/null") ;
 my $info = `ogginfo "$file"` ;
 $info =~ /REPLAYGAIN_TRACK_GAIN=(.*) dB/ || die ;
 print "$1 dB\n" ;

}

Eventually, the final script is:

# Liquidsoap script that generates the mix of a playlist
# in a single audio file, with normalization using
# replay gain, and smart crossfading.
# Author: Romain Beauxis <toots@rastageeks.org>
# License: DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# License URL: http://sam.zoy.org/wtfpl/COPYING


########### Settings ###########
# In this section, we declare
# the settings for this script.

# Log to stdout
set("log.file",false)
set("log.stdout",true)
# Uncomment to allow verbose logging..
#set("log.level",5)
# Disable real-time processing, to process with the maximun speed
set("root.sync",false)

########### Replay Gain Backend ###########
# In this section, we register the replay
# gain backend, to add replay gain information
# to each resolved file.

# Function to add replay_gain information
# to the metadata
def replaygain_metadata(~format,file)
 x = get_process_lines("./replaygain.pl #{quote(file)}")
 if list.hd(x) != "" then
   [("replay_gain",list.hd(x))]
 else
   []
 end
end

# We register the above function as a new metadata resolver.
add_metadata_resolver("replay_gain",replaygain_metadata)

########### Source Declaration ###########
# In this section, we declare the main source
# that we want to output.

# An introductory single
intro = single("./intro.mp3")

# The main playlist
playlist = playlist.once("./playlist.m3u")

# We normalize audio files, according to the
# replay_gain information (see above).
final = amplify(1.,override="replay_gain",sequence([intro,playlist]))

# We use the smart crossfade, to crossfade between tracks,
# paying attention to the relative volumes.
# It is of course advised to place this operator *after*
# the normalization !
final = smart_crossfade(final)

########### Shutdown fallback ###########
# In this section, we wrap the main source
# in order to shutdown liquidsoap when
# it has finished to play.

# We define a special transition, that
# triggers the shutdown..
def end_trans(a,b) =
shutdown ()
b
end

# The default transition
def_trans = fun (a,b) -> b

# The fallback source: play the whole mix, and
# then fallback to a blank. The end_trans transition
# makes sure that liquidsoap stops when falling back to the blank
# source, i.e. at the end of the mixed playlist.
final = fallback(transitions=[def_trans,end_trans],
                track_sensitive=false, [final,blank()])

########### Outputs ###########
# In this section, we define the output
# that we want.

# Output in mp3 format
output.file.mp3("mix.mp3",final)

# Output in ogg/vorbis format
output.file.vorbis("mix.ogg",final)

# Output in AAC+ format in 64kbps
# (needs aacplusenc in the path)
output.pipe.external(process=fun (_) -> "aacplusenc - mix.aac 64",
                    final)

Reply to this article

SPIP | template | | Site Map | Follow-up of the site's activity RSS 2.0