]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord-name-engraver.cc
* lily/parser.yy (Music_list): add error-found to music with errors.
[lilypond.git] / lily / chord-name-engraver.cc
1 /*
2   chord-name-engraver.cc -- implement Chord_name_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2004 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "engraver.hh"
10 #include "chord-name.hh"
11 #include "event.hh"
12 #include "output-def.hh"
13 #include "font-interface.hh"
14 #include "output-def.hh"
15 #include "dimensions.hh"
16 #include "item.hh"
17 #include "pitch.hh"
18 #include "protected-scm.hh"
19 #include "context.hh"
20 #include "warn.hh"
21
22 class Chord_name_engraver : public Engraver 
23 {
24   TRANSLATOR_DECLARATIONS ( Chord_name_engraver);
25 protected:
26   virtual void stop_translation_timestep ();
27   virtual void process_music ();
28   virtual bool try_music (Music *);
29   virtual void finalize ();
30   virtual void derived_mark () const;
31 private:
32   void add_note (Music *);
33   
34   Item* chord_name_;
35   Link_array<Music> notes_;
36   
37   SCM last_chord_;
38 };
39
40
41
42 void
43 Chord_name_engraver::finalize ()
44 {
45 }
46
47 void
48 Chord_name_engraver::derived_mark() const
49 {
50   scm_gc_mark (last_chord_);
51 }
52
53 Chord_name_engraver::Chord_name_engraver ()
54 {
55   chord_name_ = 0;
56   last_chord_ = SCM_EOL;
57 }
58
59 void
60 Chord_name_engraver::add_note (Music * n)
61 {
62   notes_.push (n);
63 }
64
65 void
66 Chord_name_engraver::process_music ()
67 {
68   if (!notes_.size () )
69     return;
70   
71   SCM bass = SCM_EOL;
72   SCM inversion = SCM_EOL;
73   SCM pitches = SCM_EOL;
74
75   Music* inversion_event = 0;
76   for (int i =0 ; i < notes_.size (); i++)
77     {
78       Music *n = notes_[i];
79       SCM p = n->get_property ("pitch");
80       if (!unsmob_pitch (p))
81         continue;
82       
83       if (n->get_property ("inversion") == SCM_BOOL_T)
84         {
85           inversion_event = n;
86           inversion = p;
87         }
88       else if (n->get_property ("bass") == SCM_BOOL_T)
89         bass = p;
90       else
91         pitches = scm_cons (p, pitches);
92     }
93
94   if (inversion_event)
95     {
96       SCM oct = inversion_event->get_property ("octavation");
97       if (scm_is_number (oct))
98         {
99           Pitch *p = unsmob_pitch (inversion_event->get_property ("pitch"));
100           int octavation =  scm_to_int (oct);
101           Pitch orig = p->transposed (Pitch (-octavation, 0,0));
102           
103           pitches= scm_cons (orig.smobbed_copy (), pitches);
104         }
105       else
106         programming_error ("Inversion does not have original pitch.");
107     }
108
109   pitches = scm_sort_list (pitches, Pitch::less_p_proc);
110
111   SCM name_proc = get_property ("chordNameFunction");
112   SCM markup = scm_call_4 (name_proc, pitches, bass, inversion,
113                            context ()->self_scm ());
114
115   /*
116     Ugh. 
117    */
118   SCM chord_as_scm = scm_cons (pitches, scm_cons (bass, inversion));
119   
120   chord_name_ = make_item ("ChordName",notes_[0]->self_scm ());
121   chord_name_->set_property ("text", markup);
122
123   SCM s = get_property ("chordChanges");
124   if (to_boolean (s) && scm_is_pair (last_chord_) 
125       && ly_c_equal_p (chord_as_scm, last_chord_))
126     chord_name_->set_property ("begin-of-line-visible", SCM_BOOL_T);
127
128   last_chord_ = chord_as_scm;
129 }
130
131 bool
132 Chord_name_engraver::try_music (Music* m)
133 {
134   /*
135     hmm. Should check? 
136    */
137   if (m->is_mus_type ("note-event"))
138     {
139       add_note (m);
140       return true;
141     }
142   return false;
143 }
144
145 void
146 Chord_name_engraver::stop_translation_timestep ()
147 {
148   chord_name_ = 0;
149   notes_.clear ();
150 }
151
152 /*
153   The READs description is not strictly accurate:
154   which properties are read depend on the chord naming function active.
155 */
156 ENTER_DESCRIPTION (Chord_name_engraver,
157 /* descr */       "Catch note-events "
158 "and generate the appropriate chordname.",
159 /* creats*/       "ChordName",
160 /* accepts */     "note-event",
161 /* acks  */      "",
162 /* reads */       "chordChanges chordNameExceptions chordNameFunction "
163 "chordNoteNamer chordRootNamer chordNameExceptions majorSevenSymbol",
164 /* write */       "");