Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to code music in R and play it back? (Mac OS X) [closed]

Tags:

r

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?

like image 562
M. Beausoleil Avatar asked Sep 30 '15 03:09

M. Beausoleil


2 Answers

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)
like image 106
rakshith91 Avatar answered Oct 20 '22 22:10

rakshith91


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)

enter image description here

Update:

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)
}
like image 22
M. Beausoleil Avatar answered Oct 20 '22 22:10

M. Beausoleil