MATLAB Answers

0

Create new .wav files around findpeak outputs

Asked by Charlotte Findlay on 8 Oct 2019
Latest activity Commented on by Charlotte Findlay on 9 Oct 2019
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

  0 Comments

Sign in to comment.

1 Answer

Answer by Guillaume
on 8 Oct 2019
 Accepted Answer

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

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.
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.