I wonder if there is a way to write a script in r to create music. Like coding program (SuperCollider or, less coding but still, Pure Data), I want to know if there is a way to generate sound in R.
Actually, I know this How can I play birthday music using R?, which is very nice. But I want to do chords and multi instrumental composition. Is it possible?
Is there a simpler way to play music in R than the Happy birthday link?
You can create music in R programming using the tuneR library
First you need to create simple sine waves for each note and concatenate all the notes into a vector.
Now that the tune will be ready, you can edit your sound using different sound processing techniques like timbre, filtering etc.
Example to create a simple A4 note:
library(tuneR) #import the tuneR library
setWavPlayer("audacious")
f=440 #frequency of A4 note
sr=8000
bits=16
secs=2 #length of the note set to 2
amp=1
t=seq(0, secs, 1/sr)
y= amp*sin(2*pi*f*t) #make a sinewave with above attributes
s=floor(2^(bits-2)*y) #floor it to make it an integer value
u=Wave(s, samp.rate=sr, bit=bits) #make a wave structure
play(u)
To concatenate two notes x and y, we simply use vector notation:
z=c(x,y)
w= Wave(z, samp.rate=sr, bit-bits)
To play two notes simultaneously (play chords for instance)
z=x+y
w= Wave(z, samp.rate=sr, bit-bits)
For the moment, this is the best that I've come up with:
library("audio")
library(tuneR) #import the tuneR library
for (i in 1:10) {
yo=abs(round(rnorm(1,400,500)))
f=yo #frequency of A4 note
sr=1000000
bits=116
secs=5 #length of the note set to 2
amp=1
t=seq(0, secs, 1/sr)
y= amp*sin(2*pi*f*t) #make a sinewave with above attributes
s=floor(2^(bits-2)*y) #floor it to make it an integer value
# u=Wave(s, samp.rate=sr, bit=bits) #make a wave structure
u=audioSample(x = s, rate = sr,bits = bits)
audio::play(u)
}
We could experiment with setWavPlayer('/usr/bin/afplay')
That's my modern random canon.
library(tuneR)
setWavPlayer('/usr/bin/afplay')
muss = NULL
nbnotes = 100
for (i in 1:nbnotes) {
yo = abs(round(rnorm(nbnotes,400,200)))
lengthhtime = abs(rnorm(nbnotes,0.5,0.1))
f=yo[i] #frequency of A4 note
titi = lengthhtime[i]
sr=1000
bits=16
secs=titi
amp=1
t=seq(from = 0, to = secs, by = 1/sr)
y= amp*sin(2*pi*f*t)
s=floor(2^(bits-2)*y)
muss = c(muss,s)
}
u=Wave(left = muss,right = rev(muss), samp.rate=sr, bit=bits) #make a wave structure
tuneR::play(u)
Here is a function I created to generate a random melody:
melodymachine <- function(nbnotes, seed = NULL) {
if(!is.null(seed)){set.seed(seed)}
muss = NULL
for (i in 1:nbnotes) {
yo = abs(round(rnorm(nbnotes,400,200)))
lengthhtime = abs(rnorm(nbnotes,0.0,0.2))
f=yo[i] #frequency of A4 note
titi = lengthhtime[i]
sr=1000
bits=16
secs=titi #length of the note set to 2
amp=0.99
t=seq(from = 0, to = secs, by = 1/sr)
y= amp*sin(2*pi*f*t) #make a sinewave with above attributes
s=floor(2^(bits-2)*y) #floor it to make it an integer value
muss = c(muss,s)
}
return(muss)
}
Here is an example of it:
mel1 = melodymachine(6,seed = 1)
mel2 = melodymachine(6,seed = 1)
mel3 = melodymachine(6,seed = 1)
mel4 = melodymachine(6,seed = 1)
mel5 = melodymachine(6,seed = 1)
u=Wave(left = c(mel1,mel2,mel3,mel4,mel5),
right = rev(c(mel1,mel2,mel3,mel4,mel5)),
samp.rate=sr, bit=bits) #make a wave structure
tuneR::play(u)
You can take a look at the wave here:
plot(u,
info = TRUE,
xunit = c("time"),
ylim = NULL, main = "My random melody",
sub = "made by me",
xlab = NULL, ylab = NULL,
simplify = FALSE, nr = 2500,
axes = TRUE, yaxt = par("yaxt"),
las = 1,
center = TRUE)
Below are a couple of function that will help you get started playing chords in R.
library(audio)
library(tuneR)
testit <- function(x)
{
p1 <- proc.time()
Sys.sleep(x)
proc.time() - p1 # The cpu usage should be negligible
}
full.scale = function(root = 440, dist.notes = 2^(1/12), nb.notes=12) {
all.notes = NULL
for (k in 1:nb.notes) {
if(k==1){all.notes = c(all.notes, root)}
my.note = root*(dist.notes)^k
all.notes = c(all.notes, my.note)
}
return(all.notes)
}
fq.gen <- function(f = 440,
octave = 2,
secs=1/2, sr=100000,
bits=116, amp=0.1,
play = FALSE) {
octave.select = 2^c(0:6)
t = seq(0, secs, 1/sr)
y = amp*sin(pi*octave.select[octave]*f*t) #make a sinewave with above attributes
(by = round(2/3*pi*(1/(f*octave.select[octave])),5))
s=floor(2^(bits-2)*y) #floor it to make it an integer value
u = audioSample(x = s, rate = sr,bits = bits)
if (play) {
audio::play(x = u)
}
return(list(u = u, y= y, t =t, by = by, secs=secs))
}
all.notes.from.western.scale = full.scale(root = 16.35,dist.notes = 2^(1/12), nb.notes = 107)
note.name = rep(c("c","cs","d","ds","e","f","fs","g","gs","a","as","b"),9)
octave.note = rep(seq(0,(length(all.notes.from.western.scale)/12-1), by =1), each = 12)
data.notes.wstrn = data.frame(note = note.name,
octv = octave.note,
fq = all.notes.from.western.scale,
note.otv = paste0(note.name,octave.note))
a.scale = full.scale(root = 440,dist.notes = 2^(1/12), nb.notes = 12)
c.scale = full.scale(root = 523.25)
cs.scale = full.scale(root = 554.37)
# Major chord
for (i in 1) {
secs = 2
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "a4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "cs4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "e4","fq"],octave = 2, secs = secs,play = T)
}
# Minor chord
for (i in 1) {
secs = 2
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "a4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "c4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "e4","fq"],octave = 2, secs = secs,play = T)
}
# augmented chord
for (i in 1) {
secs = 2
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "a4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "cs4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "f4","fq"],octave = 2, secs = secs,play = T)
}
# Diminished chord
for (i in 1) {
secs = 2
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "a4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "c4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "ds4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "fs4","fq"],octave = 2, secs = secs,play = T)
}
# Resolution!
for (i in 1) {
secs = 2
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "g4","fq"],octave = 1, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "b4","fq"],octave = 1, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "d5","fq"],octave = 1, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "g5","fq"],octave = 1, secs = secs,play = T)
}
# C13 chord
for (i in 1) {
secs = 4
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "g4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "b4","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "d5","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "f5","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "a5","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "c6","fq"],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = data.notes.wstrn[data.notes.wstrn$note.otv == "e6","fq"],octave = 2, secs = secs,play = T)
}
for (i in 1:length(a.scale)) {
secs = 1/5
datadf = fq.gen(f = a.scale[i], secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 3, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 4, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 5, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 6, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 7, secs = secs,play = T)
datadf.col = do.call(what = cbind, datadf)
total = which(round(datadf.col[,"t"],5) == fq.gen()$by)
datadf.col[which(round(datadf.col[,"t"],5) == fq.gen()$by),]
testit(datadf$secs-.08)
}
for (i in 1:length(a.scale)) {
secs = 1/5
datadf = fq.gen(f = a.scale[i], secs = secs,play = T)
datadf = fq.gen(f = cs.scale[i],octave = 2, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 3, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 3, secs = secs,play = T)
datadf = fq.gen(f = cs.scale[i],octave = 3, secs = secs,play = T)
datadf = fq.gen(f = a.scale[i],octave = 5, secs = secs,play = T)
datadf.col = do.call(what = cbind, datadf)
total = which(round(datadf.col[,"t"],5) == fq.gen()$by)
datadf.col[which(round(datadf.col[,"t"],5) == fq.gen()$by),]
testit(datadf$secs-.08)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With