Zweiklänge als Kluster notieren

Begonnen von kilgore, Freitag, 18. Dezember 2020, 15:51

« vorheriges - nächstes »

kilgore

Hallo an alle!

Ich habe wieder eine besondere Notation die ich mit Lilypond realisieren möchte. Hier ein kleines Beispiel davon, etwas aufwendig gebastelt:


\version "2.20.0"


\relative c' {
  << { c' \override Stem.transparent = ##t g'
       -\tweak #'extra-offset #'( .6 . -3 )
        ^\markup \override #'(thickness . 2 ) \draw-line #'( 0 . 2 )
     }
     \\
     {  \once \override Stem.transparent = ##t
        f,
        -\tweak #'extra-offset #'( .6 . 5 )
        _\markup \override #'(thickness . 2 ) \draw-line #'( 0 . 2 )
       
        c' }
  >>

}


Es sind also Zweiklänge die eigentlich als Kluster zu spielen sind. Mit meiner Methode komme ich aber im Kontext des Werkes nicht klar. Es ist zu viel anderes los, zum Teil auch mehrstimmig, um meine Bastelei anzuwenden.  Am liebsten stelle ich mir das so vor:


\zauberBefehl <f 'c>4 \zauberBefehl <c' g'>4


Also einstimmig, mit einem Befehl was die nötige Linie hinzufügt (mit beliebigem Intervall, nicht immer Quinten). Dazu soll der Teil vom Hals, welcher den Zweiklang verbindet, nicht zu sehen sein.

Hat jemand eine Idee wie ich das schaffe? Ich habe das Gefühl es müsste einem einfach Trick geben worauf ich gerade nicht komme...

Danke!
Viele Grüße
kilgore

Pusteblumi

Hallo kilgore,

etwas ähnliches kam im Sommer schon mal in der englischsprachigen Liste:
http://lilypond.1069038.n5.nabble.com/Tone-cluster-td233083.html#a233099

Hilft das als Einstieg mal weiter?

Viele Grüße,
Klaus (Blum)

kilgore

Danke Klaus!
Das ist tatsächlich ein großes Stück näher. Sieht erstmal sehr gut aus so:


\version "2.20.0"

toneCluster ={
   \once \override NoteHead.stem-attachment = #'(0 . 0)
   \once \override Stem.length =
   #(lambda (grob)
      (- (ly:stem::calc-length grob) 6))
   \once \override Stem.thickness = #2
}

% Test:
\relative c'
{
  \toneCluster <f c'>  \toneCluster <c' g'> \toneCluster <f, g'> \toneCluster <a, c''>
}


Der große ABER: Ich möchte trotzdem einen erkennbaren Notenwert sehen. Also, ob Achtel oder punktierte Viertel ist schon sehr wichtig. Irgendwie scheint das mit "stem-attachment" nicht ganz die richtige Lösung zu sein.... hmm....

Pusteblumi

Hallo kilgore,

ah ja... dann müsste man verhindern, dass die beiden Notenköpfe einen gemeinsamen Hals erhalten. Das hab ich jetzt mit \new Voice und dem Einsatz von \voiceOne bzw. \voiceTwo versucht:

\version "2.20.0"

toneClusterDown = #(define-music-function
                    (note1 note2) (ly:music? ly:music?)
                    (let*
                     (
                       (p1 (ly:music-property note1 'pitch))
                       (p2 (ly:music-property note2 'pitch))
                       (y1 (+ (* 7 (ly:pitch-octave p2)) (ly:pitch-notename p2)))
                       (y2 (+ (* 7 (ly:pitch-octave p1)) (ly:pitch-notename p1)))
                       (steps
                        (if (> y1 y2)
                            (- y1 y2)
                            (- y2 y1)
                            )
                        )
                       (note-a (if (> y1 y2) note1 note2 ))
                       (note-b (if (> y1 y2) note2 note1 ))
                       )
                     #{
                       {
                         \once \voiceTwo
                         <<
                           #note-a
                           \new Voice {
                             \voiceTwo
                             \tweak NoteHead.stem-attachment #'(0 . 0.7)
                             \tweak Stem.length #(- steps 1.4)
                             \tweak Stem.thickness #2
                             \tweak Flag.stencil ##f
                             #note-b
                           }
                         >>
                       }
                     #})
                    )

toneClusterUp = #(define-music-function
                  (note1 note2) (ly:music? ly:music?)
                  (let*
                   (
                     (p1 (ly:music-property note1 'pitch))
                     (p2 (ly:music-property note2 'pitch))
                     (y1 (+ (* 7 (ly:pitch-octave p2)) (ly:pitch-notename p2)))
                     (y2 (+ (* 7 (ly:pitch-octave p1)) (ly:pitch-notename p1)))
                     (steps
                      (if (> y1 y2)
                          (- y1 y2)
                          (- y2 y1)
                          )
                      )
                     (note-a (if (> y1 y2) note1 note2 ))
                     (note-b (if (> y1 y2) note2 note1 ))
                     )
                   #{
                     {
                       \once \voiceOne
                       <<
                         #note-b
                         \new Voice {
                           \voiceOne
                           \tweak NoteHead.stem-attachment #'(0 . 0.7)
                           \tweak Stem.length #(- steps 1.4)
                           \tweak Stem.thickness #2
                           \tweak Flag.stencil ##f
                           #note-a
                         }
                       >>
                     }
                   #})
                  )

%% Test:
{
  \toneClusterDown f'1 f'' 
  \toneClusterDown f'2 f'' 
  \toneClusterDown g'' g' 
  \toneClusterDown a' a'' 
  \toneClusterDown b'' b' 
  \toneClusterDown c''4. a'' 
  \toneClusterDown d''8 g'' 
  \toneClusterDown g'8 c'' 
  \toneClusterDown g'8 c'' 
  \toneClusterDown a cis'''
  \toneClusterDown a cis'''
  \bar "||"
  \toneClusterUp f'1 f'' 
  \toneClusterUp f'2 f'' 
  \toneClusterUp g'' g' 
  \toneClusterUp a' a'' 
  \toneClusterUp b'' b' 
  \toneClusterUp c''4. a'' 
  \toneClusterUp d''8 g'' 
  \toneClusterUp g'8 c'' 
  \toneClusterUp g'8 c'' 
  \toneClusterUp a cis'''
  \toneClusterUp a cis'''
}


Knackpunkt ist noch, dass ganze Noten keinen Hals haben.
Und: Es gibt getrennte Funktionen für die verschiedenen Halsrichtungen. Wäre cool, das automatisch hinzukriegen, aber da weiß ich nicht, wie.

Viele Grüße,
Klaus

harm6

Hi,

Klaus linked to this thread on the international mailing-list, thus I write in english.

Below my own take on the problem, a little bold and heretic :)
Seems to work, though please read the inline comments about possible problems.
The code is written for 2.20.0, changing one line makes it work with newer versions (see comment).

How should it look with <a' b'>?


\version "2.20.0"

#(define note-column-cluster
  (lambda (grob)
    (let* ((nhds-array (ly:grob-object grob 'note-heads))
           (nhds-list
             (if (ly:grob-array? nhds-array)
                 (ly:grob-array->list nhds-array)
                 #f)))
      (if nhds-list
          (let* ((staff-pos-list
                   (map
                     (lambda (nhd) (ly:grob-property nhd 'staff-position))
                     nhds-list))
                 (s-s (ly:staff-symbol-staff-space grob))
                 (staff-space 1)
                 (bottom-pos
                   (* (apply min staff-pos-list) s-s))
                 (top-pos
                   (* (apply max staff-pos-list) s-s))
                 (mid-nc
                   (interval-center
                     (ly:relative-group-extent nhds-array grob X)))
                 (stem (ly:grob-object grob 'stem))
                 (thick (* (ly:grob-property grob 'thickness 0.8) s-s))
                 ;; NB relying on all NoteHeads having the same 'duration-log
                 (dur-log
                   (ly:grob-property (car nhds-list) 'duration-log))
                 ;; NB values found by try and error
                 ;;    with non-default NoteHeads other values may be preferable
                 (corr-1
                   (* (if (positive? dur-log) 0.55 0.5) s-s))
                 (corr-2
                   (* (if (positive? dur-log) 0.1 0.5) s-s)))
   
            (ly:grob-set-property! stem 'avoid-note-head #t)
            (ly:grob-set-property! grob 'stencil
              (ly:make-stencil
                ;; NB below returns obviously a polygon
                ;;    probably curves for top/bottom borders would suit better
                `(polygon
                   ;; with 2.20.0 use
                   ',(list
                   ;; with newer versions:
                   ;,(list
                      (+ mid-nc (/ thick -2)) (+ (/ bottom-pos 2) corr-2)
                      (+ mid-nc (/ thick 2)) (+ (/ bottom-pos 2) corr-1)
                      (+ mid-nc (/ thick 2)) (- (/ top-pos 2) corr-2)
                      (+ mid-nc (/ thick -2)) (- (/ top-pos 2) corr-1))
                    ,(ly:output-def-lookup (ly:grob-layout grob) 'blot-diameter)
                    #t) 
                (cons (/ thick -2) (/ thick 2))
                (cons (/ bottom-pos 2) (/ top-pos 2)))))
          '()))))
 
 
%% likely better to use \once ...
zauberBefehl = \override NoteColumn.before-line-breaking = #note-column-cluster

\transpose c cis
{
  \cadenzaOn
  \zauberBefehl

  <g' d''>1
  <f' e''>2
 
  <e' g''>8.
  <g'' d'''>2
}

{
  <>^"How should this look?"
  <a' b'>4
}




Cheers,
  Harm

Pusteblumi

Hi,

I'm back with some improvements:

\version "2.20.0"

makeToneCluster = #(define-music-function
                    (note1 note2 downstairs) (ly:music? ly:music? boolean?)
                    (let*
                     ( ; get pitches from note1 and note2:
                       (p1 (ly:music-property note1 'pitch))
                       (p2 (ly:music-property note2 'pitch))
                       ; if stem points down, note-a should be the lower pitch, note-b the higher:
                       ; (vice versa if stem points up)
                       (swap (if downstairs (ly:pitch<? p1 p2) (not (ly:pitch<? p1 p2))))
                       (note-a (if swap note1 note2 ))
                       (note-b (if swap note2 note1 ))
                       (p1 (ly:music-property note-a 'pitch))
                       (p2 (ly:music-property note-b 'pitch))
                       ; we'll assume that both notes have the same duration:
                       (dur  (ly:music-property note1 'duration))
                       (len  (ly:duration-log dur))
                       (dot  (ly:duration-dot-count dur))
                       (fact (ly:duration-factor dur))
                       ; calculate Y position (height) for both pitches:
                       (y1 (+ (* 7 (ly:pitch-octave p2)) (ly:pitch-notename p2)))
                       (y2 (+ (* 7 (ly:pitch-octave p1)) (ly:pitch-notename p1)))
                       ; padding depends on notehead type:
                       (pad1 (cond
                              ((= len -2) (if downstairs 0.87 -0.45)) ; longa
                              ((= len -1)  0.65) ; breve
                              ((= len 0 )  0.85) ; whole note
                              ((= len 1 )  0.7 ) ; half note
                              (else 0.5 )))      ; shorter
                       (pad2 (cond
                              ((= len -2) (if downstairs 0.95 2.25)) ; longa
                              ((= len -1)  1.2 ) ; breve
                              ((= len 0 )  1.05) ; whole note
                              ((= len 1 )  0.85) ; half note
                              (else 0.5 )))      ; shorter
                       (steps
                        (if downstairs
                            (- (- y1 pad1) (+ y2 pad2))
                            (- (- y2 pad1) (+ y1 pad2))
                            )
                        )
                       )
                     (if
                      (< len 1)
                      ; turn a whole (or longer) note into a half to have a stem:
                      (ly:music-set-property! note-b 'duration
                        (ly:make-duration 1 dot (* (car fact) 1) (* (cdr fact) 2) )))
                     #{
                       { % set stem direction:
                         #(if downstairs
                              #{ \once \voiceTwo #}
                              #{ \once \voiceOne #}
                              )
                         <<
                           % first note has a normal stem:
                           #note-a 
                           % the second note's stem is abused for cluster bar:
                           \new Voice {
                             #(if downstairs
                                  #{ \once \voiceTwo #}
                                  #{ \once \voiceOne #}
                                  )
                             \once \override NoteHead.stem-attachment = #(cons 0 pad1)
                             \once \override Stem.length = #steps
                             % \once \override Stem.color = #red  % useful for debugging etc.
                             % \once \override Stem.layer = #2
                             \once \override Stem.thickness = #6
                             \once \override Flag.stencil = ##f
                             #(if (< len 1) ; correct notehead for whole (and longer) notes
                                  #{
                                    \once \override NoteHead.stencil = #ly:text-interface::print
                                    \once \override NoteHead.text =
                                    #(cond
                                      ((= len  0) (markup #:musicglyph "noteheads.s0"))
                                      ((= len -1) (markup #:musicglyph "noteheads.sM1"))
                                      ((= len -2) (if downstairs
                                                      (markup #:musicglyph "noteheads.dM2")
                                                      (markup #:musicglyph "noteheads.uM2")))
                                      )  #})
                             % now draw the second note:
                             #note-b
                           }
                         >>
                       }
                     #})
                    )

toneClusterDown = #(define-music-function
                    (note1 note2) (ly:music? ly:music?)
                    #{
                      \makeToneCluster #note1 #note2 ##t
                    #})

toneClusterUp = #(define-music-function
                  (note1 note2) (ly:music? ly:music?)
                  #{
                    \makeToneCluster #note1 #note2 ##f
                  #})

%% Test:
{
  \time 8/2
  \toneClusterDown g'\longa f'' 
  \toneClusterDown g'\breve f'' 
  \toneClusterDown g' f'' 
  \toneClusterDown g'\breve. f'' 
  \toneClusterDown g'1 f'' 
  \toneClusterDown f'2 f'' 
  \toneClusterDown g'' g' 
  \toneClusterDown a' a'' 
  \toneClusterDown b'' b' 
  \toneClusterDown c''4. a'' 
  \toneClusterDown d''8 g'' 
  \toneClusterDown g'8 c'' 
  \toneClusterDown g'8 c'' 
  \toneClusterDown a cis'''
  \toneClusterDown a cis'''
  \bar "||"
  \toneClusterUp g'\longa f'' 
  \toneClusterUp g'\breve f'' 
  \toneClusterUp g' f'' 
  \toneClusterUp g'\breve. f'' 
  \toneClusterUp g'1 f'' 
  \toneClusterUp f'2 f'' 
  \toneClusterUp g'' g' 
  \toneClusterUp a' a'' 
  \toneClusterUp b'' b' 
  \toneClusterUp c''4. a'' 
  \toneClusterUp d''8 g'' 
  \toneClusterUp g'8 c'' 
  \toneClusterUp g'8 c'' 
  \toneClusterUp a cis'''
  \toneClusterUp a cis'''
}


Harm, that looks quite promising... and much shorter than my approach. But to me it seems to contain real magic.  :o
Maybe tomorrow I'll be able to understand some parts of it. There's still a lot of things to learn for me...

Cheers,
Klaus

kilgore

Thank you both for these fantastic solutions! You were busy while I was sleeping  :o

I wish the forum had a tipping function, or something like reddit gold :)

ZitatHow should it look with <a' b'>?

I suppose such a small cluster would be better with conventional notation. The clusters I'm trying to notate are done either with the palm of the hand or the whole arm.

ZitatMaybe tomorrow I'll be able to understand some parts of it. There's still a lot of things to learn for me...

I understand just enough of it to change the thickness of the line :) everything else basically looks like magic to me. I will work with these solutions in context and see how they fare. I will be back with updates :)


harm6

#7
Hi,

I reworked the code.
It's now possible to initiate cross-staff clusters as well.
For whole and half notes the connecting cluster is not filled now. The left and right edges a hardcoded to match the note-heads extents.
The cluster of shorter notes is a filled polygon. The thickness is adjustable by:
      \override Stem.details.cluster-thick-short = ...

As a demonstration here an excerpt of "Tiger" by Henry Cowell:

On the left the original score from IMSLP, along with a retyping by the attached code.

There are still some things, which could be improved ...


Cheers,
  Harm

EDIT
For the files, also see
https://lists.gnu.org/archive/html/lilypond-user/2020-12/msg00182.html