Chciałbym grać w R. Choć R może nie być najlepszym narzędziem do tego celu, to jest to narzędzie, które znam i fajnie byłoby pokazać innym swoją elastyczność przy tak radosnej okazji.
Jak mogłem to osiągnąć?
Chciałbym grać w R. Choć R może nie być najlepszym narzędziem do tego celu, to jest to narzędzie, które znam i fajnie byłoby pokazać innym swoją elastyczność przy tak radosnej okazji.
Jak mogłem to osiągnąć?
I would like to play video using R
.
rasterImage
renderować każdą klatkę)
Odpowiedzi:
Jeśli naprawdę chciałeś to zrobić:
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)
Uwaga, musisz install.packages("audio")
najpierw. Jeśli masz już określony plik, musisz najpierw przekonwertować go do formatu WAV.
Jeśli chciałeś czegoś bardziej programistycznego niż odtwarzanie pliku WAV, oto wersja, która generuje melodię z serii fal sinusoidalnych:
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)
Należy zwrócić uwagę na kilka kwestii. Domyślną oktawą dla nut jest oktawa 4, gdzie A4 to 440 Hz (nuta używana do strojenia orkiestry). Oktawy zmieniają się w C, więc C3 jest o jeden półton wyższy niż B2. Powodem tego make_sine
jest to, że bez niego słyszalne są trzaski podczas rozpoczynania i zatrzymywania nut.
c
w do.call
, a ostatnie zadanie w make_sine
to niepotrzebne.
do.call
. Zbyt łatwo jest wpaść w pułapkę, że zrobiłeś coś podobnego a <- 1; b <- 2; c <- 3
po drodze i w takiej sytuacji do.call(c, ...)
zawiedzie, a c(1, 2, 3)
nie. Całkowicie zgadzam się jednak z ostatnim punktem i usunęliśmy niepotrzebne przypisanie!
do.call("c", ...)
będzie działać. Spróbuj c <- 4; do.call("c", list(1, 2))
. R jest dość spójne, ponieważ w większości przypadków argument akceptujący funkcję zaakceptuje samą funkcję lub nazwę funkcji. W niektórych przypadkach (np lapply
), jest za pomocą match.fun
, natomiast w innych, na przykład do.call
, getMethod
, realizacja jest kod C (na drugi za pośrednictwem wywołania C_R_getGeneric
). Rozumiem, dlaczego stylistycznie wolisz przekazać funkcję, a nie jej nazwę, ale to drugie zachowanie jest dobrze udokumentowane.
symbol
następuje nawias, nawet jeśli inna symbol
istnieje dalej na ścieżce wyszukiwania. Pozwala c <- 4; c(1, 2)
to na normalną pracę, podczas c <- paste0; c(1, 2)
gdy podstawa nie będzie używana c
. Widziałem zamieszanie stworzone przez to, gdy ktoś całkiem szczęśliwie dzwonił c(1, 2)
w swoim kodzie, ale potem do.call(c, ...)
nie działał. Pod koniec dnia nie przejmuję się tym, czy funkcje są dostarczane przez nazwę, czy bezpośrednio.