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.
rasterImagerenderować 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_sinejest to, że bez niego słyszalne są trzaski podczas rozpoczynania i zatrzymywania nut.
cw do.call, a ostatnie zadanie w make_sineto niepotrzebne.
do.call. Zbyt łatwo jest wpaść w pułapkę, że zrobiłeś coś podobnego a <- 1; b <- 2; c <- 3po 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.
symbolnastępuje nawias, nawet jeśli inna symbolistnieje 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.