¿Cómo puedo reproducir música de cumpleaños con R? [cerrado]

80

Me gustaría reproducir música usando R. Si bien R puede no ser la mejor herramienta para este propósito, es la herramienta con la que estoy familiarizado y sería bueno demostrar a otros su flexibilidad en una ocasión tan feliz.

¿Cómo podría lograr esto?

Feng Tian
fuente
7
¿Por qué querría reproducir música BD a través de R? R es un lenguaje de programación estadística, estoy seguro de que existen mejores plataformas para este tipo de tareas.
David Arenburg
13
@DavidArenburg eso es ciertamente cierto, pero eche un vistazo a la página 33 de este archivo tinyurl.com/odlurth (es "R Graphics" de Paul Murrell). El hecho de que haya mejores programas para hacer algo no debería impedir que
intentemos
11
En mi humilde opinión, puede haber algo de mérito en esa pregunta. El análisis de sonido ( 2 ) es una tarea analítica legítima, por lo que es posible imaginar una situación en la que uno esté dispuesto a verificar organolépticamente muestras de sonido mientras realiza un trabajo analítico. Habiendo dicho eso, la música de cumpleaños en el título es bastante extraña.
Konrad
8
No fomente este tipo de preguntas porque existe la posibilidad de que se hagan I would like to play video using R.
Avinash Raj
7
@AvinashRaj, curiosamente, pensé en eso como una continuación :) con toda seriedad, las opciones probablemente serían triviales (lanzar un programa externo), inútiles (reimplementar un reproductor de video en código externo) o inutilizables (usando código R para decodificar una transmisión de video y rasterImagerenderizar cada cuadro)
Nick Kennedy

Respuestas:

237

Si realmente quisieras hacer esto:

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)

Tenga en cuenta que install.packages("audio")primero deberá hacerlo . Si ya tiene un archivo específico, primero deberá convertirlo a formato WAV.

Si deseaba algo un poco más de programación que reproducir un archivo WAV, aquí hay una versión que genera la melodía a partir de una serie de ondas sinusoidales:

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)

Hay algunos puntos a tener en cuenta. La octava predeterminada para las notas es la octava 4, donde A4 está a 440 Hz (la nota utilizada para afinar la orquesta). Las octavas cambian en C, por lo que C3 es un semitono más alto que B2. El motivo del fundido de entrada make_sinees que sin él hay estallidos audibles al iniciar y detener notas.

Nick Kennedy
fuente
6
@DavidArenburg Gracias. Solo para hacer las cosas un poco más ridículas, ahora agregué un código que genera la melodía a partir de los primeros principios usando ondas sinusoidales :)
Nick Kennedy
Respuesta impresionante. Aprendí algo nuevo: no sabía sobre el desvanecimiento, y un experimento mío reciente tenía este problema exacto. Nitpick: no hay razón para citar cen do.call, y la última asignación de make_sineun carácter superfluo.
Konrad Rudolph
1
@KonradRudolph gracias. Siempre suelo citar el nombre de la función en formato do.call. Es muy fácil caer en la trampa de haber hecho algo así a <- 1; b <- 2; c <- 3en el camino, y en esa situación do.call(c, ...)fallará, mientras c(1, 2, 3)que no. Sin embargo, estoy completamente de acuerdo con el último punto y ¡hemos eliminado la tarea innecesaria!
Nick Kennedy
1
@KonradRudolph Realmente do.call("c", ...)funcionará. Prueba c <- 4; do.call("c", list(1, 2)). R es razonablemente consistente en que, en la mayoría de los casos, un argumento que acepta una función aceptará la función en sí o el nombre de la función. En algunos casos (p lapply. Ej. ), Esto es vía match.fun, mientras que en otros, p. Ej do.call. getMethod, La implementación está en el código C (para este último a través de una llamada a C_R_getGeneric). Puedo ver por qué estilísticamente puede preferir pasar la función en lugar de su nombre, pero este último comportamiento está bien documentado.
Nick Kennedy
2
@KonradRudolph Bastante justo. Supongo que el problema relacionado es que R siempre buscará una función si a symbolestá seguida de paréntesis, incluso si symbolexiste otra más adelante en la ruta de búsqueda. Esto permite c <- 4; c(1, 2)trabajar con normalidad, mientras c <- paste0; c(1, 2)que no utilizará la base c. He visto confusión creada por esto donde alguien ha estado llamando felizmente c(1, 2)en su código, pero luego do.call(c, ...)no funciona. Al final del día, no estoy muy seguro de si las funciones se proporcionan por nombre o directamente.
Nick Kennedy