Effectively divide a large audio file into R

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:

<a href="/cdn-cgi/l/email-protection" data-cfemail="6d19040e022d1e19081f0802">[email protected]</a> <- TRUE
<a href="/cdn-cgi/l/email-protection" data-cfemail="e6928f8589a6948f818e92">[email protected]</a> <- <a href="/cdn-cgi/l/email-protection" data-cfemail="3b4f5258547b575e5d4f">[email protected]</a>

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(<a href="/cdn-cgi/l/email-protection" data-cfemail="e1809485888e8c8e85a18d848795">[email protected]</a>,ncol=length(breaks))))+
system.time(replicate(100,matrix(<a href="/cdn-cgi/l/email-protection" data-cfemail="e78692838e888a8883a7958e808f93">[email protected]</a>,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?

Per Frank's request, here's one possible approach. Extract the [email protected] and [email protected] slots' vectors of sound data, then break each up into equal-length sections in one step something like:

leftsong<<a href="/cdn-cgi/l/email-protection" data-cfemail="270a4652434e48674b424153">[email protected]</a>
leftmat<-matrix(leftsong, ncol=(seglen*freq)

Where I've assumed seglen is the distance between breaks[i] and breaks[i+1] . New wave objects can then be created and processed from the matching rows in leftmat and rightmat .

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章