Як я можу відтворити музику на день народження за допомогою R? [зачинено]


80

Я хотів би відтворювати музику з використанням R. Хоча R, можливо, не найкращий інструмент для цієї мети, це інструмент, який мені знайомий, і було б непогано продемонструвати іншим свою гнучкість з такого радісного випадку.

Як я міг це досягти?


7
Чому ви хочете відтворювати музику BD через R? R - мова статистичного програмування, я впевнений, що існують кращі платформи для таких завдань.
Девід Аренбург,

13
@DavidArenburg це, безумовно, правда, але загляньте на сторінку 33 цього файлу tinyurl.com/odlurth (це "Графіка R" Пола Меррелла). Той факт, що існують кращі програми, щоб щось зробити, не повинен заважати нам намагатися допомогти Фен Тяню (можливо, щось нове в процесі)
MaZe

11
ІМХО, може бути певна заслуга у цьому питанні. Аналіз звуку ( 2 ) є законним аналітичним завданням, тому можна передбачити ситуацію, коли той, хто проводить аналітичну роботу, може бути готовий провести органолептичну перевірку зразків звуку. Сказавши це, музика до дня народження в назві досить дивна.
Конрад

8
Не заохочуйте такі запитання, оскільки може бути шанс поставити запитання I would like to play video using R.
Avinash Raj

7
@AvinashRaj цікаво, я думав про це як про продовження :), якщо говорити серйозно, варіанти, мабуть, будуть або тривіальними (запуск зовнішньої програми), безглуздими (перевстановлення відеопрогравача у зовнішньому коді) або непридатними (із використанням коду R) для декодування відеопотоку та rasterImageдля рендерінгу кожного кадру)
Нік Кеннеді

Відповіді:


237

Якщо ви дійсно хотіли це зробити:

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)

Зверніть увагу, що вам потрібно install.packages("audio")спочатку. Якщо у вас вже є певний файл, спочатку потрібно перетворити його у формат WAV.

Якщо ви хочете чогось більш програмного, ніж відтворення файлу WAV, ось версія, яка генерує мелодію з серії синусоїд:

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)

Є кілька моментів, на які слід звернути увагу. Октавою за замовчуванням для нот є октава 4, де А4 знаходиться на частоті 440 Гц (нота, що використовується для налаштування оркестру). Октави змінюються при C, тому C3 на півтону вище, ніж B2. Причина затухання make_sineполягає в тому, що без нього лунають звуки при запуску та зупинці нот.


6
@DavidArenburg Дякую. Щоб зробити речі трохи смішнішими, я зараз додав код, який генерує мелодію з перших принципів з використанням синусоїд :)
Нік Кеннеді

Чудова відповідь. Я дізнався щось нове: я не знав про згасання, і недавній мій експеримент мав саме цю проблему. Чіплятися: немає підстав процитувати cв do.call, і останнє призначення в make_sineнепотрібно.
Конрад Рудольф

1
@KonradRudolph дякую. Я схильний завжди цитувати ім'я функції в do.call. Надто легко потрапити в пастку того, що зробив щось на зразок a <- 1; b <- 2; c <- 3шляху, і в цій ситуації do.call(c, ...)зазнає невдачі, тоді як c(1, 2, 3)ні. Повністю погодьтеся з останнім пунктом і прибрали непотрібне призначення!
Нік Кеннеді

1
@KonradRudolph Насправді do.call("c", ...)буде працювати. Спробуйте c <- 4; do.call("c", list(1, 2)). R є достатньо послідовним у тому, що в більшості випадків аргумент, який приймає функцію, приймає або саму функцію, або назву функції. У деяких випадках (наприклад lapply) це відбувається через match.fun, тоді як в інших, наприклад do.call, getMethodреалізація знаходиться в коді С (для останнього - через виклик C_R_getGeneric). Я розумію, чому стилістично ви віддаєте перевагу передачі функції, а не її імені, але остання поведінка добре задокументована.
Нік Кеннеді

2
@KonradRudolph Досить справедливо. Я думаю, пов’язана проблема полягає в тому, що R завжди буде шукати функцію, якщо за a symbolслідують дужки, навіть якщо інша symbolіснує далі по шляху пошуку. Це дозволяє c <- 4; c(1, 2)працювати в звичайному режимі, в той час як c <- paste0; c(1, 2)не використовуватиме основу c. Я бачив плутанину, яка виникає внаслідок цього, коли хтось із задоволенням закликає c(1, 2)свій код, але потім do.call(c, ...)не працює. Зрештою, я не дуже впевнений у тому, чи надаються функції за іменем чи безпосередньо.
Нік Кеннеді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.