X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fnew-fingering-engraver.cc;h=06a3a8da9666669d7ab2d95672f167158887fe1b;hb=750b714488c5af6eae22d07163bba8b554734ac6;hp=0c95e5624afd206922663c0320af5d845272ace3;hpb=29c915ce2266a1a176222e8c2742c74fa9194a70;p=lilypond.git diff --git a/lily/new-fingering-engraver.cc b/lily/new-fingering-engraver.cc index 0c95e5624a..06a3a8da96 100644 --- a/lily/new-fingering-engraver.cc +++ b/lily/new-fingering-engraver.cc @@ -1,30 +1,43 @@ -/* - fingering-engraver.cc -- implement New_fingering_engraver - - source file of the GNU LilyPond music typesetter - - (c) 1998--2002 Han-Wen Nienhuys - - */ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 1998--2015 Han-Wen Nienhuys + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ -#include "warn.hh" #include "engraver.hh" -#include "side-position-interface.hh" + +#include "international.hh" #include "item.hh" -#include "event.hh" -#include "stem.hh" #include "rhythmic-head.hh" +#include "script-interface.hh" #include "self-alignment-interface.hh" -#include "script.hh" +#include "side-position-interface.hh" #include "stem.hh" +#include "stream-event.hh" +#include "warn.hh" + +#include "translator.icc" struct Finger_tuple { Grob *head_; Grob *script_; - Music *note_event_; - Music *finger_event_; - SCM description_; + Stream_event *note_event_; + Stream_event *finger_event_; + bool follow_into_staff_; int position_; Finger_tuple () @@ -32,129 +45,159 @@ struct Finger_tuple position_ = 0; head_ = script_ = 0; note_event_ = finger_event_ = 0; - description_ = SCM_EOL; + follow_into_staff_ = false; } - static int compare (Finger_tuple const & c1, Finger_tuple const & c2) - { - return c1.position_- c2.position_; - } - }; +bool +operator < (Finger_tuple const &a, Finger_tuple const &b) +{ + return a.position_ < b.position_; +} + class New_fingering_engraver : public Engraver { - Array fingerings_; - Array articulations_; - Link_array heads_; + vector fingerings_; + vector stroke_fingerings_; + vector articulations_; + vector string_numbers_; + + vector heads_; + vector accidentals_; Grob *stem_; - + + void position_all (); public: - TRANSLATOR_DECLARATIONS(New_fingering_engraver); + TRANSLATOR_DECLARATIONS (New_fingering_engraver); protected: - virtual void stop_translation_timestep (); - virtual void acknowledge_grob (Grob_info); - void add_fingering (Grob*, Music*,Music*); - void add_script (Grob*, Music*,Music*); - void position_scripts(); + void stop_translation_timestep (); + void acknowledge_rhythmic_head (Grob_info); + void acknowledge_inline_accidental (Grob_info); + void acknowledge_stem (Grob_info); + void add_fingering (Grob *, SCM, + vector *, + Stream_event *, Stream_event *); + void add_script (Grob *, Stream_event *, Stream_event *); + void add_string (Grob *, Stream_event *, Stream_event *); + void position_scripts (SCM orientations, vector *); }; void -New_fingering_engraver::acknowledge_grob (Grob_info inf) +New_fingering_engraver::acknowledge_inline_accidental (Grob_info inf) { - if (Rhythmic_head::has_interface (inf.grob_)) - { - Music * note_ev =inf.music_cause (); - - SCM arts = note_ev->get_mus_property ("articulations"); - - for (SCM s = arts; gh_pair_p (s); s = gh_cdr (s)) - { - Music * m = unsmob_music (gh_car (s)); + accidentals_.push_back (inf.grob ()); +} - if (!m) - continue; - +void +New_fingering_engraver::acknowledge_rhythmic_head (Grob_info inf) +{ + Stream_event *note_ev = inf.event_cause (); + if (!note_ev) + return; - if (m->is_mus_type ("fingering-event")) - { - add_fingering (inf.grob_ , m, note_ev); - } - else if (m->is_mus_type ("script-event")) - { - add_script (inf.grob_, m, note_ev); - } - } + SCM arts = note_ev->get_property ("articulations"); - heads_.push (inf.grob_); - } - else if (Stem::has_interface (inf.grob_)) + for (SCM s = arts; scm_is_pair (s); s = scm_cdr (s)) { - stem_ = inf.grob_; + Stream_event *ev = unsmob (scm_car (s)); + + if (!ev) + continue; + + if (ev->in_event_class ("fingering-event")) + add_fingering (inf.grob (), + ly_symbol2scm ("Fingering"), + &fingerings_, + ev, note_ev); + else if (ev->in_event_class ("text-script-event")) + ev->origin ()->warning (_ ("cannot add text scripts to individual note heads")); + else if (ev->in_event_class ("script-event")) + add_script (inf.grob (), ev, note_ev); + else if (ev->in_event_class ("string-number-event")) + { + // String numbers are used in calculating harmonics even + // when we don't want them displayed. So don't make space + // for them if 'stencil is #f + Grob *g = make_item ("StringNumber", ev->self_scm ()); + if (scm_is_true (g->get_property ("stencil"))) + add_fingering (inf.grob (), + ly_symbol2scm ("StringNumber"), &string_numbers_, + ev, note_ev); + g->suicide (); // Kill grob created to check stencil + } + else if (ev->in_event_class ("stroke-finger-event")) + add_fingering (inf.grob (), + ly_symbol2scm ("StrokeFinger"), &stroke_fingerings_, + ev, note_ev); + else if (ev->in_event_class ("harmonic-event")) + { + inf.grob ()->set_property ("style", ly_symbol2scm ("harmonic")); + Grob *d = unsmob (inf.grob ()->get_object ("dot")); + if (d && !to_boolean (get_property ("harmonicDots"))) + d->suicide (); + } } + + heads_.push_back (inf.grob ()); } -extern Grob *make_script_from_event (SCM * descr, Translator_group*tg, Music * event, - int index); void -New_fingering_engraver::add_script (Grob * head, - Music * event, - Music * head_event) +New_fingering_engraver::acknowledge_stem (Grob_info inf) { - Finger_tuple ft ; + stem_ = inf.grob (); +} - ft.script_ =make_script_from_event (&ft.description_, daddy_trans_, event, 0); +void +New_fingering_engraver::add_script (Grob *head, + Stream_event *event, + Stream_event * /* note */) +{ + Finger_tuple ft; - articulations_.push (ft); - announce_grob (ft.script_, event->self_scm ()); - - + Grob *g = make_item ("Script", event->self_scm ()); + make_script_from_event (g, context (), + event->get_property ("articulation-type"), 0); + ft.script_ = g; ft.script_->set_parent (head, X_AXIS); + + SCM forced_dir = event->get_property ("direction"); + if (to_dir (forced_dir)) + ft.script_->set_property ("direction", forced_dir); + + articulations_.push_back (ft); } - - void -New_fingering_engraver::add_fingering (Grob * head, - Music * event, - Music *hevent) +New_fingering_engraver::add_fingering (Grob *head, + SCM grob_sym, + vector *tuple_vector, + Stream_event *event, + Stream_event *hevent) { Finger_tuple ft; - ft.script_ = new Item (get_property ("Fingering")); - announce_grob (ft.script_, event->self_scm()); - + ft.script_ = make_item (grob_sym, event->self_scm ()); + Side_position_interface::add_support (ft.script_, head); - int d = gh_scm2int ( event->get_mus_property ("digit")); - - /* - TODO: - - Should add support for thumb. It's a little involved, since - the thumb lives in a different font. Maybe it should be moved? - - */ - - if (d > 5) - { - /* - music for the softenon children? - */ - event->origin()->warning (_("music for the martians.")); - } - SCM sstr = scm_number_to_string (gh_int2scm (d), gh_int2scm (10)) ; - ft.script_->set_grob_property ("text", sstr); - ft.finger_event_ = event; ft.note_event_ = hevent; ft.head_ = head; - fingerings_.push (ft); + tuple_vector->push_back (ft); } void -New_fingering_engraver::position_scripts () +New_fingering_engraver::position_scripts (SCM orientations, + vector *scripts) { + for (vsize i = 0; i < scripts->size (); i++) + if (stem_) + { + Side_position_interface::add_support (scripts->at (i).script_, stem_); + if (Grob *flag = unsmob (stem_->get_object ("flag"))) + Side_position_interface::add_support (scripts->at (i).script_, flag); + } /* This is not extremely elegant, but we have to do a little @@ -165,136 +208,195 @@ New_fingering_engraver::position_scripts () to the note head, and write a more flexible function for positioning the fingerings, setting both X and Y coordinates. */ - for (int i = 0; i < fingerings_.size(); i++) - { - fingerings_[i].position_ = gh_scm2int (fingerings_[i].head_ -> get_grob_property( "staff-position")); - } - - Array up, down, horiz; - for (int i = fingerings_.size(); i--;) + for (vsize i = 0; i < scripts->size (); i++) + (*scripts)[i].position_ = scm_to_int ((*scripts)[i].head_->get_property ("staff-position")); + + for (vsize i = scripts->size (); i--;) + for (vsize j = heads_.size (); j--;) + Side_position_interface::add_support ((*scripts)[i].script_, heads_[j]); + + vector up, down, horiz; + for (vsize i = scripts->size (); i--;) { - SCM d = fingerings_[i].finger_event_->get_mus_property ("direction"); + SCM d = (*scripts)[i].finger_event_->get_property ("direction"); if (to_dir (d)) - { - if (to_dir (d) == UP) - { - up.push (fingerings_[i]); - } - else - down.push (fingerings_[i]); - fingerings_.del (i); - } + { + ((to_dir (d) == UP) ? up : down).push_back ((*scripts)[i]); + scripts->erase (scripts->begin () + i); + } } - - fingerings_.sort (&Finger_tuple::compare); - SCM fhd = get_property ("fingerHorizontalDirection"); - - if (ly_dir_p (fhd)) - { - up.push (fingerings_.pop()); - down.push (fingerings_[0]); - fingerings_.del(0); - horiz = fingerings_; + vector_sort (*scripts, less ()); + + bool up_p = scm_is_true (scm_c_memq (ly_symbol2scm ("up"), orientations)); + bool down_p = scm_is_true (scm_c_memq (ly_symbol2scm ("down"), orientations)); + bool left_p = scm_is_true (scm_c_memq (ly_symbol2scm ("left"), orientations)); + bool right_p = scm_is_true (scm_c_memq (ly_symbol2scm ("right"), orientations)); + Direction hordir = (right_p) ? RIGHT : LEFT; + if (left_p || right_p) + { + if (up_p && !up.size () && scripts->size ()) + { + up.push_back (scripts->back ()); + scripts->pop_back (); + } + + if (down_p && !down.size () && scripts->size ()) + { + down.push_back ((*scripts)[0]); + scripts->erase (scripts->begin ()); + } + + horiz.insert (horiz.end (), scripts->begin (), scripts->end ()); + } + else if (up_p && down_p) + { + int center = scripts->size () / 2; + down.insert (down.end (), scripts->begin (), scripts->begin () + center); + up.insert (up.end (), scripts->begin () + center, scripts->end ()); + } + else if (up_p) + { + up.insert (up.end (), scripts->begin (), scripts->end ()); + scripts->clear (); } else { - int center = fingerings_.size() / 2; - down.concat (fingerings_.slice (0,center)); - up.concat (fingerings_.slice (center, fingerings_.size())); + if (!down_p) + { + warning (_ ("no placement found for fingerings")); + warning (_ ("placing below")); + } + down.insert (down.end (), scripts->begin (), scripts->end ()); + scripts->clear (); } - for (int i = 0; i < horiz.size(); i++) + for (vsize i = 0; i < horiz.size (); i++) { Finger_tuple ft = horiz[i]; - Grob* f = ft.script_; + Grob *f = ft.script_; f->set_parent (ft.head_, X_AXIS); f->set_parent (ft.head_, Y_AXIS); - f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, Y_AXIS); - f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, Y_AXIS); - f->add_offset_callback (Side_position_interface::aligned_side_proc, X_AXIS); - - f->set_grob_property( "direction", fhd); - typeset_grob (f); + f->set_property ("avoid-slur", ly_symbol2scm ("inside")); + if (hordir == LEFT + && unsmob (ft.head_->get_object ("accidental-grob"))) + Side_position_interface::add_support (f, + unsmob (ft.head_->get_object ("accidental-grob"))); + else if (unsmob (ft.head_->get_object ("dot"))) + Side_position_interface::add_support (f, + unsmob (ft.head_->get_object ("dot"))); + + Self_alignment_interface::set_aligned_on_parent (f, Y_AXIS); + Side_position_interface::set_axis (f, X_AXIS); + + f->set_property ("direction", scm_from_int (hordir)); } - int finger_prio = 200; - for (int i = 0; i < up.size(); i++) + Drul_array< vector > vertical (down, up); + for (DOWN_and_UP (d)) { - Finger_tuple ft = up[i]; - Grob* f = ft.script_; - f->set_parent (ft.head_, X_AXIS); - f->set_grob_property ("script-priority", - gh_int2scm (finger_prio + i)); - f->add_offset_callback (Side_position_interface::aligned_side_proc, Y_AXIS); - f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS); - f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, X_AXIS); - - f->set_grob_property ("direction", gh_int2scm (UP)); - - Side_position_interface::add_staff_support (f); - typeset_grob (f); - } - - for (int i = 0; i < down.size(); i++) - { - Finger_tuple ft = down[i]; - Grob* f = ft.script_; - f->set_parent (ft.head_, X_AXIS); - f->set_grob_property ("script-priority", - gh_int2scm (finger_prio + down.size() - i)); - - f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS); - f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, X_AXIS); - f->add_offset_callback (Side_position_interface::aligned_side_proc, Y_AXIS); - f->set_grob_property ("direction", gh_int2scm (DOWN)); - Side_position_interface::add_staff_support (f); - typeset_grob (f); + for (vsize i = 0; i < vertical[d].size (); i++) + { + Finger_tuple ft = vertical[d][i]; + Grob *f = ft.script_; + int finger_prio = robust_scm2int (f->get_property ("script-priority"), 200); + f->set_parent (ft.head_, X_AXIS); + f->set_property ("script-priority", + scm_from_int (finger_prio + d * ft.position_)); + + Self_alignment_interface::set_aligned_on_parent (f, X_AXIS); + Side_position_interface::set_axis (f, Y_AXIS); + + f->set_property ("direction", scm_from_int (d)); + } } } void New_fingering_engraver::stop_translation_timestep () +{ + position_all (); + stem_ = 0; + heads_.clear (); +} + +void +New_fingering_engraver::position_all () { if (fingerings_.size ()) { - position_scripts(); + position_scripts (get_property ("fingeringOrientations"), + &fingerings_); fingerings_.clear (); } - - for (int i = articulations_.size(); i--;) + + if (string_numbers_.size ()) + { + position_scripts (get_property ("stringNumberOrientations"), + &string_numbers_); + string_numbers_.clear (); + } + + if (stroke_fingerings_.size ()) + { + position_scripts (get_property ("strokeFingerOrientations"), + &stroke_fingerings_); + stroke_fingerings_.clear (); + } + + for (vsize i = articulations_.size (); i--;) { - Grob *sc = articulations_[i].script_; - - for (int j = heads_.size() ; j--;) - Side_position_interface::add_support (sc, heads_[j]); - - if (stem_ && to_dir (sc->get_grob_property ("side-relative-direction"))) - sc->set_grob_property ("direction-source", stem_->self_scm ()); - - SCM follow = scm_assoc (ly_symbol2scm ("follow-into-staff"), articulations_[i].description_); - if (gh_pair_p (follow) && to_boolean (gh_cdr (follow))) - sc->add_offset_callback (Side_position_interface::quantised_position_proc, Y_AXIS); - else - Side_position_interface::add_staff_support (sc); - typeset_grob (sc); + Grob *script = articulations_[i].script_; + + for (vsize j = 0; j < accidentals_.size (); j++) + Side_position_interface::add_support (script, accidentals_[j]); + + accidentals_.resize (0); + for (vsize j = heads_.size (); j--;) + Side_position_interface::add_support (script, heads_[j]); + + if (stem_ && to_dir (script->get_property ("side-relative-direction"))) + script->set_object ("direction-source", stem_->self_scm ()); + + if (stem_ && to_boolean (script->get_property ("add-stem-support"))) + Side_position_interface::add_support (script, stem_); } + articulations_.clear (); +} +New_fingering_engraver::New_fingering_engraver (Context *c) + : Engraver (c) +{ stem_ = 0; - heads_.clear (); - articulations_.clear(); } -New_fingering_engraver::New_fingering_engraver() +void +New_fingering_engraver::boot () { - stem_ = 0; + ADD_ACKNOWLEDGER (New_fingering_engraver, rhythmic_head); + ADD_ACKNOWLEDGER (New_fingering_engraver, inline_accidental); + ADD_ACKNOWLEDGER (New_fingering_engraver, stem); } -ENTER_DESCRIPTION(New_fingering_engraver, -/* descr */ "Create fingering-scripts for notes in a New Chord.", -/* creats*/ "Fingering", -/* accepts */ "text-script-event", -/* acks */ "rhythmic-head-interface stem-interface", -/* reads */ "fingersHorizontal", -/* write */ ""); +ADD_TRANSLATOR (New_fingering_engraver, + /* doc */ + "Create fingering scripts for notes in a new chord. This" + " engraver is ill-named, since it also takes care of" + " articulations and harmonic note heads.", + + /* create */ + "Fingering " + "StringNumber " + "StrokeFinger " + "Script ", + + /* read */ + "fingeringOrientations " + "harmonicDots " + "strokeFingerOrientations " + "stringNumberOrientations ", + + /* write */ + "" + );