function pws2textgrid (X,fname) % PWS2TEXTGRID : writes Phrase-Word-Syllable structure Praat-format TextGrid file % % pws2textgrid (X,fname) % If X is a PWS structure then the file created is [X.filename '.TextGrid'] % If X is an array of PWS structs then the file created is [X{i}.filename '.TextGrid'] for each i. % % Dinoj Surendran dinoj@cs.uchicago.edu 28 Dec 2005 % % Assumptions: there could be pauses between words of the same phrase, % but not between syllables of the same word. % Notes % (1) On the Word and Syllable Tiers, any segment of non-speech is labeled with SIL. % (2) On the Phrase Tier, phrases are labeled by phrase number (a positive integer), % and separated by -1. % (3) A word can be valid or invalid. % % See http://people.cs.uchicago.edu/~dinoj/tonerec/ for more details if (nargin<2) fname = X.filename; end fid = fopen([fname '.TextGrid'],'wt'); if isfield(X,'filename') fprintf(fid,'File type = \"ooTextFile\"\n'); fprintf(fid,'Object class = \"TextGrid\"\n\n'); fprintf(fid,'xmin = %f\n',X.phrases{1}.startwords(1)); fprintf(fid,'xmax = %f\n', X.phrases{end}.endwords(end)); fprintf(fid,'tiers? \n'); fprintf(fid,'size = 4\n'); % tiers for phrase / word / syllable / phonemes fprintf(fid,'item []:\n'); % print Phrase TextTier fprintf(fid,' item [1]:\n'); fprintf(fid,' class = \"IntervalTier\"\n'); fprintf(fid,' name = \"phrase\"\n'); fprintf(fid,' xmin = %f\n', X.phrases{1}.startwords(1) ); fprintf(fid,' xmax = %f\n', X.phrases{end}.endwords(end) ); fprintf(fid,' intervals: size = %d\n',-1+2*length(X.phrases )); for j=1:length(X.phrases) fprintf(fid, ' intervals[%d] :\n',2*j-1); % interval indices start at 1 fprintf(fid, ' xmin = %f\n',X.phrases{j}.startwords(1) ); fprintf(fid, ' xmax = %f\n',X.phrases{j}.endwords(end) ); fprintf(fid, ' text = \"%d\"\n',j); if (j X.phrases{j}.endwords(k)) count = count+1; end elseif (j < length(X.phrases)) % this is the last word in the not-last phrase if (X.phrases{j+1}.startwords(1) > X.phrases{j}.endwords(end)) count = count + 1; end end end end fprintf(fid,' intervals: size = %d\n',count); count = 1; for j=1:length(X.phrases) for k=1:length(X.phrases{j}.words) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.startwords(k) ); fprintf(fid, ' xmax = %f\n',X.phrases{j}.endwords(k) ); if ~(X.phrases{j}.validword(k)) fprintf(fid, ' text = \"0\"\n'); count = count+1; else fprintf(fid, ' text = \"%s\"\n',X.phrases{j}.words{k}.name); count = count+1; end if (k X.phrases{j}.endwords(k)) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.endwords(k) ); fprintf(fid, ' xmax = %f\n',X.phrases{j}.startwords(k+1)); fprintf(fid, ' text = \"SIL\"\n'); count = count+1; end elseif (j < length(X.phrases)) % this is the last word in the not-last phrase if (X.phrases{j+1}.startwords(1) > X.phrases{j}.endwords(end)) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.endwords(end) ); fprintf(fid, ' xmax = %f\n',X.phrases{j+1}.startwords(1)); fprintf(fid, ' text = \"SIL\"\n'); count = count + 1; end end end end %%%%%%%% now print syllable TextTier %%%%%%%%%%%% fprintf(fid,' item [3]:\n'); fprintf(fid,' class = \"IntervalTier\"\n'); fprintf(fid,' name = \"syllable\"\n'); fprintf(fid,' xmin = %f\n', X.phrases{1}.startwords(1) ); fprintf(fid,' xmax = %f\n', X.phrases{end}.endwords(end) ); count = 0; % find out how many 'syllables' (including SIL) there are for j=1:length(X.phrases) for k=1:length(X.phrases{j}.words) if ~(X.phrases{j}.validword(k)) count = count + 1; else count = count+length(X.phrases{j}.words{k}.sylls); end % check for silence between syllables if (X.phrases{j}.validword(k)) for s=1:length(X.phrases{j}.words{k}.sylls)-1 if (X.phrases{j}.words{k}.startsylls(s+1) > X.phrases{j}.words{k}.endsylls(s)) count = count + 1; end end end if (k X.phrases{j}.endwords(k)) count = count+1; end elseif (j < length(X.phrases)) % check for silence between phrases if (X.phrases{j+1}.startwords(1) > X.phrases{j}.endwords(end)) count = count + 1; end end end end fprintf(fid,' intervals: size = %d\n',count); count = 1; for j=1:length(X.phrases) for k=1:length(X.phrases{j}.words) if (~X.phrases{j}.validword(k)) % invalid words have one syllable (= "0") fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.startwords(k)); fprintf(fid, ' xmax = %f\n',X.phrases{j}.endwords(k)); fprintf(fid, ' text = \"0\"\n'); count = count+1; else for s=1:length(X.phrases{j}.words{k}.sylls) st = X.phrases{j}.words{k}.startsylls(s); en = X.phrases{j}.words{k}.endsylls(s); fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',st); fprintf(fid, ' xmax = %f\n',en); fprintf(fid, ' text = \"%s\"\n',X.phrases{j}.words{k}.sylls{s} ); count = count+1; if s>1 % check for silence between syllables within a word enprev = X.phrases{j}.words{k}.endsylls(s-1); if (st > enprev) % as opposed to just = fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',enprev); fprintf(fid, ' xmax = %f\n',st); fprintf(fid, ' text = \"SIL\"\n'); count = count+1; elseif (st < enprev) [k j s] [enprev st en] X.phrases{j}.words{k}.sylls{s} end end end end if (k X.phrases{j}.endwords(k)) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.endwords(k) ); fprintf(fid, ' xmax = %f\n',X.phrases{j}.startwords(k+1)); fprintf(fid, ' text = \"SIL\"\n'); count = count+1; end else % check for silence between phrases if (j < length(X.phrases)) if (X.phrases{j+1}.startwords(1) > X.phrases{j}.endwords(end)) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.endwords(end) ); fprintf(fid, ' xmax = %f\n',X.phrases{j+1}.startwords(1)); fprintf(fid, ' text = \"SIL\"\n'); count = count + 1; end end end end end %%%%%%%% now print phoneme TextTier %%%%%%%%%%%% fprintf(fid,' item [4]:\n'); fprintf(fid,' class = \"IntervalTier\"\n'); fprintf(fid,' name = \"phoneme\"\n'); fprintf(fid,' xmin = %f\n', X.phrases{1}.startwords(1) ); fprintf(fid,' xmax = %f\n', X.phrases{end}.endwords(end) ); count = 0; % find out how many 'phonemes' (including SIL) there are for j=1:length(X.phrases) for k=1:length(X.phrases{j}.words) if (~X.phrases{j}.validword(k)) count = count + 1; % invalid words have just one phoneme (= "0") plus the silence else count = count + length(X.phrases{j}.words{k}.phones); end if (k X.phrases{j}.endwords(k)) count = count+1; end elseif (j < length(X.phrases)) if (X.phrases{j+1}.startwords(1) > X.phrases{j}.endwords(end)) count = count + 1; end end end end fprintf(fid,' intervals: size = %d\n',count); count = 1; for j=1:length(X.phrases) for k=1:length(X.phrases{j}.words) if (~X.phrases{j}.validword(k)) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.startwords(k)); fprintf(fid, ' xmax = %f\n',X.phrases{j}.endwords(k)); fprintf(fid, ' text = \"0\"\n'); count = count+1; else for s=1:length(X.phrases{j}.words{k}.phones) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.words{k}.startphones(s) ); fprintf(fid, ' xmax = %f\n',X.phrases{j}.words{k}.endphones(s) ); fprintf(fid, ' text = \"%s\"\n',X.phrases{j}.words{k}.phones{s} ); count = count+1; end % no checking for silence between phonemes of each word end if (k X.phrases{j}.endwords(k)) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.endwords(k) ); fprintf(fid, ' xmax = %f\n',X.phrases{j}.startwords(k+1)); fprintf(fid, ' text = \"SIL\"\n'); count = count+1; end elseif ((j < length(X.phrases)) && (X.phrases{j+1}.startwords(1) > X.phrases{j}.endwords(end))) % and k==length(X.phrases{j}.words) fprintf(fid, ' intervals[%d] :\n',count); fprintf(fid, ' xmin = %f\n',X.phrases{j}.endwords(end) ); fprintf(fid, ' xmax = %f\n',X.phrases{j+1}.startwords(1)); fprintf(fid, ' text = \"SIL\"\n'); count = count + 1; end end end end fclose(fid);