]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
release: 1.3.20
[lilypond.git] / lily / lookup.cc
1 /*
2   lookup.cc -- implement simple Lookup methods.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
8   Jan Nieuwenhuizen <janneke@gnu.org>
9
10   TODO
11       Glissando
12 */
13 #include <math.h>
14 #include <ctype.h>
15 #include "lookup.hh"
16 #include "debug.hh"
17 #include "dimensions.hh"
18
19 #include "bezier.hh"
20 #include "paper-def.hh"
21 #include "string-convert.hh"
22 #include "file-path.hh"
23 #include "main.hh"
24 #include "lily-guile.hh"
25 #include "all-font-metrics.hh"
26 #include "afm.hh"
27 #include "scope.hh"
28 #include "molecule.hh"
29 #include "atom.hh"
30 #include "lily-guile.hh"
31
32
33 Lookup::Lookup ()
34 {
35   afm_l_ = 0;  
36 }
37
38 Lookup::Lookup (Lookup const& s)
39 {
40   font_name_ = s.font_name_;
41   afm_l_ = 0;  
42 }
43
44
45 /*
46   build a ledger line for small pieces.
47  */
48 Molecule
49 Lookup::ledger_line (Interval xwid) const
50 {
51   Drul_array<Molecule> endings;
52   endings[LEFT] = afm_find ("noteheads-ledgerending");
53   Molecule * e = &endings[LEFT];
54   endings[RIGHT] = *e;
55   
56   Real thick = e->dim_[Y_AXIS].length();
57   Real len = e->dim_[X_AXIS].length () - thick;
58
59   Molecule total;
60   Direction d = LEFT;
61   do {
62     endings[d].translate_axis (xwid[d] - endings[d].dim_[X_AXIS][d], X_AXIS);
63     total.add_molecule (endings[d]);    
64   } while ((flip(&d)) != LEFT);
65
66   Real xpos = xwid [LEFT] + len;
67
68   while (xpos + len + thick /2 <= xwid[RIGHT])
69     {
70       e->translate_axis (len, X_AXIS);
71       total.add_molecule (*e);
72       xpos += len;
73     }
74
75   return total;
76 }
77
78
79 Molecule
80 Lookup::afm_find (String s, bool warn) const
81 {
82   if (!afm_l_)      
83     {
84       Lookup * me = (Lookup*)(this);
85       me->afm_l_ = all_fonts_global_p->find_afm (font_name_);
86       if (!me->afm_l_)
87         {
88           warning (_f ("Can't find font: `%s'", font_name_));
89           warning (_f ("(search path `%s')", global_path.str ().ch_C()));
90           error (_ ("Aborting"));
91         }
92     }
93   AFM_CharMetricInfo const *cm = afm_l_->find_char_metric (s, warn);
94   Molecule m;
95   if (!cm)
96     {
97       m.set_empty (false);
98       return m;
99     }
100   
101   Atom at (gh_list (ly_symbol2scm ("char"),
102                     gh_int2scm (cm->code),
103                     SCM_UNDEFINED));
104
105   at.fontify (afm_l_);
106   m.dim_ = afm_bbox_to_box (cm->charBBox);
107   m.add_atom (&at);
108   return m;
109 }
110
111 Molecule
112 Lookup::simple_bar (String type, Real h, Paper_def* paper_l) const
113 {
114   SCM thick = ly_symbol2scm (("barthick_" + type).ch_C());
115   Real w = 0.0;
116   
117   if (paper_l->scope_p_->elem_b (thick))
118     {
119       w = paper_l->get_realvar (thick);
120     }
121   else
122     {
123       programming_error ("No bar thickness set ! ");
124       w = 1 PT;
125     }
126   return filledbox (Box (Interval(0,w), Interval(-h/2, h/2)));
127 }
128
129   
130 Molecule
131 Lookup::bar (String str, Real h, Paper_def *paper_l) const
132 {
133   if (str == "bracket")
134     return staff_bracket (h, paper_l);
135   else if (str == "brace")
136     {
137       Real staffht  = paper_l->get_var ("staffheight");
138       return staff_brace (h,staffht);
139     }
140   Real kern = paper_l->get_var ("bar_kern");
141   Real thinkern = paper_l->get_var ("bar_thinkern");
142
143   Molecule thin = simple_bar ("thin", h, paper_l);
144   Molecule thick = simple_bar ("thick", h, paper_l);
145   Molecule colon = afm_find ("dots-repeatcolon", paper_l);  
146
147   Molecule m;
148   
149   if (str == "")
150     {
151       return fill (Box (Interval(0, 0), Interval (-h/2, h/2)));
152     }
153   if (str == "scorepostbreak")
154     {
155       return simple_bar ("score", h, paper_l);
156     }
157   else if (str == "|")
158     {
159       return thin;
160     }
161   else if (str == "|.")
162     {
163       m.add_at_edge (X_AXIS, LEFT, thick, 0);      
164       m.add_at_edge (X_AXIS, LEFT, thin, kern);
165     }
166   else if (str == ".|")
167     {
168       m.add_at_edge (X_AXIS, RIGHT, thick, 0);
169       m.add_at_edge (X_AXIS, RIGHT, thin, kern);
170     }
171   else if (str == ":|")
172     {
173       m.add_at_edge (X_AXIS, LEFT, thick, 0);
174       m.add_at_edge (X_AXIS, LEFT, thin, kern);
175       m.add_at_edge (X_AXIS, LEFT, colon, kern);      
176     }
177   else if (str == "|:")
178     {
179       m.add_at_edge (X_AXIS, RIGHT, thick, 0);
180       m.add_at_edge (X_AXIS, RIGHT, thin, kern);
181       m.add_at_edge (X_AXIS, RIGHT, colon, kern);      
182     }
183   else if (str == ":|:")
184     {
185       m.add_at_edge (X_AXIS, LEFT, thick, thinkern);
186       m.add_at_edge (X_AXIS, LEFT, colon, kern);      
187       m.add_at_edge (X_AXIS, RIGHT, thick, kern);
188       m.add_at_edge (X_AXIS, RIGHT, colon, kern);      
189     }
190   else if (str == ".|.")
191     {
192       m.add_at_edge (X_AXIS, LEFT, thick, thinkern);
193       m.add_at_edge (X_AXIS, RIGHT, thick, kern);      
194     }
195   else if (str == "||")
196     {
197       m.add_at_edge (X_AXIS, RIGHT, thin, 0);
198       m.add_at_edge (X_AXIS, RIGHT, thin, thinkern);      
199     }
200
201   return m;
202 }
203
204 Molecule 
205 Lookup::beam (Real slope, Real width, Real thick) const
206 {
207   Real height = slope * width; 
208   Real min_y = (0 <? height) - thick/2;
209   Real max_y = (0 >? height) + thick/2;
210
211   
212   Molecule m;
213   Atom at
214     (gh_list (ly_symbol2scm ("beam"),
215               gh_double2scm (width),
216               gh_double2scm (slope),
217               gh_double2scm (thick),
218               SCM_UNDEFINED));
219
220   m.dim_[X_AXIS] = Interval (0, width);
221   m.dim_[Y_AXIS] = Interval (min_y, max_y);
222   m.add_atom (&at);
223   return m;
224 }
225
226
227
228 /*
229   FIXME.
230  */
231 Molecule
232 Lookup::dashed_slur (Bezier b, Real thick, Real dash) const
233 {
234   SCM l = SCM_EOL;
235   for (int i= 4; i -- ;)
236     {
237       l = gh_cons (ly_offset2scm (b.control_[i]), l);
238     }
239
240   Atom at (gh_list (ly_symbol2scm ("dashed-slur"),
241                     gh_double2scm (thick), 
242                     gh_double2scm (dash),
243                     ly_quote_scm (l),
244                     SCM_UNDEFINED));
245   Molecule m;
246   m.add_atom (&at);
247   return m;
248 }
249
250
251
252
253 Molecule
254 Lookup::fill (Box b) const
255 {
256   Molecule m;
257   m.dim_ = b;
258   return m;
259 }
260
261
262
263 Molecule
264 Lookup::special_time_signature (String s, int n, int d, Paper_def*pap) const
265 {
266   // First guess: s contains only the signature style
267   String symbolname = "timesig-" + s + to_str (n) + "/" + to_str (d);
268   
269   Molecule m = afm_find (symbolname, false);
270   if (!m.empty_b()) 
271     return m;
272
273   // Second guess: s contains the full signature name
274   m = afm_find ("timesig-"+s, false);
275   if (!m.empty_b ()) 
276     return m;
277
278   // Resort to default layout with numbers
279   return time_signature (n,d,pap);
280 }
281
282 Molecule
283 Lookup::filledbox (Box b ) const
284 {
285   Molecule m;
286   
287   Atom at  (gh_list (ly_symbol2scm ("filledbox"),
288                      gh_double2scm (-b[X_AXIS][LEFT]),
289                      gh_double2scm (b[X_AXIS][RIGHT]),                 
290                      gh_double2scm (-b[Y_AXIS][DOWN]),
291                      gh_double2scm (b[Y_AXIS][UP]),                    
292                      SCM_UNDEFINED));
293
294   m.dim_ = b;
295   m.add_atom (&at);
296   return m;
297 }
298
299 /*
300    TODO: THIS IS UGLY.  Since the user has direct access to TeX
301    strings, we try some halfbaked attempt to detect TeX trickery.
302  */
303 String
304 sanitise_TeX_string (String text)
305 {
306   int brace_count =0;
307   for (int i= 0; i < text.length_i (); i++)
308     {
309       if (text[i] == '\\')
310         continue;
311       
312       if (text[i] == '{')
313         brace_count ++;
314       else if (text[i] == '}')
315         brace_count --;
316     }
317   
318   if(brace_count)
319     {
320       warning (_f ("Non-matching braces in text `%s', adding braces", text.ch_C()));
321
322       if (brace_count < 0)
323         {
324           text = to_str ('{', -brace_count) + text;
325         }
326       else 
327         {
328           text = text + to_str ('}', brace_count);
329         }
330     }
331     
332   return text;
333 }
334
335 /**
336    TODO!
337  */
338 String
339 sanitise_PS_string (String t)
340 {
341   return t;
342 }
343
344 /**
345
346 */
347 Molecule
348 Lookup::text (String style, String text, Paper_def *paper_l) const
349 {
350   Molecule m;
351   if (style.empty_b ())
352     style = "roman";
353   
354   int font_mag = 0;
355   Real font_h = paper_l->get_var ("font_normal");
356   if (paper_l->scope_p_->elem_b ("font_" + style))
357     {
358       font_h = paper_l->get_var ("font_" + style);
359     }
360
361
362   if (paper_l->scope_p_->elem_b ("magnification_" + style))
363     {
364       font_mag = (int)paper_l->get_var ("magnification_" + style);
365     }
366
367   /*
368     UGH.
369   */
370   SCM l = ly_eval_str (("(style-to-cmr \"" + style + "\")").ch_C());
371   if (l != SCM_BOOL_F)
372     {
373       style = ly_scm2string (gh_cdr(l)) +to_str  ((int)font_h);
374     }
375
376   
377
378   Font_metric* metric_l = 0;
379
380   if (font_mag)
381     metric_l = all_fonts_global_p->find_scaled (style, font_mag);
382   else
383     metric_l = all_fonts_global_p->find_font (style);
384   
385   
386   if (output_global_ch == "tex")
387     text = sanitise_TeX_string  (text);
388   else if (output_global_ch == "ps")
389     text = sanitise_PS_string (text);
390     
391   m.dim_ = metric_l->text_dimension (text);
392   
393   Atom at  (gh_list (ly_symbol2scm ("text"),
394                      ly_str02scm (text.ch_C()),
395                      SCM_UNDEFINED));
396   at.fontify (metric_l);
397   
398   m.add_atom (&at);
399   return m;
400 }
401   
402
403
404
405 Molecule
406 Lookup::time_signature (int num, int den, Paper_def *paper_l) const
407 {
408   String sty = "number";
409   Molecule n (text (sty, to_str (num), paper_l));
410   Molecule d (text (sty, to_str (den), paper_l));
411   n.align_to (X_AXIS, CENTER);
412   d.align_to (X_AXIS, CENTER);
413   Molecule m;
414   if (den)
415     {
416       m.add_at_edge (Y_AXIS, UP, n, 0.0);
417       m.add_at_edge (Y_AXIS, DOWN, d, 0.0);
418     }
419   else
420     {
421       m = n;
422       m.align_to (Y_AXIS, CENTER);
423     }
424   return m;
425 }
426
427 Molecule
428 Lookup::staff_brace (Real y, int staff_size) const
429 {
430   Molecule m;
431
432   Real step  = 1.0;
433   int minht  = 2 * staff_size;
434   int maxht = 7 *  minht;
435   int idx = int (((maxht - step) <? y - minht) / step);
436   idx = idx >? 0;
437
438
439   String nm = String ("feta-braces" + to_str (staff_size));
440   SCM e =gh_list (ly_symbol2scm ("char"), gh_int2scm (idx), SCM_UNDEFINED);
441   Atom at  (e);
442
443   at.fontify (all_fonts_global_p->find_font (nm));
444   
445   m.dim_[Y_AXIS] = Interval (-y/2,y/2);
446   m.dim_[X_AXIS] = Interval (0,0);
447   m.add_atom (&at);
448   return m;
449 }
450
451
452
453 Molecule
454 Lookup::tuplet_bracket (Real dy , Real dx, Real thick, Real gap,
455                         Real height, Direction dir) const
456 {
457   Molecule m;
458
459   Atom at  (gh_list(ly_symbol2scm ("tuplet"),
460                     gh_double2scm (height),
461                     gh_double2scm (gap),
462                     gh_double2scm (dx),
463                     gh_double2scm (dy),
464                     gh_double2scm (thick),
465                     gh_int2scm (dir),
466                     SCM_UNDEFINED));
467   m.add_atom (&at);
468
469   return m;
470 }
471
472 /*
473   Make a smooth curve along the points 
474  */
475 Molecule
476 Lookup::slur (Bezier curve, Real curvethick, Real linethick) const
477 {
478   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
479   Bezier back = curve;
480
481   back.reverse ();
482   back.control_[1] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));
483   back.control_[2] += curvethick * complex_exp (Offset (0, alpha + M_PI/2));  
484
485   SCM scontrols[8];
486   for (int i=4; i--;)
487     scontrols[ i ] = ly_offset2scm (back.control_[i]);
488   for (int i=4 ; i--;)
489     scontrols[i+4] = ly_offset2scm (curve.control_[i]);
490
491   /*
492     Need the weird order b.o. the way PS want its arguments  
493    */
494   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
495   SCM list = SCM_EOL;
496   for (int i= 8; i--;  )
497     {
498       list = gh_cons (scontrols[indices[i]], list);
499     }
500   
501   
502   Atom at  (gh_list (ly_symbol2scm ("bezier-sandwich"),
503                      ly_quote_scm (list),
504                      gh_double2scm (linethick),
505                      SCM_UNDEFINED));
506
507   Molecule m; 
508   m.dim_[X_AXIS] = curve.extent (X_AXIS);
509   m.dim_[Y_AXIS] = curve.extent (Y_AXIS);
510   m.add_atom (&at);
511   return m;
512 }
513
514 Molecule
515 Lookup::staff_bracket (Real height, Paper_def* paper_l) const
516 {
517   Molecule m;
518   Atom at  ( gh_list (ly_symbol2scm ("bracket"),
519                       gh_double2scm (paper_l->get_var("bracket_arch_angle")),
520                       gh_double2scm (paper_l->get_var("bracket_arch_width")),
521                       gh_double2scm (paper_l->get_var("bracket_arch_height")),
522                       gh_double2scm (paper_l->get_var("bracket_width")),
523                       gh_double2scm (height),
524                       gh_double2scm (paper_l->get_var("bracket_arch_thick")),
525                       gh_double2scm (paper_l->get_var("bracket_thick")),
526                       SCM_UNDEFINED));
527   
528   m.add_atom (&at);                              
529   m.dim_[Y_AXIS] = Interval (-height/2,height/2);
530   m.dim_[X_AXIS] = Interval (0,4 PT);
531
532   m.translate_axis (- 4. / 3. * m.dim_[X_AXIS].length (), X_AXIS);
533   return m;
534 }
535
536 Molecule
537 Lookup::volta (Real h, Real w, Real thick, bool vert_start, bool vert_end) const
538 {
539   Molecule m; 
540
541   Atom at  (gh_list (ly_symbol2scm ("volta"),
542                      gh_double2scm (h),
543                      gh_double2scm (w),
544                      gh_double2scm (thick),
545                      gh_int2scm (vert_start),
546                      gh_int2scm (vert_end),
547                      SCM_UNDEFINED));
548
549   m.dim_[Y_AXIS] = Interval (- h/2, h/2);
550   m.dim_[X_AXIS] = Interval (0, w);
551
552   m.add_atom (&at);
553   return m;
554 }
555
556 Molecule
557 Lookup::accordion (SCM s, Real staff_space) const
558 {
559   Molecule m;
560   String sym = ly_scm2string(gh_car (s));
561   String reg = ly_scm2string(gh_car (gh_cdr(s)));
562
563   if (sym == "Discant")
564     {
565       Molecule r = afm_find("scripts-accDiscant");
566       m.add_molecule(r);
567       if (reg.left_str(1) == "F")
568         {
569           Molecule d = afm_find("scripts-accDot");
570           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
571           m.add_molecule(d);
572           reg = reg.right_str(reg.length_i()-1);
573         }
574       int eflag = 0x00;
575       if (reg.left_str(3) == "EEE")
576         {
577           eflag = 0x07;
578           reg = reg.right_str(reg.length_i()-3);
579         }
580       else if (reg.left_str(2) == "EE")
581         {
582           eflag = 0x05;
583           reg = reg.right_str(reg.length_i()-2);
584         }
585       else if (reg.left_str(2) == "Eh")
586         {
587           eflag = 0x04;
588           reg = reg.right_str(reg.length_i()-2);
589         }
590       else if (reg.left_str(1) == "E")
591         {
592           eflag = 0x02;
593           reg = reg.right_str(reg.length_i()-1);
594         }
595       if (eflag & 0x02)
596         {
597           Molecule d = afm_find("scripts-accDot");
598           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
599           m.add_molecule(d);
600         }
601       if (eflag & 0x04)
602         {
603           Molecule d = afm_find("scripts-accDot");
604           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
605           d.translate_axis(0.8 * staff_space PT, X_AXIS);
606           m.add_molecule(d);
607         }
608       if (eflag & 0x01)
609         {
610           Molecule d = afm_find("scripts-accDot");
611           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
612           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
613           m.add_molecule(d);
614         }
615       if (reg.left_str(2) == "SS")
616         {
617           Molecule d = afm_find("scripts-accDot");
618           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
619           d.translate_axis(0.4 * staff_space PT, X_AXIS);
620           m.add_molecule(d);
621           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
622           m.add_molecule(d);
623           reg = reg.right_str(reg.length_i()-2);
624         }
625       if (reg.left_str(1) == "S")
626         {
627           Molecule d = afm_find("scripts-accDot");
628           d.translate_axis(0.5 * staff_space PT, Y_AXIS);
629           m.add_molecule(d);
630           reg = reg.right_str(reg.length_i()-1);
631         }
632     }
633   else if (sym == "Freebase")
634     {
635       Molecule r = afm_find("scripts-accFreebase");
636       m.add_molecule(r);
637       if (reg.left_str(1) == "F")
638         {
639           Molecule d = afm_find("scripts-accDot");
640           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
641           m.add_molecule(d);
642           reg = reg.right_str(reg.length_i()-1);
643         }
644       if (reg == "E")
645         {
646           Molecule d = afm_find("scripts-accDot");
647           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
648           m.add_molecule(d);
649         }
650     }
651   else if (sym == "Bayanbase")
652     {
653       Molecule r = afm_find("scripts-accBayanbase");
654       m.add_molecule(r);
655       if (reg.left_str(1) == "T")
656         {
657           Molecule d = afm_find("scripts-accDot");
658           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
659           m.add_molecule(d);
660           reg = reg.right_str(reg.length_i()-1);
661         }
662       /* include 4' reed just for completeness. You don't want to use this. */
663       if (reg.left_str(1) == "F")
664         {
665           Molecule d = afm_find("scripts-accDot");
666           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
667           m.add_molecule(d);
668           reg = reg.right_str(reg.length_i()-1);
669         }
670       if (reg.left_str(2) == "EE")
671         {
672           Molecule d = afm_find("scripts-accDot");
673           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
674           d.translate_axis(0.4 * staff_space PT, X_AXIS);
675           m.add_molecule(d);
676           d.translate_axis(-0.8 * staff_space PT, X_AXIS);
677           m.add_molecule(d);
678           reg = reg.right_str(reg.length_i()-2);
679         }
680       if (reg.left_str(1) == "E")
681         {
682           Molecule d = afm_find("scripts-accDot");
683           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
684           m.add_molecule(d);
685           reg = reg.right_str(reg.length_i()-1);
686         }
687     }
688   else if (sym == "Stdbase")
689     {
690       Molecule r = afm_find("scripts-accStdbase");
691       m.add_molecule(r);
692       if (reg.left_str(1) == "T")
693         {
694           Molecule d = afm_find("scripts-accDot");
695           d.translate_axis(staff_space * 3.5 PT, Y_AXIS);
696           m.add_molecule(d);
697           reg = reg.right_str(reg.length_i()-1);
698         }
699       if (reg.left_str(1) == "F")
700         {
701           Molecule d = afm_find("scripts-accDot");
702           d.translate_axis(staff_space * 2.5 PT, Y_AXIS);
703           m.add_molecule(d);
704           reg = reg.right_str(reg.length_i()-1);
705         }
706       if (reg.left_str(1) == "M")
707         {
708           Molecule d = afm_find("scripts-accDot");
709           d.translate_axis(staff_space * 2 PT, Y_AXIS);
710           d.translate_axis(staff_space PT, X_AXIS);
711           m.add_molecule(d);
712           reg = reg.right_str(reg.length_i()-1);
713         }
714       if (reg.left_str(1) == "E")
715         {
716           Molecule d = afm_find("scripts-accDot");
717           d.translate_axis(staff_space * 1.5 PT, Y_AXIS);
718           m.add_molecule(d);
719           reg = reg.right_str(reg.length_i()-1);
720         }
721       if (reg.left_str(1) == "S")
722         {
723           Molecule d = afm_find("scripts-accDot");
724           d.translate_axis(staff_space * 0.5 PT, Y_AXIS);
725           m.add_molecule(d);
726           reg = reg.right_str(reg.length_i()-1);
727         }
728     }
729   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
730      for the rectangle */
731   else if (sym == "SB")
732     {
733       Molecule r = afm_find("scripts-accSB");
734       m.add_molecule(r);
735     }
736   else if (sym == "BB")
737     {
738       Molecule r = afm_find("scripts-accBB");
739       m.add_molecule(r);
740     }
741   else if (sym == "OldEE")
742     {
743       Molecule r = afm_find("scripts-accOldEE");
744       m.add_molecule(r);
745     }
746   else if (sym == "OldEES")
747     {
748       Molecule r = afm_find("scripts-accOldEES");
749       m.add_molecule(r);
750     }
751   return m;  
752 }
753