Jak mogę odtwarzać muzykę urodzinową za pomocą R? [Zamknięte]


80

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ąć?


7
Dlaczego miałbyś chcieć odtwarzać muzykę BD przez R? R to język programowania statystycznego, jestem pewien, że istnieją lepsze platformy do takich zadań.
David Arenburg

13
@DavidArenburg to z pewnością prawda, ale spójrz na stronę 33 tego pliku tinyurl.com/odlurth (to "R Graphics" Paula Murrella). Fakt, że istnieją lepsze programy do zrobienia czegoś, nie powinien powstrzymać nas przed próbą pomocy Feng Tian (prawdopodobnie coś nowego w procesie)
MaZe

11
IMHO, to pytanie może mieć jakąś wartość. Analiza dźwięku ( 2 ) jest uzasadnionym zadaniem analitycznym, więc można sobie wyobrazić sytuację, w której ktoś może chcieć zweryfikować organoleptycznie próbki dźwiękowe podczas wykonywania prac analitycznych. Mimo to, tytułowa muzyka urodzinowa jest raczej dziwna.
Konrad

8
Nie zachęcaj do tego rodzaju pytań, ponieważ istnieje szansa, że ​​je zadasz I would like to play video using R.
Avinash Raj

7
@AvinashRaj Co ciekawe, pomyślałem o tym jako o kontynuacji :) z całą powagą, opcje prawdopodobnie byłyby albo trywialne (uruchom zewnętrzny program), bezcelowe (reimplementacja odtwarzacza wideo w zewnętrznym kodzie) lub bezużyteczne (używając kodu R dekodować strumień wideo i rasterImagerenderować każdą klatkę)
Nick Kennedy,

Odpowiedzi:


237

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.


6
@DavidArenburg Thanks. Wystarczy, aby dokonać rzeczy nieco bardziej śmieszny, ja teraz dodałem trochę kodu, który generuje melodię z pierwszych zasad wykorzystujących fale sinusoidalne :)
Nick Kennedy

Świetna odpowiedź. Nauczyłem się czegoś nowego: nie wiedziałem o zanikaniu, a mój niedawny eksperyment miał dokładnie ten problem. Nitpick: nie ma powodu, by zacytować cw do.call, a ostatnie zadanie w make_sineto niepotrzebne.
Konrad Rudolph

1
@KonradRudolph thanks. Zwykle zawsze cytuję nazwę funkcji w 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!
Nick Kennedy

1
@KonradRudolph Właściwie 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.
Nick Kennedy

2
@KonradRudolph W porządku. Wydaje mi się, że powiązany problem polega na tym, że R zawsze będzie szukał funkcji, jeśli po a 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.
Nick Kennedy,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.