Иногда мои процессы 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.