Create new .wav files around findpeak outputs

2 views (last 30 days)
Hi everyone,
I would like to create short .wav files containing the audio data of each detected peak (see plot below as example). I would like the data in each .wav file to include the peak and a buffer on either side of roughly 0.02 s (e.g. black boxes around peaks would each be seperate .wav files). I have include my code so far and added a zip file with a short sample of the data to run code below.
% Read in audio file
[y,Fs] = audioread('test_MATLABAsk.wav');
info = audioinfo('test_MATLABAsk.wav');
sound(y,Fs) % Play the sound
% plot the data
% Create a time component using info
t = 0:seconds(1/Fs):seconds(info.Duration);
t = t(1:end-1);
figure(1)
plot(t,y)
xlabel('Time (s)')
ylabel('Audio Signal')
% Detect peaks from y
[pk_Fs, locs_Fs] = findpeaks(y,Fs, 'MinPeakDistance',0.03, 'MinPeakHeight',0.01); % See plot example below

Accepted Answer

Guillaume
Guillaume on 8 Oct 2019
Here's how I'd do it:
infile = 'C:\somewhere\somefolder\test_100m.wav'; %I'd recommend you use full path instead of relying on the current directory
outfolder = 'C:\somewhere\someotherfolder';
outformat = 'split%03d.wav'; %using sprintf format to insert peak number
halfwidth = seconds(0.02); %half width of signal to keep around peak
%read file, convert to timetable, find peak locations
[samples, Fs] = audioread(infile);
audiotable = timetable(samples, 'SampleRate', Fs);
[~, peaklocs] = findpeaks(samples, Fs, 'MinPeakDistance', 0.03, 'MinPeakHeight', 0.01);
%iterate over peaks, extract signal and save to file
for peakidx = 1:numel(peaklocs)
peaktime = audiotable.Time(peakloc(peakidx));
tokeep = isbetween(audiotable.Time, peaktime - halfwidth, peaktime + halfwidth);
audiowrite(fullfile(outfolder, sprintf(outformat, peakidx)), audiotable.samples(tokeep), Fs);
end
  19 Comments
Guillaume
Guillaume on 9 Oct 2019
Ok, so peaktime makes sense, you're using a wav file much longer than the one you originally posted. The duration of that file is at least 110 seconds.
peaktime is simply (peaklocs-1) ./ Fs
and peaktime is a plain vector. I did write in a comment that if it's a plain vector you needed to convert that to a duration vector with seconds. Otherwise, it's interpreted as days when you subtract audiotable.Time. So, correct code using Fs for findpeaks:
infile = 'C:\somewhere\somefolder\test_100m.wav'; %I'd recommend you use full path instead of relying on the current directory
outfolder = 'C:\somewhere\somefolder\OutWav';
outformat = 'split%03d.wav'; %using sprintf format to insert peak number
halfwidth = seconds(0.02); % half width of signal to keep around peak
%read file, convert to timetable, find peak locations
[samples, Fs] = audioread(infile);
audiotable = timetable(samples, 'SampleRate', Fs);
[~, peaktimes] = findpeaks(samples, Fs, 'MinPeakDistance', 0.03, 'MinPeakHeight', 0.01);
peaktimes = seconds(peaktimes);
%iterate over peaks, extract signal and save to file
for peakidx = 1:numel(peaktimes)
tokeep = abs(audiotable.Time - peaktimes(peakidx)) <= halfwidth;
audiowrite(fullfile(outfolder, sprintf(outformat, peakidx)), audiotable.samples(tokeep), Fs);
end
For what it's worth, I've raise a service request with Mathworks to get them to improve the documentation of findpeaks.
Charlotte Findlay
Charlotte Findlay on 9 Oct 2019
This is great! Thank you so much for explaining and helping me to resolve this issue.
Apologies, I must have mis-understood that I needed to convert duration with seconds.
I think updating findpeaks documentation is a good idea as well, just to ensure its clearer for others using the function!

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!