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