I have some very long .wav files that are taking a long time to process. There are only short sections within this longer file that I'm interested in analysing. Is there an efficient way to split these up into, for example, 10 minute sections, without having to manually open each file and do it by hand? I'm sure there must be some simple R/Matlab code.
12 Answers
In R you have the option to only upload a section of a wave file with arguments "from" and "to" within the function readWave (tuneR package). for example:
library (tuneR)
NewSection<-readWave("PathToMyWav",from=0, to=2, units="seconds")
This will only take the two first seconds of your file. You can then directly work on your this section in R or save the section in a new Wave file with the function writeWave. With "FOR" loops or parallel calculation in R you can then change automatically the arguments "from" and "to" without doing it manually:
library (tuneR)
start_times = c (0, 10, 20)
end_times = c (10, 20, 30)
Path= "PathToMyWav"
PathResult="PathToResultFolder"
for (i in 1:length(start_times))
{
NewSection<-readWave(Path,from=start_times[i], to=end_times[i], units="minutes")
writeWave(NewSection, file=paste(PathResult,"/",basename(Path),"_",start_times[i],"_",end_times[i],sep=""))
}
-
2$\begingroup$ I'd just add to this that you can also read in the wav all together and then use the cutw() function to cut it after the fact and write out those cut sections. Reading once, cutting, then writing may be a bit faster than a higher number of read/write operations. This also does rely on the sections of your wav files you want to cut being constant across all the files (for example, if you always want the time from 30 seconds to 40 seconds). If you need more varied timestamps for your clips, a different approach would be needed. $\endgroup$– dtsavageCommented Jul 5, 2022 at 14:16
-
3$\begingroup$ Yes, keeping in mind that loading a one-hour file in R can be really long but I agree that it is an option $\endgroup$ Commented Jul 5, 2022 at 15:53
In Matlab, you can do this. Can be modified if all the files in your folder are continuous.
clear
filepath = 'C:\[insert your file path]\';
files = dir([filepath '*.wav']);
%% Loop within a folder containing multiple files
for rr = 1:length(files);
info = audioinfo([filepath files(rr).name]);
fs = info.SampleRate; % samples per second
filelength = info.TotalSamples;
%%define chunk length
tenmins_samples = 10*60*fs; %10 mins * 60 seconds in a min * number of sample per sec
numloops = ceil(filelength/tenmins_samples); %round up, last output file may be <10 mins
%% Loop over number of ten min iterations within a file
for qq = 1:numloops;
%% Define the sample numbers for start and stop of each 10 min chunk
if qq==1
samples = [1, tenmins_samples];
elseif qq==numloops
samples = [(qq-1)*tenmins_samples+1, filelength];
else
samples = [(qq-1)*tenmins_samples+1, qq*tenmins_samples];
end
chunk2keep = audioread([filepath files(1).name], samples);
%% name and write the output file
outputfilename = [files(rr).name(1:end-4) '_chunk' num2str(qq) '.wav'];
audiowrite([filepath outputfilename], chunk2keep, fs)
clear samples chunk2keep outputfilename
end %qq
clear numloops info filelength fs
end %rr
-
1$\begingroup$ This is my "chunking" approach of choice! Excellent bit of code, @chloe $\endgroup$– seleneCommented Jul 5, 2022 at 14:10
-
$\begingroup$ Hi @chloe this code works great for splitting. However, I would also like to rename the files as they are created using their start time in the new filename, i.e. the first sound file would keep its original name, the second would start 10 minutes later, the next one 20 minutes later and so on. I am a bit stuck to change the script accordingly. Would you be able to help with this? My filename looks like this for example: 5122.220531103154.wav with date/time information in the file name after the first 5 characters. $\endgroup$– DeniseRCommented Sep 23, 2022 at 16:14
-
$\begingroup$ found the solution eventually, in case it helps anyone else. replace the section on naming and writing output file with the following: %% name and write the output files thisstarttime = starttime+seconds((qq-1)*fifteenmins_samples/fs); outputfilename = [files(rr).name(1:4) '.' char(thisstarttime,'yyMMddHHmmss') '.wav']; audiowrite([filepath '15min\', outputfilename], chunk2keep, fs) clear samples chunk2keep outputfilename $\endgroup$– DeniseRCommented Oct 22, 2022 at 13:50
If you have (or install) sox, a command line tool, you can use the following to split input.wav
into 10-minute files (named output001.wav
, output002.wav
, etc):
sox input.wav output%3n.wav trim 0 600 : newfile : restart
Details:
sox
- the name of the application
input.wav
- the name of the sound file (in the current directory) you wish to split. Can also supply as /path/to/input.wav
output%3n.wav
- the pattern of the name to use for the output files. %3n
will get converted into an incrementing three-digit number (001
for the first file, 002
for the second, etc)
trim
- the action that sox
will take
0 600
- start at time 0 and extract 600 seconds (10 mins)
: newfile : restart
- tells sox
to enter multiple output file mode and repeat the trim
command until it reaches the end of the input file
-
6$\begingroup$ This answer needs expanding. It will not be obvious to many this is command line. A quick tutorial e.g. open terminal, navigate using cd /myfiles/etc and then sox stuff would be much more helpful for the community. $\endgroup$– user213Commented Jul 5, 2022 at 10:12
-
1$\begingroup$ Even though the handling may look a bit daunting at first glance, I can absolutely recommend SoX as well. It is remarkably fast and it is possible to do batch processing (requires bash scripting), for example to process all audio files in a directory in some way. $\endgroup$ Commented Jul 29, 2022 at 19:39
Here is a broad solution based in Python with the SoundFile package
import soundfile as sf
file_path = '<path_to_your_file_here>'
# get the frequency of sampling
fs = sf.info(file_path).samplerate
# make up some start and end times in seconds
start_times , end_times = [0.01, 200, 300], [140, 190, 500]
for start_s, end_s in zip(start_times, end_times):
short_section, _ = sf.read(file_path , start=int(fs*start_s), stop=int(fs*end_s))
sf.write(<output_file_name_that_changes_every_loop>, short_section, samplerate=fs)
In R you can also use the function split_sound_files from the package warbleR. For instance splitting in 1 s segments:
library(warbleR)
#load example sound files and save to temporary working directory
data(list = c("Phae.long1", "Phae.long2"))
writeWave(Phae.long1, file.path(tempdir(), "Phae.long1.wav"))
writeWave(Phae.long2, file.path(tempdir(), "Phae.long2.wav"))
#split files in 1 s files
split_sound_files(sgmt.dur = 1, path = tempdir())
# Check this folder
tempdir()
You can also split all files in a fixed number of segments with the argument 'sgmts'
There are already a number of good answers on how to do the splitting. You might however prefer to use solutions that do not split files. Most languages will let you read small sections of an audio file, and I would suggest keeping a list of times you want to process, reading these chunks, and then processing them. There are multiple advantages to doing this:
- you do not create multiple copies of your data,
- it remains easy to examine the context of your data (e.g., what happened a few seconds before),
- and if you are using a library that let's you keep your audio file open between reads, multiple reads from the same file will be much faster. There is a large overhead for opening and closing files.
Best of luck.
Another option: my computer programmer colleague Yukio Fukuzawa made a tool that splits wav files; you simply specify how long you want the audio sections to be, and how many seconds of overlap between sections.
The overlap option is a nice feature in case there is an acoustic unit at the breakpoint -- you can make sure you have the entire unit in the first or second segment to take measurements on (rather than spoiling the unit through splitting).
To run the tool you will need to install Python. After that it's just a simple line of code that you type into your command prompt.
The tool and instructions are found here: https://github.com/fzyukio/split-songs
If you are in the world of Intel-processor macOS, give a try at xACT (x Audio Compression Toolkit), a nice app that does many different batch tasks with audio files. It was built on top of many of the tasks performed by SoX. Once there, check the shntool tab for the splitting file function.
-
$\begingroup$ Anyone tried this with multi-channel wav files? $\endgroup$– user213Commented Jul 6, 2022 at 16:44
QUT's Analysis Programs has an audio cutter feature.
Usage:
AP audiocutter -d 60 VeryLongFile.wav ./CutFiles
A agree with Marie R that often the best solution is not to split your sound files for analysis but use software that facilitates annotating long recordings and quickly jumping among annotations compare spectrograms, audio playback, and measurements.
Raven Lite is one example of such software. If you really do need to excerpt short audio clips from long recordings, Raven Lite allows you to "Save Active Selection As" or "Save All Selections In Current Table As" from the file menu if you have annotated the bits you want to excerpt.
I'm fully aware that this answer strays into 'self-promotion' territory, but it does address the question. A little while back, I developed a workflow incorporating R and Audacity to split large audio files. An overview with a link to the R code (via GitHub) is published on my data science blog, Wrangling In The Antipodes (https://wranglingintheantipodes.wordpress.com/2021/10/20/preparing-big-audio-files-for-analysis/)
A function written in R creates a table of labels that can then be imported into an Audacity session, applied to an audio file of a given length and then exported as multiple files. The function written is R is very straightforward, so this could very easily be rewritten in Python, C, etc.
Reading some of the previous answers to this question, my approach might not be the most efficient workflow but I thought I'd put it out there as an alternative.