PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/melba.m

http://github.com/smcg/MARTA
MATLAB | 1 lines | 1 code | 0 blank | 0 comment | 0 complexity | 4c7d69bf127f13f1e5bb714f79ad884a MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. function mOut = melba(varargin) %MELBA - Matlab Event Labelling By Acoustics % % usage: melba data % melba(data) % melba(data, params) % % melba abort % close all MELBA viewers % % where DATA is one of % MAVIS-compatible struct % AUDIO object % signal, sRate pair (where signal can be a [nSamps x nSignals] aggregate) % string evaluating to a (possibly wild-carded) MS WAV filename (include extension) % string evaluating to a (possibly wild-carded) variable name % cell string array of variable names % (if variables not found in workspace loaded from mat or wav files on path) % % and PARAMS is one of the following NAME, VALUE pairs: % CLOSE - user-specified function to call when window closes % CONFIG - specify a previously saved configuration variable % LABELS - specify a set of previously defined labels % LPROC - specify a user labelling procedure % PALATE - specify a [nPoints x X,Y] palate trace % SEX - specify subject gender ({'M'}|'F'; affects F0 heuristics) % SPLINE - specify indices into data of (tongue) points to connect by spline % SPREAD - specify signal scaling (use 'AUTO' for self-normalization) % HEAD/TAIL - specify display offsets in msecs % CHANNEL - specify {'B'}|'L'|'R' for stereo input signals ('B' for both) % % entering melba alone will pop any active viewers forward, else display help % % mark tiede fecit vers = 'mkt 01/10/08 v4.0'; %----------------------------------------------------------------------------- % no args: if any MELBA viewers active, pop 'em forward, else show help if nargin < 1, set(0,'ShowHiddenHandles', 'on'); h = findobj('Tag', 'MELBA'); set(0,'ShowHiddenHandles', 'off'); if isempty(h), eval('help melba'); else, for i = 1 : length(h), figure(h(i)); end; end; return; end; %----------------------------------------------------------------------------- % parse args if ischar(varargin{1}), % command line argument action = upper(varargin{1}); elseif isstruct(varargin{1}), % mavis-compatible data action = 'INIT'; data = varargin{1}; labels = []; for i = 1 : length(data), % use 1st monodimensional vector if size(data(i).SIGNAL,2) == 1, signal = double(data(i).SIGNAL); sRate = data(i).SRATE; if isstruct(data) & isfield(data,'LABELS'), labels = data(i).LABELS; if isfield(labels,'NOTE'), % bw compatibility lx = rmfield(labels, 'NOTE'); for li = 1 : length(labels), lx(li).HOOK = labels(li).NOTE; end; labels = lx; end; end; break; end; end; names = {data.NAME}; k = strmatch('FORMANTS',names,'exact'); if ~isempty(k), formants = data(k).SIGNAL; data(k) = []; else, formants = []; end; k = strmatch('F0',names,'exact'); if ~isempty(k), f0 = data(k).SIGNAL; data(k) = []; else, f0 = []; end; if length(data) > 1, data = 1; % flag mavis data available but don't clone it (avoid memory whack) else, data = 0; end; elseif isa(varargin{1}, 'audio'), % audio object action = 'INIT'; signal = varargin{1}; sRate = signal.SRATE; signal = double(signal); labels = []; data = 0; formants = []; f0 = []; elseif nargin>1 & all([isnumeric(varargin{1}) isnumeric(varargin{2})]), action = 'INIT'; % signal vector, srate signal = double(varargin{1}); sRate = varargin{2}; labels = []; data = 0; formants = []; f0 = []; elseif iscellstr(varargin{1}), vList = varargin{1}; if nargin > 1, args = varargin(2:end); else, args = []; end; args{end+1} = 'VLIST'; args{end+1} = vList; melba(vList{1}, args{:}); return; elseif iscell(varargin{1}), action = 'INIT'; sRate = varargin{1}; signal = double(sRate{1}); sRate = sRate{2}; labels = []; data = 0; formants = []; f0 = []; else, error('MELBA: unrecognized data format'); end; %----------------------------------------------------------------------------- % branch by action switch action, %----------------------------------------------------------------------------- % ABORT: force exit case 'ABORT', set(0,'ShowHiddenHandles', 'on'); delete(findobj('Tag', 'MELBA')); set(0,'ShowHiddenHandles', 'off'); %----------------------------------------------------------------------------- % ABOUT: display help case 'ABOUT', s = {'MELBA - Matlab Event Labelling By Acoustics'; '' [' ' vers]}; helpwin(s, 'About MELBA'); %----------------------------------------------------------------------------- % AUTO: toggle auto update status case 'AUTO', state = get(gcbf, 'userdata'); s = get(gcbo,'checked'); state.AUTO = strcmp(s,'off'); set(gcbf, 'userdata', state); if state.AUTO, s = 'on'; else, s = 'off'; end; set(state.AUTOMENU, 'checked', s); if state.AUTO, SetBounds(state); end; %----------------------------------------------------------------------------- % CFGSPEC: configure spectra analysis case 'CFGSPEC', state = get(gcbf, 'userdata'); cfg = struct('NUDGE', state.NUDGE, ... 'WSIZE', state.WSIZE, ... 'ORDER', state.ORDER, ... 'FRAME', state.FRAME, ... 'AVGW', state.AVGW, ... 'OLAP', state.OLAP, ... 'BWCLIP', state.BWCLIP, ... 'PREEMP', state.PREEMP, ... 'SOFF', state.SOFF, ... 'SPECLIM', state.SPECLIM, ... 'ANAL', state.ANAL, ... 'F0THR', state.F0THR, ... 'ISF', state.ISF); cfg = ConfigSpectra(cfg); if isempty(cfg), return; end; state.FRAME = cfg.FRAME; state.ORDER = cfg.ORDER; state.WSIZE = cfg.WSIZE; state.NUDGE = cfg.NUDGE; state.AVGW = cfg.AVGW; state.OLAP = cfg.OLAP; state.BWCLIP= cfg.BWCLIP; state.PREEMP= cfg.PREEMP; state.SOFF = cfg.SOFF; state.F0THR = cfg.F0THR; % RECOMPUTE F0 if state.SOFF<=0, state.SOFF = 1; end; if state.SPECLIM ~= cfg.SPECLIM, specLim = cfg.SPECLIM; if specLim > state.SRATE/2, specLim = state.SRATE/2; end; state.SPECLIM = specLim; set(state.SPECTRA, 'xlim', [1 specLim]); end; state.ANAL = cfg.ANAL; state.ISF = cfg.ISF; set(gcbf, 'userdata', state); SetCursor(state); SetBounds(state, 0); %----------------------------------------------------------------------------- % CLONE: duplicate window for copy, print visibility case 'CLONE', state = get(gcbf, 'userdata'); h = gcbf; ch = figure('colormap', get(h, 'colormap'), 'name', state.NAME); copyobj(flipud(findobj(h,'type','axes')), ch); set(findobj(ch,'type','patch'), 'edgeColor', [1 1 1], 'faceColor', 'none', 'eraseMode', 'normal'); uicontrol(ch, ... % head 'style', 'text', ... 'horizontalAlignment', 'left', ... 'string', sprintf('Head: %.1f', state.HEAD), ... 'units', 'characters', ... 'backgroundColor', get(ch, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [4 3.0 15 1]); uicontrol(ch, ... % tail 'style', 'text', ... 'horizontalAlignment', 'left', ... 'string', sprintf('Tail: %.1f', state.TAIL), ... 'units', 'characters', ... 'backgroundColor', get(ch, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [4 1.0 15 1]); uicontrol(ch, ... % cursor 'style', 'text', ... 'horizontalAlignment', 'right', ... 'string', sprintf('Cursor: %.1f', state.CURSOR), ... 'units', 'characters', ... 'backgroundColor', get(ch, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [18 3.0 15 1]); %----------------------------------------------------------------------------- % COG: display spectral center-of-gravity measures case 'COG', state = get(gcbf, 'userdata'); [L1, skew, kurt] = cog(state.SIGNAL, state.SRATE, state.CURSOR); fprintf('Cursor @ %d (%g ms), \tL1: %g skew: %g kurt: %g\n', ... floor(state.CURSOR*state.SRATE/1000)+1, state.CURSOR, ... L1, skew, kurt); %----------------------------------------------------------------------------- % CONTRAST: adjust spectrogram contrast case 'CONTRAST', state = get(gcbf, 'userdata'); colormap(flipud(gray(256).^get(gcbo,'value'))); ih = findobj(state.SPECGRAM, 'type', 'image'); if ~isempty(ih), set(ih,'cdata', get(ih, 'cdata')); end; %----------------------------------------------------------------------------- % CURCHG: manual cursor entry case 'CURCHG', if nargin > 2, fh = varargin{3}; else, fh = gcbf; end; state = get(fh, 'userdata'); if nargin > 1, c = varargin{2}; else, c = str2num(get(state.CURSORF, 'string')); end; if c < 0, c = 0; elseif c > state.DUR, c = state.DUR; end; state.CURSOR = c; set(fh, 'userdata', state); SetCursor(state); %----------------------------------------------------------------------------- % DOWN: mouse down case 'DOWN', state = get(gcbf, 'userdata'); curPt = get(gca, 'CurrentPoint'); mod = get(gcbf, 'selectionType'); x = curPt(1,1); y = curPt(1,2); switch varargin{2}, % click in framing panel is bounds adjust case 'FRAME', if strcmp(mod, 'open'), state.HEAD = 0; % double click sets full selection state.TAIL = state.DUR; set(gcbf, 'userData', state); SetBounds(state); return; end; slop = state.DUR * .008; % grabbing tolerance if state.HEAD>x-slop & state.HEAD<x+slop, state.MOVEMODE = 'HEAD'; % move head elseif state.TAIL>x-slop & state.TAIL<x+slop, state.MOVEMODE = 'TAIL'; % move tail elseif x>state.HEAD & x<state.TAIL, state.MOVEMODE = -x; % move selection (save starting point) else, return; end; state.MOVED = 0; set(gcbf, 'userdata', state, ... 'windowButtonMotionFcn', 'melba MOVESEL', ... 'windowButtonUpFcn', 'melba UP'); % click in temporal panel sets cursor/label case 'CURSOR', if strcmp(mod, 'open'), return; end; % ignore double click % set(state.CURSORL, 'xData', [x x]); % update cursor position state.CURSOR = x; SetCursor(state); switch mod, case 'normal', % (left button/unmodified click) fall thru state.MOVEMODE = 'CURSOR'; % cursor update case 'open', % (double-click) return; otherwise, % (right button/modified click) if strcmp(mod, 'extend'), state.MOVEMODE = 'LBL_SILENT'; % shift: silent labelling else, state.MOVEMODE = 'LBL_NOISY'; % ctl/alt: annotated labelling end; if ~isempty(state.LPROC), % user proc labelling set(gcbf, 'userdata', state); % update mode lpState = feval(state.LPROC, state.LPSTATE, 'DOWN', state.CURSOR); if ~isempty(lpState), state = get(gcbf, 'userData'); state.LPSTATE = lpState; set(gcbf, 'userdata', state); % allow state update end; return; end; end; xy = get(state.SPECGRAM, 'currentPoint'); xy = round(xy(1,2)); if xy>0 & xy <state.SRATE/2, % click within spectrogram set(state.HEADFL, 'string', 'Hz'); set(state.HEADF, 'string', [' ',int2str(xy)]); line([xy xy], get(state.SPECTRA, 'ylim'), ... 'parent', state.SPECTRA, 'tag', 'CURSOR', ... 'color', 'c', 'eraseMode','xor'); end; set(gcbf, 'userdata', state, ... 'windowButtonMotionFcn', 'melba MOVECUR', ... 'windowButtonUpFcn', 'melba UP', ... 'pointer', 'crosshair'); % click in spectrum panel reports location case 'SPECTRA', if ~strcmp(mod, 'normal'), % modified click - plot spectrum in external window PlotSpectra(state); return; end; set(state.HEADFL, 'string', 'Hz'); set(state.TAILFL, 'string', 'dB'); set(state.HEADF, 'string', [' ',round(x)]); set(state.TAILF, 'string', sprintf(' %.1f',y)); state.MOVEMODE = 'SPECTRA'; set(gcbf, 'userData', state, ... 'windowButtonMotionFcn', 'melba MOVESPEC', ... 'windowButtonUpFcn', 'melba UP', ... 'pointer', 'crosshair'); end; %----------------------------------------------------------------------------- % FORMANTS: list formant peaks case 'FORMANTS', state = get(gcbf, 'userdata'); % compute F0 c = floor(state.CURSOR*state.SRATE/1000)+1; % msecs->samples ns = round(40/1000*state.SRATE); % frame (40 msecs->samples) F0 = zeros(1,3); v = F0; for fi = 1 : 3, % compute for 3 buffers centered on cursor h = c - round(ns/2)*(3-fi); if h < 1, h = 1; end; t = h + ns - 1; if t > length(state.SIGNAL), t = length(state.SIGNAL); h = t - ns + 1; end; [F0(fi),v,R] = ComputeF01(state.SIGNAL(h:t), state.SRATE, state.ISF); end; if length(find(F0)) < 2, % if any two buffers 0 F0 = NaN; % bogus elseif std(F0(find(F0))) > 15, % if std dev > 15 Hz F0 = F0(find(F0)); if min(F0) < .67*max(F0), % check for pitch doubling F0 = min(F0); else, F0 = NaN; end; elseif F0(2), % center result available F0 = F0(2); % cursor-centered result else, % otherwise F0 = mean(F0(find(F0))); % mean of non-zero results end; % compute zero crossings, RMS for WSIZE centered on cursor ht = floor((state.CURSOR+[-state.WSIZE state.WSIZE]*.5)*state.SRATE/1000)+1; % msecs -> samps if ht(1)<1, ht(1) = 1; end; if ht(2)>length(state.SIGNAL), ht(2) = length(state.SIGNAL); end; s = state.SIGNAL(ht(1):ht(2)); zc = sum(abs(diff(s>=0))); rms = sqrt(mean(s.^2)); % compute formants [p,f,formants,bws,amps] = ComputeSpectra(state); fprintf('\n\tCursor @ %g ms\nWindow %.1f ms: %d zero crossings, RMS = %.1f, F0 = %d Hz\nFormants (Bandwidths, Amplitudes):\n [', ... state.CURSOR, state.WSIZE, zc, rms, F0); nf = min([length(formants) state.NFMTS]); for i = 1 : nf, fprintf(' %d (%d, %.1f) ', formants(i), bws(i), amps(i)); end; fprintf(']\n'); % show canned values, if any if ~isempty(state.F0), k = round(c/length(state.SIGNAL) * length(state.F0)); if k < 1, k = 1; elseif k > length(state.F0), k = length(state.F0); end; fprintf('Stored F0 == %.0f Hz\n', state.F0(k)); end; if ~isempty(state.FORMANTS), lf = size(state.FORMANTS,1); k = round(c/length(state.SIGNAL) * lf); if k < 1, k = 1; elseif k > lf, k = lf; end; fprintf('Stored Formants:'); fprintf(' %.0f', state.FORMANTS(k,1:nf)); fprintf('\n'); end; % selection head = floor(state.HEAD*state.SRATE/1000)+1; % msecs -> samps tail = floor(state.TAIL*state.SRATE/1000)+1; fprintf('Selection is %.1f : %.1f (%.1f) ms\n', ... state.HEAD, state.TAIL, state.TAIL-state.HEAD); %----------------------------------------------------------------------------- % GETCFG: return current configuration case 'GETCFG', state = varargin{2}; mOut = struct('FIGPOS', get(gcbf, 'position'), ... % figure position 'FRAME', state.FRAME, ... % # FFT evaluation points 'ORDER', state.ORDER, ... % LPC order 'WSIZE', state.WSIZE, ... % LPC evaulation window (msecs) 'NFMTS', state.NFMTS, ... % # recorded formants 'NUDGE', state.NUDGE, ... % nudge length (msecs) 'AVGW', state.AVGW, ... % averaging window (msecs) 'OLAP', state.OLAP, ... % averaging overlap (msecs) 'ZOOMW', state.ZOOMW, ... % zoomed waveform window (msecs) 'BWCLIP', state.BWCLIP, ... % formant bandwidth clipping (Hz) 'PREEMP', state.PREEMP, ... % pre-emphasis (negated is adaptive) 'SOFF', state.SOFF, ... % SPL spectral offset 'SPECLIM', state.SPECLIM, ... % spectral display limit (Hz) 'SGWIN', get(state.SGWIN,'value'), ... % spectrogram window multiplier 'CONTRAST', get(state.CONTRAST, 'value'), ... % spectrogram contrast value 'AUTO', state.AUTO, ... % auto update 'FMTS', state.FMTS, ... % formants display 'LPROC', state.LPROC, ... % default label proc 'LPSTATE', state.LPSTATE, ... % label proc data 'TARGETS', state.TARGETS, ... % export targets 'PALATE', state.PALATE, ... % palate trace 'SPLINE', state.SPLINE, ... % tongue spline data indices 'ANAL', state.ANAL, ... % spectra analysis 'SPREAD', state.SPREAD, ... % signal scaling (negative flags auto) 'CLOSEFCN', state.CLOSEFCN, ... % close function 'SLIST', state.SLIST, ... % superimposed labels 'CHANNEL', state.CHANNEL, ... % stereo handling 'F0THR', state.F0THR, ... % F0 trim thresh 'ISF', state.ISF); % true if female subject %----------------------------------------------------------------------------- % INITialize case 'INIT', % parse PARAMS if any cfg = struct('FIGPOS', [], ... % default figure position 'FRAME', 256, ... % # FFT evaluation points 'ORDER', [], ... % LPC order 'WSIZE', 30, ... % analysis window (msecs) 'NFMTS', 3, ... % # recorded formants 'NUDGE', 5, ... % nudge length (msecs) 'AVGW', 6, ... % averaging window (msecs) 'OLAP', 1, ... % averaging overlap (msecs) 'ZOOMW', 30, ... % zoomed waveform window (msecs) 'BWCLIP', 300, ... % formant bandwidth clipping (Hz) 'PREEMP', .98, ... % pre-emphasis (negated is adaptive) 'SOFF', 20, ... % SPL spectral offset (dB) 'SPECLIM', [], ... % spectral display limit (Hz) 'SGWIN', 1, ... % spectrogram window multiplier 'CONTRAST', 4, ... % spectrogram contrast factor 'AUTO', [], ... % auto update 'FMTS', [], ... % formants display 'LPROC', [], ... % default label proc 'LPSTATE', [], ... % label proc data 'TARGETS', [], ... % export targets 'PALATE', [], ... % palate trace 'SPLINE', [], ... % tongue spline data indices 'ANAL', 3, ... % spectra analysis (LPC, DFT) 'SPREAD', 'AUTO', ... % signal scaling (auto) 'CLOSEFCN', [], ... % close function 'SLIST', [], ... % superimposed labels 'CHANNEL', 'B', ... % use both if available 'F0THR', .4, ... % F0 trim thresh 'ISF', 0); % true if female subject vList = []; vListSel = []; head = 0; tail = []; name = inputname(1); signals = []; closefcn = []; if nargin > 2, i = 2; if isnumeric(varargin{2}), i = i + 1; end; while i < nargin, if ~ischar(varargin{i}), error(sprintf('argument error (arg %d)', i)); end; switch upper(varargin{i}), case 'CHANNEL', cfg.CHANNEL = upper(varargin{i+1}(1)); case 'CLOSE', closefcn = varargin{i+1}; case 'CONFIG', cfg = varargin{i+1}; case 'LABELS', labels = varargin{i+1}; case 'LPROC', cfg.LPROC = varargin{i+1}; case 'PALATE', cfg.PALATE = varargin{i+1}; case 'VLIST', % variable list vList = varargin{i+1}; case 'VLSEL', % selection within it vListSel = varargin{i+1}; case 'SLIST', % labels for superimposition cfg.SLIST = varargin{i+1}; case 'HEAD', head = varargin{i+1}; case 'TAIL', tail = varargin{i+1}; case 'NAME', name = varargin{i+1}; case 'SPLINE', cfg.SPLINE = varargin{i+1}; case 'SPREAD', cfg.SPREAD = varargin{i+1}; case 'HEAD', head = varargin{i+1}; case 'TAIL', tail = varargin{i+1}; case 'SEX', cfg.ISF = (upper(varargin{i+1}(1)) == 'F'); case 'SIGNALS', signals = varargin{i+1}; otherwise, error(sprintf('unknown argument: %s', varargin{i})); end; i = i + 2; end; end; if isempty(cfg.ORDER), % Markel & Gray heuristic if cfg.ISF, cfg.ORDER = round(sRate/1000)+8; % female else, cfg.ORDER = round(sRate/1000)+4; % male end; end; if length(cfg.SLIST) ~= length(vList), cfg.SLIST = []; end; % fail silently on length mismatch % set up window if isempty(cfg.FIGPOS), figPos = round(get(0, 'ScreenSize')/2); set(0,'ShowHiddenHandles', 'on'); h = findobj('Tag', 'MELBA'); set(0,'ShowHiddenHandles', 'off'); figPos = [10+length(h)*10 , figPos(4)-200-65-length(h)*25 , figPos(3)+100 , figPos(4)+200]; if figPos(2) < 0, % slide over figPos(1) = figPos(1) + 50; figPos(2) = figPos(4) - 200 - 65; end; else, figPos = cfg.FIGPOS; end; fh = colordef('new', 'black'); % figure handle set(fh, ... 'tag', 'MELBA', ... 'numberTitle', 'off', ... 'position', figPos, ... 'menubar', 'none', ... 'resizeFcn', 'melba RESIZE', ... 'visible', 'off'); % framing panel fa = axes('position', [.05 .87 .94 .1], ... % framing axis 'box', 'on', 'hitTest', 'off'); [nSamps,n] = size(signal); if n>nSamps && nSamps==1, signal = signal'; nSamps = n; elseif n>1, % [nSamps x nSignals] aggregate switch cfg.CHANNEL, case 'B', signals = signal; signal = signal(:,1); for k = 1 : size(signals,2), vList{k} = sprintf('%s(:,%d)',name,k); end; case 'L', signal = signal(:,1); case 'R', signal = signal(:,2); end; end; if n>nSamps, signal = signal'; nSamps = n; end; % force [nSamps x 1] dur = 1000*(nSamps-1)/sRate; % msecs if isempty(tail), tail = min([dur 3000]); % limit displayed portion to 3 secs elseif tail > dur, tail = dur; end; maxV = max(abs(signal)); if isempty(cfg.SPREAD), if maxV <= 1, cfg.SPREAD = 1; elseif maxV <= 2048, cfg.SPREAD = 2048; elseif maxV <= 32768, cfg.SPREAD = 32768; else, cfg.SPREAD = maxV; end; elseif ischar(cfg.SPREAD), % 'AUTO' (max range) cfg.SPREAD = -maxV; elseif cfg.SPREAD < 0, % AUTO range (from saved cfg) cfg.SPREAD = -maxV; end; spread = abs(cfg.SPREAD) * 1.1; % pad for display plot(signal, 'w'); set(fa, 'xtick', [], 'ytick', [], ... 'xlim', [1 nSamps], 'ylim', [-1 1]*spread); hold on; ec = [.25 .25 .25]; sh = patch([1 1 nSamps nSamps], [-1 1 1 -1]*spread, ec, ... 'EdgeColor', ec, ... 'EraseMode', 'xor'); hold off; axes('position', [.05 .87 .94 .1],'color','none', ... 'xlim', [0 dur], 'ylim', [0 1], ... 'xtick', [], 'ytick', [], ... 'buttonDownFcn', 'melba(''DOWN'',''FRAME'')'); % selection panel sa = axes('position', [.05 .7 .94 .167], ... % selection axis 'box', 'on', 'hitTest', 'off'); plot(signal, 'w'); set(sa, 'xticklabel', [], 'ytick', [], ... 'xlim', [1 nSamps], 'ylim', [-1 1]*spread); % spectrogram panel ka = axes('position', [.05 .4 .94 .305], ... % spectrogram axis 'box', 'on', 'hitTest', 'off'); % F0 panel f0a = axes('position', [.05 .3 .94 .1], ... % F0 axes 'box','on', 'hitTest','off'); try, if isempty(f0), f0 = ComputeF0({signal(:,1), sRate},'F0THR',cfg.F0THR); end; idx = isnan(f0); f0(idx) = 0; k = linspace(1,length(f0),size(signal,1)); f0 = interp1(f0,k); idx = interp1(idx,k); f0(find(idx>0)) = NaN; plot(f0, 'c'); set(f0a, 'xticklabel',[],'xlim',[1 length(f0)],'ylim',[nanmin(f0)-10 nanmax(f0)+20]); catch, f0 = []; set(f0a, 'xtick',[],'ytick',[],'box','on'); fprintf('error attempting F0 estimation\n'); end; % RMS panel rmsa = axes('position', [.05 .2 .94 .1], ... % RMS axes 'box','on', 'hitTest','off'); wl = round(20*sRate/1000); rms = sqrt(filtfilt(rectwin(wl)/wl,1,signal(:,1).^2)); plot(rms, 'color', [1 1 .8]); set(rmsa, 'xticklabel', [], 'ytick', [], ... 'xlim', [1 nSamps], 'ylim', [0 max(rms)*1.1]); % cursor axis hold on; % cursor axis ca = axes('position', [.05 .2 .94 .665], ... 'xlim', [0 dur], 'ylim', [0 1], ... 'ytick', [], 'color', 'none', ... 'buttonDownFcn', 'melba(''DOWN'',''CURSOR'')'); cl = line([0 0], [0 1], 'color', 'white', ... % cursor line handle 'eraseMode', 'xor', ... 'buttonDownFcn', 'melba(''DOWN'',''CURSOR'')'); hold off; % spectra axis if isempty(cfg.SPECLIM), specLim = sRate/2; else, specLim = cfg.SPECLIM; end; % ra = axes('position', [.575 .01 .42 .15], ... % spectra axis ra = axes('position', [.625 .01 .365 .13], ... % spectra axis 'xaxislocation', 'top', 'yticklabel', [], ... 'xlim', [1 specLim], 'ylim', [5 100], ... 'box', 'on', 'buttonDownFcn', 'melba(''DOWN'',''SPECTRA'')'); rl = line(0, 0, 'color', 'w', 'eraseMode', 'xor', ... 'buttonDownFcn', 'melba(''DOWN'',''SPECTRA'')'); % zoom axis menu = uicontextmenu; uimenu(menu, 'label', 'Plot', 'callback', 'melba(''ZOOM'',''PLOT'')'); uimenu(menu, 'label', 'Shrink', 'separator', 'on', 'callback', 'melba(''ZOOM'',''SHRINK'')'); uimenu(menu, 'label', 'Expand', 'callback', 'melba(''ZOOM'',''EXPAND'')'); uimenu(menu, 'label', 'Zoom', 'separator', 'on', 'callback', 'melba(''ZOOM'',''ZOOM'')'); uimenu(menu, 'label', 'Unzoom', 'callback', 'melba(''ZOOM'',''UNZOOM'')'); uimenu(menu, 'label', '5 ms', 'separator', 'on', 'callback', 'melba(''ZOOM'',''5'')'); uimenu(menu, 'label', '10 ms', 'callback', 'melba(''ZOOM'',''10'')'); uimenu(menu, 'label', '20 ms', 'callback', 'melba(''ZOOM'',''20'')'); uimenu(menu, 'label', '30 ms', 'callback', 'melba(''ZOOM'',''30'')'); uimenu(menu, 'label', '50 ms', 'callback', 'melba(''ZOOM'',''50'')'); uimenu(menu, 'label', '75 ms', 'callback', 'melba(''ZOOM'',''75'')'); uimenu(menu, 'label', '100 ms', 'callback', 'melba(''ZOOM'',''100'')'); ns = floor(cfg.ZOOMW*sRate/1000); % za = axes('position', [.42 .01 .149 .15], ... za = axes('position', [.4 .01 .219 .13], ... 'xtick', [], 'ytick', [], ... 'xlim', [1 ns], 'ylim', [-maxV maxV], ... 'box', 'on', 'uicontextmenu', menu); line(round(ns/2)*[1 1],[-maxV maxV],'color','g','linestyle',':','tag','CURSOR', 'hitTest','off'); zoom = line(0,0,'color','w', 'eraseMode','xor', 'userData', [-maxV maxV], 'buttonDownFcn', 'melba(''ZOOM'',''PLOT'')'); % controls hfl = uicontrol(fh, ... % head field 'style', 'text', ... 'horizontalAlignment', 'right', ... 'string', 'Head', ... 'units', 'characters', ... 'backgroundColor', get(fh, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [1 3.0 6 1]); hf = uicontrol(fh, ... 'style', 'edit', ... 'horizontalAlignment', 'left', ... 'units', 'characters', ... 'string', ' 0', ... 'position', [8 2.8 12 1.8], ... 'callback', 'melba(''SELCHG'',1)'); tfl = uicontrol(fh, ... % tail field 'style', 'text', ... 'horizontalAlignment', 'right', ... 'string', 'Tail', ... 'units', 'characters', ... 'backgroundColor', get(fh, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [1 1.0 6 1]); tf = uicontrol(fh, ... 'style', 'edit', ... 'horizontalAlignment', 'left', ... 'units', 'characters', ... 'string', sprintf(' %.1f', dur), ... 'position', [8 0.8 12 1.8], ... 'callback', 'melba(''SELCHG'',2)'); uicontrol(fh, ... % cursor field 'style', 'text', ... 'horizontalAlignment', 'right', ... 'string', 'Cursor', ... 'units', 'characters', ... 'backgroundColor', get(fh, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [21 3.0 9 1]); cf = uicontrol(fh, ... 'style', 'edit', ... 'horizontalAlignment', 'left', ... 'units', 'characters', ... 'string', ' 0', ... 'position', [31 2.8 12 1.8], ... 'callback', 'melba CURCHG'); uicontrol(fh, ... % spectrogram window popup 'style', 'text', ... 'horizontalAlignment', 'right', ... 'string', 'Sgram', ... 'units', 'characters', ... 'backgroundColor', get(fh, 'color'), ... 'foregroundColor', [1 1 1], ... 'position', [21 1.0 9 1]); wsm = uicontrol(fh, ... 'style', 'popupmenu', ... 'horizontalAlignment', 'left', ... 'units', 'characters', ... 'position', [31 0.8 12 1.3], ... 'string', 'wideband|mid 1|mid 2|narrow', ... 'value', cfg.SGWIN, ... 'HorizontalAlignment', 'left', ... 'callback', 'melba SPECUD'); % set(cf, 'units', 'pixels'); % p = get(cf, 'position'); set(wsm, 'units', 'pixels'); p = get(wsm, 'position'); p = [p(1)+p(3)+10 , p(2) , 10 , 70-p(2)]; slider = uicontrol(fh, ... % spectrogram slider 'style', 'slider', ... 'min', 1, 'max', 20, ... 'value', cfg.CONTRAST, ... 'position', p, ... 'callback', 'melba CONTRAST'); % MELBA menu menu = uimenu(fh, 'label', 'MELBA', 'HandleVisibility', 'Callback'); uimenu(menu, 'label', 'About MELBA...', ... 'callback', 'melba ABOUT'); if isempty(cfg.AUTO), if nSamps > 50000, auto=0; cs='off'; else, auto=1; cs='on'; end; else, auto = cfg.AUTO; if auto, cs = 'on'; else, cs = 'off'; end; end; autoMenu = uimenu(menu, 'label', 'Auto Update', ... 'separator', 'on', ... 'checked', cs, ... 'callback', 'melba AUTO'); uimenu(menu, 'label', 'Update', ... 'accelerator', 'U', ... 'callback', 'melba UPDATE'); uimenu(menu, 'label', 'Set Head', ... 'separator', 'on', ... 'accelerator', 'D', ... 'callback', 'melba(''SELCHG'',-1)'); uimenu(menu, 'label', 'Set Tail', ... 'accelerator', 'T', ... 'callback', 'melba(''SELCHG'',-2)'); uimenu(menu, 'label', 'Shrink Selection', ... 'accelerator', '[', ... 'callback', 'melba(''SELCHG'',-3)'); uimenu(menu, 'label', 'Expand Selection', ... 'accelerator', ']', ... 'callback', 'melba(''SELCHG'',-4)'); h = uimenu(menu, 'label', 'Play'); ph(1) = uimenu(h, 'label', 'Selection', ... 'accelerator', 'P', ... 'callback', 'melba(''PLAY'',1)'); ph(2) = uimenu(h, 'label', 'Entire File', ... 'callback', 'melba(''PLAY'',2)'); ph(3) = uimenu(h, 'label', 'To Cursor', ... 'callback', 'melba(''PLAY'',3)'); ph(4) = uimenu(h, 'label', 'From Cursor', ... 'callback', 'melba(''PLAY'',4)'); ph(5) = uimenu(h, 'label', '150ms @ Cursor', ... 'callback', 'melba(''PLAY'',5)'); set(ph, 'userData', ph); uimenu(menu, 'label', 'Save Selection...', ... 'accelerator', 'S', ... 'callback', 'melba SAVESEL'); uimenu(menu, 'label', 'Export Selection...', ... 'accelerator', 'X', ... 'callback', 'melba SAVESELX'); uimenu(menu, 'label', 'Save Configuration...', ... 'separator', 'on', ... 'callback', 'melba SAVECFG'); uimenu(menu, 'label', 'Duplicate Window', ... 'callback', 'melba CLONE'); uimenu(menu, 'label', 'Close Window', ... 'accelerator', 'W', ... 'callback', 'close'); uimenu(menu, 'label', 'Close All', ... 'callback', 'melba ABORT'); % Spectra menu menu = uimenu(fh, 'label', 'Spectra', 'HandleVisibility', 'Callback'); uimenu(menu, 'label', 'Step Forward', ... 'accelerator', 'F', ... 'callback', 'melba(''NUDGE'',1)'); uimenu(menu, 'label', 'Step Backward', ... 'accelerator', 'B', ... 'callback', 'melba(''NUDGE'',-1)'); uimenu(menu, 'label', 'List Formants', ... 'accelerator', 'R', ... 'callback', 'melba FORMANTS'); uimenu(menu, 'label', 'List COG Measures', ... 'accelerator', 'G', ... 'callback', 'melba COG'); uimenu(menu, 'label', 'Config Spectral Anal', ... 'separator', 'on', ... 'accelerator', 'A', ... 'callback', 'melba CFGSPEC'); if isempty(cfg.FMTS), if nSamps > 50000, fmts=0; cs='off'; else, fmts=1; cs='on'; end; else, fmts = cfg.FMTS; if fmts, cs = 'on'; else, cs = 'off'; end; end; fmtsMenu = uimenu(menu, 'label', 'Track Formants', ... 'accelerator', 'J', ... 'checked', cs, ... 'callback', 'melba TRACKFMTS'); uimenu(menu, 'label', 'Waterfall Plot', ... 'callback', 'melba WATERFALL'); % Labels menu menu = uimenu(fh, 'label', 'Labels', 'HandleVisibility', 'Callback'); uimenu(menu, 'label', 'Make Label...', ... 'accelerator', 'M', ... 'callback', 'melba LMAKE'); uimenu(menu, 'label', 'Edit Labels...', ... 'accelerator', 'E', ... 'callback', 'melba LEDIT'); uimenu(menu, 'label', 'Save Labels...', ... 'accelerator', 'V', ... 'callback', 'melba LSAVE'); uimenu(menu, 'label', 'Export Labels...', ... 'callback', 'melba LEXPORT'); uimenu(menu, 'label', 'Import Labels...', ... 'callback', 'melba LIMPORT'); uimenu(menu, 'label', 'Clear All Labels', ... 'callback', 'melba LCLEAR'); h = uimenu(menu, 'label', 'Labelling Behavior', ... 'separator', 'on'); if isempty(cfg.LPROC), s = '<Default>'; else, s = cfg.LPROC; end; lblMenu = uimenu(h, 'label', s); uimenu(h, 'label', 'Clear', ... 'separator', 'on', ... 'callback', 'melba(''LSETPROC'',0);'); uimenu(h, 'Label', 'Select...', ... 'accelerator', 'L', ... 'callback', 'melba(''LSETPROC'',1);'); uimenu(h, 'Label', 'Configure...', ... 'accelerator', 'K', ... 'callback', 'melba(''LSETPROC'',2);'); % Variable List menu if ~isempty(vList), menu = uimenu(fh, 'label', 'Variables', 'HandleVisibility', 'Callback'); cs = {'off','on'}; if isempty(vListSel), vListSel = 1; end; if isempty(name), name = vList{vListSel}; end; uimenu(menu, 'label', 'Previous', ... 'accelerator', '1', ... 'callback', 'melba(''VARLIST'',-1);'); uimenu(menu, 'label', 'Next', ... 'accelerator', '2', ... 'callback', 'melba(''VARLIST'',1);'); uimenu(menu, 'label', 'Next; close current', ... 'accelerator', '3', ... 'callback', 'melba(''VARLIST'',1);close(gcbf);'); uimenu(menu, 'label', 'Next plus export', ... 'accelerator', '4', ... 'callback', 'melba(''LEXPORT'');melba(''VARLIST'',1);close(gcbf);'); uimenu(menu, 'label', 'Next; export, close current', ... 'accelerator', '5', ... 'callback', 'melba(''LEXPORT'');melba(''VARLIST'',1);close(gcbf);'); uimenu(menu, 'label', 'Next; save labs, close current', ... 'accelerator', '6', ... 'callback', 'melba(''LSAVE'',1);melba(''VARLIST'',1);close(gcbf);'); uimenu(menu, 'label', vList{1}, ... 'separator', 'on', ... 'checked', cs{(vListSel==1)+1}, ... 'userData', 1, ... 'callback', 'melba(''VARLIST'',0)'); for i = 2 : length(vList), uimenu(menu, 'label', vList{i}, ... 'checked', cs{(vListSel==i)+1}, ... 'userData', i, ... 'callback', 'melba(''VARLIST'',0)'); end; end; % Movement menu if data, menu = uimenu(fh, 'label', 'Movement', 'HandleVisibility', 'Callback'); uimenu(menu, 'label', 'Temporal Plot', ... 'accelerator', '3', ... 'callback', 'melba PLOTTRAJ'); uimenu(menu, 'label', 'Spatial Plot', ... 'accelerator', '4', ... 'callback', 'melba PLOTSPAT'); uimenu(menu, 'label', 'Display 2D Plot', ... 'accelerator', '5', ... 'callback', 'melba(''SHOWSPAT'',gcbo);'); uimenu(menu, 'label', 'Select Targets...', ... 'separator', 'on', ... 'accelerator', '6', ... 'callback', 'melba LSELECT'); uimenu(menu, 'label', 'Apply Labels...', ... 'accelerator', '7', ... 'callback', 'melba LAPPLY'); end; % init internal state state = struct('FH', fh, ... % figure handle 'FPANEL', fa, ... % framing panel handle 'BOUNDS', sh, ... % selector bounds handle 'SELECTION', sa, ... % selection panel handle 'SPECGRAM', ka, ... % spectrogram panel handle 'SPECTRA', ra, ... % spectra panel handle 'SPECTRAL', rl, ... % spectra line handle 'ZOOMA', za, ... % zoom panel handle 'ZOOM', zoom, ... % zoom line handle 'CURSORH', ca, ... % cursor axis handle 'CURSORL', cl, ... % cursor line handle 'F0A', f0a, ... % F0 panel handle 'F0', f0, ... % F0 'F0THR', cfg.F0THR, ... % F0 trim thresh 'FORMANTS', formants, ... % formants 'RMSA', rmsa, ... % RMS panel handle 'RMS', rms, ... % RMS 'HEADF', hf, ... % head field handle 'TAILF', tf, ... % tail field handle 'HEADFL', hfl, ... % head field label handle 'TAILFL', tfl, ... % tail field label handle 'CURSORF', cf, ... % cursor field handle 'HEAD', head, ... % head (msecs) 'TAIL', tail, ... % tail 'CURSOR', 0, ... % cursor 'DUR', dur, ... % signal duration (msecs) 'NUDGE', cfg.NUDGE, ... % nudge length (msecs) 'FRAME', cfg.FRAME, ... % # FFT evaluation points 'ORDER', cfg.ORDER, ... % LPC order 'WSIZE', cfg.WSIZE, ... % analysis window size (msecs) 'NFMTS', cfg.NFMTS, ... % # formants recorded 'AVGW', cfg.AVGW, ... % averaging window (msecs) 'OLAP', cfg.OLAP, ... % averaging overlap (msecs) 'ZOOMW', cfg.ZOOMW, ... % zoomed waveform window (msecs) 'BWCLIP', cfg.BWCLIP, ... % formant bandwidth clipping (Hz) 'PREEMP', cfg.PREEMP, ... % pre-emphasis (negated is adaptive) 'SOFF', cfg.SOFF, ... % spectral offset 'SPECLIM', specLim, ... % spectral display limit (Hz) 'ANAL', cfg.ANAL, ... % spectra analysis 'ISF', cfg.ISF, ... % true if female subject 'SGWIN', wsm, ... % sgram window size popup menu handle 'CONTRAST', slider, ... % spectrogram contrast slider 'SIGNAL', signal, ... % signal data 'SRATE', sRate, ... % sampling rate 'SPREAD', cfg.SPREAD, ... % signal scaling 'MOVEMODE', '', ... % movement mode 'MOVED', 0, ... % movement flag 'AUTOMENU', autoMenu, ... % auto update menu handle 'AUTO', auto, ... % auto update enabled 'FMTSMENU', fmtsMenu, ... % formant display menu handle 'FMTS', fmts, ... % formant display enabled 'LBLMENU', lblMenu, ... % labelling behavior menu handle 'LPROC', cfg.LPROC, ... % labelling procedure 'LPSTATE', cfg.LPSTATE, ... % labelling procedure data 'LABELS', labels, ... % label list 'NAME', name, ... % input data name 'PALATE', cfg.PALATE, ... % palate trace 'SPLINE', cfg.SPLINE, ... % tongue spline data indices 'DATA', [], ... % mavis trajectory data 'TARGETS', cfg.TARGETS, ... % export targets 'SPATWIN', [], ... % spatial display 'VLIST', [], ... % variable list 'VLISTSEL', vListSel, ... % current varlist selection 'SLIST', cfg.SLIST, ... % superimposed label list 'CLOSEFCN', closefcn, ... % function called at window close 'CHANNEL', cfg.CHANNEL, ... % stereo handling 'SIGNALS', signals); % signals aggregate if data, % retain movement data if available state.DATA = varargin{1}; if isempty(state.TARGETS), loaded = {}; exported = {}; for i = 1 : length(state.DATA), if size(state.DATA(i).SIGNAL,2) > 1, exported{end+1} = state.DATA(i).NAME; end; end; targets = struct('LOADED', [], ... 'EXPORTED', [], ... 'COMPONENTS', [1 1 0 0 0]); % X, Y; no tilt, vel, acc targets.LOADED = loaded; targets.EXPORTED = exported; state.TARGETS = targets; end; end; % this assignment must be done separately to avoid cloning state if ~isempty(vList), state.VLIST = vList; end; % update selection SetBounds(state, 2); SetCursor(state); % plot any labels if ~isempty(labels), axes(state.CURSORH); y = get(state.CURSORH, 'yLim') * .98; labels(1).HANDS = []; for i = 1 : length(labels), if isempty(cfg.LPROC), x = labels(i).OFFSET; labels(i).HANDS = line([x x], y, 'tag', 'LABEL', 'eraseMode', 'xor', ... 'buttonDownFcn', 'melba(''LMOVE'',''DOWN'');'); if ~isempty(labels(i).NAME), labels(i).HANDS(end+1) = text(x, y(2), [' ', labels(i).NAME], ... 'verticalAlignment', 'top', ... 'eraseMode', 'xor', ... 'fontname', 'geneva', ... 'fontsize', 9); end; else, labels(i) = feval(cfg.LPROC, cfg.LPSTATE, 'PLOT', labels(i), y); end; end; state.LABELS = labels; end; % 'superimposed' labels (SLIST): must be a matrix of msec offsets [length(vList) x nLabs] % created as immoveable anonymous labels if ~isempty(cfg.SLIST), axes(state.CURSORH); y = get(state.CURSORH, 'yLim') * .98; x = [1;1] * cfg.SLIST(vListSel,:); line(x,y,'tag','LABEL','color','g'); end; % turn on visibility if ~isempty(state.SIGNALS), name = vList{vListSel}; end; if isempty(closefcn), closefcn = 'closereq'; end; set(fh, 'userdata', state, ... 'name', ['MELBA: ' name], ... 'handleVisibility', 'callback', ... 'closeRequestFcn', closefcn, ... 'visible', 'on'); % config label proc if necessary if ~isempty(cfg.LPROC) & isempty(cfg.LPSTATE), lpState = feval(cfg.LPROC, [], 'CONFIG', state); % call user proc config handler if ~isempty(lpState), if isnumeric(lpState) & lpState == -1, % call label procedure immediately set(fh, 'handleVisibility', 'on'); feval(state.LPROC, [], 'DOWN', 0, 1, fh); if ~state.AUTO, SetBounds(get(fh, 'userData'),0); end; set(fh, 'handleVisibility', 'callback'); else, state.LPSTATE = lpState; % store configured label state set(fh, 'userdata', state); end; end; end; if strncmp(computer, 'MAC' ,3), % focus X [s,r] = unix('osascript -e ''tell application "MATLAB" to activate'''); end; %----------------------------------------------------------------------------- % LAPPLY: apply labels to trajectory data, output as spreadsheet file case 'LAPPLY', state = get(gcbf, 'userdata'); if isempty(state.LABELS), return; end; if isempty(state.DATA) | isempty(state.TARGETS.EXPORTED), error('no MAVIS-compatible trajectory data available'); end; trajList = state.TARGETS.EXPORTED; valList = {}; c = state.TARGETS.COMPONENTS; if c(1), valList{end+1} = 'X'; end; if c(2), valList{end+1} = 'Y'; end; if c(3), valList{end+1} = 'T'; end; if c(4), valList{end+1} = 'vX'; valList{end+1} = 'vY'; valList{end+1} = 'V'; end; if c(5), valList{end+1} = 'aX'; valList{end+1} = 'aY'; valList{end+1} = 'A'; end; eval([state.NAME '=state.DATA;ApplyLabels(' state.NAME ',state.LABELS,[],trajList,valList)']); %----------------------------------------------------------------------------- % LCLEAR: clear all labels case 'LCLEAR', if strcmp(questdlg('Clear all labels...', 'Verify...', 'Yes', 'No', 'Yes'), 'Yes'), state = get(gcbf, 'userdata'); state.LABELS = []; set(gcbf, 'userdata', state); delete(findobj(state.CURSORH, 'tag', 'LABEL')); end; %----------------------------------------------------------------------------- % LCLRSEL: clear selected labels case 'LCLRSEL', cfgState = get(gcbf, 'UserData'); state = get(cfgState.GUI, 'UserData'); killList = get(cfgState.LISTBOX, 'Value'); if isempty(killList), return; end; curLabs = size(get(cfgState.LISTBOX, 'String'),1); for i = killList, delete(state.LABELS(i).HANDS); end; state.LABELS(killList) = []; set(cfgState.GUI, 'UserData', state); set(cfgState.LISTBOX, 'Value', [], 'String', MakeList(state)); %----------------------------------------------------------------------------- % LCONFIG: configure labelling case 'LCONFIG', state = get(gcbf, 'userdata'); figPos = get(0, 'ScreenSize'); width = 280; height = 220; macpc = strcmp(computer, 'MAC2') | strcmp(computer, 'PCWIN'); if macpc, height = height - 30; end; figPos = [figPos(1)+(figPos(3)-width)/2, figPos(2)+(figPos(4)-height)/2, width, height]; cfg = dialog('Name', 'Default Labelling Behavior', ... 'Tag', 'MELBA', ... 'menubar', 'none', ... 'Position', figPos, ... 'KeyPressFcn', 'set(gcbf,''UserData'',1);uiresume', ... 'UserData', 0); blurb = ['A label is set at cursor offset on modified click release. ' ... 'Use shift-click to create label without annotation; ctl/alt-click ' ... 'to create an annotated label. Select number of output formants below.']; if macpc, h = 20; else, h = 0; end; uicontrol(cfg, ... 'Style', 'frame', ... 'Position', [10 height-90+h width-20 80-h]); uicontrol(cfg, ... 'Style', 'text', ... 'HorizontalAlignment', 'left', ... 'String', blurb, ... 'Position', [13 height-87+h width-26 74-h]); v = state.LPSTATE; if isstruct(v) | isempty(v) | v<1, v = 0; else, v = 1; end; propLab = uicontrol(cfg, ... % propagate labels checkbox 'Style', 'checkbox', ... 'String', 'Propagate labels', ... 'Value', v, ... 'Units', 'characters', ... 'Position', [8 7 30 1.5]); p = [4 4 26 1.5]; if macpc, p(3) = p(3) + 4; end; uicontrol(cfg, ... % # formants popup 'Style','text', ... 'HorizontalAlignment', 'right', ... 'String','Number of output formants:', ... 'Units', 'characters', ... 'Position', p); p = [32 4.2 12 1.5]; if macpc, p(1)=p(1)+4; p(2)=p(2)-.1; p(3)=p(3)+2; end; nf = uicontrol(cfg, ... 'Style', 'popupmenu', ... 'HorizontalAlignment', 'left', ... 'String', '0|1|2|3|4|5', ... 'value', state.NFMTS+1, ... 'Units', 'characters', ... 'Position', p); uicontrol(cfg, ... % buttons 'Position',[width/2-70 15 60 25], ... 'String','OK', ... 'Callback','set(gcbf,''UserData'',1);uiresume'); uicontrol(cfg, ... 'Position',[width/2+10 15 60 25], ... 'String','Cancel', ... 'Callback','uiresume'); % wait for input uiwait(cfg); if ~ishandle(cfg), return; end; if get(cfg, 'userData'), state.NFMTS = get(nf, 'value') - 1; state.LPSTATE = get(propLab, 'value'); set(gcbf, 'userData', state); end; delete(cfg); %----------------------------------------------------------------------------- % LEDIT: edit labels case 'LEDIT', state = get(gcbf, 'userdata'); figPos = get(0, 'ScreenSize'); width = 350; height = 250; figPos = [figPos(1)+(figPos(3)-width)/2, figPos(2)+(figPos(4)-height)/2, width, height]; cfg = dialog('Name', 'Edit Labels', ... 'Position', figPos, ... 'keyPressFcn', 'uiresume'); h = 19; w = 0; pc = strcmp(computer, 'PCWIN'); if pc, w = 9; h = 17; end; uicontrol(cfg, ... 'HorizontalAlignment', 'center', ... 'units', 'characters', ... 'Position', [2 h 7 1], ... 'String','Label', ... 'Style','text'); uicontrol(cfg, ... 'HorizontalAlignment', 'center', ... 'units', 'characters', ... 'Position', [18+w h 8 1], ... 'String','Offset', ... 'Style','text'); uicontrol(cfg, ... 'HorizontalAlignment', 'center', ... 'units', 'characters', ... 'Position', [27+w h 10 1], ... 'String','Comments', ... 'Style','text'); lb = uicontrol(cfg, ... % listbox 'Position',[10 60 width-20 height-90], ... 'FontName', 'Courier', ... 'String', MakeList(state), ... 'Style','listbox', ... 'Max', 2, ... 'Value', [], ... 'UserData', [], ... 'Callback','melba LEDSEL;'); uicontrol(cfg, ... % buttons 'Position',[width/2-120 15 60 25], ... 'String', 'Done', ... 'callback', 'uiresume'); uicontrol(cfg, ... 'Position',[width/2-30 15 60 25], ... 'String', 'Edit', ... 'callback', 'melba LEDSEL'); uicontrol(cfg, ... 'Position',[width/2+60 15 60 25], ... 'String', 'Clear', ... 'callback', 'melba LCLRSEL'); cfgState = struct('GUI', gcbf, 'LISTBOX', lb); set(cfg, 'userdata', cfgState); % wait for input uiwait(cfg); if ishandle(cfg), delete(cfg); end; %----------------------------------------------------------------------------- % LEDSEL: edit selected label case 'LEDSEL', cfgState = get(gcbf, 'userData'); state = get(cfgState.GUI, 'userData'); if gcbo == cfgState.LISTBOX & ~strcmp(get(gcbf, 'selectionType'), 'open'), return; % ignore single listbox clicks end; i = get(cfgState.LISTBOX, 'Value'); % index of label to edit if size(i,2) ~= 1, return; end; % edit single selection only label = EditLabel(state.LABELS(i), 'Edit'); if isempty(label), return; end; % cancel set(state.CURSORL, 'visible', 'off'); delete(state.LABELS(i).HANDS); axes(state.CURSORH); y = get(state.CURSORH, 'yLim'); if isempty(state.LPROC), % default plotting label = melba('LPLOT', label, y); set(label.HANDS(1), 'buttonDownFcn', 'melba(''LMOVE'',''DOWN'');'); else, % user proc label = feval(state.LPROC, state.LPSTATE, 'PLOT', label, y); end; set(state.CURSORL, 'visible', 'on'); state.LABELS(i) = label; set(cfgState.GUI, 'userData', state); set(cfgState.LISTBOX, 'String', MakeList(state)); %----------------------------------------------------------------------------- % LEXPORT: default label export (write formants values to spreadsheet file) case 'LEXPORT', state = get(gcbf, 'userdata'); if ~isempty(state.LPROC), feval(state.LPROC, state.LPSTATE, 'EXPORT', state.LABELS, state.NAME); return; end; if isempty(state.LABELS), return; end; [fileName, pathName] = uiputfile([state.NAME '.lab'], 'Save labels as'); if fileName == 0, return; end; % cancelled fileName = [pathName, fileName]; cd(pathName); % change working directory to save destination % open the file [fid, msg] = fopen(fileName, 'wt'); if fid == -1 error(sprintf('error attempting to open %s', fileName)); end; % write headers, data fprintf(fid, 'LABEL\tOFFSET\tNOTE'); nf = state.NFMTS; for i = 1 : nf, fprintf(fid, '\tF%d', i); end; for i = 1 : nf, fprintf(fid, '\tBW%d', i); end; fprintf(fid, '\n'); for i = 1 : length(state.LABELS), fprintf(fid, '%s\t%g\t', state.LABELS(i).NAME, state.LABELS(i).OFFSET); if ischar(state.LABELS(i).HOOK), fprintf(fid, '%s', state.LABELS(i).HOOK); end; [p,f,formants,bws] = ComputeSpectra(state, state.LABELS(i).OFFSET); val = repmat(NaN, 2, nf); val(:,1:length(formants)) = [formants;bws]; fprintf(fid, '\t%g', val(:,1:nf)'); fprintf(fid, '\n'); end; % clean up fclose(fid); fprintf('Labels written to %s\n', fileName); %----------------------------------------------------------------------------- % LIMPORT: import labels from previously exported spreadsheet file (.lab) % from landmark label file (.lm) % from LEX style label files (.label) % % note: recreated as default labels case 'LIMPORT', [f, p] = uigetfile('*.*', 'Select label file'); if f == 0, return; end; % cancelled fileName = [p f]; [p,f,ext] = fileparts(fileName); fid = fopen(fileName, 'rt'); if fid == -1, error(['error attempting to open ' fileName]); end; switch upper(ext), % headers case '.LM', % landmark labels while 1, lin = fgetl(fid); if lin(1) == '#', break; end; end; case '.LABEL', % LEX style labels ; case '.TEXTGRID', % PRAAT style ; otherwise, % assume melba tab-delimited format lin = fgetl(fid); [label,lin] = strtok(lin); [offset,lin] = strtok(lin); if ~all([strcmp(label…

Large files files are truncated, but you can click here to view the full file