Hive Jam is a loop-oriented, multi-player framework for making music with Sonic Pi. Players turn on and off grid cells representing synths or samples. A cursor sweeps with the beat across the grid, playing any cells that are on. Rows (tracks) can be parameterized to change the sound of a synth or sample.
Tracks can also represent sub-grids which contain their own tracks and parameters. A sub-grid will be activated when the parent track is on. Sub-grids can contain their own sub-grids and so forth.
- Install and run Sonic Pi.
- Download and run the latest Hive Jam binary.
- Open http://localhost:8080
From a Google Cloud Engine instance:
- Install docker:
sudo apt-get install -y docker.io
- Run Hive Jam:
sudo docker run -d -p 8080:8080 -p 8000:8000 -p 4550:4550 josephburnett/hive-jam
- Open the UI webserver at
EXTERNAL_IP:8080
Click on a cell to toggle it on (1
) and off (0
).
Click on the properties icon {..}
at the end of a track to add a synth or sample. It will be played when the cursor is on a cell which is on.
Click on the track builder [+ 8]
to add new tracks. Pro tip: click on the +
to show more options; click on the 8
to add another track of the same length.
Click on the properties icon {..}
at the top of a grid to change the beats-per-sample (bpc
) and to change the grid width (+/-
).
You can add parameters (params
) to a synth or sample in the track properties. Look at the Sonic Pi help pages for each synth or sample to see supported parameters.
You can add effects (fx
) to a track in the track properties. Effects are applied in the order in which they are added. You can parameterize effects, just like synths and samples. See Sonic Pi help pages for supported parameters.
In addition to synth and sample tracks, you can create grid tracks which contain an entirely separate sub-grid. The sub-grid will be played when the cursor is at a cell which is on.
Sub-grids tracks have their own parameters and effects. However the tracks in a sub-grid can inherit some parameters and effects from their containing (parent) track. For example, a parent track which has a sub-grid type (grid-type
) of sample
will cause all tracks in the sub-grid to be interpreted as sample tracks. Parameters which are set on the parent track, such as pitch
, will apply to all the sub-grid tracks (unless they have an pitch
parameter of their own.)
Parameters are what make Sonic Pi synths and samples interesting to play with. In addition to providing a scalar value, you can provide a function (lambda) which will be evaluated each time the track is played. Any parameter which starts with the \
character is interpreted as a lambda.
The lambda could do anything from returning a random value to increasing its value over time. The evaluation context is the same as the Sonic Pi editor except that two additional values are in scope: 1) beat_index
which is the zero-based index at which the cursor (beat) is in the track and 2) row_index
which is the zero-based index at which the track is in the grid. beat_index
can be used to change the parameters of a track over time, restarting at the end of each loop. row_index
can be used to implement something like a piano roll (see Patterns below.)
Pro tip: right-click on a cell to make a synth sustain (2
, 3
, ...)
When building a melody it is useful to have the tracks of a grid represent the notes of a scale. This can be done by parameterizing a parent track with a lambda which calculates pitch
based on row_index
.
Hive Jam is built from the ground-up to support multiple players. For example, two players can jam on the same instance by visiting the same URL in their browser. Changes to one will immediately take effect in the other.
Sub-grids can be used to give each player their own space to work in. The players can take turns (call-and-response) or play together.
Hive Jam is a framework for controlling Sonic Pi. It uses a single live-loop to sweep through a data structure, dispatching parameterized calls to the Sonic Pi functions synth
and sample
on the beat.
Server state is kept in the Sonic Pi variable _state
which is a HiveJam::State
instance. The granularity of state manipulation is a single grid through the set_state
and get_state
methods.
{
root: {
bpc: 1,
tracks: [
{
type: "sample",
sample: "bass_drop_c",
beats: [[1], [1], [1], [1]]
},
{
type: "grid",
grid-id: "abcd",
beats: [[1]]
]
},
abcd: {
bpc: 1,
tracks: [
{
type: "synth",
synth: "fm",
synth-params: {
pitch: 20,
}
beats: [[1], [0], [0], [0]]
}
]
}
}
In the main live-loop a HiveJam::Dispatch
instance traverses the state, generating a list of materialized dispatch structures. Dispatch is responsible for determining which tracks and sub-grids are on/off, implementing sub-grid inheritance and running lambdas to generate scalar parameter values.
[
{ sample: "base_drop_c" },
{ synth: "fm", params: { pitch: 20 }}
]
[
{ sample: "base_drop_c" }
]
[
{ sample: "base_drop_c" },
{ synth: "fm", params: { pitch: 20 }}
]
+----+ (audio)
| UI |<---------------------------------------------------------+
+----+ |
^ |
| (state) |
V |
+--------+ +---------------------+ |
| Hive | | +----------+ | +---------------+ |
| Server |<---->| Dispatch | Sonic |--->| Supercollider | |
+--------+ | | Server | Pi | | Synthesizer | |
| +----------+ | +---------------+ |
+---------------------+ | |
V |
+------+ |
| Jack | |
+------+ |
| |
V |
+---------+ |
| Darkice | |
+---------+ |
| |
V |
+---------+ |
| Icecast |---------+
+---------+
The Dispatch Server (ruby/server.rb
) is bootstrapped into Sonic Pi through a series OSC messages to /run-code
on port 4557. It starts an OSC server on port 4560.
The Hive Server (golang/server/server.go
) starts an OSC server on port 4559 and a websocket server on 4550. It multiplexes messages from multiple clients to the Dispatch Server.
The UI (cljs/src/core.cljs
) communicates with the Hive Server over a websocket connection. It requests synth and sample lists, transmits and receives state changes, and receives a stream of cursor updates (current location of the beat). Supercollider outputs its audio to Jack. Darkice feeds it into Icecast which streams the audio back to the UI.
The typical development workflow is to build Hive Jam from head and launch it. Then start Figwheel for interactive, live UI coding. Any change to files in cljs
will take effect immediately--even without reloading the browser. Any changes to golang
or ruby
require a rebuild (bin/build
).
- Launch an Ubuntu 16.04 instance
- Open ports 3449, 4550, 8000 and 8080 to TCP connections (Networking)
$ bin/deps-ubuntu
(configure Icecast2 with random password--it will be overwritten)$ bin/build
$ sudo bin/with-gce-env launch
$ bin/with-gce-env figwheel
- Navigate to http://$EXTERNAL_IP:3449
$ bin/deps-ubuntu
$ bin/build
$ sonic-pi
$ build/hive-jam
$ bin/with-local-env figwheel
- Navigate to http://localhost:3449
$ bin/deps-ubuntu
$ bin/build
$ sudo bin/with-local-env launch
$ bin/with-local-env figwheel
- Navigate to http://localhost:3449
$ bin/deps-raspberry-pi
$ bin/build
$ sonic-pi
$ build/hive-jam
$ bin/with-local-env figwheel
- Navigate to http://localhost:3449
- Install Sonic Pi (http://sonic-pi.net)
- Install git (type
git
and follow instructions) - Install java (type
java
and follow instructions) - Install golang (https://golang.org/dl/)
$ bin/build
- Start Sonic Pi
$ build/hive-jam
$ bin/with-local-env figwheel
- Navigate to http://localhost:3449
Encountering any problems? Please report an issue: https://github.com/josephburnett/hive-jam/issues
If possible, please include:
- What you were doing
- Any error messages
- Operating system
- Sonic Pi version
- Hive Jam version or commit