Làm cách nào để phát nhạc mừng sinh nhật bằng R? [đóng cửa]


80

Tôi muốn chơi nhạc bằng R. Mặc dù R có thể không phải là công cụ tốt nhất cho mục đích này, nhưng nó là công cụ mà tôi quen thuộc và sẽ rất vui khi chứng minh cho người khác thấy sự linh hoạt của nó trong một dịp vui như vậy.

Làm thế nào tôi có thể thực hiện điều này?


7
Tại sao bạn muốn phát nhạc BD qua R? R là một ngôn ngữ lập trình thống kê, tôi chắc chắn rằng có những nền tảng tốt hơn cho những tác vụ như vậy.
David Arenburg

13
@DavidArenburg điều đó chắc chắn đúng, nhưng hãy xem trang 33 của tệp tinyurl.com/odlurth này (đó là "R Graphics" của Paul Murrell). Thực tế là có những chương trình tốt hơn để làm điều gì đó không nên ngăn cản chúng ta cố gắng để giúp đỡ Feng Tian (có thể là một cái gì đó mới trong quá trình này)
Maze

11
IMHO, có thể có một số giá trị cho câu hỏi đó. Phân tích âm thanh ( 2 ) là một nhiệm vụ phân tích hợp pháp nên có thể dự kiến ​​tình huống mà người đó có thể sẵn sàng xác minh về mặt cảm quan các mẫu âm thanh trong khi thực hiện công việc phân tích. Phải nói rằng, âm nhạc sinh nhật trong tiêu đề khá kỳ quặc.
Konrad

8
Không khuyến khích những câu hỏi kiểu này vì có thể sẽ có cơ hội hỏi I would like to play video using R.
Avinash Raj

7
@AvinashRaj thú vị là tôi đã coi đó là một phần tiếp theo :) nghiêm túc mà nói, các tùy chọn có thể sẽ là tầm thường (khởi chạy chương trình bên ngoài), vô nghĩa (thực hiện lại trình phát video trong mã bên ngoài) hoặc không sử dụng được (sử dụng mã R để giải mã luồng video và rasterImagehiển thị từng khung hình)
Nick Kennedy

Câu trả lời:


237

Nếu bạn thực sự muốn làm điều này:

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)

Lưu ý bạn sẽ cần phải làm install.packages("audio")trước. Nếu bạn đã có một tệp cụ thể, trước tiên bạn cần chuyển đổi nó sang định dạng WAV.

Nếu bạn muốn thứ gì đó mang tính lập trình nhiều hơn một chút so với phát tệp WAV, thì đây là phiên bản tạo giai điệu từ một loạt các sóng sin:

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)

Có một số điểm cần lưu ý. Quãng tám mặc định cho các nốt là quãng 8, trong đó A4 ở tần số 440 Hz (nốt dùng để điều chỉnh dàn nhạc). Các quãng tám thay đổi ở C, vì vậy C3 cao hơn B2 một nửa cung. Lý do cho sự mờ dần make_sinelà do không có nó sẽ có âm thanh bật lên khi bắt đầu và dừng các nốt.


6
@DavidArenburg Cảm ơn. Chỉ cần để làm cho mọi việc hơi lố bịch hơn, bây giờ tôi đã thêm một số mã để tạo giai điệu từ các nguyên tắc đầu tiên sử dụng sóng sin :)
Nick Kennedy

Câu trả lời tuyệt vời. Tôi học được một điều mới: Tôi không biết về sự phai màu, và một thí nghiệm gần đây của tôi đã gặp vấn đề chính xác này. Nitpick: không có lý do để trích dẫn ctrong do.call, và nhiệm vụ cuối cùng trong make_sinelà không cần thiết.
Konrad Rudolph

1
@KonradRudolph cảm ơn. Tôi có xu hướng luôn luôn trích dẫn tên hàm trong do.call. Tất cả đều quá dễ dàng để rơi vào cái bẫy của việc đã làm một điều gì đó giống như a <- 1; b <- 2; c <- 3trên đường đi, và trong tình huống đó do.call(c, ...)sẽ thất bại, trong khi c(1, 2, 3)thì không. Tuy nhiên, hoàn toàn đồng ý với điểm thứ hai và đã loại bỏ nhiệm vụ không cần thiết!
Nick Kennedy

1
@KonradRudolph Trên thực tế do.call("c", ...)sẽ hoạt động. Cố gắng c <- 4; do.call("c", list(1, 2)). R nhất quán hợp lý ở chỗ trong hầu hết các trường hợp, một đối số chấp nhận một hàm sẽ chấp nhận chính hàm hoặc tên của hàm. Trong một số trường hợp (ví dụ lapply), điều này là thông qua match.fun, trong khi ở những người khác, ví dụ như do.call, getMethod, việc thực hiện là trong mã C (dành cho sau này thông qua một cuộc gọi đến C_R_getGeneric). Tôi có thể hiểu tại sao về mặt phong cách, bạn có thể thích truyền hàm hơn là tên của nó, nhưng hành vi sau này đã được ghi nhận đầy đủ.
Nick Kennedy

2
@KonradRudolph Đủ công bằng. Tôi đoán vấn đề liên quan là R sẽ luôn tìm kiếm một hàm nếu a symbolđược theo sau bởi dấu ngoặc đơn, ngay cả khi một hàm khác symboltồn tại xa hơn trên đường tìm kiếm. Điều này cho phép c <- 4; c(1, 2)hoạt động như bình thường, trong khi c <- paste0; c(1, 2)sẽ không sử dụng đế c. Tôi đã thấy sự nhầm lẫn được tạo ra bởi điều này trong đó ai đó đã khá vui vẻ gọi c(1, 2)vào mã của họ, nhưng sau đó do.call(c, ...)không hoạt động. Vào cuối ngày, tôi không cảm thấy mạnh mẽ về việc liệu các chức năng được cung cấp theo tên hay trực tiếp.
Nick Kennedy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.