├── configs
├── sshconfig
├── tidebox-service.yml
├── tidebox.yml
├── screenrc
├── emacsrc
├── tidebox.ini
└── ffserver.conf
├── demo.gif
├── tidal
├── hello.tidal
└── init.tidal
├── Dockerfile
└── README.md
/configs/sshconfig:
--------------------------------------------------------------------------------
1 | Host github.com
2 | IdentityFile ~/.ssh/id_rsa
3 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DoubleDensity/tidebox/HEAD/demo.gif
--------------------------------------------------------------------------------
/tidal/hello.tidal:
--------------------------------------------------------------------------------
1 | -- default test rhythm to verify stream connectivity; should start within 10 seconds
2 | d1 $ stack [sound "bd sn:2" , sound "casio:2 casio:1 house:2*1"]
3 |
4 | hush
5 |
--------------------------------------------------------------------------------
/tidal/init.tidal:
--------------------------------------------------------------------------------
1 | hush
2 |
3 | d1 $ silence
4 |
5 | d2 $ silence
6 |
7 | d3 $ silence
8 |
9 | d4 $ silence
10 |
11 | d5 $ silence
12 |
13 | d6 $ silence
14 |
15 | d7 $ silence
16 |
17 | d8 $ silence
18 |
19 | d9 $ silence
20 |
--------------------------------------------------------------------------------
/configs/tidebox-service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: tideboxsvcs
5 | spec:
6 | type: LoadBalancer
7 | ports:
8 | -
9 | name: sshd
10 | port: 22
11 | targetPort: 22
12 | -
13 | name: ffserver
14 | port: 8090
15 | targetPort: 8090
16 | selector:
17 | app: tidebox
18 |
--------------------------------------------------------------------------------
/configs/tidebox.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: tidebox
5 | labels:
6 | app: tidebox
7 | spec:
8 | containers:
9 | - name: tidebox
10 | image: quay.io/doubledensity/tidebox:0.2
11 | ports:
12 | - containerPort: 8090
13 | name: ffserver
14 | - containerPort: 22
15 | name: sshd
16 | imagePullSecrets:
17 | - name: myregistrykey
18 |
--------------------------------------------------------------------------------
/configs/screenrc:
--------------------------------------------------------------------------------
1 | defshell -zsh
2 |
3 | screen -t tidal
4 | select 0
5 | stuff "emacs^M"
6 | screen -t jackd
7 | select 1
8 | stuff "tail -f ~/jackd.log^M"
9 | screen -t dirt
10 | select 2
11 | stuff "tail -f ~/dirt.log^M"
12 | screen -t ffserver
13 | select 3
14 | stuff "tail -f ~/ffserver.log^M"
15 | screen -t ffmpeg
16 | select 4
17 | stuff "tail -f ~/ffmpeg.log^M"
18 | screen -t files
19 | select 5
20 | stuff "cd /work/scratchpool^M"
21 | select 0
22 |
23 | altscreen off
24 | term screen-256color
25 | bind ',' prev
26 | bind '.' next
--------------------------------------------------------------------------------
/configs/emacsrc:
--------------------------------------------------------------------------------
1 | (require 'package)
2 | (custom-set-variables
3 | ;; custom-set-variables was added by Custom.
4 | ;; If you edit it by hand, you could mess it up, so be careful.
5 | ;; Your init file should contain only one such instance.
6 | ;; If there is more than one, they won't work right.
7 | '(package-archives
8 | (quote
9 | (("gnu" . "http://elpa.gnu.org/packages/")
10 | ("melpa-stable" . "http://stable.melpa.org/packages/")))))
11 |
12 | ;; Hide splash-screen and startup-message
13 | (setq inhibit-splash-screen t)
14 | (setq inhibit-startup-message t)
15 |
16 | (add-hook 'isearch-update-post-hook 'redraw-display)
17 |
18 | (add-to-list 'load-path "/repos/tidal")
19 | (add-to-list 'load-path "/work")
20 | (require 'haskell-mode)
21 | (require 'tidal)
22 |
23 | (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
24 |
25 | (find-file "~/init.tidal")
26 |
27 | (fset 'stidal
28 | "\C-c\C-s")
29 |
30 | (fset 'splay
31 | "\C-c\C-c")
32 |
33 | (execute-kbd-macro (symbol-function 'stidal))
34 |
35 | (find-file "~/hello.tidal")
36 |
37 | (delete-other-windows)
38 |
39 | (defun sseek ()
40 | (interactive)
41 | (with-no-warnings
42 | (goto-line 2)))
43 |
44 | (sseek)
45 |
46 | (sleep-for 5)
47 | (execute-kbd-macro (symbol-function 'splay))
48 |
--------------------------------------------------------------------------------
/configs/tidebox.ini:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | nodaemon=true
3 | logfile = /tmp/supervisord.log
4 |
5 | [program:sshd]
6 | command=/usr/sbin/sshd -D
7 |
8 | [program:jackd]
9 | command=/usr/bin/jackd -d dummy
10 | user=tidal
11 | priority=10
12 | startsecs=10
13 | environment=HOME="/home/tidal",USER="tidal"
14 | autostart=true
15 | autorestart=true
16 | redirect_stderr=true
17 | stdout_logfile=/home/tidal/jackd.log
18 | stderr_logfile=/home/tidal/jackd.error_log
19 |
20 | [program:dirt]
21 | command=/repos/Dirt/dirt
22 | user=tidal
23 | priority=30
24 | startsecs=10
25 | environment=HOME="/repos/Dirt",USER="tidal"
26 | directory=/repos/Dirt
27 | autostart=true
28 | autorestart=true
29 | redirect_stderr=true
30 | stdout_logfile=/home/tidal/dirt.log
31 | stderr_logfile=/home/tidal/dirt.error_log
32 |
33 | [program:ffserver]
34 | command=/usr/bin/ffserver -f /home/tidal/ffserver.conf
35 | user=tidal
36 | priority=40
37 | startsecs=10
38 | autostart=true
39 | autorestart=true
40 | redirect_stderr=false
41 | stdout_logfile=/home/tidal/ffserver.log
42 | stderr_logfile=/home/tidal/ffserver.error_log
43 |
44 | [program:ffmpeg]
45 | command=/usr/bin/ffmpeg -f jack -i ffmpeg -ac 2 http://localhost:8090/feed1.ffm
46 | user=tidal
47 | priority=50
48 | startsecs=10
49 | autostart=true
50 | autorestart=true
51 | redirect_stderr=false
52 | stdout_logfile=/home/tidal/ffmpeg.log
53 | stderr_logfile=/home/tidal/ffmpeg.error_log
54 |
55 | [program:jackd_connect1]
56 | command=/usr/bin/jack_connect dirt:output_0 ffmpeg:input_1
57 | user=tidal
58 | priority=500
59 | startsecs=5
60 | autostart=true
61 | autorestart=false
62 |
63 | [program:jackd_connect2]
64 | command=/usr/bin/jack_connect dirt:output_1 ffmpeg:input_2
65 | user=tidal
66 | priority=500
67 | startsecs=5
68 | autostart=true
69 | autorestart=false
--------------------------------------------------------------------------------
/configs/ffserver.conf:
--------------------------------------------------------------------------------
1 | # Port on which the server is listening. You must select a different
2 | # port from your standard HTTP web server if it is running on the same
3 | # computer.
4 | Port 8090
5 |
6 | # Address on which the server is bound. Only useful if you have
7 | # several network interfaces.
8 | BindAddress 0.0.0.0
9 |
10 | # Number of simultaneous HTTP connections that can be handled. It has
11 | # to be defined *before* the MaxClients parameter, since it defines the
12 | # MaxClients maximum limit.
13 | MaxHTTPConnections 2000
14 |
15 | # Number of simultaneous requests that can be handled. Since FFServer
16 | # is very fast, it is more likely that you will want to leave this high
17 | # and use MaxBandwidth, below.
18 | MaxClients 1000
19 |
20 | # This the maximum amount of kbit/sec that you are prepared to
21 | # consume when streaming to clients.
22 | MaxBandwidth 1000
23 |
24 | # Access log file (uses standard Apache log file format)
25 | # '-' is the standard output.
26 | CustomLog -
27 |
28 | # Suppress that if you want to launch ffserver as a daemon.
29 | NoDaemon
30 |
31 |
32 | ##################################################################
33 | # Definition of the live feeds. Each live feed contains one video
34 | # and/or audio sequence coming from an ffmpeg encoder or another
35 | # ffserver. This sequence may be encoded simultaneously with several
36 | # codecs at several resolutions.
37 |
38 |
39 |
40 | # You must use 'ffmpeg' to send a live feed to ffserver. In this
41 | # example, you can type:
42 | #
43 | # ffmpeg http://localhost:8090/feed1.ffm
44 |
45 | # ffserver can also do time shifting. It means that it can stream any
46 | # previously recorded live stream. The request should contain:
47 | # "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify
48 | # a path where the feed is stored on disk. You also specify the
49 | # maximum size of the feed, where zero means unlimited. Default:
50 | # File=/tmp/feed_name.ffm FileMaxSize=5M
51 | File /tmp/feed1.ffm
52 | FileMaxSize 200K
53 |
54 | # You could specify
55 | # ReadOnlyFile /saved/specialvideo.ffm
56 | # This marks the file as readonly and it will not be deleted or updated.
57 |
58 | # Specify launch in order to start ffmpeg automatically.
59 | # First ffmpeg must be defined with an appropriate path if needed,
60 | # after that options can follow, but avoid adding the http:// field
61 | #Launch ffmpeg
62 |
63 | # Only allow connections from localhost to the feed.
64 | #ACL allow 127.0.0.1
65 |
66 |
67 |
68 |
69 | ##################################################################
70 | # Now you can define each stream which will be generated from the
71 | # original audio and video stream. Each format has a filename (here
72 | # 'test1.mpg'). FFServer will send this stream when answering a
73 | # request containing this filename.
74 |
75 | # MP3 audio
76 |
77 | Feed feed1.ffm
78 | Format mp2
79 | AudioCodec libmp3lame
80 | AudioBitRate 320
81 | AudioChannels 2
82 | AudioSampleRate 44100
83 | NoVideo
84 |
85 |
86 |
87 | # Ogg Vorbis audio
88 | #
89 | #Feed feed1.ffm
90 | #Format ogg
91 | #AudioCodec libvorbis
92 | #Title "Stream title"
93 | #AudioBitRate 64
94 | #AudioChannels 2
95 | #AudioSampleRate 44100
96 | #NoVideo
97 | #
98 |
99 | ##################################################################
100 | # Special streams
101 |
102 | # Server status
103 |
104 |
105 | Format status
106 |
107 | # Only allow local people to get the status
108 | ACL allow localhost
109 | ACL allow 192.168.1.0 192.168.1.255
110 |
111 | #FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico
112 |
113 |
114 | # Redirect index.html to the appropriate site
115 |
116 | URL http://www.ffmpeg.org/
117 |
118 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM fedora
2 |
3 | MAINTAINER Buttetsu Batou
4 |
5 | # Install dependencies and audio tools
6 |
7 | RUN dnf groupinstall -y "C Development Tools and Libraries"
8 | RUN dnf install -y git zsh wget man sudo
9 | RUN dnf install -y libsndfile-devel libsamplerate-devel liblo-devel jack-audio-connection-kit-devel jack-audio-connection-kit-example-clients alsa-lib-devel xz htop grep procps-ng yasm screen supervisor openssh-server
10 | RUN dnf install -y cabal-install ghc-Cabal-devel
11 |
12 | # Install editor
13 | RUN dnf -y install emacs-nox emacs-haskell-mode
14 |
15 | # Build Dirt synth
16 | WORKDIR /repos
17 | RUN git clone --recursive https://github.com/tidalcycles/Dirt.git
18 | WORKDIR Dirt
19 | RUN make
20 |
21 | # Build & Install libmp3lame
22 | WORKDIR /repos
23 | RUN git clone https://github.com/rbrito/lame.git
24 | WORKDIR lame
25 | RUN ./configure --prefix=/usr
26 | RUN make install
27 | WORKDIR /repos
28 | RUN rm -fr lame
29 |
30 | # Build & Install ffmpeg, ffserver
31 | WORKDIR /repos
32 | RUN git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
33 | WORKDIR ffmpeg
34 | RUN ./configure --enable-indev=jack --enable-libmp3lame --enable-nonfree --prefix=/usr
35 | RUN make install
36 | WORKDIR /repos
37 | RUN rm -fr ffmpeg
38 |
39 | # Install Tidebox supervisord config
40 | COPY configs/tidebox.ini /etc/supervisord.d/tidebox.ini
41 |
42 | # Initialize and configure sshd
43 | RUN ssh-keygen -b 1024 -t rsa -f /etc/ssh/ssh_host_key
44 | RUN ssh-keygen -b 1024 -t rsa -f /etc/ssh/ssh_host_rsa_key
45 | RUN ssh-keygen -b 1024 -t dsa -f /etc/ssh/ssh_host_dsa_key
46 | RUN sed -i 's/UsePAM\syes/UsePAM no/' /etc/ssh/sshd_config
47 |
48 | # Expose sshd service
49 | EXPOSE 22
50 |
51 | # Expose ffserver streaming service
52 | EXPOSE 8090
53 |
54 | # Pull Tidal Emacs binding
55 | RUN mkdir /repos/tidal
56 | WORKDIR /repos
57 | WORKDIR tidal
58 | RUN wget https://raw.github.com/yaxu/Tidal/master/tidal.el
59 |
60 | # Create and configure Tidal user
61 | RUN useradd tidal -s /bin/zsh
62 | RUN echo 'tidal:livecoding' | chpasswd
63 | RUN echo "tidal ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
64 |
65 | USER tidal
66 |
67 | ENV HOME /home/tidal
68 | WORKDIR /home/tidal
69 |
70 | RUN ln -s /repos /home/tidal/repos
71 | RUN ln -s /work /home/tidal/work
72 |
73 | # Install Tidal
74 | RUN cabal update
75 | RUN cabal install tidal
76 |
77 | # Install Oh-My-Zsh
78 | RUN sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
79 |
80 | # Disable Zsh automatic window titling
81 | RUN sed -i 's/# DISABLE_AUTO_TITLE="true"/DISABLE_AUTO_TITLE="true"/g' /home/tidal/.zshrc
82 |
83 | # Install default configurations
84 | COPY configs/emacsrc /home/tidal/.emacs
85 | COPY configs/screenrc /home/tidal/.screenrc
86 | COPY configs/ffserver.conf /home/tidal/ffserver.conf
87 |
88 | # Install default Tidal files
89 | COPY tidal/init.tidal /home/tidal/init.tidal
90 | COPY tidal/hello.tidal /home/tidal/hello.tidal
91 |
92 | # Prepare scratch workspace for version control
93 | RUN sudo mkdir /work
94 | RUN sudo chown -R tidal:tidal /work
95 | WORKDIR /work
96 | RUN mkdir /home/tidal/.ssh
97 | ADD https://raw.githubusercontent.com/DoubleDensity/scratchpool/master/id_rsa-scratchpool /home/tidal/.ssh/id_rsa
98 | RUN sudo chmod 600 /home/tidal/.ssh/id_rsa
99 | RUN sudo chown tidal.tidal /home/tidal/.ssh/id_rsa
100 | COPY configs/sshconfig /home/tidal/.ssh/config
101 | RUN sudo chmod 600 /home/tidal/.ssh/config
102 | RUN sudo chown tidal.tidal /home/tidal/.ssh/config
103 | RUN ssh-keyscan -H github.com >> ~/.ssh/known_hosts
104 | RUN git clone git@github.com:DoubleDensity/scratchpool.git
105 | WORKDIR /work/scratchpool
106 | RUN git config user.name "Tidebox User"
107 | RUN git config user.email "tidal@jankycloud.com"
108 |
109 | # Set Tidal shell to Screen
110 | USER root
111 | RUN echo "/usr/bin/screen" >> /etc/shells
112 | RUN usermod -s /usr/bin/screen tidal
113 | RUN chown -R tidal.tidal /home/tidal/*.tidal
114 |
115 | CMD ["/usr/bin/supervisord"]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tidebox
2 |
3 | [](https://quay.io/repository/doubledensity/tidebox)
4 |
5 | > A complete Tidal musical live coding and audio streaming environment inside Docker
6 |
7 | ## What is Tidal?
8 |
9 | According to the official [homepage](http://tidal.lurk.org):
10 |
11 | "Tidal is a language for live coding pattern(s). It provides a way to express music with very flexible timing, providing a little language for describing patterns as discrete sequences (which can be polyphonic and polymetric), some generators of continuous patterns (e.g. sinewaves, sawtooths) and a wide range of pattern transformations."
12 |
13 | Said differently, Tidal lets you rock out and explore sound and rhythm in real time from the context of a text editor.
14 |
15 | If you are interested in more detail about the theory and execution of Tidal I highly suggest you read [this paper](https://raw.githubusercontent.com/yaxu/Tidal/master/doc/farm/farm.pdf) from its creator [Alex McLean](https://twitter.com/yaxu).
16 |
17 | For an example of the types of patterns and techniques which are possible in Tidal, see the album [Expedition](https://kindohm.bandcamp.com/album/expedition) from [Kindohm](https://twitter.com/kindohm).
18 |
19 | ## Why Tidebox?
20 |
21 | The goal of Tidebox is to allow anyone to run Tidal immediately on any available compute node and stream the output to any target. No package installation or configuration need. No sound hardware or elevated permissions are required on the Docker host.
22 | This allows for the use of very-low end performance hardware to control and compose the session while harnessing greater resources on remote hosts, clusters and public cloud infrastructure.
23 |
24 | Many thanks to Tidal and the entire live coding community for making such fun and exciting software!
25 |
26 | ## Getting started
27 |
28 | First you will want to start the container:
29 |
30 | ```bash
31 | docker run -d quay.io/doubledensity/tidebox:0.2
32 | ```
33 |
34 | Tidebox has been re-written for 0.2 so that it can now be run 'headless' as a detached Docker container and no longer requires an interactive terminal to run.
35 |
36 | * After launching the container you can ssh in to it using the user name `tidal` and the password `livecoding`
37 |
38 | The Tidal session will begin automatically upon login. You can detach at any time from your session by using `CTRL-A-D`; Tidal will keep playing, and you can re-attach at any time by ssh'ing back in.
39 |
40 | The FFserver process providing the audio stream is exposed on port 8090 and sshd is on port 22.
41 |
42 | 
43 |
44 | You can connect to the stream with any media player which supports streaming mp3 such as VLC, iTunes, MPlayer, mpg123, etc.
45 |
46 | Here is an example of connecting to the stream with MPlayer:
47 |
48 | ```bash
49 | mplayer http://172.17.0.2:8090/stream.mp3
50 | ```
51 | * You may need to find the IP address of your Tidebox container using the Docker `inspect` command if you don't use the `--net=host` option
52 |
53 | By default Tidebox will start to play a test Tidal audio sequence automatically when you first login to the container so you can verify audio connectivity.
54 |
55 | ## Controls
56 |
57 | The various components of Tidebox are running in separate windows within the GNU Screen terminal window manager, and should initialize automatically.
58 |
59 | The Emacs / Haskell Tidal environment is the default window `0`, but you can find the logs for the additional components JACK, Dirt, ffmpeg, and ffserver on windows `1-4`.
60 |
61 | Window `5` is currently set aside as an interactive shell for working with and managing Tidal files or anything else you may wish to pull down or manipulate for use in your session.
62 |
63 | You can switch between the Screen windows using `CTRL-,` and `CTRL-.` forward and backward, or `CTRL-A` followed by the default window numbers 1-5.
64 |
65 | ## References
66 |
67 | - [Tidal](http://tidal.lurk.org)
68 | - [Dirt synth](https://github.com/tidalcycles/Dirt)
69 | - [JACK Audio Connection Kit](http://www.jackaudio.org/)
70 | - [FFmpeg](https://www.ffmpeg.org/)
71 | - [GNU Emacs](https://www.gnu.org/software/emacs/)
72 | - [GNU Screen](https://www.gnu.org/software/screen/)
73 | - [TOPLAP The Home of Live Coding](http://toplap.org/)
74 | - [Supervisor](http://supervisor.org)
--------------------------------------------------------------------------------