Efficiently split a large audio file in R

Viewed 2211


Previously I asked this question on SO about splitting an audio file. The answer I got from @Jean V. Adams worked relatively (downside: input was stereo and output was mono, not stereo) well for small sound objects:

library(seewave)

# your audio file (using example file from seewave package)
data(tico)
audio <- tico # this is an S4 class object
# the frequency of your audio file
freq <- 22050
# the length and duration of your audio file
totlen <- length(audio)
totsec <- totlen/freq

# the duration that you want to chop the file into
seglen <- 0.5

# defining the break points
breaks <- unique(c(seq(0, totsec, seglen), totsec))
index <- 1:(length(breaks)-1)
# a list of all the segments
subsamps <- lapply(index, function(i) cutw(audio, f=freq, from=breaks[i], to=breaks[i+1]))

I applied this solution to one (out of around 300) of the files I'm preparing for analysis (~150 MB), and my computer worked on it for ( > 5 hours now), but I ended up closing the session before it finished.

Does anyone have any thoughts or solutions to efficiently perform this task of splitting up a large audio file (specifically, an S4 class Wave object) into smaller pieces using R? I'm hoping to cut down drastically on the time it takes to make smaller files out of these larger files, and I'm hoping to use R. However, if I cannot get R to do the task efficiently, I would appreciate suggestions of other tools for the job. The example data above is mono, but my data is in stereo. The example data can be made to be stereo using:

tico@stereo <- TRUE
tico@right <- tico@left

UPDATE

I identified another solution that builds on work from the first solution:

lapply(index, function(i) audio[(breaks[i]*freq):(breaks[i+1]*freq)])

Comparing the performance of three solutions:

# Solution suggested by @Jean V. Adams
system.time(replicate(100,lapply(index, function(i) cutw(audio, f=freq, from=breaks[i], to=breaks[i+1], output="Wave"))))
user  system elapsed 
1.19    0.00    1.19 
# my modification of the previous solution
system.time(replicate(100,lapply(index, function(i) audio[(breaks[i]*freq):(breaks[i+1]*freq)])))
user  system elapsed 
0.86    0.00    0.85 

# solution suggested by @CarlWitthoft 
audiomod <- audio[(freq*breaks[1]):(freq*breaks[length(breaks)-1])] # remove unequal part at end
system.time(replicate(100,matrix(audiomod@left,ncol=length(breaks))))+
system.time(replicate(100,matrix(audiomod@right,ncol=length(breaks))))
user  system elapsed 
0.25    0.00    0.26 

The method using indexing (i.e. [) seems to faster (3-4x). @CarlWitthoft's solution is even faster, the downside is that it puts the data into a matrix rather than multiple Wave objects, which I will be saving using writeWave. Presumably, convert from the matrix format to a separate Wave objects will be relatively trivial if I properly understand how to create this type of S4 object. Any further room for improvement?

2 Answers
Related