Home > bml > sync > bml_sync_audio_event.m

bml_sync_audio_event

PURPOSE ^

bml_sync_audio_event synchronizes zoom audio files according to

SYNOPSIS ^

function sync_roi = bml_sync_audio_event(cfg)

DESCRIPTION ^

 bml_sync_audio_event synchronizes zoom audio files according to
 events

 Use as 
    sync_roi = bml_sync_audio_event(cfg)

   cfg.master_events - events to align to in annot table in master time
   cfg.roi - roi table for zoom audio files to be synchronized
   cfg.timewarp - logical: Should slave time be warped? defaults to 
            true.
   cfg.scan - double: number of seconds to scan for optimal alignment 
             (defaults to 100)
   cfg.scan_step - double: step size of initial scan for alignment
             (defaults to 0.1)
   cfg.diagnostic_plot - logical
   cfg.timetol - numeric, time tolerance in seconds. Defaults to 1e-6
   cfg.min_events - integer. Minimum number of events required to attemp
             alingment, defaults to 10. 
   cfg.strict - logical. Issue errors if timetol is violated instead of errors. 
             Defaults to false. 

 returns a roi table

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function sync_roi = bml_sync_audio_event(cfg)
0002 
0003 % bml_sync_audio_event synchronizes zoom audio files according to
0004 % events
0005 %
0006 % Use as
0007 %    sync_roi = bml_sync_audio_event(cfg)
0008 %
0009 %   cfg.master_events - events to align to in annot table in master time
0010 %   cfg.roi - roi table for zoom audio files to be synchronized
0011 %   cfg.timewarp - logical: Should slave time be warped? defaults to
0012 %            true.
0013 %   cfg.scan - double: number of seconds to scan for optimal alignment
0014 %             (defaults to 100)
0015 %   cfg.scan_step - double: step size of initial scan for alignment
0016 %             (defaults to 0.1)
0017 %   cfg.diagnostic_plot - logical
0018 %   cfg.timetol - numeric, time tolerance in seconds. Defaults to 1e-6
0019 %   cfg.min_events - integer. Minimum number of events required to attemp
0020 %             alingment, defaults to 10.
0021 %   cfg.strict - logical. Issue errors if timetol is violated instead of errors.
0022 %             Defaults to false.
0023 %
0024 % returns a roi table
0025 
0026 scan_step         = bml_getopt(cfg,'scan_step',0.1);
0027 scan              = bml_getopt(cfg,'scan',100);
0028 timewarp          = bml_getopt(cfg,'timewarp',false);
0029 master_events     = bml_getopt(cfg,'master_events');
0030 roi               = bml_getopt(cfg,'roi');
0031 diagnostic_plot   = bml_getopt(cfg,'diagnostic_plot',false);
0032 timetol           = bml_getopt(cfg,'timetol',1e-6);
0033 min_events        = bml_getopt(cfg,'min_events',10);
0034 strict            = bml_getopt(cfg,'strict',false);
0035 
0036 assert(~isempty(roi),'roi required');
0037 assert(~isempty(master_events),'master_events required');
0038 
0039 all_slave_dt = zeros(height(roi),1);
0040 all_warpfactor = ones(height(roi),1);
0041 all_meanerror = zeros(height(roi),1);
0042 for i=1:height(roi)
0043   
0044   %getting events
0045     cfg=[];
0046     cfg.roi = roi(i,:);
0047     audio= bml_load_continuous(cfg);
0048     min_peak_height = max(abs(audio.trial{1}(1,:)))*0.5;
0049     MinPeakDistance = 0.25;
0050     [pks,locs] = findpeaks(abs(audio.trial{1}(1,:)),audio.fsample,...
0051     'MinPeakHeight',min_peak_height,'MinPeakDistance',MinPeakDistance);
0052     
0053 
0054   if isempty(locs) || length(locs) < min_events
0055     all_slave_dt(i) = nan;
0056     all_warpfactor(i) = nan;
0057   else
0058     %creating annot table with events
0059     starts = (roi.starts(i) + locs)';
0060     ends = starts;
0061     i_slave_events=bml_annot_table(table(starts,ends));
0062     i_slave_events.type = repmat({'audio'},[height(i_slave_events),1]);
0063     i_slave_events.value = repmat(1,[height(i_slave_events),1]);
0064     i_slave_events.sample = locs';
0065     
0066     
0067 
0068     
0069     %doing time alingment
0070     cfg=[]; 
0071     cfg.scan=scan; 
0072     cfg.scan_step=scan_step; 
0073     cfg.timewarp = timewarp; 
0074     [slave_dt, min_cost, warpfactor]=bml_timealign_annot(cfg,master_events,i_slave_events);
0075     all_slave_dt(i) = slave_dt;
0076     all_warpfactor(i) = warpfactor;
0077 
0078     if diagnostic_plot
0079       tbar = mean(i_slave_events.starts);
0080       i_slave_events_starts = (i_slave_events.starts - tbar) .* warpfactor + tbar + slave_dt;
0081       figure;
0082       plot(master_events.starts,ones(1,height(master_events)),'bo');
0083       hold on;
0084       plot(i_slave_events_starts,ones(1,length(i_slave_events_starts)),'r*');
0085     end
0086 
0087     all_meanerror(i) = min_cost/height(i_slave_events);
0088     if all_meanerror(i) > timetol
0089       if strict
0090         error('could not time align within timetol. Mean error %f > %f. File %s',all_meanerror(i),timetol,roi.name{i});
0091       else
0092         warning('could not time align within timetol. Mean error %f > %f. File %s. Ignoring this file during consolidation.',all_meanerror(i),timetol,roi.name{i});
0093         all_slave_dt(i) = nan;
0094         all_warpfactor(i) = nan;
0095       end
0096     end
0097   end
0098 end
0099 
0100 if ~timewarp
0101   all_slave_dt = repmat(nanmean(all_slave_dt),length(all_slave_dt),1);
0102 end
0103 
0104 %consolidating results
0105 roi.slave_dt = all_slave_dt;
0106 roi.warpfactor = all_warpfactor;
0107 roi.alignment_error = all_meanerror;
0108 
0109 cfg=[];
0110 cfg.criterion = @(x) (abs((max(x.ends)-min(x.starts))-sum(x.duration))<10e-3);
0111 cont_roi = bml_annot_consolidate(cfg,roi);
0112 
0113 consolidated_roi = table();
0114 for i=1:height(cont_roi)
0115   i_roi = roi(roi.id >= cont_roi.id_starts(i) & roi.id <= cont_roi.id_ends(i),:);
0116   i_roi.slave_dt(:) = nanmean(i_roi.slave_dt);
0117   i_roi.warpfactor(:) = nanmean(i_roi.warpfactor);
0118   consolidated_roi = [consolidated_roi; i_roi];
0119 end
0120 roi = consolidated_roi;
0121 
0122 if any(ismissing(roi.slave_dt))
0123   warning('Using mean dt for some files');
0124   roi.slave_dt(ismissing(roi.slave_dt)) = nanmean(roi.slave_dt);
0125 end
0126 if any(ismissing(roi.warpfactor))
0127   warning('Using mean warpfactor for some files');
0128   roi.warpfactor(ismissing(roi.warpfactor)) = nanmean(roi.warpfactor);
0129 end
0130 
0131 midpoint_a = (roi.ends + roi.ends) ./ 2;
0132 midpoint_t = (roi.t1 + roi.t2) ./ 2;
0133 roi.starts = (roi.starts - midpoint_a) .* roi.warpfactor + midpoint_a + roi.slave_dt;
0134 roi.ends = (roi.ends - midpoint_a) .* roi.warpfactor + midpoint_a + roi.slave_dt;
0135 roi.t1 = (roi.t1 - midpoint_t) .* roi.warpfactor + midpoint_t + roi.slave_dt;
0136 roi.t2 = (roi.t2 - midpoint_t) .* roi.warpfactor + midpoint_t + roi.slave_dt;
0137 
0138 roi.chunk_id = (1:height(roi))';
0139 roi.sync_channel = repmat({'digital'},height(roi),1);
0140 roi.sync_type = repmat({'slave'},height(roi),1);
0141 
0142 sync_roi = bml_roi_table(roi);
0143 
0144 sync_roi(:,{'id','starts','ends','duration','name','warpfactor'})

Generated on Tue 25-Sep-2018 10:08:19 by m2html © 2005