I would like to play music using R. While R may not be the best tool for this purpose, it is the tool that I am familiar with and it would be nice to demonstrate to others its flexibility on such a joyous occasion.
How could I accomplish this?
I would like to play music using R. While R may not be the best tool for this purpose, it is the tool that I am familiar with and it would be nice to demonstrate to others its flexibility on such a joyous occasion.
How could I accomplish this?
If you really wanted to do this:
library("audio")
bday_file <- tempfile()
download.file("http://www.happybirthdaymusic.info/01_happy_birthday_song.wav", bday_file, mode = "wb")
bday <- load.wave(bday_file)
play(bday)
Note you'll need to install.packages("audio")
first. If you already have a specific file, you'll need to convert it to WAV format first.
If you wanted something a bit more programmery than playing a WAV file, here's a version that generates the tune from a series of sine waves:
library("dplyr")
library("audio")
notes <- c(A = 0, B = 2, C = 3, D = 5, E = 7, F = 8, G = 10)
pitch <- "D D E D G F# D D E D A G D D D5 B G F# E C5 C5 B G A G"
duration <- c(rep(c(0.75, 0.25, 1, 1, 1, 2), 2),
0.75, 0.25, 1, 1, 1, 1, 1, 0.75, 0.25, 1, 1, 1, 2)
bday <- data_frame(pitch = strsplit(pitch, " ")[[1]],
duration = duration)
bday <-
bday %>%
mutate(octave = substring(pitch, nchar(pitch)) %>%
{suppressWarnings(as.numeric(.))} %>%
ifelse(is.na(.), 4, .),
note = notes[substr(pitch, 1, 1)],
note = note + grepl("#", pitch) -
grepl("b", pitch) + octave * 12 +
12 * (note < 3),
freq = 2 ^ ((note - 60) / 12) * 440)
tempo <- 120
sample_rate <- 44100
make_sine <- function(freq, duration) {
wave <- sin(seq(0, duration / tempo * 60, 1 / sample_rate) *
freq * 2 * pi)
fade <- seq(0, 1, 50 / sample_rate)
wave * c(fade, rep(1, length(wave) - 2 * length(fade)), rev(fade))
}
bday_wave <-
mapply(make_sine, bday$freq, bday$duration) %>%
do.call("c", .)
play(bday_wave)
There's a few points to note. The default octave for the notes is octave 4, where A4 is at 440 Hz (the note used to tune the orchestra). Octaves change over at C, so C3 is one semitone higher than B2. The reason for the fade in make_sine
is that without it there are audible pops when starting and stopping notes.
c
in do.call
, and the last assignment in make_sine
is unnecessary. –
Unbacked do.call
. It's all too easy to fall into the trap of having done something like a <- 1; b <- 2; c <- 3
along the way, and in that situation do.call(c, ...)
will fail, while c(1, 2, 3)
won't. Completely agree with the latter point though, and have removed the unnecessary assignment! –
Smoulder do.call('c', …)
will also fail. At any rate, I argue that, except when used with match.fun
, quoting function names is fundamentally nonsense: a string is not a function. The fact that R allows us to treat them like this is a terrible flaw and should not be relied on. –
Unbacked do.call("c", ...)
will work. Try c <- 4; do.call("c", list(1, 2))
. R is reasonably consistent in that in most cases an argument that accepts a function will accept either the function itself or the name of the function. In some cases (e.g. lapply
), this is via match.fun
, whereas in others, e.g. do.call
, getMethod
, the implementation is in the C code (for the latter via a call to C_R_getGeneric
). I can see why stylistically you might prefer to pass the function rather than its name, but the latter behaviour is well-documented. –
Smoulder do.call
uses match.fun
(or similar) internally. I agree that the behaviour is consistent. Still, I maintain that it’s bad. –
Unbacked symbol
is followed by parentheses, even if another symbol
exists further up the seach path. This allows c <- 4; c(1, 2)
to work as normal, while c <- paste0; c(1, 2)
will not use the base c
. I've seen confusion created by this where someone has been quite happily calling c(1, 2)
in their code, but then do.call(c, ...)
fails to work. At the end of the day, I don't feel strongly about whether functions are provided by name or directly. –
Smoulder freq
changes the key, but is there any way to be able to play with two ranges at once ? –
Ardeth © 2022 - 2024 — McMap. All rights reserved.
I would like to play video using R
. – EaldormanrasterImage
to render each frame) – Smoulder