0001 function sync_roi = bml_sync_audio_event(cfg)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
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
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
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
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
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'})