#===========================#
__ __
.--| |.--| |.----.
| _ || _ || _|
|_____||_____||__|
data-driven rhythms in R
#===========================#
ddr
has ~ 1 GB of built-in instruments. It will take awhile to install from github.
library("devtools")
install_github("ddr", "csv")
library("ddr")
Computers without shit tons of RAM may crash if you try installing that way. If that happens, try this, which uses less RAM.
git clone git://github.com/csv/ddr.git
cd ddr
Rscript -e 'library(devtools);install()'
You'll probably also want seewave
, which indirectly depends on BWidget
.
sudo pacman -S bwidge # In Arch Linux
Rscript -e 'install.packages("seewave")'
NOTE: YOU MUST RUN ddr_init
EVERYTIME YOU START UP ddr
!
The way ddr
makes noises is by creating temporary wave files and playing them through an audio player of your preference. You can set your desired audio player as follows:
ddr_init(player="path_to_player")
By default, ddr
is set to look for QuickTime
on Mac OSX, eg:
ddr_init(player="/Applications/'QuickTime Player.app'/Contents/MacOS/'QuickTime Player'")
However, you might want to use mplayer
, eg:
ddr_init(player="/usr/bin/env mplayer'")
One weird thing about using QuickTime
is that, when it plays a temporary file, it will freeze the R console until you press esc
. So, if you see this:
> play(piano$C3)
just press esc
and ddr
will move on to the next task.
ddr
comes with 5 instruments and 2 drum kits:
# Instruments:
blip -- a sinewave with a quick attack
piano -- a classic-sounding grand piano
rhodes -- a fender rhodes
sinewave -- a simple sinewave
sweeplow -- a cheesy synth
# Drums:
moog -- moog drum hits
roland -- a roland 707
Instruments and drum kits are simply R lists with each element being a separate wave file. For instance, you can select middle C on a piano as follows:
piano$C3
# or, alternatively:
piano[["C3"]]
If you want to see the names of the wave file in a given instrument, just type: names(instrument)
, eg: names(piano)
or names(moog)
Slice 'em up!
chop(piano$C3, bpm=100, count=1/8)
Reverse too!
reverse(piano$C3)
Chop and screw!
chop(pitch(piano$C3, -36), bpm=100, count=2)
Loop!
loop(chop(piano$C3, bpm=100, count=1/8), 16)
Generate chords!
chord(C3, piano, "maj", bpm=100, count=4)
ddr
comes with a simple sound sequencing engine. This is best explained through an example:
# let's make a four-on-the-floor drum loop!
# first, let's put our drum sounds in a list:
wavs <- list(roland$HHO, roland$SD1, roland$BD1)
# now let's write a series of 1's and 0's indicating when we want each sound to play
# when we're done, let's also put these in a list:
hihat <- c(0,1,0,1)
kick <- c(1,0,1,0)
snare <- c(0,0,1,0)
seqs <- list(hihat, snare, kick)
# now lets put these lists into our sequence function and include a bpm and the count each note recieves
four_on_the_floor <- sequence(wavs, seqs, bpm=120, count=1/8)
play(loop(four_on_the_floor, 10))
Now lets take this logic and include chords to generate the chorus of Call Me Maybe
c1 <- chord(A4, sweeplow, "maj", bpm=119, count=1)
c2 <- chord(E4, sweeplow, "maj", bpm=119, count=1)
c3 <- chord(B4, sweeplow, "maj", bpm=119, count=1)
c4 <- chord(C.4, sweeplow, "min", bpm=119, count=1)
wavs <- list(c1, c2, c3, c4, roland$HHC, roland$TAM, roland$HHO, roland$BD1, roland$SD1)
A <- c(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0)
E <- c(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0)
B <- c(0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0)
C.m<-c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
H <- c(0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1)
T <- c(0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0)
O <- c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1)
K <- c(1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0)
S <- c(0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0)
seqs <- list(A, E, B, C.m, H, T, O, K, S)
callmemaybe <- sequence(wavs, seqs, bpm=59.5, count=1/16)
play(loop(callmemaybe, 4))
But wait, there's more! ddr
can also generate sequences that include amplitude changes. Here, any number between 0 and 1 simply corresponds with the relative amplitude of the wave:
wavs <- list(roland$HHC)
seqs <- list(c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8))
hihats <- sequence(wavs, seqs, bpm=59.5, count=1/16)
play(loop(hihats, 4))
BUT NOW IM REALLY GOING TO BLOW YOUR MIND. Since sequences are (mostly) binomial distributions, you can use built-in R functions to generate random music!
wavs <- list(roland$HHC, roland$TAM, roland$HHO, roland$BD1, roland$SD1)
H <- rnorm(32, mean=0.5, sd=0.1)
T <- rbinom(32, 1, prob=0.05)
O <- rbinom(32, 1, prob=0.075)
K <- rbinom(32, 1, prob=0.2)
S <- rbinom(32, 1, prob=0.3)
seqs <- list(H, T, O, K, S)
random_loop <- sequence(wavs, seqs, bpm=59.5, count=1/16)
play(loop(random_loop, 4))
Finally, ddr
has a function for creating silly data sonifications. It's called arpeggidata
. arpeggidata
works by scaling a numeric vector onto a musical scale. YOU HAVE TO HEAR IT TO BELIEVE IT!
# Let's use ChickWeight - Iris is so played out...
data('ChickWeight')
cw <- ChickWeight
chicks <- arpeggidata(sqrt(cw$weight),
blip,
scale="Emajor",
bpm=200,
count=1/32)
play(chicks)
I used ddr
to make the music in FMS Symphony. Here's the code (fms_data is built-in to ddr
):
bpm <- 280
ct <- 1/4
rate <- arpeggidata(fms_data$rate,
sinewave,
low_note="",
high_note="",
descending = FALSE,
scale="Cmajor",
remove=NULL,
bpm=bpm,
count=ct)
writeWave(rate, "rate.wav")
ceil <- arpeggidata(fms_data$dist_to_ceiling,
sinewave,
low_note="",
high_note="",
descending = TRUE,
scale="Emajor",
remove=NULL,
bpm=bpm,
count=ct)
writeWave(ceil, "ceiling.wav")
gen_chords <- function(z) {
if (z < 0) {
if (z <= -0.5) {
c <- chord(A3, sinewave,
"min", bpm=bpm,
count=ct)
} else {
c <- chord(A4, sinewave,
"min", bpm=bpm,
count=ct)
}
} else {
if (z >= 0.5) {
c <- chord(C4, sinewave,
"maj", bpm=bpm,
count=ct)
} else {
c <- chord(C3, sinewave,
"maj", bpm=bpm,
count=ct)
}
}
return(c)
}
chords <- llply(fms_data$z_change, gen_chords, .progress="text")
bind_list_of_waves <- function(x, y) {
bind(x, y)
}
reduce_waves <- function(list_of_waves) {
Reduce(bind_list_of_waves, list_of_waves)
}
chords <- reduce_waves(chords)
writeWave(chords, "chords.wav")