Akkorde mit Bass

Begonnen von hurrlipurr, Dienstag, 11. Dezember 2018, 09:01

« vorheriges - nächstes »

hurrlipurr

Hi,

ist es möglich bei einem Basslauf
f2:m7 f2:m7/bes
beim zweiten Akkord das "Fm7" wegzulassen und nur das "/Bb" zu setzen?

VG Oliver

Malte

Ja, das geht, z. B. so:\version "2.19.82"

\chords {
  f2:m7
  \once \set ChordNames.chordRootNamer = #(lambda (pitch lowercase?) empty-markup)
  \once \set ChordNames.chordNoteNamer = #note-name->markup
  f:/bes
}

Die beiden \set-Befehle kann man noch in eine Variable packen, um sie nicht immer wieder ausschreiben zu müssen.

Folgendes geht leider nicht:

bass =
#(define-music-function (b) (ly:pitch?)
   #{
     \once \set ChordNames.chordRootNamer = #(lambda (p l) empty-markup)
     \once \set ChordNames.chordNoteNamer = #note-name->markup
     \chordmode { c:/$b }
   #})

\chords {
  f:7 \bass g \bass gis \bass a
}

hurrlipurr

Cool, ich verstehe zwar (fast) nur Bahnhof, aber es tut genau das Gewünschte. :-)

Malte

chordNoteNamer ist eine Funktion, die aus einer Tonhöhe (pitch) und einer Angabe, ob Klein- oder Großbuchstaben verwendet werden sollen (lowercase?) ein Markup macht. Das gleiche gilt erstmal für chordRootNamer.

Nun will ich aber aus den zwei Tonhöhen F und B in f:/bes nur ein ,,/B♭" statt ,,F/B♭" machen. LilyPond ruft für die ,,root" (keine Ahnung, wie ich das auf deutsch nennen würde, in diesem Fall F) anscheinend den chordRootNamer auf und für alle anderen Tonhöhen chordNoteNamer. Deshalb habe ich chordRootNamer zu einer Funktion gemacht, die zwar pitch und lowercase? als Argumente hat, in jedem Fall aber einfach ein leeres Markup (empty-markup) zurückgibt.

Dann hab ich allerdings festgestellt, daß LilyPond merkwürdigerweise auch für das B den chordRootNamer verwendet, solange chordNoteNamer nicht explizit definiert ist. Deshalb hab ich das nachgeholt und den Standardwert (note-name->markup) gesetzt ;)

Fazit: Diese Erklärung beschreibt nur, was ich dachte, wie LilyPond funktioniert und wie ich meine Ansicht angepaßt hab. Was LilyPond tatsächlich mit den beiden Funktionen macht, müßte ich wohl nochmal im Code oder der Dokumentation nachlesen.

harm6

#4
Hallo,

wiewohl ich Malte's Vorschlag schon vorher gesehen habe, greift er doch zu kurz.

Bei alterierten Akkorden und/oder solchen mit Zusatztönen, werden diese gedruckt:

\chords {
  b:m5-.7/fis
  \once \set ChordNames.chordRootNamer = #(lambda (pitch lowercase?) empty-markup)
  \once \set ChordNames.chordNoteNamer = #note-name->markup
  b:m5-.7/+fis
}

Wenn man jetzt einen simplen b:m/+fis verwendet, wird zumindest das midi falsch.

chordRootNamer und chordRootNamer sind aber lediglich setzbare context-properties, die der eigentlichen chordNameFunction (auch ein context-property, per default auf ignatzek-chord-names gesetzt) zuarbeiten.

Man sollte vielmehr die eigentliche chordNameFunction angehen, am besten mit einem patch, der ein context-property (z.B. chordBassOnly) einführt welches der chordNameFunction sagt, ob ausschließlich Bass (oder Inversion) gedruckt werden soll.

Das Ganze ist aber auch in einem ly-file möglich:

\version "2.19.82"


#(define (define-translator-property symbol type? description)
  (if (not (and (symbol? symbol)
            (procedure? type?)
            (string? description)))
      (ly:error "error in call of define-translator-property"))
  (if (not (equal? (object-property symbol 'translation-doc) #f))
      (ly:error (_ "symbol ~S redefined") symbol))

  (set-object-property! symbol 'translation-type? type?)
  (set-object-property! symbol 'translation-doc description)
  symbol)

#(for-each
  (lambda (x)
    (apply define-translator-property x))
    `((chordBassOnly ,boolean? "DOCME")
      ;; others
    ))

\layout {
  \context {
    \Score
    chordNameFunction =
      #(lambda (in-pitches bass inversion context)
         (let* ((slash-shord-separator
                  (ly:context-property context 'slashChordSeparator))
                (chord-root-namer (ly:context-property context 'chordRootNamer))
                (chord-note-namer
                  (ly:context-property context 'chordNoteNamer #f))
                (chord-name-lowercase-minor
                  (ly:context-property context 'chordNameLowercaseMinor))
                (chord-name-function
                  (ly:context-property context 'chordNameFunction))
                (chord-bass-only?
                  (ly:context-property context 'chordBassOnly #f))
                (bass-markup
                  (lambda (pitch)
                    (make-line-markup
                      (list
                        slash-shord-separator
                        ((or chord-note-namer chord-root-namer)
                         pitch
                         chord-name-lowercase-minor))))))
           (cond ((and chord-bass-only? (ly:pitch? bass))
                   (bass-markup bass))
                 ((and chord-bass-only? (ly:pitch? inversion))
                   (bass-markup inversion))
                 (else
                   (ignatzek-chord-names in-pitches bass inversion context)))))
  }
}

\new ChordNames
  \chordmode {
    b:m5-.7/fis
    \set chordBassOnly = ##t
    b:m5-.7/+fis
  }


Gruß,
  Harm

EDIT code vereinfacht

hurrlipurr

Ups, nachdem die Lösung einfach funktionierte, habe ich gar nicht mehr hier reingeschaut.

Vielen Dank für Eure Erläuterungen. Da ich vor 100 Jahren mal rudimentär in LISP programmieren konnte, verstehe ich jetzt wenigstens, auf welches Gleis ich gehen müsste, um den Zug zu erreichen.  ;D

VG Oliver