1 unit analyze;
2
3 { Decide which lines of paragraphs go where; test total duration of lines. }
4
5 interface uses control, globals;
6
7 procedure testParagraph;
8 procedure describeParagraph;
9 procedure paragraphSetup (var voice: voice_index0);
10 procedure includeStartString;
11
12 implementation uses mtx, strings, lyrics, mtxline, uptext,
13 preamble, utility;
14
15 procedure includeStartString;
16 var voice: voice_index;
17 mus: paragraph_index0;
18 begin for voice:=1 to nvoices do
19 begin mus:=musicLineNo(voice); if mus>0 then
20 P[mus]:=startString(voice)+P[mus];
21 end;
22 end;
23
describenull24 function describe(nbar,extra: integer): string;
25 begin describe:=toString(nbar)+' bar'+plural(nbar)+' + '+
26 toString(extra)+'/64 notes';
27 end;
28
29 procedure testParagraph;
30 var voice, leader, nv: voice_index0;
31 mus: paragraph_index0;
32 extra, l, nbar: integer;
33 begin
34 nbars:=0; pickup:=0; nleft:=0; if top>bottom then exit;
35 pickup:=0; nv:=0; leader:=0; multi_bar_rest := false;
36 for voice:=top to bottom do
37 begin mus:=musicLineNo(voice);
38 if mus>0 then {* -------------- Voice is present ---- }
39 begin inc(nv); line_no:=orig_line_no[mus];
40 scanMusic(voice,l);
41 if multi_bar_rest and (nv>1) then error(
42 'Multi-bar rest allows only one voice',print);
43 if not pmx_preamble_done then
44 if voice=top then pickup:=l
45 else if pickup<>l then
46 error3(voice,'The same pickup must appear in all voices');
47 nbar := numberOfBars(voice); extra := extraLength(voice);
48 if multi_bar_rest and ((nbar>0) or (extra>0)) then error3(voice,
49 'Multi-bar rest allows no other rests or notes');
50 if (nbar>nbars) or (nbar=nbars) and (extra>nleft) then
51 begin nbars:=nbar; nleft:=extra; leader:=voice; end;
52 if not final_paragraph and (meternum>0) and (extra>0) then
53 begin writeln('Line has ', describe(nbar,extra));
54 error(' Line does not end at complete bar',print);
55 end;
56 if pmx_preamble_done and (l>0) and (meternum>0) then
57 error3(voice,'Short bar with no meter change');
58 end
59 end;
60 if not pmx_preamble_done then
61 begin
62 xmtrnum0 := pickup/one_beat; { Don't want an integer result }
63 if beVerbose then writeln ('Pickup = ', pickup, '/64');
64 end;
65 if leader>0 then
66 for voice:=top to bottom do if musicLineNo(voice)>0 then
67 if voice<>leader then
68 begin mus:=musicLineNo(voice);
69 line_no:=orig_line_no[mus];
70 if (numberOfBars(voice)<>numberOfBars(leader))
71 or (extraLength(voice)<>extraLength(leader)) then
72 begin
73 writeln('Following line has ',
74 describe(numberOfBars(voice), extraLength(voice)));
75 writeln(musicLine(voice));
76 writeln('Longest line has ',
77 describe(numberOfBars(leader), extraLength(leader)));
78 writeln(musicLine(leader));
79 error('Line duration anomaly',print);
80 end;
81 end;
82 end;
83
84 procedure describeParagraph;
85 var voice: voice_index0;
86 begin writeln('---- Paragraph ',paragraph_no,
87 ' starting at line ', orig_line_no[1], ' bar ', bar_no);
88 for voice:=top to bottom do describeVoice(voice,lyricsReport(voice));
89 end;
90
91 procedure paragraphSetup (var voice: voice_index0);
92 var l: integer;
93 k: voice_index0;
94 P_keep, w: string;
95 is_labelled: boolean;
96
97 procedure maybeUptext(i: integer);
98 begin if not doUptext then exit;
99 if (length(w)=1) then if (voice=nvoices) then
100 warning('Uptext line below bottom voice should be labelled',print);
101 if length(w)=1 then {* Standard chord line ------ }
102 begin k:=voice+1; if k>nvoices then dec(k);
103 setUptextLineNo(k,i);
104 end
105 else {* Labelled chord line ---- }
106 begin predelete(w,1); k:=findVoice(w);
107 if k=0 then error('Uptext line belongs to unknown voice',print)
108 else setUptextLineNo(k,i);
109 end
110 end;
111
112 procedure maybeChords(i: integer);
113 begin if not doChords then exit;
114 if (length(w)=1) and (voice=0) and pedanticWarnings then
115 warning('Chord line above top voice should be labelled',print);
116 if length(w)=1 then {* Standard chord line ------ }
117 begin k:=voice; if k=0 then k:=1;
118 setChordLineNo(k,i);
119 end
120 else {* Labelled chord line ---- }
121 begin predelete(w,1); k:=findVoice(w);
122 if k=0 then error('Chord line belongs to unknown voice',print)
123 else setChordLineNo(k,i);
124 end
125 end;
126
127 procedure analyzeParagraph;
128 var i: paragraph_index;
129 begin voice:=0; bottom:=0; top:=nvoices+1;
130 clearLabels; clearTags; clearUptext;
131 for i:=1 to para_len do { ----- Paragraph analysis main loop ----- }
132 if (P[i]<>'') and (P[i,1]<>comment) then
133 begin
134 w:=NextWord(P[i],blank,colon); line_no := orig_line_no[i];
135 l:=length(w);
136 is_labelled := (w[l]=colon) and (w[l-1]<>barsym);
137 if is_labelled then
138 begin P_keep := P[i]; predelete(P[i],l); shorten(w,l-1);
139 k:=findVoice(w); { First look for a voice label }
140 if k>0 then
141 begin voice:=k; setMusicLineNo(voice,i);
142 end
143 else if w[1]='L' then maybeLyrics(voice,i,w)
144 else if w[1]='C' then maybeChords(i)
145 else if w[1]='U' then maybeUptext(i)
146 else begin {* ------------ Maybe Space command ------------ }
147 if startsWithIgnoreCase(w,'SPACE') then
148 begin setSpace(P[i]); must_respace:=true;
149 end
150 else {* ------------ Maybe Voices command ------------ }
151 if startsWithIgnoreCase(w,'VOICES') then
152 begin selectVoices(P[i]); must_restyle:=true;
153 end
154 else begin {* Could be sticky attribute *}
155 P[i] := P_keep; is_labelled := false;
156 if not isNoteOrRest(w) then error('Unknown line label',print);
157 end
158 end
159 end;
160 if not is_labelled then
161 begin inc(voice); setMusicLineNo(voice,i);
162 end;
163 if voice>bottom then bottom:=voice;
164 if (voice>0) and (voice<top) then top:=voice;
165 end;
166 end;
167
168 procedure obliterate;
169 var i: paragraph_index;
170 new_only: string;
171 begin new_only:='';
172 for i:=1 to para_len do if startsWithIgnoreCase(P[i],'only:')
173 then begin new_only:=P[i]; P[i]:='%'; end;
174 if new_only<>'' then setOnly(new_only)
175 else for i:=1 to para_len do if omitLine(i) then P[i]:='%';
176 end;
177
178 begin obliterate; analyzeParagraph; reviseLyrics;
179 end;
180
181 end.
182