X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fquote-iterator.cc;h=885e1bd3b658ef593f0418a19b66449a881a0e77;hb=4d405ef96a8a62771d7d9a283ff5369a772e89d8;hp=266ca9ed1a25838b4cf88c13f98d3f6ba505b14b;hpb=b1323f33e9aa4b9eea05eefb8755c907d4d762d4;p=lilypond.git diff --git a/lily/quote-iterator.cc b/lily/quote-iterator.cc index 266ca9ed1a..885e1bd3b6 100644 --- a/lily/quote-iterator.cc +++ b/lily/quote-iterator.cc @@ -1,160 +1,291 @@ -/* - quote-iterator.cc -- implement Quote_iterator +/* + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 2004--2015 Han-Wen Nienhuys - (c) 2004 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 "music-wrapper-iterator.hh" + #include "context.hh" -#include "event.hh" -#include "music-sequence.hh" +#include "dispatcher.hh" +#include "input.hh" +#include "international.hh" #include "lily-guile.hh" -#include "music-iterator.hh" +#include "music-sequence.hh" #include "music.hh" -#include "input.hh" #include "warn.hh" - -class Quote_iterator : public Music_iterator +class Quote_iterator : public Music_wrapper_iterator { public: Quote_iterator (); - + Moment vector_moment (int idx) const; + Context_handle quote_outlet_; + Moment start_moment_; + Moment stop_moment_; SCM event_vector_; int event_idx_; - int end_idx_ ; + int end_idx_; + + SCM transposed_musics_; - DECLARE_SCHEME_CALLBACK(constructor, ()); + DECLARE_SCHEME_CALLBACK (constructor, ()); + bool quote_ok () const; + bool accept_music_type (Stream_event *, bool is_cue = true) const; protected: + virtual void derived_mark () const; virtual void construct_children (); virtual Moment pending_moment () const; virtual void process (Moment); + virtual void do_quit (); virtual bool ok () const; }; -Quote_iterator::Quote_iterator () +void +Quote_iterator::do_quit () { - event_vector_ = SCM_EOL; - event_idx_ = 0; - end_idx_ = 0; + Music_wrapper_iterator::do_quit (); + quote_outlet_.set_context (0); } bool -moment_less (SCM a, SCM b) +Quote_iterator::accept_music_type (Stream_event *ev, bool is_cue) const +{ + SCM accept = SCM_EOL; + // Cue notes use the quotedCueEventTypes property, otherwise (and as fallback + // for cue notes if quotedCueEventTypes is not set) use quotedEventTypes + if (is_cue) + accept = get_outlet ()->get_property ("quotedCueEventTypes"); + if (scm_is_null (accept)) + accept = get_outlet ()->get_property ("quotedEventTypes"); + + for (; scm_is_pair (accept); accept = scm_cdr (accept)) + { + if (ev->internal_in_event_class (scm_car (accept))) + return true; + } + return false; +} + +void +Quote_iterator::derived_mark () const { - return *unsmob_moment (a) < *unsmob_moment (b); + Music_wrapper_iterator::derived_mark (); + scm_gc_mark (transposed_musics_); } +Quote_iterator::Quote_iterator () +{ + transposed_musics_ = SCM_EOL; + event_vector_ = SCM_EOL; + event_idx_ = 0; + end_idx_ = 0; +} int -binsearch_scm_vector (SCM vec, SCM key, bool (*is_less)(SCM a,SCM b)) +binsearch_scm_vector (SCM vec, SCM key, bool (*is_less) (SCM a, SCM b)) { - int lo; - int hi; - lo = 0; - hi = SCM_VECTOR_LENGTH (vec); + int lo = 0; + int hi = scm_c_vector_length (vec); /* binary search */ do - { - int cmp = (lo + hi) / 2; + { + int cmp = (lo + hi) / 2; - SCM when = gh_car (SCM_VECTOR_REF(vec, cmp)); - bool result = (*is_less) (key, when); + SCM when = scm_caar (scm_c_vector_ref (vec, cmp)); + bool result = (*is_less) (key, when); if (result) - hi = cmp; + hi = cmp; else - lo = cmp; + lo = cmp; } while (hi - lo > 1); return lo; } - void Quote_iterator::construct_children () { - SCM dur = get_music ()->get_property ("duration"); - if (!unsmob_duration (dur)) - return ; + Music_wrapper_iterator::construct_children (); - set_translator (get_outlet ()->get_default_interpreter ()); - - Moment now = get_outlet ()->now_mom (); - Moment stop = now + unsmob_duration (dur)->get_length (); - - start_moment_ = now; - event_vector_ = get_music ()->get_property ("quoted-events"); + SCM name = get_music ()->get_property ("quoted-context-type"); + SCM id = get_music ()->get_property ("quoted-context-id"); - if (scm_vector_p (event_vector_) == SCM_BOOL_T) + if (scm_is_symbol (name)) { - event_idx_ = binsearch_scm_vector (event_vector_, now.smobbed_copy (), &moment_less); - end_idx_ = binsearch_scm_vector (event_vector_, stop.smobbed_copy (), &moment_less); + Context *cue_context = + get_outlet ()->find_create_context (name, + robust_scm2string (id, ""), + SCM_EOL); + quote_outlet_.set_context (cue_context); } -} + else + quote_outlet_.set_context (get_outlet ()->get_default_interpreter ()); + event_vector_ = get_music ()->get_property ("quoted-events"); + + /* + We have to delay initting event_idx_ , since we have to + take starting grace notes into account. Those may offset + event_idx_. + */ + event_idx_ = -1; +} bool Quote_iterator::ok () const { - return (event_idx_ <= end_idx_); + return + Music_wrapper_iterator::ok () + || quote_ok (); } +bool +Quote_iterator::quote_ok () const +{ + return (event_idx_ >= 0 + && scm_is_vector (event_vector_) + && event_idx_ <= end_idx_ + + /* + Don't quote the grace notes leading to an unquoted note. + */ + && vector_moment (event_idx_).main_part_ < stop_moment_.main_part_); +} Moment Quote_iterator::pending_moment () const { - SCM entry = SCM_VECTOR_REF (event_vector_, event_idx_); - return *unsmob_moment (gh_car (entry)) - start_moment_; + Rational infty; + infty.set_infinite (1); + Moment m (infty); + + if (Music_wrapper_iterator::ok ()) + m = min (m, Music_wrapper_iterator::pending_moment ()); + + /* + In case event_idx_ < 0, we're not initted yet, and the wrapped + music expression determines the starting moment. + */ + if (quote_ok ()) + m = min (m, vector_moment (event_idx_) - start_moment_); + + return m; } +Moment +Quote_iterator::vector_moment (int idx) const +{ + SCM entry = scm_c_vector_ref (event_vector_, idx); + return *unsmob (scm_caar (entry)); +} void Quote_iterator::process (Moment m) { - SCM entry = SCM_EOL; + if (Music_wrapper_iterator::ok ()) + Music_wrapper_iterator::process (m); - m += start_moment_; - while (event_idx_ < end_idx_) - { - entry = SCM_VECTOR_REF (event_vector_, event_idx_); + if (!scm_is_vector (event_vector_)) + return; - Moment em = *unsmob_moment (gh_car (entry)); + if (event_idx_ < 0) + { + event_idx_ = binsearch_scm_vector (event_vector_, + get_outlet ()->now_mom ().smobbed_copy (), + &moment_less); + start_moment_ = get_outlet ()->now_mom () - music_start_mom (); + stop_moment_ = start_moment_ + get_music ()->get_length (); + + end_idx_ = binsearch_scm_vector (event_vector_, + stop_moment_.smobbed_copy (), + &moment_less); + } + m += start_moment_; + while (event_idx_ <= end_idx_) + { + Moment em = vector_moment (event_idx_); if (em > m) - return ; + return; if (em == m) - break ; + break; event_idx_++; } - if (gh_pair_p (entry)) + if (quote_ok ()) { - for (SCM s = gh_cdr (entry); gh_pair_p (s); s = gh_cdr (s)) - { - SCM ev_acc = gh_car (s); - - - Music * mus = unsmob_music (gh_car (ev_acc)); - if (mus) - { - bool b = get_outlet ()->try_music (mus); - - if (!b) - mus->origin ()->warning (_f ("In quotation: junking event %s", mus->name())); - } - else - programming_error ("need music in quote."); - } + SCM entry = scm_c_vector_ref (event_vector_, event_idx_); + Pitch *quote_pitch = unsmob (scm_cdar (entry)); + + /* + The pitch that sounds when written central C is played. + */ + Pitch temp_pitch; + Pitch *me_pitch = unsmob (get_music ()->get_property ("quoted-transposition")); + if (!me_pitch) + me_pitch = unsmob (get_outlet ()->get_property ("instrumentTransposition")); + else + { + // We are not going to win a beauty contest with this one, + // but it is slated for replacement and touches little code. + // quoted-transposition currently has a different sign + // convention than instrumentTransposition + temp_pitch = me_pitch->negated (); + me_pitch = &temp_pitch; + } + SCM cid = get_music ()->get_property ("quoted-context-id"); + bool is_cue = scm_is_string (cid) && (ly_scm2string (cid) == "cue"); + + for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s)) + { + SCM ev_acc = scm_car (s); + + Stream_event *ev = unsmob (scm_car (ev_acc)); + if (!ev) + programming_error ("no music found in quote"); + else if (accept_music_type (ev, is_cue)) + { + /* create a transposed copy if necessary */ + if (quote_pitch || me_pitch) + { + Pitch qp, mp; + if (quote_pitch) + qp = *quote_pitch; + if (me_pitch) + mp = *me_pitch; + + Pitch diff = pitch_interval (mp, qp); + ev = ev->clone (); + ev->make_transposable (); + ev->transpose (diff); + transposed_musics_ = scm_cons (ev->unprotect (), transposed_musics_); + } + quote_outlet_.get_context ()->event_source ()->broadcast (ev); + } + } + + event_idx_++; } - event_idx_ ++; } IMPLEMENT_CTOR_CALLBACK (Quote_iterator);