]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 2617: simple chord inversions take 2 octaves
authorDavid Kastrup <dak@gnu.org>
Wed, 9 Jul 2014 15:31:11 +0000 (17:31 +0200)
committerDavid Kastrup <dak@gnu.org>
Fri, 18 Jul 2014 10:28:50 +0000 (12:28 +0200)
With this change, chord inversions transpose all notes following the
inversion from the original chord down along with the inversion, as long
as the result ends up below the root note of the uninverted chord.

So with \chordmode { c:11 } => < c' e' g' bes' d'' f'' >
we get \chordmode { c:11/e } => < e g bes c' d'' f'' >

In order to have the Chord_name_engraver reconstruct the correct
uninverted chord, all the additionally octavated note events are given
an octavation property like the inversion event itself.

An "inversion" on the chord root just transposes the chord root one
octave down, leaving the rest in place.

lily/chord-name-engraver.cc
scm/chord-entry.scm

index 0ca322716fde1e8153034b99028feb95bd7d6257..0cb0a7d8e417c0de8d501578dbac3b1079927d91 100644 (file)
@@ -92,7 +92,6 @@ Chord_name_engraver::process_music ()
       markup = chord_name->get_property ("text");
       if (!Text_interface::is_markup (markup))
         {
-          Stream_event *inversion_event = 0;
           for (vsize i = 0; i < notes_.size (); i++)
             {
               Stream_event *n = notes_[i];
@@ -100,30 +99,25 @@ Chord_name_engraver::process_music ()
               if (!unsmob_pitch (p))
                 continue;
 
-              if (n->get_property ("inversion") == SCM_BOOL_T)
-                {
-                  inversion_event = n;
-                  inversion = p;
-                }
-              else if (n->get_property ("bass") == SCM_BOOL_T)
+              if (n->get_property ("bass") == SCM_BOOL_T)
                 bass = p;
               else
-                pitches = scm_cons (p, pitches);
-            }
-
-          if (inversion_event)
-            {
-              SCM oct = inversion_event->get_property ("octavation");
-              if (scm_is_number (oct))
                 {
-                  Pitch *p = unsmob_pitch (inversion_event->get_property ("pitch"));
-                  int octavation = scm_to_int (oct);
-                  Pitch orig = p->transposed (Pitch (-octavation, 0, 0));
-
-                  pitches = scm_cons (orig.smobbed_copy (), pitches);
+                  SCM oct = n->get_property ("octavation");
+                  if (scm_is_number (oct))
+                    {
+                      Pitch orig = unsmob_pitch (p)->transposed (Pitch (-scm_to_int (oct), 0, 0));
+                      pitches = scm_cons (orig.smobbed_copy (), pitches);
+                    }
+                  else
+                    pitches = scm_cons (p, pitches);
+                  if (n->get_property ("inversion") == SCM_BOOL_T)
+                    {
+                      inversion = p;
+                      if (!scm_is_number (oct))
+                        programming_error ("inversion does not have original pitch");
+                    }
                 }
-              else
-                programming_error ("inversion does not have original pitch");
             }
 
           pitches = scm_sort_list (pitches, Pitch::less_p_proc);
index 0ea8e032a0e774bb95265e15df406739979e40db..ae649700aee3e810caa4882ac49246aeb1a75dd6 100644 (file)
@@ -16,7 +16,7 @@
 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 
 ;; for define-safe-public when byte-compiling using Guile V2
-(use-modules (scm safe-utility-defs))
+(use-modules (scm safe-utility-defs) (ice-9 receive))
 
 (define-public (construct-chord-elements root duration modifications)
   "Build a chord on root using modifiers in @var{modifications}.
@@ -174,26 +174,42 @@ the bass specified.
 
 (define (make-chord-elements pitches bass duration inversion original-inv-pitch)
   "Make EventChord with notes corresponding to PITCHES, BASS and
-DURATION, and INVERSION."
-  (define (make-note-ev pitch)
-    (make-music 'NoteEvent
-                'duration duration
-                'pitch pitch))
-  (let ((nots (map make-note-ev pitches))
-        (bass-note (if bass (make-note-ev bass) #f))
-        (inv-note (if inversion (make-note-ev inversion) #f)))
-    (if bass-note
-        (begin
-          (set! (ly:music-property bass-note 'bass) #t)
-          (set! nots (cons bass-note nots))))
-    (if inv-note
-        (begin
-          (set! (ly:music-property inv-note 'inversion) #t)
-          (set! (ly:music-property inv-note 'octavation)
-                (- (ly:pitch-octave inversion)
-                   (ly:pitch-octave original-inv-pitch)))
-          (set! nots (cons inv-note nots))))
-    nots))
+DURATION, and INVERSION.  Notes above INVERSION are transposed downward
+along with the inversion as long as they end up below at least one
+non-inverted note."
+  (define (make-note-ev pitch . rest)
+    (apply make-music 'NoteEvent
+           'duration duration
+           'pitch pitch
+           rest))
+  (cond (inversion
+         (let* ((octavation (- (ly:pitch-octave inversion)
+                               (ly:pitch-octave original-inv-pitch)))
+                (down (ly:make-pitch octavation 0 0)))
+           (define (invert p) (ly:pitch-transpose down p))
+           (define (make-inverted p . rest)
+             (apply make-note-ev (invert p) 'octavation octavation rest))
+           (receive (uninverted high)
+                    (span (lambda (p) (ly:pitch<? p original-inv-pitch))
+                          pitches)
+                    (receive (invertible rest)
+                             (if (null? uninverted)
+                                 ;; The following line caters for
+                                 ;; inversions "on the root", turning
+                                 ;; f/f into <f a' c''> rather than <f a c'>
+                                 ;; or <f' a' c''>
+                                 (values '() high)
+                                 (span (lambda (p)
+                                         (ly:pitch<? (invert p) (car uninverted)))
+                                       high))
+                             (cons (make-inverted original-inv-pitch 'inversion #t)
+                                   (append (if bass (list (make-note-ev bass 'bass #t)) '())
+                                           (map make-inverted invertible)
+                                           (map make-note-ev uninverted)
+                                           (map make-note-ev rest)))))))
+        (bass (cons (make-note-ev bass 'bass #t)
+                    (map make-note-ev pitches)))
+        (else (map make-note-ev pitches))))
 
 ;;;;;;;;;;;;;;;;
 ;; chord modifiers change the pitch list.