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
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
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 >
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)" }
}
<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)
chExceptions = #( append
( sequential-music-to-chord-exceptions chExceptionMusic #t)
ignatzekExceptions)
( 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 }
\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
))
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))))
(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) '())
;; 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)))
)
)
)
;; 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))
)
)
)
)
;; 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 (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
;; 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))
)
)
)
)
( 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.
%% 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)
)
)
(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)
}
>>
}
\new Staff
<<
\new Voice $(make-sequential-music (append (list myMusik) Ergebnis))
\new ChordNames {
s1
$(make-sequential-music Ergebnis)
}
>>
}
_______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user