Иногда мои процессы R занимают много времени, и я не могу сесть за компьютер, чтобы увидеть, когда все это закончится. Я подумал, что было бы круто составить выбор из триумфальных мелодий и поставить их в конце моих сценариев, чтобы, когда процесс выполняется успешно, я мог слышать что-то, что говорит мне, что все прошло хорошо.

Поэтому я изучил пакет audio в R, который позволяет создавать и воспроизводить звуки, взаимодействуя с аудиоустройствами на основе сэмплов на вашем компьютере, и сохранять их в виде файлов wave. Строки текста и чисел можно преобразовать в значения частоты, а затем, в сочетании с данными о длине ноты, преобразовать в синусоидальные волны. Затем это создаст небольшую аккуратную мелодию, которую можно будет воспроизвести в вашем сеансе R или на любом мультимедийном устройстве.

Написание темы "Звездных войн"

Начнем с загрузки необходимых пакетов:

library(dplyr)
library(audio)

Давайте также определим значения нот в октаве. Для этого вам нужно думать полутонами, чтобы учесть балки и диезы, которые будут определены позже:

notes <- c(A = 0, B = 2, C = 3, D = 5, E = 7, F = 8, G = 10)

Теперь давайте напишем заметки для темы «Звездных войн», игнорируя длину каждой заметки. Вы можете сделать это по нотам, если умеете их читать. Вы можете организовать это как угодно в формате вектора символов, поскольку мы очистим его позже. Я решил написать строку для каждого такта с примечаниями, разделенными пробелами внутри строк.

Позже мы настроим код, чтобы понимать символ # как диез, а b как плоский, чтобы сделать вещи интуитивно понятными для музыкантов.

Нам нужно будет разделить октавы в музыке. Позже я настрою свой код для интерпретации простой ноты, например A как находящейся в четвертой октаве, а любая другая октава обозначается путем помещения числа октавы после ноты (например, A5 или B3)

pitch <- paste("D D D",
               "G D5",
               "C5 B A G5 D5",
               "C5 B A G5 D5",
               "C5 B C5 A D D D",
               "G D5",
               "C5 B A G5 D5",
               "C5 B A G5 D5",
               "C5 B C5 A D D",
               "E E C5 B A G",
               "G A B A E F# D D",
               "E E C5 B A G",
               "D5 A D D",
               "E E C5 B A G",
               "G A B A E F# D5 D5",
               "G5 F5 D#5 D5 C5 A# A G",
               "D5 D D D",
               "G D5",
               "C5 B A G5 D5",
               "C5 B A G5 D5",
               "C5 B C5 A D D D",
               "G D5",
               "C5 B A G5 D5",
               "G5 F5 D#5 Bb5 A5",
               "G5 G G G G")

И затем вы можете написать числовой вектор с длиной нот, с одной долей, представленной числовым 1. Чтобы не усложнять свои обозначения, я стараюсь выделять одну строку для каждого такта.

duration <- c(0.33, 0.33, 0.33, 
              2, 2, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 0.33, 0.33, 0.33, 
              2, 2, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 0.75, 0.25,
              1.5, 0.5, 0.5, 0.5, 0.5, 0.5, 
              0.33, 0.33, 0.33, 0.75, 0.25, 1, 0.75, 0.25, 
              1.5, 0.5, 0.5, 0.5, 0.5, 0.5,
              1, 2, 0.75, 0.25,
              1.5, 0.5, 0.5, 0.5, 0.5, 0.5, 
              0.33, 0.33, 0.33, 0.75, 0.25, 1, 0.75, 0.25, 
              0.75, 0.25, 0.75, 0.25, 0.75, 0.25, 0.75, 0.25, 
              3, 0.33, 0.33, 0.33,   
              2, 2, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 0.33, 0.33, 0.33, 
              2, 2, 
              0.33, 0.33, 0.33, 2, 1, 
              0.33, 0.33, 0.33, 2, 1, 
              1,  0.33, 0.33, 0.33, 1)

Теперь у нас есть все необходимое сырье.

Преобразование нот в частоты в синусоиде

Сначала мы конвертируем наши векторы высоты тона и длительности в кадр данных, где каждая нота является элементом, имеющим высоту и длительность. В случае с темой «Звездных войн» всего 126 нот.

starwars <- data_frame(pitch = strsplit(pitch, " ")[[1]],
                     duration = duration)

Теперь мы расширим этот фрейм данных, включив в него несколько новых столбцов:

  • octave который извлекает из pitch нотации, в какой октаве нота должна быть сыграна
  • note, который извлекает исходное значение ноты из нашего исходного notes вектора, а затем настраивает его для резких, плоских и октавных вариантов.
  • freq, который преобразует note в частоту в МГц
starwars <-
  starwars %>%
  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)

Теперь мы определим функцию, которая преобразует ноту и продолжительность в синусоидальную волну. Для этого мы установим темп в ударах в минуту и ​​частоту дискретизации (обычно 44,1 кГц):

tempo <- 150
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))
}

Наконец, мы просто применяем функцию к нашим freq и duration столбцам в starwars фрейме данных, а затем просто проигрываем мелодию.

starwars_wave <-
  mapply(make_sine, starwars$freq, starwars$duration) %>%
  do.call("c", .)
audio::play(starwars_wave)

Вы также можете сохранить мелодию в виде файла .wav и использовать его по своему усмотрению с помощью

audio::save.wave(starwars_wave, "starwars.wav")

Здесь есть весь код, который вам нужен, чтобы вы могли попробовать это, но вот ссылка на код в GitHub, если вы хотите вытащить его и поиграть с другими мелодиями. Не стесняйтесь отправлять свои мелодии обратно в тот же репозиторий GitHub в отдельных файлах R, чтобы другие могли им насладиться.

Изначально я был чистым математиком, затем стал психометриком и специалистом по анализу данных. Я с энтузиазмом отношусь к применению всех этих дисциплин к сложным человеческим вопросам. Я также помешан на кодировании и большой поклонник японских ролевых игр. Найдите меня в LinkedIn или Twitter.