+2004-02-02 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+ * scm/define-music-types.scm (music-descriptions): add
+ Solo{One,Two}Event and UnisonoEvent
+
+ * lily/new-part-combine-iterator.cc (unisono): add state_
+ variable, signal changes with part-combine-event.
+
+ * input/regression/new-part-combine-text.ly: new file.
+
+ * lily/part-combine-engraver.cc: new file.
+
2004-02-02 Jan Nieuwenhuizen <janneke@gnu.org>
* scripts/filter-lilypond-book.py: Handle snippet options.
2004-02-02 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * scm/music-functions.scm (determine-split-list): detect solo1/2
+ and unisono.
+
* lily/new-lyric-combine-music-iterator.cc (construct_children):
revert fix, document why.
--- /dev/null
+
+\header {
+ texidoc ="The new part combiner:
+
+Detect a2, solo1, solo2 and print texts accordingly.
+"
+
+
+ }
+
+
+vone = \notes \relative a' { R1 a4 r4 r r a a a a }
+vtwo = \notes \relative a' { R1 f4 f4 f4 f f f a a }
+
+\score {
+ \newpartcombine \vone \vtwo
+}
+
"
}
-theMusic = \context Staff \notes { c4 d8-. }
-
-
-
vone = \notes \relative a' { g2 g g g4 g f' c c( c) c c c ~ c
c2. c4 c
}
bool is_shared_ ;
SCM split_list_;
+ enum {
+ APART, TOGETHER,
+ SOLO1, SOLO2,
+ UNISONO,
+ } state_;
+
Interpretation_context_handle one_;
Interpretation_context_handle two_;
Interpretation_context_handle null_;
first_iter_ = 0;
second_iter_ = 0;
split_list_ = SCM_EOL;
+ state_ = APART;
}
void
void
New_pc_iterator::chords_together ()
{
- first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
- first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
- second_iter_->substitute_outlet (two_.report_to (), shared_.report_to ());
- second_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
+ if (state_ == TOGETHER)
+ return;
+ else
+ {
+ state_ = TOGETHER;
+ first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
+ first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
+ second_iter_->substitute_outlet (two_.report_to (), shared_.report_to ());
+ second_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
+ }
}
void
New_pc_iterator::solo1 ()
{
- first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
- first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
+ if (state_ == SOLO1)
+ return;
+ else
+ {
+ state_ = SOLO1;
+ first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
+ first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
- second_iter_->substitute_outlet (two_.report_to (), null_.report_to ());
- second_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
-}
+ second_iter_->substitute_outlet (two_.report_to (), null_.report_to ());
+ second_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
+
+ static Music* event;
+ if (!event)
+ event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
+ first_iter_-> try_music_in_children (event);
+ }
+}
void
New_pc_iterator::unisono ()
{
- /*
- like solo1, but should set a2 string.
- */
- first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
- first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
-
- second_iter_->substitute_outlet (two_.report_to (), null_.report_to ());
- second_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
-}
+ if (state_ == UNISONO)
+ return;
+ else
+ {
+ state_ = UNISONO;
+
+ first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
+ first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
+
+ second_iter_->substitute_outlet (two_.report_to (), null_.report_to ());
+ second_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
+ static Music* event;
+ if (!event)
+ event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
+
+ first_iter_-> try_music_in_children (event);
+ }
+}
+
void
New_pc_iterator::solo2 ()
{
- second_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
- second_iter_->substitute_outlet (two_.report_to (), shared_.report_to ());
+ if (state_ == SOLO2)
+ return;
+ else
+ {
+ state_ = SOLO2;
+ second_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
+ second_iter_->substitute_outlet (two_.report_to (), shared_.report_to ());
- first_iter_->substitute_outlet (one_.report_to (), null_.report_to ());
- first_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
-}
+ first_iter_->substitute_outlet (one_.report_to (), null_.report_to ());
+ first_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
+ static Music* event;
+ if (!event)
+ event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
+
+ second_iter_-> try_music_in_children (event);
+ }
+}
void
New_pc_iterator::apart ()
{
- first_iter_->substitute_outlet (null_.report_to (), one_.report_to ());
- first_iter_->substitute_outlet (shared_.report_to (), one_.report_to ());
+ if (state_ == APART)
+ return;
+ else
+ {
+ state_ = APART;
+
+ first_iter_->substitute_outlet (null_.report_to (), one_.report_to ());
+ first_iter_->substitute_outlet (shared_.report_to (), one_.report_to ());
- second_iter_->substitute_outlet (null_.report_to (), two_.report_to ());
- second_iter_->substitute_outlet (shared_.report_to (), two_.report_to ());
+ second_iter_->substitute_outlet (null_.report_to (), two_.report_to ());
+ second_iter_->substitute_outlet (shared_.report_to (), two_.report_to ()); }
}
-
void
New_pc_iterator::construct_children ()
{
--- /dev/null
+/*
+ part-combine-engraver.cc -- implement PC-engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
+
+ Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "engraver.hh"
+#include "item.hh"
+#include "text-item.hh"
+#include "note-head.hh"
+#include "stem.hh"
+#include "side-position-interface.hh"
+#include "multi-measure-rest.hh"
+
+class Part_combine_engraver : public Engraver
+{
+ TRANSLATOR_DECLARATIONS(Part_combine_engraver);
+
+protected:
+ virtual void acknowledge_grob (Grob_info);
+ virtual void process_music ();
+ virtual void stop_translation_timestep ();
+ virtual bool try_music (Music *);
+private:
+ Item *text_;
+ Music *event_;
+};
+
+bool
+Part_combine_engraver::try_music (Music*m)
+{
+ event_ = m;
+ return true;
+}
+
+Part_combine_engraver::Part_combine_engraver ()
+{
+ text_ = 0;
+ event_ =0;
+}
+
+void
+Part_combine_engraver::process_music ()
+{
+ if (event_
+ && to_boolean (get_property ("soloADue")))
+ {
+ SCM what = event_->get_mus_property ("part-combine-status");
+ SCM text = SCM_EOL;
+ if (what == ly_symbol2scm ("solo1"))
+ text = get_property ("soloText");
+ else if (what== ly_symbol2scm ("solo2"))
+ text = get_property ("soloIIText");
+ else if (what == ly_symbol2scm ("unisono"))
+ text = get_property ("aDueText");
+
+ if (Text_item::markup_p (text))
+ {
+ text_ = make_item ("CombineTextScript");
+ text_->set_grob_property ("text", text);
+ announce_grob (text_, event_->self_scm ());
+ }
+ }
+}
+
+void
+Part_combine_engraver::acknowledge_grob (Grob_info i)
+{
+ if (text_)
+ {
+ if (Note_head::has_interface (i.grob_))
+ {
+ Grob*t = text_;
+ Side_position_interface::add_support (t, i.grob_);
+ if (Side_position_interface::get_axis (t) == X_AXIS
+ && !t->get_parent (Y_AXIS))
+ t->set_parent (i.grob_, Y_AXIS);
+ }
+ if (Stem::has_interface (i.grob_))
+ {
+ Side_position_interface::add_support (text_, i.grob_);
+ }
+ }
+}
+
+void
+Part_combine_engraver::stop_translation_timestep ()
+{
+ if (text_)
+ {
+ typeset_grob (text_);
+ text_ = 0;
+ }
+ event_ = 0;
+}
+
+ENTER_DESCRIPTION(Part_combine_engraver,
+/* descr */ "Part combine engraver for orchestral scores: "
+ "Print markings a2, Solo, Solo II, and unisono ",
+/* creats*/ "CombineTextScript",
+/* accepts */ "part-combine-event",
+/* acks */ "multi-measure-rest-interface "
+"slur-interface stem-interface note-head-interface"
+,/* reads */ "soloADue",
+/* write */ "");
\consists "Percent_repeat_engraver"
\consists "Slash_repeat_engraver"
\consists "Melisma_engraver"
+ \consists "Part_combine_engraver"
%{
Must come before text_engraver, but after note_column engraver.
(font-family . roman)
(meta . ((interfaces . (text-script-interface text-interface side-position-interface font-interface item-interface ))))
))
-
+ (CombineTextScript
+ . (
+ (molecule-callback . ,Text_item::brew_molecule)
+ (no-spacing-rods . #t)
+ (Y-offset-callbacks . (,Side_position_interface::aligned_side))
+ (X-offset-callbacks . (,Self_alignment_interface::aligned_on_self))
+ (direction . 1)
+ (padding . 0.5)
+ (staff-padding . 0.5)
+ (script-priority . 200)
+ ;; todo: add X self alignment?
+ (baseline-skip . 2)
+ (font-family . roman)
+ (font-series . bold)
+ (meta . ((interfaces . (text-script-interface text-interface side-position-interface font-interface item-interface ))))
+ ))
(TextSpanner
. (
(molecule-callback . ,Text_spanner::brew_molecule)
"Do these operations for instantiating the context.")
(music-property-description 'predicate procedure? "the predicate of a \\outputproperty")
(music-property-description 'type symbol? "The type of this music object. Determines iteration in some cases.")
-(music-property-description 'types list? "The types of this music object. Determines iteration in some cases.")
+(music-property-description 'types list? "The types of this music
+object; determines by what engraver this music expression is
+processed.")
+
(music-property-description 'repeat-count integer? "do a @code{\repeat} how ofen?")
(music-property-description 'span-direction ly:dir? "Does this start or stop a spanner?")
(music-property-description 'split-list list? "splitting moments for part combiner.")
(music-property-description 'value scheme? "Assignment value for a
translation property")
(music-property-description 'what symbol? "What to change for auto-change. FIXME, naming")
+(music-property-description 'part-combine-status symbol?
+ "Change to what kind of state? Options are
+solo1, solo2 and unisono")
(music-property-description 'figure string? "a `figure' (which may be
a string) for figured bass")
(CrescendoEvent
. (
- (description . "Begins or ends a crescendo. Syntax: @var{note}\\cr
+ (description . "Begins or ends a crescendo. Syntax: @var{note}\\cr
... @var{note}\\rc (you can also use \\<, \\!, \\cresc, and
\\endcresc. See the user manual for details.).")
(iterator-ctor . ,Sequential_music_iterator::constructor)
(types . (general-music sequential-music))
))
+
+ (SoloOneEvent
+ . (
+ (description . "Print Solo.1")
+ (internal-class-name . "Event")
+ (part-combine-status . solo1)
+ (types . (general-music event part-combine-event))
+ ))
+ (SoloTwoEvent
+ . (
+ (description . "Print Solo.2")
+ (internal-class-name . "Event")
+ (part-combine-status . solo2)
+ (types . (general-music event part-combine-event))
+ ))
+ (UnisonoEvent
+ . ((description . "Print a2")
+ (internal-class-name . "Event")
+ (part-combine-status . unisono)
+ (types . (general-music event part-combine-event))))
(SimultaneousMusic
. (
(cdr (vector-ref v i)))
(define chord-threshold 8)
+ (define (get-note-evs v i)
+ (define (f? x)
+ (equal? (ly:get-mus-property x 'name) 'NoteEvent))
+ (filter f? (map car (what v i))))
(define result
(list->vector
(helper analyse-tie-end active evs) evs) evs)
active<?))
- (define (get-note-evs v i)
- (define (f? x)
- (equal? (ly:get-mus-property x 'name) 'NoteEvent))
- (filter f? (map car (what v i))))
-
+
(define (put x . index)
"Put the result to X, starting from INDEX backwards."
(let
(cond
((> (length notes1) 1) (put 'apart))
((> (length notes2) 1) (put 'apart))
+ ((not (= (length notes1) (length notes2)))
+ (put 'apart))
((and
(= (length durs1) 1)
(= (length durs2) 1)
(put 'apart))
(else
- (if
- (and (= (length pitches1) 1) (= (length pitches2) 1)
- (< chord-threshold (ly:pitch-steps
- (ly:pitch-diff (car pitches1) (car pitches2)))))
- (put 'apart)
-
-
- ;; copy previous split state from spanner state
- (begin
- (map (lambda (key-idx)
- (let*
- ((idx (cdr key-idx))
- (prev (what result idx))
- )
- (if (symbol? prev)
- (put prev))
- )) (append active1 active2))
- (if (and (null? new-active1) (null? new-active2))
- (put 'chords ri)))
-
- ))) )
+ (if (and (= (length pitches1) (length pitches2)))
+ (if
+ (and (pair? pitches1) (pair? pitches2)
+ (< chord-threshold (ly:pitch-steps
+ (ly:pitch-diff (car pitches1) (car pitches2)))))
+ (put 'apart)
+
+
+ ;; copy previous split state from spanner state
+ (begin
+ (map (lambda (key-idx)
+ (let*
+ ((idx (cdr key-idx))
+ (prev (what result idx))
+ )
+ (if (symbol? prev)
+ (put prev))
+ )) (append active1 active2))
+ (if (and (null? new-active1) (null? new-active2))
+ (put 'chords ri))))
+
+ ))))
+
;; active states different:
- (put 'apart) )
- (analyse-time-step (1+ i1) (1+ i2) (1+ ri) new-active1 new-active2))
- )))))
+ (put 'apart))
+ (analyse-time-step (1+ i1) (1+ i2) (1+ ri) new-active1 new-active2)))
+ ))))
;;
-
-
+ (define (analyse-solo12 i1 i2 ri)
+ (cond
+ ((= ri (vector-length result)) '())
+ ((= i1 (vector-length ev1)) '())
+ ((= i2 (vector-length ev2)) '())
+ (else
+ (let*
+ (
+ (m1 (when ev1 i1))
+ (m2 (when ev2 i2))
+ (notes1 (get-note-evs ev1 i1))
+ (durs1 (sort (map (lambda (x) (ly:get-mus-property x 'duration)) notes1) ly:duration<?))
+ (pitches1 (sort
+ (map (lambda (x) (ly:get-mus-property x 'pitch)) notes1) ly:pitch<?))
+ (notes2 (get-note-evs ev2 i2))
+ (durs2 (sort (map (lambda (x) (ly:get-mus-property x 'duration)) notes2) ly:duration<?))
+ (pitches2 (sort
+ (map (lambda (x) (ly:get-mus-property x 'pitch)) notes2) ly:pitch<?))
+ )
+
+ (if (equal? (what result ri) 'apart)
+ (cond
+ ((and (= 0 (length notes1))
+ (< 0 (length notes2)))
+ (set-cdr! (vector-ref result ri) 'solo2))
+ ((and (< 0 (length notes1))
+ (= 0 (length notes2)))
+ (set-cdr! (vector-ref result ri) 'solo1))
+ ))
+
+ (if (and
+ (equal? (what result ri) 'chords)
+ (pair? pitches1)
+ (equal? pitches1 pitches2))
+ (set-cdr! (vector-ref result ri) 'unisono) )
+
+ (cond
+ ((ly:moment<? m1 m2)
+ (analyse-solo12 (1+ i1) i2 (1+ ri) ))
+ ((ly:moment<? m2 m1)
+ (analyse-solo12 i1 (1+ i2) (1+ ri) ))
+ (else
+ (analyse-solo12 (1+ i1) (1+ i2) (1+ ri)))
+ )))))
(analyse-time-step 0 0 0 '() '())
-; (display result)
+ (analyse-solo12 0 0 0)
+ (display result)
(vector->list result))