-/*
- 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--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
- (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ 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 <http://www.gnu.org/licenses/>.
*/
+#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
{
- return *unsmob_moment (a) < *unsmob_moment (b);
+ 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 (accept == SCM_EOL)
+ 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
+{
+ 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 tab = get_outlet()->get_property ("quotes");
- if (scm_hash_table_p (tab) != SCM_BOOL_T)
- {
- get_music ()->origin ()->warning ("Context property `quotes' unset; cannot process quote.");
- return ;
- }
-
- SCM name = get_music ()->get_mus_property ("quoted-name");
- SCM dur = get_music ()->get_mus_property ("duration");
+ Music_wrapper_iterator::construct_children ();
- if (!unsmob_duration (dur))
- return ;
+ SCM name = get_music ()->get_property ("quoted-context-type");
+ SCM id = get_music ()->get_property ("quoted-context-id");
- 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_ = scm_hash_ref (tab, name, SCM_BOOL_F);
-
- 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
- get_music ()->origin ()->warning ("Can't find requested source");
-}
+ 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_moment (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_pitch (scm_cdar (entry));
+
+ /*
+ The pitch that sounds when written central C is played.
+ */
+ Pitch temp_pitch;
+ Pitch *me_pitch = unsmob_pitch (get_music ()->get_property ("quoted-transposition"));
+ if (!me_pitch)
+ me_pitch = unsmob_pitch (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_stream_event (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 ();
+
+ transpose_mutable (ev->get_property_alist (true), 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);