From: Han-Wen Nienhuys <hanwen@xs4all.nl>
Date: Tue, 3 Feb 2004 20:03:44 +0000 (+0000)
Subject: * lily/slur.cc (height): robustness fix.
X-Git-Tag: release/2.1.23~114
X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=101d8517e5f6b9727d3f0947e21a45489853e28f;p=lilypond.git

* lily/slur.cc (height): robustness fix.

* scm/music-functions.scm (determine-split-list): further analysis.
---

diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi
index 95ea4ad532..0ca5c7bb2e 100644
--- a/Documentation/topdocs/NEWS.texi
+++ b/Documentation/topdocs/NEWS.texi
@@ -58,8 +58,6 @@ It is more robust and less buggy. The part-combiner can be used with
 @noindent
 See @file{input/regression/new-part-combine.ly} for an example.
 
-(This feature is still experimental.)
-
 @item Formatting of rehearsal marks has been improved. The @code{\mark}
 command now only does automatic incrementing for marks specified as
 integer. For example, @code{\mark #1} will print an A in the default
diff --git a/lily/slur.cc b/lily/slur.cc
index 8d69ddb2c2..4f763205d5 100644
--- a/lily/slur.cc
+++ b/lily/slur.cc
@@ -531,7 +531,7 @@ Slur::height (SCM smob, SCM ax)
   SCM mol = me->get_uncached_molecule ();
   Interval ext;
   if (Molecule * m = unsmob_molecule (mol))
-    ext = m->extent (a);
+    ext = m->extent= (a);
   return ly_interval2scm (ext);
 }
 
diff --git a/scm/lily.scm b/scm/lily.scm
index d0881b90de..e819bf653a 100644
--- a/scm/lily.scm
+++ b/scm/lily.scm
@@ -371,6 +371,7 @@ L1 is copied, L2 not.
        "new-markup.scm"
        "bass-figure.scm"
        "music-functions.scm"
+       "part-combiner.scm"
        "define-music-properties.scm"
        "auto-beam.scm"
        "chord-name.scm"
diff --git a/scm/music-functions.scm b/scm/music-functions.scm
index c40d4b0783..46fe30b49f 100644
--- a/scm/music-functions.scm
+++ b/scm/music-functions.scm
@@ -786,313 +786,3 @@ Rest can contain a list of beat groupings
 
      ))))
 
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; part-combiner.
-
-
-	
-(define noticed '())
-(define part-combine-listener '())
-(define-public (set-part-combine-listener x)
-  (set! part-combine-listener x))
-
-(define-public (notice-the-events-for-pc context lst)
-  (set! noticed (acons (ly:context-id context) lst noticed)))
-
-(define-public (make-new-part-combine-music music-list)
-  (let*
-     ((m (make-music-by-name 'NewPartCombineMusic))
-      (m1 (context-spec-music (car music-list) 'Voice "one"))
-      (m2 (context-spec-music (cadr music-list) 'Voice "two"))
-      (props '((denies Thread)
-	       (consists Rest_engraver)
-	       (consists Note_heads_engraver)
-	       )))
-    
-    (ly:set-mus-property! m 'elements (list m1 m2))
-    (ly:set-mus-property! m1 'property-operations props)
-    (ly:set-mus-property! m2 'property-operations props)
-    (ly:run-translator m2 part-combine-listener)
-    (ly:run-translator m1 part-combine-listener)
-    (ly:set-mus-property! m 'split-list
-			 (determine-split-list (reverse (cdr (assoc "one" noticed)))
-					       (reverse (cdr (assoc "two" noticed)))))
-    (set! noticed '())
-    
-    m))
-
-
-
-;;
-;; todo: this function is rather too hairy and too long.
-;;
-(define-public (determine-split-list evl1 evl2)
-  "EVL1 and EVL2 should be ascending"
-  (define pc-debug #t)
-  (define ev1 (list->vector evl1))
-  (define ev2 (list->vector evl2))
-  (define (when v i)
-    (car (vector-ref v i)))
-  (define (what v i)
-    (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 moments (uniq-list
-		   (merge (map car evl1) (map car evl2) ly:moment<?)))
-  (define result '())
-  
-  (define (analyse-time-step i1 i2 ri
-			     active1
-			     active2)
-
-    (define (analyse-tie-start active ev)
-      (if (equal? (ly:get-mus-property ev 'name) 'TieEvent)
-	  (acons 'tie ri active)
-	  active
-	  ))
-    
-    (define (analyse-tie-end active ev)
-      (if (equal? (ly:get-mus-property ev 'name) 'NoteEvent)
-	  (assoc-remove!  active 'tie)
-	  active) )
-    
-    (define (active<? a b)
-      (cond
-       ((symbol<? (car a) (car b)) #t)
-       ((symbol<? (car b) (car b)) #f)
-       (else
-	(< (cdr a) (cdr b)))
-       ))
-    
-    (define (analyse-span-event active ev)
-      (let*
-	  ((name (ly:get-mus-property ev 'name))
-	   (key (cond
-		       ((equal? name 'SlurEvent) 'slur)
-		       ((equal? name 'PhrasingSlurEvent) 'tie)
-		       ((equal? name 'BeamEvent) 'beam)
-		       ((equal? name 'CrescendoEvent) 'cresc)
-		       ((equal? name 'DecrescendoEvent) 'decr)
-		       (else #f)) )
-	   (sp (ly:get-mus-property ev 'span-direction))
-	   )
-
-	(if (and (symbol? key) (ly:dir? sp))
-	    (if (= sp STOP)
-		(assoc-remove! active key)
-		(acons key ri active))
-	    active)
-	))
-
-    (define (analyse-events active evs)
-      (define (helper analyzer active evs)
-	(if (pair? evs)
-	    (helper analyzer (analyzer active (car evs)) (cdr evs))
-	    active
-	    ))
-      (sort
-       (helper analyse-span-event
-	       (helper analyse-tie-start
-		       (helper analyse-tie-end active evs) evs) evs)
-       active<?))
-    
-
-    (define (put x . index)
-      "Put the result to X, starting from INDEX backwards."
-      (let
-	  ((i (if (pair? index) (car index) ri)))
-
-	(if (and (<= 0 i) (not (symbol? (what result i))))
-	    (begin
-	      (set-cdr! (vector-ref result i) x)
-	      (put x (1- i))
-	    ))
-	))
-	
-
-    (cond
-     ((= ri (vector-length result)) '())
-     ((= i1 (vector-length ev1)) (put 'apart))
-     ((= i2 (vector-length ev2)) (put 'apart))
-     (else
-      (let*
-	  ((now (when result ri))
-;	   (x (display (list "\nelse" (= i1 (vector-length ev1)) i2  (vector-length ev2) (= i2 (vector-length ev2)))))
-	   (m1 (when ev1 i1))
-	   (m2 (when ev2 i2))
-;	   (x (display "oked"))
-	   (evs1 (map car (what ev1 i1)))
-	   (evs2 (map car (what ev2 i2)))
-	   (new-active1 (analyse-events active1 evs1))
-	   (new-active2 (analyse-events active2 evs2))
-	   )
-
-	
-	(or #t (display (list (when result ri) i1 i2 ri
-		       active1 "->" new-active1
-		       active2 "->" new-active2
-		       (vector-length ev1) (vector-length ev2) (vector-length result)  "\n")))
-    
-	
-	(if (not (or (equal? m1 now)
-		     (equal? m2 now)))
-	    (begin
-	      (display
-	       (list "<? M1,M2 != result :"
-		     m1 m2 (when result ri)))
-	      (scm-error "boem")))
-
-	(cond
-	 ((ly:moment<? m1 m2)
-	  (put 'apart)
-	  (if (> ri 0) (put 'apart (1- ri)))
-	  (analyse-time-step (1+ i1) i2 (1+ ri) new-active1 active2))
-	 ((ly:moment<? m2 m1)
-	  (put 'apart)
-	  (if (> ri 0) (put 'apart (1- ri)))
-	  (analyse-time-step i1 (1+ i2) (1+ ri) active1 new-active2))
-	 (else
-
-	  (if (and (equal? active1 active2) (equal? new-active2 new-active1))
-	      (let*
-		  ((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<?))
-		   )
-		(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)
-		   (not (equal? (car durs1) (car durs2))))
-
-		  (put 'apart))
-		 (else
-		  (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:
-	      ;; must mark differently so
-	      ;; it doesn't transform into solo 
-	      (put 'apart-spanner))
-	  (analyse-time-step (1+ i1) (1+ i2) (1+ ri) new-active1 new-active2)))
-	 ))))
-
-;; 
-   (define (analyse-solo12 i1 i2 ri)
-     (define (put x)
-       (set-cdr! (vector-ref result ri) x) )
-     (cond
-      ((= ri (vector-length result)) '())
-      ((= i1 (vector-length ev1)) '())
-      ((= i2 (vector-length ev2)) '())
-      (else
-       (let*
-	  ((now (when result ri))
-	   (m1 (when ev1 i1))
-	   (m2 (when ev2 i2))
-	   (notes1 (get-note-evs ev1
-				 (if (ly:moment<?  now m1)
-				     (1- i1) 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
-				 (if (ly:moment<? now m2)
-				     (1- i2) i2)))
-	   (n2 (length notes2))
-	   (n1 (length notes1))
-	   (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 pc-debug (display (list
-			 "\n"
-			 (when result ri) i1 "/" (vector-length ev1)
-			      m1 ":" notes1
-			      i2 "/" (vector-length ev2) m2 ":"
-			      notes2
-			      ri "/" (vector-length result)  " = "
-			      (what  result ri)
-			      "\n"
-			      )))
-    
-
-	
-	 (if (equal? (what result ri) 'apart)
-	     (cond
-	      ((and (= 0 n1)
-		    (< 0 n2)
-		    (equal? now m2)
-		    )
-	       (put 'solo2))
-	      ((and (< 0 n1)
-		    (= 0 n2)
-		    (equal? now m1)
-		    )
-	       (put 'solo1))
-	      ((and (= 0 n1)
-		    (= 0 n2))
-	       (put 'apart-silence))
-	      ))
-
-	 (if (and
-	      (equal? (what result ri) 'chords)
-	      (equal? pitches1 pitches2))
-	     (put (if (pair? pitches2)
-		      'unisono 'unisilence) ))
-	 
-	 (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)))
-	  )))))
-   (set! result (list->vector
-		 (map (lambda (x)
-			(cons x '())) moments)))
-   
-   (analyse-time-step 0 0  0 '() '())
-   (if pc-debug (display result))
-   (analyse-solo12 0 0 0)
-   (if pc-debug (display result))
-   
-   (vector->list result))
diff --git a/scm/part-combiner.scm b/scm/part-combiner.scm
new file mode 100644
index 0000000000..a5cf9f595c
--- /dev/null
+++ b/scm/part-combiner.scm
@@ -0,0 +1,466 @@
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; part-combiner.
+
+(use-modules (oop goops))
+
+(define-class <Voice-state> ()
+  (event-list #:init-value '() #:accessor events #:init-keyword #:events)
+  (when-moment #:accessor when #:init-keyword #:when)
+  (split-idx #:accessor split-idx )
+  (spanner-state #:init-value '() #:accessor span-state)
+  )
+  
+
+
+(define-class <Split-state> ()
+  (configuration #:init-value '() #:accessor configuration)
+  (when-moment #:accessor when #:init-keyword #:when)
+  (is #:init-keyword #:indexes #:accessor indexes)
+  (synced  #:init-keyword #:synced #:init-value  #f #:getter synced?)
+  )
+
+(define-method (write (x <Voice-state> ) file)
+  (display (when x) file)
+  (display " evs = " file)
+  (display (events x) file)
+  (display " active = " file)
+  (display (span-state x) file)
+  (display "\n" file)
+  )
+
+(define-method (write (x <Split-state> ) f)
+  (display (when x) f)
+  (display " = " f)
+  (display (configuration x) f)
+  (if (synced? x)
+      (display " synced "))
+  (display "\n" f)
+  )
+
+
+(define (make-voice-states evl)
+  (list->vector
+  (map
+   (lambda (v)
+     (make <Voice-state>
+       #:when (car v)
+       #:events (map car (cdr v))
+       ))
+     evl)))
+
+(define (moment-min a b)
+  (if (ly:moment<? a b) a b))
+
+(define (make-split-state vs1 vs2)
+  "Merge lists VS1 and VS2, containing Voice-state objects into vector
+of Split-state objects, crosslinking the Split-state vector and
+Voice-state objects
+"
+  
+  (define (helper ss-idx ss-list idx1 idx2)
+    (let*
+	((m1 (if (< idx1 (vector-length vs1)) (when (vector-ref vs1 idx1)) #f) )
+	 (m2 (if (< idx2 (vector-length vs2)) (when (vector-ref vs2 idx2)) #f) )
+	 (min (cond ((and m1 m2) (moment-min m1 m2))
+		    (m1 m1)
+		    (m2 m2)
+		    (else #f)
+		    ))
+
+	 (inc1 (if (and m1 (equal? min m1)) 1 0))
+	 (inc2 (if (and m2 (equal? min m2)) 1 0))
+	 (ss-object
+	  (if min
+	      (make <Split-state>
+		#:when min
+		#:indexes (cons idx1 idx2)
+		#:synced (= inc1 inc2)
+		) #f))
+	 )
+      (if m1
+	  (set! (split-idx (vector-ref vs1 idx1)) ss-idx))
+      (if m2
+	  (set! (split-idx (vector-ref vs2 idx2)) ss-idx))
+      
+      (if min
+	  (helper (1+ ss-idx)
+		  (cons ss-object ss-list)
+		  (+ idx1 inc1)
+		  (+ idx2 inc2))
+	  ss-list
+	  )
+      ))
+
+    (list->vector
+     (reverse!
+      (helper 0 '() 0  0) '()))
+    )
+      
+
+
+(define (analyse-spanner-states voice-state-vec)
+
+  (define (helper index active)
+    "Analyse EVS at INDEX, given state ACTIVE."
+    
+    (define (analyse-tie-start active ev)
+      (if (equal? (ly:get-mus-property ev 'name) 'TieEvent)
+	  (acons 'tie index active)
+	  active
+	  ))
+    
+    (define (analyse-tie-end active ev)
+      (if (equal? (ly:get-mus-property ev 'name) 'NoteEvent)
+	  (assoc-remove! active 'tie)
+	  active) )
+    
+    (define (active<? a b)
+      (cond
+       ((symbol<? (car a) (car b)) #t)
+       ((symbol<? (car b) (car b)) #f)
+       (else
+	(< (cdr a) (cdr b)))
+       ))
+    
+    (define (analyse-span-event active ev)
+      (let*
+	  ((name (ly:get-mus-property ev 'name))
+	   (key (cond
+		 ((equal? name 'SlurEvent) 'slur)
+		 ((equal? name 'PhrasingSlurEvent) 'tie)
+		 ((equal? name 'BeamEvent) 'beam)
+		 ((equal? name 'CrescendoEvent) 'cresc)
+		 ((equal? name 'DecrescendoEvent) 'decr)
+		 (else #f)) )
+	   (sp (ly:get-mus-property ev 'span-direction))
+	   )
+
+	(if (and (symbol? key) (ly:dir? sp))
+	    (if (= sp STOP)
+		(assoc-remove! active key)
+		(acons key index active))
+	    active)
+	))
+
+    (define (analyse-events active evs)
+      "Run all analyzers on ACTIVE and EVS"
+
+      (define (run-analyzer analyzer active evs)
+	(if (pair? evs)
+	    (run-analyzer analyzer (analyzer active (car evs)) (cdr evs))
+	    active
+	    ))
+
+      (sort
+
+       ;; todo: use fold or somesuch.
+       (run-analyzer
+	analyse-span-event
+	(run-analyzer
+	 analyse-tie-start
+	 (run-analyzer analyse-tie-end active evs) evs) evs)
+       
+       active<?))
+
+    ;; must copy, since we use assoc-remove!
+    (if (< index (vector-length voice-state-vec))
+	(begin
+	  (set! active (analyse-events active (events (vector-ref voice-state-vec index))))
+	  (set! (span-state (vector-ref voice-state-vec index))
+		(list-copy active))
+
+	  (helper (1+ index) active)))
+    )
+
+
+  (helper 0 '())
+  
+  )
+
+
+	
+(define noticed '())
+(define part-combine-listener '())
+(define-public (set-part-combine-listener x)
+  (set! part-combine-listener x))
+
+(define-public (notice-the-events-for-pc context lst)
+  (set! noticed (acons (ly:context-id context) lst noticed)))
+
+(define-public (make-new-part-combine-music music-list)
+  (let*
+     ((m (make-music-by-name 'NewPartCombineMusic))
+      (m1 (context-spec-music (car music-list) 'Voice "one"))
+      (m2 (context-spec-music (cadr music-list) 'Voice "two"))
+      (props '((denies Thread)
+	       (consists Rest_engraver)
+	       (consists Note_heads_engraver)
+	       )))
+    
+    (ly:set-mus-property! m 'elements (list m1 m2))
+    (ly:set-mus-property! m1 'property-operations props)
+    (ly:set-mus-property! m2 'property-operations props)
+    (ly:run-translator m2 part-combine-listener)
+    (ly:run-translator m1 part-combine-listener)
+    (ly:set-mus-property! m 'split-list
+			 (determine-split-list (reverse (cdr (assoc "one" noticed)))
+					       (reverse (cdr (assoc "two" noticed)))))
+    (set! noticed '())
+    
+    m))
+
+
+    
+    
+
+
+
+;;
+;; todo: this function is rather too hairy and too long.
+;;
+(define-public (determine-split-list evl1 evl2)
+  "EVL1 and EVL2 should be ascending"
+
+  (let*
+      ((pc-debug #f)
+       (chord-threshold 8)
+       (voice-state-vec1 (make-voice-states evl1))
+       (voice-state-vec2 (make-voice-states evl2))
+       (result (make-split-state voice-state-vec1 voice-state-vec2))
+       )
+
+
+  (define (analyse-time-step ri)
+    (define (put x . index)
+      "Put the result to X, starting from INDEX backwards.
+
+Only set if not set previously.
+"
+      
+      (let
+	  ((i (if (pair? index) (car index) ri)))
+
+	(if (and (<= 0 i)
+		 (not (symbol? (configuration (vector-ref result i)))))
+	    (begin
+	      (set! (configuration (vector-ref result i)) x)
+	      (put x (1- i))
+	    ))
+	))
+
+    (define (get-note-evs vs)
+      (define (f? x)
+	(equal? (ly:get-mus-property  x 'name) 'NoteEvent))
+      (filter f? (events vs)))
+    
+    (define (copy-state-from state-vec vs)
+      (define (copy-one-state key-idx)
+	(let*
+	    ((idx (cdr key-idx))
+	     (start-vs (vector-ref state-vec idx))
+	     (prev-ss (vector-ref result (split-idx start-vs)))
+	     (prev (configuration prev-ss))
+	     )
+	  (if (symbol? prev)
+	      (put prev))))
+      
+      (map copy-one-state (span-state vs))
+      )
+
+    (define (analyse-notes now-state) 
+      (let*
+	  (
+	   (i1 (car (indexes now-state)))
+	   (i2 (cdr (indexes now-state)))
+	   (vs1 (vector-ref voice-state-vec1 i1))
+	   (vs2 (vector-ref voice-state-vec2 i2))
+	   
+	   (notes1 (get-note-evs vs1))
+	   (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 vs2))
+	   (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<?))
+	   )
+	
+	(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)
+	   (not (equal? (car durs1) (car durs2))))
+
+	  (put 'apart))
+	 (else
+	  (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
+		    (if (> i1 0)
+			(copy-state-from voice-state-vec1 (vector-ref voice-state-vec1 (1- i1))))
+		    (if (> i2 0)
+			(copy-state-from voice-state-vec2 (vector-ref voice-state-vec2 (1- i2))))
+		    (if (and (null? (span-state vs1)) (null? (span-state vs2)))
+			(put 'chords))
+		    
+		    ))))
+	 )))
+	 
+
+
+    (if (< ri (vector-length result))
+	(let*
+	    ((now-state (vector-ref result ri))
+	     (i1 (car (indexes now-state)))
+	     (i2 (cdr (indexes now-state))))
+	  
+	  (cond
+	   ((= i1 (vector-length voice-state-vec1)) (put 'apart))
+	   ((= i2 (vector-length voice-state-vec2)) (put 'apart))
+	   (else
+	    (let*
+		(
+		 (vs1 (vector-ref voice-state-vec1 i1))
+		 (vs2 (vector-ref voice-state-vec2 i2))
+		 
+		 (active1
+		  (if (> i1 0)
+		      (span-state (vector-ref voice-state-vec1 (1- i1)))
+		      '()))
+		 (active2
+		  (if (> i2 0)
+		      (span-state (vector-ref voice-state-vec2 (1- i2)))
+		      '()))
+
+		 (new-active1 (span-state vs1))
+		 (new-active2 (span-state vs2))
+
+		 )
+	      (if
+	       pc-debug
+	       (display (list (when now-state) i1 i2 ri
+				    active1 "->" new-active1
+				    active2 "->" new-active2
+				    "\n")))
+
+	      
+	      
+	      (if (and (synced? now-state)
+		       (equal? active1 active2)
+		       (equal? new-active1 new-active2))
+
+		  (analyse-notes now-state)
+
+		  ;; active states different:
+		  (put 'apart)
+		  )
+	      )
+
+					; go to the next one, if it exists.
+	    (analyse-time-step (1+ ri))
+	    )))))
+    
+    
+   (define (analyse-solo12 ri)
+     (define (put x)
+       (set-cdr! (vector-ref result ri) x) )
+     
+     (if (< ri (vector-length result))
+
+       (let*
+	  ((now (when result ri))
+	   (m1 (when ev1 i1))
+	   (m2 (when ev2 i2))
+	   (notes1 (get-note-evs ev1
+				 (if (ly:moment<?  now m1)
+				     (1- i1) 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
+				 (if (ly:moment<? now m2)
+				     (1- i2) i2)))
+	   (n2 (length notes2))
+	   (n1 (length notes1))
+	   (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 pc-debug (display (list
+			 "\n"
+			 (when result ri) i1 "/" (vector-length ev1)
+			      m1 ":" notes1
+			      i2 "/" (vector-length ev2) m2 ":"
+			      notes2
+			      ri "/" (vector-length result)  " = "
+			      (what  result ri)
+			      "\n"
+			      )))
+    
+
+	
+	 (if (equal? (what result ri) 'apart)
+	     (cond
+	      ((and (= 0 n1)
+		    (< 0 n2)
+		    (equal? now m2)
+		    )
+	       (put 'solo2))
+	      ((and (< 0 n1)
+		    (= 0 n2)
+		    (equal? now m1)
+		    )
+	       (put 'solo1))
+	      ((and (= 0 n1)
+		    (= 0 n2))
+	       (put 'apart-silence))
+	      ))
+
+	 (if (and
+	      (equal? (what result ri) 'chords)
+	      (equal? pitches1 pitches2))
+	     (put (if (pair? pitches2)
+		      'unisono 'unisilence) ))
+	 
+	 (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-spanner-states voice-state-vec1)
+   (analyse-spanner-states voice-state-vec2)
+;  (display voice-state-vec1)
+;   (display voice-state-vec2)
+;   (display result)
+     
+   (analyse-time-step 0)
+;   (analyse-solo12 0 0 0)
+   (display result)
+;   (if pc-debug (display result))
+
+   (set! result    (map
+		    (lambda (x) (cons (when x) (configuration x)))
+		    (vector->list result)))
+
+;   (if pc-debug (display result))
+   result))