Autor Thema: Mein Harmonieanalysator funktioniert - Verbesserungsvorschläge erwünscht (GELÖST  (Gelesen 1451 mal)

Manuela

  • Member
Zunächst nochmals vielen Dank an Harm für seine äußerst hilfreiche Unterstützung. Ohne deine Hilfe wäre ich nie so weit gekommen.  :)

Ich freue mich, dass ich es so hingekriegt habe, dass es überhaupt funktioniert. Die Idee war, dass eine Liste von Tönen (myMusik) daraufhin untersucht wird, in welchen Akkorden sie vorkommt.

Der größte Nachteil an meinem Code ist, dass ich jeden Akkord zweimal eingeben muss. Ideal wäre es, wenn ich nur eine Liste mit den Basisbezeichnungen, also c:1 c:2 c:3 ... erstellen müsste und der Rest automatisch ginge. Meine Schemekenntnisse reichen derzeit nicht aus, um dieses Vorhaben in einer vernünftigen Zeit zu realisieren, es geht für mich viel schneller, neue Akkorde einzeln hinzuzufügen.

Die Chord-Exceptions werden auch nicht verarbeitet, wobei ich froh bin, dass überhaupt Akkordbezeichnungen angezeigt werden. Irgendwelche Ausgabeformatierungen finden derzeit auch nicht statt.

\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 ))
#(display (length Ergebnis))  % just for interest
\score {
  \new Staff
  <<
    \new Voice $(make-sequential-music  (append (list myMusik) Ergebnis))
    \new ChordNames {
      s1
      $(make-sequential-music Ergebnis)
    }
  >>
}
« Letzte Änderung: Mittwoch, 30. März 2016, 06:22 von Manuela »

ingmar

  • Member
Re: Mein Harmonieanalysator funktioniert - Verbesserungsvorschläge erwünscht
« Antwort #1 am: Sonntag, 27. März 2016, 10:22 »
Es scheint zu funktionieren, allerdings weiß ich nicht so recht, wo man das brauchen kann... außer natürlich als die Programmierübung, um die es hier offenbar ging.

Unter Programmieraspekten kann ich das Ergebnis leider nicht beurteilen, weil sich mir bisher diese Tiefen von Scheme nicht erschlossen haben.

Andere Kommentare, nach kurzem, unsysthematischen Herumprobieren  - aber bitte nicht falsch verstehen, vielleicht waren die gar nicht in deinem Fokus:

Anwendersicht:
- Wer "c e" in einer bestimmten Oktav eingibt, würde den Akkord auch gerne in einer Lage sehen, wo die eingegebenen Töne in der originalen Oktave erscheinen.
- Wie ist es gemeint? Zeigt das Ergebnis [1] zugrundeliegende Harmonien, die man als Analyseergebnis annehmen darf, wenn NUR diese beiden Töne klingen, oder [2] mögliche Harmonisierungen, die diese Töne enthalten?

Musiktheoretische Sicht:
- Du solltest eine konsistente Bezeichungstheorie verwenden, nicht verschiedene durcheinander.
- Die Akkorde "C 78" und "C4 sus 4 3" gibt es nicht.
- Akkorde mit großer Septime ("C7j") fehlen.
- Andere Akkorde sind falsch ("c e g a" müsste entweder als "C 56" [Generalbass] oder als "am7" [Jazz-Harmonik] bezeichnet werden, nicht als "C 6"; "C sus 2" hat nicht nur zwei Töne).
- c' g' bringt ganz andere Ergebnisse als g' c''. Das ist nur richtig, wenn oben [1] gemeint war.


Gruß,
--ingmar

Manuela

  • Member
Re: Mein Harmonieanalysator funktioniert - Verbesserungsvorschläge erwünscht
« Antwort #2 am: Sonntag, 27. März 2016, 21:26 »
Es scheint zu funktionieren, allerdings weiß ich nicht so recht, wo man das brauchen kann... außer natürlich als die Programmierübung, um die es hier offenbar ging.

Wenn du nicht weißt, wozu du das brauchen kannst, dann brauchst du es auch nicht  ;)
Ich kann das sehr wohl brauchen und weiß auch wozu.


Andere Kommentare, nach kurzem, unsysthematischen Herumprobieren  - aber bitte nicht falsch verstehen, vielleicht waren die gar nicht in deinem Fokus:

Anwendersicht:
- Wer "c e" in einer bestimmten Oktav eingibt, würde den Akkord auch gerne in einer Lage sehen, wo die eingegebenen Töne in der originalen Oktave erscheinen.
- Wie ist es gemeint? Zeigt das Ergebnis [1] zugrundeliegende Harmonien, die man als Analyseergebnis annehmen darf, wenn NUR diese beiden Töne klingen, oder [2] mögliche Harmonisierungen, die diese Töne enthalten?

Musiktheoretische Sicht:
- Du solltest eine konsistente Bezeichungstheorie verwenden, nicht verschiedene durcheinander.
- Die Akkorde "C 78" und "C4 sus 4 3" gibt es nicht.
- Akkorde mit großer Septime ("C7j") fehlen.
- Andere Akkorde sind falsch ("c e g a" müsste entweder als "C 56" [Generalbass] oder als "am7" [Jazz-Harmonik] bezeichnet werden, nicht als "C 6"; "C sus 2" hat nicht nur zwei Töne).
- c' g' bringt ganz andere Ergebnisse als g' c''. Das ist nur richtig, wenn oben [1] gemeint war.

Die Bezeichnung stammen nicht von mir, sondern von Lilypond. Die Liste in meinem Beispiel ist bei weitem nicht vollständig, ich bin derzeit bei 88 Akkorden, wobei allerdings Doubletten vorhanden sind, das muss ich noch ausmerzen.

Es war eigentlich beabsichtigt, dass c g die gleichen Ergebnisse bringt wie c' g'' etc. Anscheinend tut es das doch nicht, dem muss ich noch nachgehen.

Update: ich habe das ausgebügelt. Das kam daher, dass die Sortierfunktion nur dann das (von mir; Experten wissen es besser) erwartete Ergebnis liefert, wenn sich alle Pitches innerhalb einer Oktave befinden.
« Letzte Änderung: Sonntag, 27. März 2016, 21:45 von Manuela »