├── Dockerfile ├── Procfile ├── README.md ├── asoundrc ├── darkice.cfg ├── icecast.xml ├── radio.sc └── startup.scd /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y software-properties-common && \ 7 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FABAEF95 && \ 8 | add-apt-repository -y ppa:supercollider/ppa && \ 9 | add-apt-repository -y multiverse && \ 10 | apt-get update && \ 11 | apt-get install -y icecast2 darkice libasound2 libasound2-plugins alsa-utils alsa-oss jack-tools supercollider xvfb curl && \ 12 | apt-get clean 13 | 14 | RUN curl -o forego.tgz https://bin.equinox.io/c/ekMN3bCZFUn/forego-stable-linux-amd64.tgz && \ 15 | tar xvf forego.tgz && \ 16 | rm forego.tgz && \ 17 | mv forego /usr/bin/forego && \ 18 | chmod +x /usr/bin/forego 19 | 20 | COPY asoundrc /root/.asoundrc 21 | 22 | COPY icecast.xml /etc/icecast2/icecast.xml 23 | COPY darkice.cfg /etc/darkice.cfg 24 | 25 | COPY startup.scd /root/.config/SuperCollider/startup.scd 26 | COPY radio.sc /radio.sc 27 | 28 | COPY Procfile Procfile 29 | 30 | EXPOSE 8000 31 | RUN mv /etc/security/limits.d/audio.conf.disabled /etc/security/limits.d/audio.conf && \ 32 | usermod -a -G audio root 33 | 34 | CMD ["forego", "start"] 35 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | icecast2: icecast2 -c /etc/icecast2/icecast.xml 2 | jackd: jackd -r -d dummy -r 44100 3 | darkice: darkice -c /etc/darkice.cfg 4 | sclang: xvfb-run -a sclang /radio.sc 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An example internet radio server using SuperCollider. 2 | 3 | You could use this as a starting point for a procedural radio station. 4 | 5 | * Supercollider for audio generation 6 | * JACK with 'dummy' driver to work on cloud hardware 7 | * Darkice to connect with icecast 8 | * Icecast for mp3 streaming 9 | 10 | It runs headless in Docker so your composition can be running on a server in the cloud somewhere. 11 | 12 | To use, install Docker then: 13 | 14 | docker build -t scradio . 15 | docker run -p 8000:8000 scradio 16 | 17 | Then the stream will be accessible at http://localhost:8000/stream.mp3 18 | 19 | I've only tested this on Linux. 20 | -------------------------------------------------------------------------------- /asoundrc: -------------------------------------------------------------------------------- 1 | pcm.rawjack { 2 | type jack 3 | playback_ports { 4 | 0 darkice:left 5 | 1 darkice:right 6 | } 7 | } 8 | pcm.jack { 9 | type plug 10 | slave { pcm "rawjack" } 11 | hint { 12 | description "JACK Audio Connection Kit" 13 | } 14 | } 15 | pcm.!default 16 | { 17 | type plug 18 | slave 19 | { 20 | pcm "rawjack" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /darkice.cfg: -------------------------------------------------------------------------------- 1 | [general] 2 | duration = 0 3 | bufferSecs = 1 4 | reconnect = yes 5 | realtime = no 6 | 7 | [input] 8 | device = jack 9 | jackClientName = darkice 10 | sampleRate = 44100 11 | bitsPerSample = 16 12 | channel = 2 13 | 14 | [icecast2-0] 15 | bitrateMode = vbr 16 | quality = 1.0 17 | format = mp3 18 | bitrate = 256 19 | server = localhost 20 | port = 8000 21 | password = password 22 | mountPoint = stream.mp3 23 | name = stream 24 | -------------------------------------------------------------------------------- /icecast.xml: -------------------------------------------------------------------------------- 1 | 2 | The Astral Plane 3 | admin@example.com 4 | 5 | 6 | 500 7 | 2 8 | 5 9 | 524288 10 | 30 11 | 15 12 | 10 13 | 1 14 | 65535 15 | 16 | 17 | 18 | password 19 | password 20 | 21 | admin 22 | password 23 | 24 | 25 | localhost 26 | 27 | 28 | 8000 29 | 30 | 31 | 0 32 | scradio 33 | 34 | 35 | /usr/share/icecast2 36 | 37 | 38 | 39 | - 40 | - 41 | 3 42 | 43 | 44 | 45 | 0 46 | 47 | icecast2 48 | icecast 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /radio.sc: -------------------------------------------------------------------------------- 1 | Server.default.waitForBoot({ 2 | 3 | b = Buffer.alloc(s,44100 * 2, 2); 4 | 5 | // play a demo sound 6 | 7 | SynthDef("help-PingPong",{ arg out=0,bufnum=0,feedback=0.5,delayTime=0.2; 8 | var left, right; 9 | left = Decay2.ar(Impulse.ar(0.7, 0.25), 0.01, 0.25, 10 | SinOsc.ar(SinOsc.kr(3.7,0,200,500))); 11 | right = Decay2.ar(Impulse.ar(0.5, 0.25), 0.01, 0.25, 12 | Resonz.ar(PinkNoise.ar(4), SinOsc.kr(2.7,0,1000,2500), 0.2)); 13 | 14 | Out.ar(0, 15 | PingPong.ar(bufnum, [left,right], delayTime, feedback, 1) 16 | ) 17 | }).play(s,[\out, 0, \bufnum, b.bufnum,\feedback,0.5,\delayTime,0.1]); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /startup.scd: -------------------------------------------------------------------------------- 1 | "SC_JACK_DEFAULT_OUTPUTS".setenv( 2 | "darkice:left," 3 | "darkice:right," 4 | ); 5 | 6 | ServerQuit.add({ 7 | 'FAIL: scsynth quit'.postln; 8 | 1.exit(); 9 | }, Server.default); 10 | --------------------------------------------------------------------------------