├── .gitignore ├── Vagrantfile ├── DockerHostVagrantfile ├── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker' 2 | DOCKER_HOST_NAME = "dockerhost" 3 | DOCKER_HOST_VAGRANTFILE = "./DockerHostVagrantfile" 4 | 5 | Vagrant.configure("2") do |config| 6 | 7 | config.vm.define "sonicpi" do |a| 8 | a.vm.provider "docker" do |d| 9 | #d.ports = ["4557:4557/udp", "5900:5900"] 10 | d.build_dir = "." 11 | d.build_args = ["-t=sonic-pi"] 12 | d.remains_running = true 13 | # Port forwarding tcp was not working out 14 | #d.create_args = ["-p", "4557:4557/tcp", "-p", "5900:5900", "--privileged", "-v", "/dev/snd:/dev/snd:rw"] 15 | d.create_args = ["-p", "5900:5900", "--privileged", "-v", "/dev/snd:/dev/snd:rw"] 16 | #d.volumes = ["/Users/xavierriley/Projects/sonic-pi:/usr/local/src"] 17 | d.vagrant_machine = "#{DOCKER_HOST_NAME}" 18 | d.vagrant_vagrantfile = "#{DOCKER_HOST_VAGRANTFILE}" 19 | d.has_ssh = true 20 | end 21 | a.ssh.username = 'developer' 22 | a.ssh.password = 'sonicpi' 23 | a.ssh.port = 22 24 | a.ssh.forward_x11 = true 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /DockerHostVagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | 3 | config.vm.provision "docker" 4 | 5 | config.vm.provision "shell", inline: <<-SHELL 6 | set -e # Stop on any error 7 | 8 | sudo sed -i '/tty/!s/mesg n/tty -s \\&\\& mesg n/' /root/.profile 9 | 10 | # Taken from https://github.com/GeoffreyPlitt/vagrant-audio/blob/master/Vagrantfile 11 | # --------------- SETTINGS ---------------- 12 | # Other settings 13 | export DEBIAN_FRONTEND=noninteractive 14 | sudo apt-get update 15 | # ---- OSS AUDIO 16 | sudo usermod -a -G audio vagrant 17 | sudo apt-get install -y linux-sound-base alsa-base alsa-utils linux-headers-3.13.0-53 debconf-utils 18 | if [[ ! -L /lib/modules/$(uname -r)/source && ! -d /lib/modules/$(uname -r)/source ]] 19 | then 20 | sudo ln -s /usr/src/linux-headers-$(uname -r)/ /lib/modules/$(uname -r)/source 21 | fi 22 | sudo debconf-set-selections <<< "linux-sound-base linux-sound-base/sound_system select alsa" 23 | echo "READY." 24 | # have to reboot for drivers to kick in, but only the first time of course 25 | if [ ! -f ~/runonce ] 26 | then 27 | touch ~/runonce 28 | sudo reboot 29 | fi 30 | 31 | # The following line terminates all ssh connections. Therefore 32 | # Vagrant will be forced to reconnect. 33 | # That's a workaround to have the docker command in the PATH 34 | ps aux | grep 'sshd:' | awk '{print $2}' | xargs kill 35 | SHELL 36 | 37 | config.vm.define "dockerhost" 38 | config.vm.box = "ubuntu/trusty64" 39 | config.vm.network "forwarded_port", 40 | guest: 4557, host: 4557, protocol: "tcp" 41 | config.ssh.forward_x11 = true # useful since some audio testing programs use x11 42 | 43 | config.vm.provider :virtualbox do |vb| 44 | vb.name = "dockerhost" 45 | vb.memory = 2048 46 | vb.cpus = 4 47 | vb.customize ["modifyvm", :id, '--audio', 'coreaudio', '--audiocontroller', 'ac97'] # choices: hda sb16 ac97 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.1 2 | 3 | RUN echo "deb http://http.debian.net/debian jessie main" >> /etc/apt/sources.list 4 | 5 | RUN apt-get update && \ 6 | DEBIAN_FRONTEND=noninteractive apt-get -y install \ 7 | git-core \ 8 | sudo \ 9 | fftw3-dev \ 10 | supercollider-server \ 11 | supercollider-dev \ 12 | libqt5scintilla2-dev \ 13 | libqt5scintilla2-l10n \ 14 | qt5-qmake \ 15 | qtbase5-dev \ 16 | qttools5-dev-tools \ 17 | cmake \ 18 | pkg-config \ 19 | libffi-dev \ 20 | dbus-x11 \ 21 | vim \ 22 | libdbus-glib-1-2 \ 23 | libgtk2.0-0 \ 24 | libxrender1 \ 25 | libxt6 \ 26 | xz-utils \ 27 | xauth \ 28 | openssh-server pwgen \ 29 | --no-install-recommends && \ 30 | rm -rf /var/lib/apt/lists/* && \ 31 | mkdir -p /var/run/sshd && \ 32 | sed -i "s/UsePrivilegeSeparation.*/UsePrivilegeSeparation no/g" /etc/ssh/sshd_config && \ 33 | sed -i "s/PermitRootLogin without-password/PermitRootLogin yes/g" /etc/ssh/sshd_config && \ 34 | echo "X11Forwarding yes" >> /etc/ssh/sshd_config && \ 35 | echo "X11UseLocalhost no" >> /etc/ssh/sshd_config 36 | 37 | ENV LANG en_GB.UTF-8 38 | 39 | # RUN mv /etc/security/limits.d/audio.conf.disabled /etc/security/limits.d/audio.conf 40 | # TODO figure out how to get jackd2 working 41 | # RUN dpkg-reconfigure -p high jackd2 42 | 43 | # Replace 1000 with your user / group id 44 | RUN export uid=1000 gid=1000 && \ 45 | mkdir -p /home/developer && \ 46 | echo "developer:x:${uid}:${gid}:Developer,,,:/home/developer:/bin/bash" >> /etc/passwd && \ 47 | echo "developer:x:${uid}:" >> /etc/group && \ 48 | echo "developer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/developer && \ 49 | chmod 0440 /etc/sudoers.d/developer && \ 50 | chown ${uid}:${gid} -R /home/developer 51 | 52 | RUN echo 'developer:sonicpi' | chpasswd 53 | 54 | RUN sudo usermod -aG audio developer 55 | 56 | # Build the SuperCollider Extra UGens 57 | RUN cd /usr/src && git clone git://github.com/supercollider/sc3-plugins.git && \ 58 | cd sc3-plugins && git submodule init && git submodule update && \ 59 | mkdir build && cd build && \ 60 | cmake -DSC_PATH=/usr/include/SuperCollider -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. && \ 61 | make && make install && ldconfig 62 | 63 | # app is a significant folder for the Ruby baseimage 64 | RUN cd /usr/src && git clone https://github.com/samaaron/sonic-pi.git app 65 | RUN chown -R developer /usr/src/app 66 | 67 | USER developer 68 | ENV HOME /home/developer 69 | ENV QT_SELECT qt5 70 | 71 | # RUN mkdir ~/.vnc 72 | # # Setup a password 73 | # RUN x11vnc -storepasswd 1234 ~/.vnc/passwd 74 | # RUN x11vnc -nopw -create -forever & 75 | 76 | WORKDIR /usr/src/app 77 | 78 | RUN sed -i -e 's/^.*Qt4Qt5 -lqscintilla2$/ LIBS += -L\/usr\/lib -lqt5scintilla2/' /usr/src/app/app/gui/qt/SonicPi.pro 79 | RUN sed -i -e 's/^.*+= -lqscintilla2$//' /usr/src/app/app/gui/qt/SonicPi.pro 80 | RUN sed -i -e 's/^ INCLUDEPATH.*/ INCLUDEPATH += -L\/usr\/lib/' /usr/src/app/app/gui/qt/SonicPi.pro 81 | RUN sed -i -e 's/^ DEPENDPATH.*/ DEPENDPATH += -L\/usr\/lib/' /usr/src/app/app/gui/qt/SonicPi.pro 82 | 83 | # RUN sed -i -e 's/localhost/127.0.0.1/' /usr/src/app/app/server/core.rb 84 | # RUN sed -i -e 's/localhost/127.0.0.1/' /usr/src/app/app/server/bin/sonic-pi-server.rb 85 | 86 | RUN ./app/server/bin/compile-extensions.rb 87 | RUN ./app/gui/qt/rp-build-app 88 | 89 | RUN echo "/usr/bin/jackd -m -dalsa -r44100 -p4096 -n3 -s -D -Chw:I82801AAICH -Phw:I82801AAICH" > ~/.jackdrc && chmod 755 ~/.jackdrc 90 | 91 | RUN sudo gem install sonic-pi-cli 92 | 93 | RUN echo "eval \`dbus-launch --auto-syntax 2>&1\`" > ~/.bash_profile 94 | 95 | EXPOSE 22 96 | 97 | # CMD ["/bin/bash", "-l", "-c", "/usr/src/app/app/server/bin/sonic-pi-server.rb"] 98 | # TCP not working for some reason 99 | # CMD ["/bin/bash", "-l", "-c", "/usr/src/app/app/server/bin/sonic-pi-server.rb -t"] 100 | 101 | # At some point we might be able to get X11 forwarding working 102 | # to run the QT app inside Docker as well 103 | #CMD ["/bin/bash", "-i", "-l", "-c", "/usr/src/app/app/gui/qt/rp-app-bin"] 104 | 105 | # Must be run as root for sshd to work 106 | RUN sudo /usr/bin/ssh-keygen -A 107 | CMD sudo /usr/sbin/sshd -D 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Running Sonic Pi in Docker 2 | 3 | Probably only of interest to Sonic Pi developers or anyone looking to 4 | Dockerize similar audio applications that used `jackd`. 5 | 6 | ## Getting Started (OS X) 7 | 8 | This uses Vagrant and VirtualBox so you'll need plenty of spare RAM and disk space. 9 | 10 | ``` 11 | # (cd into this dir) 12 | 13 | brew tap caskroom/cask 14 | brew cask install virtualbox 15 | brew cask install vagrant 16 | ``` 17 | 18 | Alternatively install vagrant from [https://www.vagrantup.com/downloads.html](https://www.vagrantup.com/downloads.html) 19 | 20 | Then start a new terminal and run: 21 | 22 | ``` 23 | vagrant plugin install vagrant-docker-exec 24 | vagrant up 25 | ``` 26 | 27 | The first time this will take something like 30 minutes as its 28 | building a docker host with 40Gb of disk and 2Gb of RAM, and then 29 | proceeding to build the docker container for Sonic Pi 30 | 31 | To run the GUI you have to ssh into the running Docker instance with X11 forwarding like so: 32 | 33 | ``` 34 | vagrant ssh -- -Y 35 | ``` 36 | 37 | It will ask you for the password which is `sonicpi` 38 | 39 | Once you're logged into the container, run the following to start the GUI: 40 | 41 | ``` 42 | developer@97fc279e468b:~$ /usr/src/app/app/gui/qt/rp-app-bin 43 | ``` 44 | 45 | To quit just ctrl+c the GUI process and log out of the SSH session with ctrl+d 46 | 47 | Then to stop the Docker container just run 48 | 49 | ``` 50 | vagrant halt 51 | ``` 52 | 53 | to rebuild from the Docker file (don't worry about the error) 54 | 55 | ``` 56 | vagrant reload; vagrant up 57 | ``` 58 | 59 | and to shut down the Docker host image (the big Ubuntu VM that's actually running docker) 60 | 61 | ``` 62 | VAGRANT_VAGRANTFILE=DockerHostVagrantfile vagrant halt 63 | ``` 64 | 65 | ## Rationale 66 | 67 | With Docker we have a way to run sandboxed 68 | Sonic Pi code on a server for recording Gists in a sandbox and the like. It would also help 69 | in some development situations, mainly to test against a similar distro to Raspbian 70 | but on a faster machine than the RPi. 71 | 72 | ## Goals 73 | 74 | - [x] Make beeps using sonic\_pi gem 75 | - [x] Run sshd server 76 | - [x] Run the GUI via X11 and ssh forwarding 77 | - [ ] Remove the `--privileged` flag so code is truly sandboxed 78 | 79 | ## Related blog posts 80 | 81 | I had to do a lot of research just to figure out how to get Linux audio 82 | to work in VirtualBox in the way I wanted. In that sense I think this repo 83 | has made some progress in that area and I can see useful approaches in here for 84 | other libraries that used `jackd` like SuperCollider or Overtone. With that in mind, 85 | heres a "reading list" of useful resources in Dockerizing audio applications in general. 86 | 87 | - [Running GUI apps with Docker](http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/) 88 | - [Docker containers on the Desktop](https://blog.jessfraz.com/post/docker-containers-on-the-desktop/) 89 | - [Docker Desktop](https://github.com/rogaha/docker-desktop) 90 | - [Running an SSH service on Docker](https://docs.docker.com/examples/running_ssh_service/) 91 | - [SuperCollider and jackd the easy way](http://carlocapocasa.com/supercollider-jack-the-easy-way/) 92 | - [Top 5 wrong ways to fix your (Linux) audio](http://voices.canonical.com/david.henningsson/2012/07/13/top-five-wrong-ways-to-fix-your-audio/) 93 | 94 | ## Headless Sonic Pi 95 | 96 | ``` 97 | vagrant docker-exec -- sonic_pi "play 70" 98 | ``` 99 | 100 | For something slightly more fun try 101 | 102 | ``` 103 | vagrant docker-exec -- sonic_pi "$(wget -O - https://gist.githubusercontent.com/xavriley/ab0e7ad9b956c18af9f9/raw/68157657a9324e37fa8868a6137af6ace6952e30/wxg_piece.rb)" 104 | # Listen to the output for a while 105 | vagrant docker-exec -- sonic_pi "stop" 106 | ``` 107 | 108 | NB with that last command it's actually the OSX host that's downloading the gist, 109 | not the Docker container which is just being fed a string. 110 | 111 | ## `boot2docker` won't work for this 112 | 113 | OSX and windows users can't use Docker directly. They need to run a virtual copy of 114 | linux \(a 'host' in docker terms\) which then allows you to run the Docker containers 115 | inside that. The popular solution for this is called `boot2docker` and it's the one 116 | all the tutorials will point you to if you have a Mac or Windows machine. 117 | 118 | The problem is that `boot2docker` runs a version of Linux that doesn't have any sound 119 | drivers installed \(It's a custom build of Tiny Core Linux for anyone who's curious...\) 120 | 121 | > "No problem, I'll just `boot2docker ssh` and install the sound drivers using the package manager!" 122 | 123 | Erm, yeah about that... This version of Tiny Core Linux renames the 124 | kernel when building to `boot2docker-4.0.4` or similar. The package 125 | manager in Tiny Core Linux happens to use the kernel name to figure out 126 | which packages to install - whether they need 32 or 64 bit - and the 127 | main repo has no idea that boot2docker exists. That means you can't 128 | actually use the package manager for many things with `boot2docker`. On 129 | top of that, any changes you made would get nuked on upgrade. That means 130 | `boot2docker` is a no-go until I can figure out how to do a build with 131 | sound support \(which I've started on 132 | [here](https://github.com/xavriley/boot2docker)\) 133 | --------------------------------------------------------------------------------