#!/usr/bin/liquidsoap -v ################################################################################ # Another fine mess by # +-+-+-+-+-+-+-+-+-+-+-+-+-+ # |B|a|c|k|R|o|o|m|R|a|d|i|o| # +-+-+-+-+-+-+-+-+-+-+-+-+-+ # * We QSL for dollars * # (support our ribbon mic addiction) # www.backroomradio.com | studio@backroomradio.com # COBBLED TOGETHER BY ASHWORTH PAYNE # (while standing on the shoulders of giants) ################################################################################ # Log dir set("log.file.path","/tmp/BRRadio.log") ################################################################################ # You'll need to edit these. See the liquid soap docs. set("alsa.buffer_length",1746) set("alsa.periods",40) set("frame.size",4) ################################################################################ ################################################################################ set("server.telnet", true) set("server.telnet.bind_addr","0.0.0.0") set("server.telnet.port",1234) ################################################################################ # ################################################################################ # Fade-in and out, and # add a jingle when returning # from a live source def to_live( old, new) old = fade.final( old) sequence( [old, new]) end def from_live( jingle, old, new) source.skip( new) s = add( [ jingle, old]) sequence( [s, new]) end ################################################################################ # ################################################################################ # SQLite Authentication. Not recommended. Very basic test with no locking. # If you are using airtime, you probably dont want this. def auth_sql(user,password) = ret = get_process_lines("/home/BRR/sq #{user} #{password}") ret = list.hd(ret) if ret == "true" then true else false end end ################################################################################ # Lets build a harbor and require auth... # THIS IS HOW AIRTIME CONNECTS TO THE HELPER SCRIPT. # SETUP AIRTIME TO USE THIS. # AND DON'T FORGET THAT THIS IS WHAT AIRTIME CONNECTS TO :) # Use a different auth scheme.. really. set("harbor.bind_addr","0.0.0.0") dj_harbor = input.harbor("live",auth=auth_sql,port=6846) ################################################################################ # ################################################################################ # Randomizers and timers # the first is a directory of music thats randomly played-from (input) # jingles is full of station jinlges. they're played during source-fades and every # 20 minutes when in fallback. input = playlist(mode='randomize',reload=1,reload_mode="rounds",conservative=true,"/mnt/folder/imported/") jingles = playlist(mode='randomize',reload=1,reload_mode="rounds",conservative=true,"/mnt/jingles/folder/") timed_promotions = delay(1200.,jingles) main_source = fallback([timed_promotions,input]) ################################################################################ # This is from a usb stereo interface. You could use line-in of a soundcard. # In your shell, type: # aplay -l # to get a list of audio devices that alsa is aware of. live = input.alsa(device="hw:1,0") ################################################################################ # If silence from mixer, fallback to the dj_harbor. This should be where airtime # is connected.... basicly, point airtime to the port listed above in dj_harbor. # when the console is silent for 10 seconds, it'll automatically fade to Airtime. # IF IF IF IF airtime has somehow failed, or isn't outputting anything, it will # fallback to random play (threshold=-45. may need to be changed. I forget what # the levels are for airtime when there is no content) from_live_j = from_live( jingles) radio1 = fallback( track_sensitive = false, transitions=[to_live, from_live_j], [strip_blank( max_blank=10., threshold=-65., live),strip_blank( max_blank=10., threshold=-45., dj_harbor), main_source]) ################################################################################ # ################################################################################ # Allow meta updates on telnet server and scrobble all meta # the first line allows you to telnet to the server and update the metadata. # the secondline sends all metadata to last.fm.. handy as hell if you want to pull # last.fm data into a website.... see www.backroomradio.com for an example. radio1 = server.insert_metadata(id="AA",radio1) radio1 = on_metadata(lastfm.submit(user="USERNAME",password="PASSWORDS"), radio1) ################################################################################ # Recieve metadata updates via http. Allows live DJ's who use turntables/decks # or *alternative* sources to comply with station rules... # Which suck. But royalties umbrella accounts require rules. # I posted some sample code on the savonet-users mailing list for a windows app # that will allow you to manually update meta over the network. Its written # in autohotkey and is dead simple to make. x = insert_metadata(radio1) # Get the function insert = fst(x) # Redefine s as the new source s = snd(x) # The handler def set_meta(~protocol,~data,~headers,uri) = # Split uri of the form request?foo=bar&... # into (request,[("foo","bar"),..]) x = url.split(uri) # Filter out unusual metadata meta = metadata.export(snd(x)) # Grab the returned message ret = if meta != [] then insert(meta) # "#{meta)" # else # "No metadata to add!" end # Return response http_response( protocol=protocol, code=200, headers=[("Content-Type","text/html")], # Output the meta. Maybe log? # data="#{ret}" ) end # Register handler on port 8080 harbor.http.register(port=8080,method="GET","/setmeta",set_meta) ################################################################################ # Audio processing...see # https://github.com/JamesHarrison/conduit/blob/master/conduit.liq # Do not enable unless you have: # * Plenty of processing power # * A clue about audio processing.. because these are NOT ideal and need work # * LADSPA support compiled into ls. # Gate the input for starters, stops noise from clobbering things in silent periods. #source = ladspa.gate(s, threshold = -40.0, attack = 0.15, hold = 1.0, decay = 200.0, range = -25.0) # Multiband compression - split up, compress, recombine, sky does it all, but is not very configurable. 3-band. #source = sky(s) # Now overall compression, faster attack, harder ratio, mostly RMS based. #source = compress(source, attack = 5.0, gain = 0.0, knee = 10.0, ratio = 5.0, release = 100.0, threshold = -18.0, rms_window = 0.7) # Normalize, with a higher threshold to stop suck-up. #source = normalize(source, target = -3.0, threshold = -15.0) # Limiter, this one's a scaling one which limits nicely and without artefacting mostly #source = ladspa.tap_limiter(source, limit_level = -0.5) # And a final limiter - this should never really get hit, but stops anything nasty hitting the DAC. Highly peak-focused. #source = limit(source, threshold = -0.2, attack = 2.0, release = 25.0, rms_window = 0.02) # Stick a meter on this. This is queryable via telnet. Force the source name. radio2 = server.rms(s, id="input_source") ################################################################################ # LS FLows. I get a little traffic from this. radio2 = register_flow( radio="BackRoom Radio", website="http://www.backroomradio.com/", description="Hillybilly music from Mount Holly NC", genre="Folk, Bluegrass, Newgrass, Alternative Country", user="USERNAME", password="PASSWORD", streams=[("mp3/128k","http://remote.stream.1.fm:6846/listen.m3u?sid=1"),("aacplus/32k","http://remote.stream.2.fm:8217/live.m3u")], radio2) ################################################################################ #Playout to shoutcast output.shoutcast(%mp3,host="remote.stream.1.fm",port=6846,user="USER", password="CHANGEME",name="BackRoom Radio",url="www.backroomradio.com", public=true,genre="Bluegrass",icy_metadata="true",fallible=true,radio2) #playout to icecast output.icecast(%aacplus(channels=2, samplerate=44100, bitrate=32),host="remote.stream.2.fm", port=8217,password="CHANGEME",mount="live",name="BackRoom Radio Mobile Service", icy_metadata="true",description="Bluegrass, folk, newgrass, and hillbilly music from Mount Holly NC, USA", url="www.backroomradio.com",public=true,genre="Bluegrass, Newgrass, Folk, Hillbilly",fallible=true,radio2) ################################################################################ # Playout to Alsa on soundcard # If it sounds choppy, refer to top of script. # This WILL BE DELAYED. #output.alsa(fallible=true,device="hw:1,0",radio2) ################################################################################