summaryrefslogtreecommitdiff
path: root/Build/source/utils/m-tx/mtx-src/preamble.pas
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/m-tx/mtx-src/preamble.pas')
-rw-r--r--Build/source/utils/m-tx/mtx-src/preamble.pas688
1 files changed, 688 insertions, 0 deletions
diff --git a/Build/source/utils/m-tx/mtx-src/preamble.pas b/Build/source/utils/m-tx/mtx-src/preamble.pas
new file mode 100644
index 00000000000..ffc3716567b
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/preamble.pas
@@ -0,0 +1,688 @@
+unit preamble;
+{$X+}
+{ Interpret preamble paragraph, compose PMX preamble }
+
+interface uses globals;
+
+function thisCase: boolean;
+procedure preambleDefaults;
+procedure interpretCommands;
+procedure doPreamble;
+procedure doPMXpreamble;
+procedure respace;
+procedure restyle;
+function startString(voice: voice_index0): string;
+procedure augmentPreamble(control_para: boolean);
+function omitLine(line: paragraph_index): boolean;
+procedure nonMusic;
+procedure setOnly(line: string);
+function isCommand(command: string): boolean;
+
+const known = true;
+
+implementation uses control, mtxline, strings, files, status, utility;
+
+const blank = ' ';
+ colon = ':';
+ semicolon = ';';
+ comma = ',';
+ known_styles: integer = 12;
+ max_styles = 24;
+ warn_redefine: boolean = false;
+
+type command_type =
+ ( none, title, composer, pmx, tex, options, msize, bars, shortnote,
+ style, sharps, flats, meter, space, pages, systems, width, height,
+ enable, disable, range, name, indent,
+ poet, part, only, octave, start );
+
+ line_type = ( unknown, colon_line, command_line, comment_line,
+ plain_line );
+
+ style_index = 1..max_styles;
+ style_index0 = 0..max_styles;
+
+const c1 = title; cn = start;
+ commands: array[command_type] of string[16] =
+ ( 'NONE', 'TITLE', 'COMPOSER', 'PMX', 'TEX', 'OPTIONS',
+ 'SIZE', 'BARS/LINE', 'SHORT',
+ 'STYLE', 'SHARPS', 'FLATS', 'METER', 'SPACE', 'PAGES', 'SYSTEMS', 'WIDTH',
+ 'HEIGHT', 'ENABLE', 'DISABLE', 'RANGE',
+ 'NAME', 'INDENT', 'POET', 'PART', 'ONLY', 'OCTAVE', 'START');
+ cline: array[command_type] of string =
+ ( '', '', '', '', '', '', '', '', '1/4', (* short *)
+ '', '0', '', 'C', '', '1', '1', (* systems *)
+ '190mm', '260mm', '', '', '', '', '', '', '', '', '', '' );
+ redefined: array[command_type] of boolean =
+ ( false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false );
+
+(** Known styles *)
+ known_style: array[style_index] of string = (
+'SATB: Voices S,A T,B; Choral; Clefs G F',
+'SATB4: Voices S A T B; Choral; Clefs G G G8 F',
+'SINGER: Voices Voice; Vocal; Clefs G',
+'PIANO: Voices RH LH; Continuo; Clefs G F',
+'ORGAN: Voices RH LH Ped; Continuo; Clefs G F F',
+'SOLO: Voices V; Clefs G',
+'DUET: Voices V1 Vc; Clefs G F',
+'TRIO: Voices V1 Va Vc; Clefs G C F',
+'QUARTET: Voices V1 V2 Va Vc; Clefs G G C F',
+'QUINTET: Voices V1 V2 Va Vc1 Vc2; Clefs G G C F F',
+'SEXTET: Voices V1 V2 Va1 Va2 Vc1 Vc2; Clefs G G C C F F',
+'SEPTET: Voices V1 V2 Va1 Va2 Vc1 Vc2 Cb; Clefs G G C C F F F',
+'', '', '', '', '', '', '', '', '', '', '', '');
+
+var old_known_styles: style_index;
+ style_used: array[style_index] of boolean;
+ omit_line: array[paragraph_index] of boolean;
+ orig_style_line: array[style_index] of style_index0;
+ orig_range_line: integer;
+
+var nclefs, n_pages, n_systems, n_sharps, ngroups: integer;
+ part_line, title_line, composer_line, pmx_line, options_line,
+ start_line, voices, clefs: string;
+ group_start, group_stop: array[1..maxgroups] of integer;
+ instr_name: array[stave_index] of string[40];
+ style_supplied: boolean;
+
+{ ------------------ Styles ------------------ }
+
+function voiceCount(s: string): voice_index0;
+ var i, l: integer;
+ begin l:=length(s); for i:=1 to l do if s[i]=comma then s[i]:=blank;
+ voiceCount:=wordCount(s);
+ end;
+
+function findStyle(s: string): style_index0;
+ var i: style_index0;
+begin
+ i:=0; s:=s+colon; findStyle:=0;
+ while i<known_styles do
+ begin inc(i);
+ if startsWithIgnoreCase(known_style[i],s) then
+ begin findStyle:=i; exit; end;
+ end;
+end;
+
+procedure addStyle (S: string);
+ var sn: style_index0;
+begin
+ sn:=findStyle(NextWord(S,colon,dummy));
+ if sn>0 then known_style[sn] := S
+ else if known_styles < max_styles then
+ begin inc(known_styles);
+ known_style[known_styles] := S;
+ end
+ else error('Can''t add another style - table full',print);
+end;
+
+procedure readStyles;
+ var eofstyle: boolean;
+ S: string;
+ l: style_index0;
+begin if styleFileFound then eofstyle:=true else eofstyle := eof(stylefile);
+ l:=0;
+ while not eofstyle do
+ begin readln(stylefile,S); if S<>'' then
+ begin addStyle(S); inc(l); orig_style_line[known_styles]:=l; end;
+ eofstyle := eof(stylefile);
+ end;
+end;
+
+procedure applyStyle(s, stylename: string;
+ first_inst, first_stave: stave_index);
+ var clef, subline, subcommand: string;
+ i, last_inst, last_stave: stave_index0;
+ continuo, toosoon, vocal: boolean;
+ begin last_inst:=first_inst-1;
+ toosoon := false; continuo:=false; vocal := false;
+ subline:=GetNextWord(s,blank,colon);
+ while s<>'' do
+ begin subline:=GetNextWord(s,semicolon,dummy);
+ i:=curtail(subline,semicolon);
+ subcommand:=GetNextWord(subline,blank,dummy);
+ if equalsIgnoreCase(subcommand,'VOICES') then
+ begin voices:=voices+' '+subline;
+ last_stave := first_stave + wordCount(subline) - 1;
+ last_inst := first_inst + voiceCount(subline) - 1;
+ end
+ else if equalsIgnoreCase(subcommand,'CLEFS')
+ then
+ begin clef:=subline; clefs:=clefs+' '+clef; end
+ else if equalsIgnoreCase(subcommand,'VOCAL') then
+ if last_inst<first_inst then toosoon:=true
+ else begin some_vocal := true; vocal := true;
+ for i:=first_inst to last_inst do setVocal(i,true);
+ end
+ else if equalsIgnoreCase(subcommand,'CHORAL') or
+ equalsIgnoreCase(subcommand,'GROUP') then
+ if last_inst<first_inst then toosoon:=true
+ else begin
+ if equalsIgnoreCase(subcommand,'CHORAL') then
+ begin some_vocal := true; vocal := true;
+ for i:=first_inst to last_inst do setVocal(i,true);
+ end;
+ if ngroups=maxgroups then error('Too many groups',print)
+ else begin inc(ngroups);
+ group_start[ngroups] := first_stave;
+ group_stop[ngroups] := last_stave;
+ end
+ end
+ else if equalsIgnoreCase(subcommand,'CONTINUO') then continuo := true
+ else error('Subcommand ' + subcommand + ' in STYLE unknown',print);
+ if toosoon then
+ error('You must first give VOICES before specifying ' + subcommand,
+ print);
+ end;
+ if vocal and continuo then error(
+ 'A continuo instrument may not be vocal',print);
+ if wordCount(clef)<>last_stave-first_stave+1 then error(
+ 'Number of clefs does not match number of voices',print);
+ if (first_stave=last_stave) or continuo
+ then instr_name[first_stave]:=stylename
+ else for i:=first_stave to last_stave do instr_name[i]:='';
+ if continuo then
+ begin inc(ninstr); stave[ninstr] := first_stave;
+ for i:=first_stave to last_stave do instr[i]:=ninstr;
+ end
+ else for i:=first_stave to last_stave do
+ begin inc(ninstr); stave[ninstr] := i; instr[i] := ninstr;
+ end;
+ end;
+
+procedure applyStyles;
+ var n1, n2, sn: integer;
+ s: string;
+ begin voices:=''; clefs:=''; ninstr:=0;
+ while cline[style]<>'' do
+ begin n1:=voiceCount(voices)+1;
+ n2:=wordCount(voices)+1;
+ s:=GetNextWord(cline[style],blank,comma);
+ curtail(s,comma);
+ sn:=findStyle(s); if sn=0 then error ('Style ' + s +' unknown',print);
+ line_no := orig_style_line[sn]; applyStyle(known_style[sn],s,n1,n2);
+ style_used[sn] := true;
+ end;
+ end;
+
+{ ------------------------------------------------------------- }
+
+procedure wipeCommands;
+ var c: command_type;
+begin for c:=c1 to cn do cline[c]:='';
+end;
+
+function omitLine(line: paragraph_index): boolean;
+begin omitLine := (line>0) and omit_line[line]
+end;
+
+procedure setName;
+ var i: integer;
+begin if not redefined[name] then exit;
+ setFeature('instrumentNames',true);
+ for i:=1 to ninstr do
+ instr_name[i] := getNextWord(cline[name],blank,dummy);
+end;
+
+procedure setIndent;
+begin if redefined[indent] then fracindent := cline[indent];
+end;
+
+procedure setInitOctave;
+begin if redefined[octave] then initOctaves(cline[octave]);
+end;
+
+procedure setVoices(var line: string);
+ var k: integer;
+ s, w: string;
+ procedure checkLabel(w: string);
+ var j: voice_index;
+ begin
+ for j:=1 to nvoices do if w=voice_label[j] then
+ begin warning('Voice label '+w+' not unique',print); exit;
+ end;
+ if length(w)>2 then exit;
+ if pos1(w[1],'CLU')>0 then
+ if length(w)>1 then if pos1(w[2],'123456789')=0 then exit
+ else
+ else
+ else if pos1(w[1],'123456789')=0 then exit;
+ error('Voice label '+w+' conflicts with reserved label',print);
+ end;
+begin nvoices:=0; nstaves:=0;
+ repeat s:=GetNextWord(line,blank,dummy);
+ if length(s)>0 then
+ begin inc(nstaves); k:=0;
+ first_on_stave[nstaves] := nvoices + 1;
+ repeat
+ w:=GetNextWord(s,blank,comma); curtail(w, comma);
+ if w<>'' then
+ begin
+ inc(k); if k<=2 then
+ begin inc(nvoices); checkLabel(w);
+ voice_label[nvoices]:=w;
+ if instr_name[nstaves]='' then instr_name[nstaves]:=w;
+ setStavePos(nvoices,nstaves,k);
+ end
+ end;
+ until w='';
+ if k>2 then error('More than two voices per stave: ' + s,print);
+ if k=2 then instr_name[nstaves]:='\mtxTwoInstruments{'
+ + voice_label[nvoices-1] + '}{'+ voice_label[nvoices] + '}';
+ number_on_stave[nstaves] := k;
+ end
+ until length(line)=0;
+ for k:=1 to nvoices do selected[k]:=true;
+end;
+
+procedure setClefs(line: string);
+ var s: string;
+begin
+ nclefs:=0;
+ repeat
+ s:=getnextword(line,blank,dummy);
+ if s<>'' then
+ begin inc(nclefs);
+ if length(s)=1 then clef[nclefs]:=s[1] else clef[nclefs]:=s[2];
+ end;
+ until s='';
+end;
+
+procedure setDimension(line: string; lno: command_type);
+ var l, n, p: integer;
+begin
+ if line = '' then exit;
+ l := length(line);
+ n := 0;
+ p := 0;
+ repeat n := n+1;
+ if line[n]='.' then p:=p+1;
+ until (n>l) or not ((line[n]='.') or (line[n]>='0') and (line[n]<='9'));
+ if (n=p) or (p>1) or
+ not ((line[n]='i') or (line[n]='m') or (line[n]='p')) then
+ error('Dimension must be a number followed by in, mm or pt',print);
+ cline[lno] := 'w' + substr(line,1,n);
+end;
+
+procedure setSize(line: string);
+ var i: stave_index0;
+ word: string;
+ begin i:=0;
+ while i<ninstr do
+ begin word:=GetNextWord(line,blank,dummy);
+ if word='' then break;
+ inc(i); getNum(word,musicsize);
+ stave_size[i] := musicsize;
+ end;
+ if not (musicsize in [16,20]) then
+ for i:=1 to ninstr do
+ if stave_size[i] = unspec then stave_size[i] := musicsize;
+ if musicsize<16 then musicsize:=16
+ else if musicsize>20 then musicsize:=20;
+ end;
+
+function findCommand(var command: string): command_type;
+ var j: command_type;
+begin curtail(command,':');
+ if equalsIgnoreCase(command,'STYLE') then style_supplied := true;
+ for j:=c1 to cn do if equalsIgnoreCase(command,commands[j]) then
+ begin findCommand:=j; exit; end;
+ findCommand:=none;
+end;
+
+function isCommand(command: string): boolean;
+begin isCommand:=findCommand(command)<>none end;
+
+function mustAppend(command: command_type): boolean;
+begin mustAppend := command=tex end;
+
+procedure doEnable(var line: string; choice: boolean);
+ var word: string;
+begin
+ repeat word:=GetNextWord(line,blank,dummy);
+ if word<>'' then if not setFeature(word,choice) then
+ Error('No such feature: '+word,not print)
+ until word=''
+end;
+
+procedure setRange(line: string);
+ var v,p: integer;
+begin
+ line_no := orig_range_line;
+ for v:=1 to nvoices do
+ begin p:=pos(voice_label[v]+'=',line);
+ if p>0 then
+ begin
+ if length(line)<p+6 then
+ error('At least five characters must follow "'+voice_label[v]+'="',
+ print);
+ defineRange(v,substr(line,p+2,5));
+ end
+ else defineRange(v,'');
+ end;
+end;
+
+function isAssertion(var line: string): boolean;
+begin
+ exit(false)
+end;
+
+function doCommand(line: string): line_type;
+ var command: string;
+ last_command: command_type;
+ starts_with_note: boolean;
+begin
+ if (line[1]=comment) and not isAssertion(line) then
+ begin doCommand:=comment_line; exit; end;
+ starts_with_note := maybeMusicLine(line);
+ command:=GetNextWord(line,blank,colon);
+ if endsWith(command,colon) then
+ begin last_command:=findCommand(command);
+ doCommand:=command_line;
+ if last_command = enable then doEnable(line,true)
+ else if last_command = disable then doEnable(line,false)
+ else if last_command = range then orig_range_line := line_no;
+ if last_command<>none then
+ begin
+ if mustAppend(last_command) and redefined[last_command] then
+ cline[last_command]:=cline[last_command]+#10+line
+ else
+ begin cline[last_command]:=line;
+ if warn_redefine and redefined[last_command] then
+ warning('You have redefined preamble command '+command,print);
+ end;
+ if last_command=start then start_line:=line;
+ redefined[last_command]:=true;
+ end
+ else begin doCommand:=colon_line; addStyle(command+colon+' '+line);
+ orig_style_line[known_styles] := line_no;
+ end
+ end
+ else if starts_with_note then doCommand:=plain_line
+ else doCommand:=unknown;
+end;
+
+procedure setOnly(line: string);
+ var num, num1, num2, l: integer;
+ s: string;
+begin if line='' then exit;
+ if startsWithIgnoreCase(line,'only') then GetNextWord(line,colon,dummy);
+ for l:=1 to lines_in_paragraph do omit_line[l]:=true;
+ repeat s:=GetNextWord(line,blank,comma); if s='' then exit;
+ curtail(s, comma);
+ if pos1('-',s)=0 then
+ begin getNum(s,num);
+ if (num>0) and (num<=lines_in_paragraph) then omit_line[num]:=false
+ else warning('Invalid line number in Only: is skipped',print);
+ end else
+ begin getTwoNums(s,num1,num2);
+ if (num1>0) and (num2<=lines_in_paragraph) then
+ for num:=num1 to num2 do omit_line[num]:=false
+ else warning('Invalid line range in Only: is skipped',print);
+ end;
+ until false;
+end;
+
+procedure interpretCommands;
+ var i, num, den, nbars: integer;
+begin
+ title_line := cline[title];
+ part_line := cline[part];
+ if (cline[poet]<>'') or (cline[composer]<>'') then
+ composer_line:='\mtxComposerLine{'+cline[poet]+'}{'+cline[composer]+'}'
+ else composer_line:='';
+ pmx_line := cline[pmx];
+ options_line := GetNextWord(cline[options],blank,dummy);
+ for i:=1 to known_styles do style_used[i] := false;
+ applyStyles; setVoices(voices);
+ for i:=old_known_styles+1 to known_styles do
+ if not style_used[i] then
+ begin warning('The following style was supplied but not used',not print);
+ writeln(known_style[i]);
+ end;
+ setClefs(clefs);
+ if not redefined[meter] then warning(
+ 'You have not defined Meter, assuming "'+cline[meter]+'" ',not print);
+ getMeter(cline[meter],meternum, meterdenom, pmnum, pmdenom);
+ setDefaultDuration(meterdenom);
+ if (meternum=0) and
+ not (redefined[pages] or redefined[systems] or redefined[bars])
+ then begin cline[bars] := '1'; redefined[bars]:=true; end;
+ if redefined[pages] or redefined[systems] then
+ begin if redefined[bars] then
+ warning('BARS/LINE ignored since you specified PAGES or SYSTEMS',print);
+ if redefined[systems] then getNum(cline[systems],n_systems)
+ else warning('PAGES specified but not SYSTEMS',not print);
+ if redefined[pages] then getNum(cline[pages],n_pages)
+ else warning('SYSTEMS specified but not PAGES',not print);
+ end
+ else if redefined[bars] then
+ begin getNum(cline[bars],nbars); if nbars>0 then
+ begin n_pages:=0; n_systems:=nbars end;
+ end;
+ getNum(cline[sharps],n_sharps);
+ setSpace(cline[space]);
+ setSize(cline[msize]);
+ getTwoNums(cline[shortnote],num, den); if den=0 then den:=1;
+ short_note := (num*64) div den;
+ if cline[flats]<>'' then
+ begin getNum(cline[flats],n_sharps); n_sharps:=-n_sharps; end;
+ setName; setIndent; setInitOctave; setOnly(cline[only]);
+ setRange(cline[range]);
+ setDimension(cline[width],width);
+ setDimension(cline[height],height);
+ if options_line <>'' then begin
+ warning('"Options" is cryptic and obsolescent.', not print);
+ writeln(' Use "Enable" and "Disable" instead.')
+ end;
+ for i:=1 to length(options_line) do processOption(options_line[i]);
+end;
+
+procedure preambleDefaults;
+ var i: integer;
+begin
+ xmtrnum0:=0; fracindent:='0'; musicsize:=20; start_line:='';
+ some_vocal:=false; ngroups:=0;
+ style_supplied := false;
+ for i:=1 to maxvoices do setVocal(i,false);
+ for i:=1 to maxstaves do
+ begin nspace[i]:=unspec; stave_size[i]:=unspec; end;
+ n_pages:=1; n_systems:=1;
+ readStyles; old_known_styles := known_styles;
+ for i:=1 to lines_in_paragraph do omit_line[i]:=false;
+end;
+
+procedure preambleGuess(maybe_voices: voice_index);
+begin
+ case maybe_voices of
+ 1: cline[style] := 'Solo';
+ 2: cline[style] := 'Duet';
+ 3: cline[style] := 'Trio';
+ 4: cline[style] := 'Quartet';
+ 5: cline[style] := 'Quintet';
+ 6: cline[style] := 'Sextet';
+ 7: cline[style] := 'Septet';
+ else begin error('I cannot guess a style',not print); exit; end;
+ end;
+ writeln('I guess this piece is a ',cline[style],
+ ' for strings in C major.');
+ writeln(' Why not provide a STYLE in the setup paragraph to make sure?');
+end;
+
+{ ------------------------------------------------------------------ }
+
+procedure nonMusic;
+ var i: paragraph_index;
+begin for i:=1 to para_len do doCommand(P[i]);
+ setOnly(cline[only]); wipeCommands;
+end;
+
+function thisCase: boolean;
+begin thisCase:=true;
+ if not startsWithIgnoreCase(P[1],'case:') then exit;
+ thisCase:=(choice<>' ') and (pos1(choice,P[1])>0); P[1]:='%';
+end;
+
+procedure augmentPreamble(control_para: boolean);
+ var i: paragraph_index;
+ l: line_type;
+ s: array[line_type] of integer;
+begin
+ if not thisCase then exit;
+ for l:=unknown to plain_line do s[l]:=0;
+ for i:=1 to para_len do
+ begin line_no:=orig_line_no[i]; l:=doCommand(P[i]);
+ inc(s[l]);
+ if (l=comment_line) and (P[i,2]=comment)
+ then begin predelete(P[i],2); putLine(P[i]); end;
+ if not control_para and (l=unknown) then
+ error('Unidentifiable line',print);
+ end;
+ if not control_para and (s[command_line]>0) and (s[plain_line]>0)
+ then error('Mixture of preamble commands and music',not print);
+end;
+
+procedure doPreamble;
+ var i: paragraph_index;
+ maybe_voices: voice_index0;
+begin maybe_voices:=0;
+ if not style_supplied then
+ begin {augmentPreamble(not known);}
+ if not style_supplied then warning('No STYLE supplied',not print);
+ for i:=1 to para_len do if maybeMusicLine(P[i]) then
+ inc(maybe_voices);
+ if maybe_voices>0 then preambleGuess(maybe_voices)
+ else error('No voices found',not print);
+ end
+end;
+
+procedure respace;
+ var i, j: stave_index;
+ begin
+ for i:=ninstr downto 2 do
+ begin j:=ninstr-i+1;
+ if nspace[j]<>unspec then TeXtype2('\mtxInterInstrument{'+toString(i-1)+
+ '}{'+toString(nspace[j])+'}');
+ end;
+ if nspace[ninstr]<>unspec then TeXtype2('\mtxStaffBottom{'+
+ toString(nspace[ninstr])+'}');
+ must_respace:=false;
+ end;
+
+procedure restyle;
+begin
+ must_restyle:=false;
+end;
+
+function clefno ( cl: char ): integer;
+begin
+ case cl of
+'G','0','t','8': clefno:=0;
+'s','1': clefno:=1;
+'m','2': clefno:=2;
+'a','3': clefno:=3;
+'n','4': clefno:=4;
+'r','5': clefno:=5;
+'F','b','6': clefno:=6;
+'C': clefno:=3;
+ else
+ begin warning('Unknown clef code - replaced by treble',print);
+ clefno:=0;
+ end;
+ end
+end;
+
+procedure doTenorClefs;
+ var i: voice_index;
+ c: char;
+begin for i:=1 to nclefs do
+ begin
+ c:=clef[i]; if (c='8') or (c='t') then
+ putLine('\\mtxTenorClef{' + toString(PMXinstr(i)) + '}\' );
+ end;
+end;
+
+procedure insertTeX;
+begin
+ if redefined[tex] then TeXtype2(cline[tex]);
+end;
+
+procedure doPMXpreamble;
+ const clefcode: string[8]='0123456';
+ var i, j: integer;
+ clefs: string;
+ function pmxMeter: string;
+ var denom, num: integer;
+ begin if meternum=0 then
+ begin num := beatsPerLine; {* denom := 0; *}
+ old_meter_word := meterChange(num,meterdenom,true);
+ end
+ else begin num := meternum; {* denom := pmdenom; *} end;
+ { CMO: unconditonally assign value of pmdenom to denom }
+ denom := pmdenom;
+ pmxMeter := toString(num) + ' ' + toString(PMXmeterdenom(meterdenom)) +
+ ' ' + toString(pmnum) + ' ' + toString(denom);
+ end;
+ function sizecode(k: integer): string;
+ begin sizecode:='\mtxNormalSize';
+ case k of
+13: if musicsize=20 then sizecode:='\mtxTinySize' else sizecode:='\mtxSmallSize';
+16: if musicsize=20 then sizecode:='\mtxSmallSize';
+20: if musicsize=16 then sizecode:='\mtxLargeSize';
+24: if musicsize=20 then sizecode:='\mtxLargeSize' else sizecode:='\mtxHugeSize';
+29: sizecode:='\mtxHugeSize';
+ else error('Valid sizes are 13, 16, 20, 24, 29',print);
+ end;
+ end;
+begin
+ if composer_line <> '' then putline(composer_line);
+ if title_line <> '' then putline('\mtxTitleLine{'+title_line+'}');
+ putLine('---');
+ if instrumentNames and not redefined[indent] then fracindent:='0.12';
+ write(outfile, nstaves);
+ write(outfile, ' ', -ninstr);
+ stave[ninstr+1]:=nstaves+1;
+ for j:=ninstr downto 1 do write(outfile, ' ', stave[j+1] - stave[j]);
+ writeln(outfile, ' ', pmxMeter, ' ',xmtrnum0:8:5, ' ',n_sharps,
+ ' ', n_pages, ' ',n_systems, ' ',musicsize, ' ',fracindent);
+ for i:=1 to ninstr do if not instrumentNames then putLine('')
+ else putLine('\mtxInstrName{'+instr_name[ninstr+1-i]+'}');
+ clefs:='';
+ for i:=nclefs downto 1 do clefs:=clefs+clefcode[1+clefno(clef[i])];
+ putLine(clefs);
+ if texdir='' then texdir := './';
+ putLine(texdir);
+
+ pmx_preamble_done:=true; insertTeX; respace;
+
+ for j:=1 to ngroups do
+ writeln(outfile,'\\mtxGroup{'+toString(j)+'}{'
+ +toString(ninstr+1-group_start[j])+'}{'
+ +toString(ninstr+1-group_stop[j])+'}\');
+ for j:=1 to ninstr do
+ if (stave_size[j]<>unspec) then
+ putLine(
+ '\\mtxSetSize{'+toString(ninstr+1-j)+'}{'+sizecode(stave_size[j])+'}\');
+ if part_line <> '' then
+ begin putLine('Ti'); putLine(part_line); end;
+ if title_line <> '' then
+ begin putLine('Tt'); putLine('\mtxTitle'); end;
+ if composer_line <> '' then
+ begin putLine('Tc'); putLine('\mtxPoetComposer'); end;
+ if pmx_line <> '' then putLine(pmx_line);
+ doTenorClefs;
+ if cline[width] <> '' then putLine(cline[width]);
+ wipeCommands;
+end;
+
+function startString(voice: voice_index0): string;
+ var s, w: string;
+ j: voice_index;
+begin s:=start_line;
+ for j:=1 to voice do w:=getNextWord(s,dummy,';');
+ curtail(w,';'); if w<>'' then startString:=w+' ' else startString:=w;
+end;
+
+end.