Leitereigene Mehrklänge mittels Scheme erzeugen

Zur Navigation springen Zur Suche springen

Dieses Programm erzeugt Mehrklänge, indem es die Töne einer vorgegebenen Sequenz übereinander stapelt.

Normalerweise ist diese Sequenz eine Tonleiter, dies muss aber nicht zwingend der Fall sein.

Der erste Parameter der Eingabe the-scale muss ein musikalischer Ausdruck sein, der zweite list-or-number-or-pair ein Scheme-Ausdruck.

the-scale wird normalerweise eine Tonleiter sein, kann jedoch eine beliebige Abfolge von Tönen sein. Das Programm überprüft die Eingabe in dieser Hinsicht nicht. Allerdings werden Duplikate entfernt und die Pitches nach ihrer Höhe sortiert, es wäre eine Idee, dies per Parameter zu unterdrücken oder eine eigene Funktion dafür zu schreiben.

list-or-number-or-pair kann ein Paar, eine Liste oder eine Zahl sein.

Eine einfach Zahl #n gibt an, wie viele Terzen übereinander geschichtet werden sollen.

Wenn list-or-number-or-pair ein Paar ist, legt car(list-or-number-or-pair) - 1 die Zahl der Wiederholungen des Intervalls cdr(list-or-number-or-pair) fest. Die Differenz hat programmtechnische Gründe, wenn man drei Wiederholungen von Quinten haben will, gibt man einfach #'(4 . 5) an.

Eine Liste gibt eine Abfolge von Intervallen an. Dadurch kann man Umkehrungen von Akkorden erzeugen, die erste Umkehrung eines Dreiklangs wird durch #'( 3 4 ) generiert, die zweite durch #'( 4 3 ). Dabei muss beachtet werden, dass die Tonleiter auf der Stufe beginnt, die dem untersten Ton des Dreiklangs entspricht. Für die erste Umkehrung (Terzquartakkord) von C-Dur muss die Tonleiter folgendermaßen geschrieben werden: Dure = \relative c' { e1 f g a h c d }. Ich füge an den Namen der Tonleiter den Startton an.

Die Intervalle werden durch Zahlen definiert, wobei 1 eine Prim, 2 eine Sekund usw. ist. Dies gilt nur, wenn der Abstand der Töne von the-scale ein Ganz- oder Halbton ist. Programmiertechnisch werden die Pitches abgezählt, unter Anwendung der Modulo-Funktion werden die Töne berechnet.

Die Funktion pitches->chord konvertiert eine Liste von Tönen plist in einen Akkord.

<< \new Staff { \mark "C-Moll" {
       c'1 d'1 es'1 f'1 g'1 as'1 b'1
     } } \new Staff { \mark "\\IMus \\CMoll #'(3 5 2 )" {
       < c' es' b' c'' >1 < d' f' c'' d'' >1 < es' g' d'' es'' >1 < f' as' es'' f'' >1 < g' b' f'' g'' >1 < as' c'' g'' as'' >1 < b' d'' as'' b'' >1
     } } \new Staff { \mark "\\IMus \\CMoll #5" {
       < c' es' g' b' d'' >1 < d' f' as' c'' es'' >1 < es' g' b' d'' f'' >1 < f' as' c'' es'' g'' >1 < g' b' d'' f'' as'' >1 < as' c'' es'' g'' b'' >1 < b' d'' f'' as'' c''' >1
     } } \new Staff { \mark "\\IMus \\CMoll #'(3 . 4)" {
       < c' f' b' >1 < d' g' c'' >1 < es' as' d'' >1 < f' b' es'' >1 < g' c'' f'' >1 < as' d'' g'' >1 < b' es'' as'' >1
     } } >>
Einfügen: {{:Leitereigene Mehrklänge mittels Scheme erzeugen/code}}
#(define (pitches->chord plist)
   (make-music 'EventChord 'elements
     (if (list? plist)
         (map (lambda (p)
                (make-music
                 'NoteEvent 'duration (ly:make-duration 0)
                 'pitch p))
           plist)
         (make-music
          'NoteEvent 'duration (ly:make-duration 0)
          'pitch plist)
         )))

%% convert pitchlist to plain music
#(define (pitches->music plist)
   (if (list? plist)
       (make-music 'SequentialMusic 'elements
         (map (lambda (p)
                (make-music
                 'NoteEvent 'duration (ly:make-duration 0)
                 'pitch p))
           plist))
       (make-music 'SequentialMusic 'elements
         (make-music
          'NoteEvent 'duration (ly:make-duration 0)
          'pitch plist))))

%% create all n-th chords from scale
%% actually we staple every other pitch from the-scale
%% until we reach n

%% create chords with arbitraty intervals from the scale
%% input: scale
%% list: the distances of the notes, 3=terz, 4=quart ...

#(define (stacked-intervals the-scale list-or-number-or-pair)
   ;; the-scale: music from which the pitchlist is constructed
   ;; usually a scale, but could be any music
   ;; duplicate pitches are removed and sorting according to pitch height is done
   ;; list-or-number-or-pair: tells the programm which intervals to produce
   ;; list: a list of chords, 3=third, 4=forth etc. '(2 4) creates a quart-sext chord
   ;; pair: '(a . b)  a: how many notes the chord contains, b: the interval, 3=third, 4=forth
   ;; number: terzes are stapled, 3=triad, 4=tetrads, 5=pentachord etc
   ;; actually the program does not much counting
   ;; a list of intervals is created by picking notes in the order they appear
   ;; in the scale leaving gaps defined by the list
   (let* ((scpi (music-pitches the-scale))
          (pili (sort
                 (delete-duplicates scpi) ly:pitch<?))
          (m (length pili))
          (elist (cond
                  ((list? list-or-number-or-pair)
                   ;; we need to add an element to the list
                   ;; otherwise the last element of the list would not appear
                   ;; in the result
                   (append list-or-number-or-pair '(1)))
                  ((pair? list-or-number-or-pair)
                   ;; car: number of notes
                   ;; cdr: distance, 3=third, 4=forth etc.
                   (make-list  (car list-or-number-or-pair) (cdr list-or-number-or-pair)))
                  ((number? list-or-number-or-pair)
                   ;; standard definition: chord consists of thirds
                   (make-list list-or-number-or-pair 3))))
          (n (length elist)))
     (map
      (lambda (w)
        (let ((u 0))
          (map
           (lambda (x)
             (let* ((y (modulo (+ u w) m))
                    (q (quotient (+ u w) m))
                    (z (list-ref pili y))
                    (a (ly:pitch-alteration z))
                    (o (ly:pitch-octave z))
                    (n (ly:pitch-notename z))
                    (p (ly:make-pitch (+ o q) n a)))
               (set! u (+ u (list-ref elist x) -1))
               p))
           (iota n))))
      (iota m))))
\language "deutsch"

\layout {
  \context {
    \Score
    \remove Mark_engraver
    \remove Bar_engraver
    \remove Span_bar_engraver
    \remove System_start_delimiter_engraver
    \override VerticalAxisGroup.staff-staff-spacing.padding = #6
  }
  \context {
    \Staff
    \consists Mark_engraver
    \override RehearsalMark.self-alignment-X = #-1
  }
}

IMus=
#(define-music-function (the-scale pair-list-number)(ly:music? scheme?)
   ;; creates the pure music without chordnames and other staff
   (make-sequential-music
    (map (lambda(x) (pitches->chord x))
      (stacked-intervals the-scale pair-list-number))))

CMoll = \relative c'' { c,1 d es f g as b }

<<
  \new Staff
  {
    \mark "C-Moll"
    \CMoll
  }
  \new Staff {
    \mark "\IMus \CMoll #'(3 5 2 )"
    \IMus \CMoll #'( 3 5 2 )
  }

  \new Staff {
    \mark "\IMus \CMoll #5"
    \IMus \CMoll #5
  }
  \new Staff {
    \mark "\IMus \CMoll #'(3 . 4)"
    \IMus \CMoll #'(3 . 4)
  }
>>
\language "deutsch"

\layout {
  \context {
    \Score
    \remove Mark_engraver
    \remove Bar_engraver
    \remove Span_bar_engraver
    \remove System_start_delimiter_engraver
    \override VerticalAxisGroup.staff-staff-spacing.padding = #6
  }
  \context {
    \Staff
    \consists Mark_engraver
    \override RehearsalMark.self-alignment-X = #-1
  }
}

IMus=
#(define-music-function (the-scale pair-list-number)(ly:music? scheme?)
   ;; creates the pure music without chordnames and other staff
   (make-sequential-music
    (map (lambda(x) (pitches->chord x))
      (stacked-intervals the-scale pair-list-number))))

CMoll = \relative c'' { c,1 d es f g as b }

<<
  \new Staff
  {
    \mark "C-Moll"
    \CMoll
  }
  \new Staff {
    \mark "\IMus \CMoll #'(3 5 2 )"
    \IMus \CMoll #'( 3 5 2 )
  }

  \new Staff {
    \mark "\IMus \CMoll #5"
    \IMus \CMoll #5
  }
  \new Staff {
    \mark "\IMus \CMoll #'(3 . 4)"
    \IMus \CMoll #'(3 . 4)
  }
>>