以前我问this question on SO about splitting an audio file。我从@Jean V. Adams那里得到的答案是相对的(下方:输入是立体声,输出是单声道,而不是立体声)适用于小型声音对象:
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]))
我将此解决方案应用于我准备分析的文件中的一个(大约300个)(~150 MB),并且我的计算机正在处理它(现在> 5小时),但我结束了在完成之前关闭会议。
有没有人有任何想法或解决方案来有效地执行使用R将大型音频文件(特别是S4类Wave对象)拆分成小块的任务?我希望大幅减少从这些较大的文件中制作较小文件的时间,并且我希望使用R.但是,如果我不能让R有效地完成任务,我我希望得到其他工具的建议。上面的示例数据是单声道,但我的数据是立体声。可以使用以下方式将示例数据设为立体声:
tico@stereo <- TRUE
tico@right <- tico@left
我发现了另一个基于第一个解决方案的工作的解决方案:
lapply(index, function(i) audio[(breaks[i]*freq):(breaks[i+1]*freq)])
比较三种解决方案的表现:
# 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
使用索引(即[
)的方法似乎更快(3-4x)。 @ CarlWitthoft的解决方案甚至更快,缺点是它将数据放入矩阵而不是多个Wave
对象,我将使用writeWave
保存。据推测,如果我正确理解如何创建这种类型的S4对象,从矩阵格式转换为单独的Wave
对象将是相对微不足道的。还有进一步改进的空间吗?
答案 0 :(得分:3)
我最终使用的方法是建立@CarlWitthoft和@JeanV.Adams提供的解决方案。与我使用的其他技术相比,这是非常快的,并且它允许我在几个小时而不是几天内分割大量文件。
以下是使用小型Wave对象的整个过程(我目前的音频文件大小不超过150 MB,但将来我可能会收到更大的文件(即录制12-24小时录音的声音文件) )内存管理将变得更加重要):
library(seewave)
library(tuneR)
data(tico)
# force to stereo
tico@stereo <- TRUE
tico@right <- tico@left
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 (in seconds)
seglen <- 0.5
# defining the break points
breaks <- unique(c(seq(0, totsec, seglen), totsec))
index <- 1:(length(breaks)-1)
# the split
leftmat<-matrix(audio@left, ncol=(length(breaks)-2), nrow=seglen*freq)
rightmat<-matrix(audio@right, ncol=(length(breaks)-2), nrow=seglen*freq)
# the warnings are nothing to worry about here...
# convert to list of Wave objects.
subsamps0409_180629 <- lapply(1:ncol(leftmat), function(x)Wave(left=leftmat[,x],
right=rightmat[,x], samp.rate=d@samp.rate,bit=d@bit))
# get the last part of the audio file. the part that is < seglen
lastbitleft <- d@left[(breaks[length(breaks)-1]*freq):length(d)]
lastbitright <- d@right[(breaks[length(breaks)-1]*freq):length(d)]
# convert and add the last bit to the list of Wave objects
subsamps0409_180629[[length(subsamps0409_180629)+1]] <-
Wave(left=lastbitleft, right=lastbitright, samp.rate=d@samp.rate, bit=d@bit)
这不是我原始问题的一部分,但我的最终目标是保存这些新的,较小的Wave对象。
# finally, save the Wave objects
setwd("C:/Users/Whatever/Wave_object_folder")
# I had some memory management issues on my computer when doing this
# process with large (~ 130-150 MB) audio files so I used rm() and gc(),
# which seemed to resolve the problems I had with allocating memory.
rm("breaks","audio","freq","index","lastbitleft","lastbitright","leftmat",
"rightmat","seglen","totlen","totsec")
gc()
filenames <- paste("audio","_split",1:(length(breaks)-1),".wav",sep="")
# Save the files
sapply(1:length(subsamps0409_180629),
function(x)writeWave(subsamps0409_180629[[x]],
filename=filenames[x]))
这里唯一真正的缺点是输出文件非常大。例如,我输入一个130 MB的文件并将其拆分为18个文件,每个文件大约50 MB。我想这是因为我的输入文件是.mp3,输出是.wav。我把这个答案发布到我自己的问题上,以便用我用来解决它的完整解决方案来解决我遇到的问题,但是其他答案很受欢迎,我会花时间查看每个解决方案并评估它们提供的内容。我相信有更好的方法可以完成这项任务,并且方法可以更好地处理非常大的音频文件。在解决这个问题时,我几乎没有涉及内存管理的问题。
答案 1 :(得分:2)
根据弗兰克的要求,这是一种可行的方法。
提取声音数据的audio@left
和audio@right
槽'向量,然后在一步中将每个向上分成等长的部分,如:
leftsong<-audio@left
leftmat<-matrix(leftsong, ncol=(seglen*freq)
我假设seglen
是breaks[i]
和breaks[i+1]
之间的距离。
然后可以从wave
和leftmat
中的匹配行创建和处理新的rightmat
对象。