lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Scheme experts, please help me improve my code


From: Manuela
Subject: Scheme experts, please help me improve my code
Date: Sun, 27 Mar 2016 01:10:34 +0100

Hi altogether,
some time ago I had the idea to write a kind of harmony analyzer. It works in the following manner: you enter some notes (myMusik) and you get a list of chords which contain these notes.
I had no idea of Scheme, so I studies several manuals, and Harm from the German Lilypond forum helped me a lot but still I am sometimes lost in parentheses. The code as it is now is working and I am very glad about that. But there is much room for improvement, and the chordNameExceptions don't work, so I ask for your help
Basically I would prefer to enter a list of chords like I do in Lilypond, such as c:7 c:m7 c:maj7 ... and the program should do the rest, create list etc. My scheme knowledge is not good enough for that.
Please excuse the German comments.
 
Here is the code:
 
Hi altogether,
some time ago I had the idea to write a kind of harmony analyzer. It works in the following manner: you enter some notes and you get a list of chords which contain these notes.
I had no idea of Scheme, so I studies several manuals, and Harm from the German Lilypond forum helped me a lot but still I am sometimes lost in parentheses. The code as it is now is working and I am very glad about that. But there is much room for improvement, and the chordNameExceptions don't work, so I ask for your help
Basically I would prefer to enter a list of chords like I do in Lilypond, such as c:7 c:m7 c:maj7 ... and the program should do the rest, create list etc. My scheme knowledge is not good enough for that.
Please excuse the German comments.
Here is the code:
 
\version "2.19.37"
\language "deutsch"
myMusik= < c' e' >1_"Input"
Tonleitern=< c des d es e f fis ges g as a b h >
chExceptionMusic = {
  <c es ges>1-\markup { \super "dim" }
  <c e gis>1-\markup { \super "maj" }
  <c e geses>1-\markup { \super "ddim" }
  <c eses ges >1-\markup { \super "dddim" }
  <c e g h>1-\markup { \super "maj7" }
  <c es g h>1-\markup { "m" \super "maj7" }
  <c es ges h>1-\markup { "m" \super { "maj7" \flat "5" } }
  <c e  ges h>1-\markup { \super { "maj7" \flat "5" } }
  <c es ges heses>1-\markup { \super "dim7" }
  <c e g h d'>1-\markup { \super "maj9" }
  <c e g b d' f a' >1-\markup { \super "13" }
  %<c e g  d' >1-\markup { \super "add9" }
  <c e g b des' as' >1-\markup { \super {  \flat "9"  \flat 13 } }
  <c e g b d' a' >1-\markup { \super "13" }
  <c e g a d'>1-\markup { \super "6(add9)" }
}
% Convert music to list and prepend to existing exceptions.
chExceptions = #( append
                  ( sequential-music-to-chord-exceptions chExceptionMusic #t)
                  ignatzekExceptions)
chExceptions = #( append
                  ( sequential-music-to-chord-exceptions chExceptionMusic #t)
                  ignatzekExceptions)
ChordI = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:1 }
ChordII = \chordmode {  \germanChords
    \set chordNameExceptions = #chExceptions c:2 }
ChordIII = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:3 }
ChordIV = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:4 }
ChordV = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:5 }
ChordVI = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:6 }
ChordVII = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:7 }
ChordVIII = \chordmode { \germanChords
    \set chordNameExceptions = #chExceptions c:8 }
#(define MusLis (list
                 ChordI
                 ChordII
                 ChordIII
                 ChordIV
                 ChordV
                 ChordVI
                 ChordVII
                 ChordVIII
                 ))
#(define (pitch-equals? p1 p2)
   (and
    (= (ly:pitch-alteration p1) (ly:pitch-alteration p2))
    (= (ly:pitch-notename p1) (ly:pitch-notename p2))))
#(define myInput (sort (music-pitches myMusik) ly:pitch<?) )
#(define mk-pitch
   ;; wir erschaffen eine Pitchliste aus der Musikliste
   (lambda (ls)
     (cond
      ;; wir haben fertig, wenn Liste leer ist
      ((null? ls) '())
      ;; wenn das Listenelement ein gültiger Musikausdruck ist
      ;; dann fügen wir die sortierte Pitchliste als Listenelement hinzu
      ((ly:music? (car ls))
       (cons (sort (music-pitches (car ls) ) ly:pitch<?)
         ;(cons (car l2) (vvv l1 (cdr l2)))
         (mk-pitch (cdr ls)))
       )
      ;; ansonsten machen wir mit dem Rest der Liste weiter
      (else (mk-pitch (cdr ls)))
      )
     )
   )
#(define is-in?
   ;; wir versuchen zu eruieren
   ;; ob alle Elemente der Liste l1 in l2 enthalten sind
   ;; genauer gesagt müssen nur notename und alteration stimmen
   ;; die Oktavlage interessiert uns nicht
   (lambda ( l1 l2 )
     ( cond
       ;; zunächst prüfen wir, ob die Testliste bereits erschöpft ist
       ;; wenn ja dann ist es wahr
       ((null? l1) #t
         )
       ;; wenn die Zielliste erschöpft ist
       ;; ist es falsch
       ((null? l2) #f
         )
       ;; wir überprüfen das erste Element der Testliste
       ;; wenn es gleich dem ersten Element der Zielliste ist
       ;; dann können wir mit dem restlichen Teil der Testliste fortsetzen
       ((pitch-equals? (car l1) (car l2))
        (is-in? (cdr l1) l2)
        ;'equalPitch
        )
       ;; ansonsten versuchen wir es mit dem folgenden Element der Zielliste
       (else (is-in? l1 (cdr l2))
         )
       )
     )
   )
#(begin
  (define (ist-in? l1 l2)
    (every (lambda (x) (->bool (member x l2 pitch-equals?))) l1)
    )
  )
#(define www
   ;; wir wollen jetzt die Musikausdrücke in eine Liste hängen
   ;; l1 ist unsere Testliste
   ;; l2 enthält die Pitches
   ;; l3 enthält die Musik (in diesem Fall die Akkorde bzw. Akkordnamen
   (lambda (l1 l2 l3)
     ( cond
       ;; wenn die Akkordliste leer ist, dann verabschieden wir uns
       ((null? l2) '()
         )
       ;; wenn die Testliste leer ist, dann ist es auch aus
       ((null? l1) '() )
       ;; wenn die Noten der Testliste im ersten Akkord enthalten sind,
       ;; wird der Akkord hinzugefügt
       ((is-in? l1 (car l2))
        (cons (car l3) (www l1 (cdr l2) (cdr l3)))
        )
       ;; wenn die Noten von l1 nicht im ersten Akkort enthalten sind
       ;; machen wir mit der restlichen Akkordliste weiter
       (else (www l1 (cdr l2) (cdr l3))
         )
       )
     )
   )
%% Liste der transponierten AKkorde
%% in zwei Stufen
%% die innere Funktion durchläuft die Akkordliste
%% die äußere die Tonleiterliste
%% das hat den Sinn, dass ich die Liste der Akkorde insgesamt transponieren will
%% und nicht jeden Akkord in alle Tonarten und dann den nächsten Akkord etc.
#(define ( Akkorde-in-allen-Tonleitern Pitch Musik)
   (append-map
    (lambda (p)
      (map
       (lambda (music)
         #{ { \transpose c $p $music } #})
       Musik
       )
      )
    (event-chord-pitches Pitch)
    )
   )
#(define MusikListe (Akkorde-in-allen-Tonleitern Tonleitern MusLis))
#(define PitLis (mk-pitch MusikListe))
#(define Ergebnis (www myInput PitLis MusikListe )) % just for interest
#(display (length Ergebnis))
\score {
  \new Staff
  <<
    \new Voice $(make-sequential-music  (append (list myMusik) Ergebnis))
    \new ChordNames {
      s1
      $(make-sequential-music Ergebnis)
    }
  >>
}

Attachment: Analysator.png
Description: PNG image


reply via email to

[Prev in Thread] Current Thread [Next in Thread]