# Liquidsoap

## Audio Stream Generation

### users_radiopi.liq

    #!/usr/bin/liquidsoap

    # === Settings ===

    set("log.file.path","/var/log/liquidsoap/pi.log")
    set("init.daemon",true)
    set("init.daemon.pidfile.path","/var/run/liquidsoap/pi.pid")
    set("server.telnet",true)
    set("harbor.bind_addr","0.0.0.0")
    set("harbor.port",8000)
    set("harbor.password","xxxxxx")
    set("log.level",4)
    set("scheduler.event_queues",4)
    set("scheduler.log",false)

    scripts = "/path/to/scripts/"

    pass = "xxxxxx"
    ice_host = "host"

    descr = "Radio Piston"
    url = "http://radiopi.org"

    # === Live relays ===

    def live_start() =
      log("got live source, starting relays..")
      ignore(execute("stream_relay.start"))
      ignore(execute("archives.start"))
    end

    def live_stop() =
      log("live source has gone, stoping relays..")
      ignore(execute("stream_relay.stop"))
      ignore(execute("archives.stop"))
    end

    # Live source through harbor
    live = input.harbor(id="live",on_connect=live_start,on_disconnect=live_stop,"live.ogg")
    live_safe = mksafe(live)

    # Live relay to secondary encoder
    output.icecast.vorbis(id="stream_relay",start=false,restart=true,host="1.2.3.4",port=8005,password="xxxx",mount="live.ogg",live_safe)

    # File source for archiving
    title = '$(if $(title),"$(title)","Emission inconnue")$(if $(artist), " par  $(artist)") - %m-%d-%Y, %H:%M:%S'
    output.file.vorbis(id="archives",start=false,reopen_on_metadata=true,"/path/to/archives/" ^ title ^ ".ogg",live_safe)

    # === Main script ===

    # Specialize the output functions by partial application
    output.icecast     = output.icecast.mp3(restart=true,description=descr, url=url)
    out = output.icecast(host=ice_host,port=8080,password=pass)

    # A file for playing during failures
    interlude =
      single("/path/to/failure.mp3")

    def fallback.transition(previous,next)
      add([fade.in(next),fade.final(duration=5.,previous)])
    end

    # === Channels ===

    # Lastfm submission
    def lastfm (m) =
    # Only submit songs of type "chansons" (got type using annotate..)
      if (m["type"] == "chansons") then
        canal = m["canal"]
        user = "radiopi-" ^ canal
        lastfm.submit(user=user,password="xxxxxx",m)
      end
    end

    # To create a channel from a basic source, add:
    # - a new-track notification for radiopilote
    # - metadata rewriting
    # - the live shows
    # - the failsafe 'interlude' source to channels
    # - blank detection
    def mklive(source)
      # Add lastfm submission
      source = on_metadata(lastfm,source)

      # Feedback the system
      source = on_metadata(fun (meta) ->
                        system(scripts ^ "radiopilote-feedback "
                               ^quote(meta["canal"])^" "
                               ^quote(meta["file_id"])), source)

      # Rewrite metadata to add channel name and mode..
      # Got data from annotate..
      rewrite_metadata(
       [("artist",'$(if $(display_artist),"$(display_artist)","$(artist)")'),
        ("comment",""),
        ("title", '$(if $(display_title),"$(display_title)","$(title)")'),
        ("album", '$(if $(display_album),"$(display_album)","$(album)")')],

       # Default fallback
       fallback(track_sensitive=false,[
         # Strip blank to avoid live streaming only blank..
         strip_blank(live, length=10., threshold=-50.),
            source, interlude ]) )
    end

    # === Basic sources ===

    # Create a radiopilote-driven source
    def channel_radiopilote(~skip=true,name)
      log("Creating canal #{name}")

      # Request function
      def request () =
        log("Request for #{name}")
        request.create(audio=true,
            get_process_output(scripts ^ "radiopilote-getnext " ^ quote(name)))
      end

      # Basic source
      source =   request.dynamic(
              id="dyn_"^name,request)

      # Add smart crossfading
      source = smart_crossfade(source)

      # Only skip some channels
      if skip then
        skip_blank(source, length=10., threshold=-40.)
      else
        source
      end
    end

    # Channels encoded here
    reggae = channel_radiopilote("reggae")
    jazz = channel_radiopilote("jazz")
    discoqueen = channel_radiopilote("discoqueen")
    # Avoid skiping blank with classic music !!
    classique = channel_radiopilote(skip=false,"classique")
    That70Sound = channel_radiopilote("That70Sound")

    # Create a channel using mklive(), encode and output it to icecast.
    def mkoutput(mount,source,name,genre)
      out(mount=mount,name=name,genre=genre,
         mklive(source))
    end

    # === Outputs ===

    # These channels are encoded on this machine
    reggae  = mkoutput("reggae", reggae, "RadioPi - Canal Reggae","reggae")
    jazz    = mkoutput("jazz", jazz, "RadioPi - Canal Jazz","jazz")
    discoqueen  = mkoutput("discoqueen", discoqueen, "RadioPi - Canal DiscoQueen","discoqueen")
    classique = mkoutput("classique", classique, "RadioPi - Canal Classique","classique")
    That70Sound = mkoutput("That70Sound", That70Sound,
                           "RadioPi - Canal That70Sound","That70Sound")

    # Channels from the other encoder:
    def get_channel(mount)
     input.http(autostart=true,id="input_"^mount,"http://host:8080/"^mount)
    end
    metal = get_channel("metal")
    electro = get_channel("electro")
    hiphop = get_channel("hiphop")

    # Finally the web channel, and its mp3 version
    web =
      out(mount="radioPi",name="RadioPi - www.radiopi.org",
          fallback([ switch(track_sensitive=false,
                            [ ( { 6h-12h }, reggae  ),
                              ( { 12h-14h }, discoqueen ),
                              ( { 14h-16h }, electro ),
                              ( { 16h-19h }, reggae ),
                              ( { 19h-20h }, That70Sound ),
                              ( { 20h-22h }, metal ),
                              ( { 22h-0h }, reggae ),
                              ( {  0h-6h  }, jazz  ),
                             ]),
                     interlude ]))

Download