Autor Thema: Wieder mal Scheme - for-each und define-music-function  (Gelesen 4118 mal)

Manuela

  • Gast
Wieder mal Scheme - for-each und define-music-function
« am: Donnerstag, 24. März 2016, 10:27 »
Hi,

ich kämpfe noch immer  :-[
Ich möchte eine Notenfolge automatisch in verschiedene Tonlagen transponieren
Die Funktion TuWasO liefert den Output für eine Transponierung, for-each liefert zwar keine Fehlermeldung, bewirkt jedoch auch keine Ausgabe.
Wahrscheinlich geht das sowieso viel eleganter und einfacher...

\version "2.18.2"

myMusik= \relative c' { e c d e f }
myPitch = des

#(begin

  (define TuWas
    (lambda Musik Pitch
      (define-music-function (parser location Musik Pitch)
        (ly:music? ly:pitch?)
        #{ \transpose c $Pitch { $Musik } #}
        )
      "Blödsinn"
      )
    )

  (define TuWasO
    (define-music-function (parser location Musik Pitch)
      (ly:music? ly:pitch?)
      #{ \transpose c $Pitch { $Musik } #}
      )
    )

  (define PitchListe
    (list
     (ly:make-pitch 0 0 NATURAL)
     (ly:make-pitch 0 1 NATURAL)
     (ly:make-pitch 0 2 NATURAL)

     )
    )
  (define n-Musik (make-list 3 myMusik))
  (for-each TuWas n-Musik PitchListe)
  )

\TuWasO \myMusik \myPitch
« Letzte Änderung: Donnerstag, 24. März 2016, 10:28 von Manuela »

harm6

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #1 am: Donnerstag, 24. März 2016, 15:15 »
Hallo Manuela,

zunächst die Frage nach dem Ziel der potenziellen Funktion.
Soll die finale Ausgabe äquivalent

mus = \relative c' { c4 d e2 }

\new Staff
{
  \transpose c cis  \mus
  \transpose c d    \mus
  \transpose c dis  \mus
}

sein oder eher

mus = \relative c' { c4 d e2 }

\new Staff \transpose c cis  \mus
\new Staff \transpose c d    \mus
\new Staff \transpose c dis  \mus
?

Zu `for-each' hier ein paar kommentierte Beispiele:

%% Zu jeden Element der Liste ls wird 1 addiert
%% _und_ neue Liste wird ausgegeben.
#(display
  (let ((ls '(1 2 3)))
    (map 1+ ls)))
   
%% Zu jeden Element der Liste ls wird 1 addiert
%% Sonst passiert nichts
%% Die Ausgabe ist #<unspecified>
#(display
  (let ((ls '(1 2 3)))
    (for-each 1+ ls)))
   
%% (1) `mus' wird lokal definiert indem die Noten c, e und g aus einem
%%     Akkord ausgelesen werden
%% (2) Dann läuft eine procedure ab, die in das 'tweak-property eine Frabe
%%     setzt.
%%     Allerdings wird in der procedure `ly:music-set-property!' verwendet,
%%     es setzt das property aber dessen Ausgabe ist #<unspecified>
%%     Insoweit ist die Gesamtausgabe:
%%     (list #<unspecified>
%%           #<unspecified>
%%           #<unspecified>)
%% Hier sollte man `for-each' verwenden nicht `map'
#(display-scheme-music
  (let ((mus (event-chord-notes #{ <c e g> #})))
    (map
      (lambda (m col)
        (ly:music-set-property! m 'tweaks (list (cons 'color col))))
      mus
      (list red green cyan))))
   
%% Selbst wenn man `mus' nachher ausgibt, so hat man doch erst eine Liste
%% erstellt und diese dann weggeworfen.
%% Schlechter Programmierstil!!
%% Besser:
#(display-scheme-music
  (let ((mus (event-chord-notes #{ <c e g> #})))
    (for-each
      (lambda (m col)
        (ly:music-set-property! m 'tweaks (list (cons 'color col))))
      mus
      (list red green cyan))
    mus))
   
%% Um das Ergebnis auch gedruckt zu sehen, muß man es in sequentielle Musik
%% überführen:
$(make-sequential-music
  (let ((mus (event-chord-notes #{ <c e g> #})))
    (for-each
      (lambda (m col)
        (ly:music-set-property! m 'tweaks (list (cons 'color col))))
      mus
      (list red green cyan))
    mus))

Zu Deinem Code:
(1)
Es ist nicht nötig alles in einen Ausdruck (begin ...) zu packen.

(2)
Insbesondere music-functions kann man auf toplevel-niveau definieren, d.h.

myFunction = #(define-music-function ...)

(3)
(lambda Musik Pitch ...)
ist tatsächlich "Blödsinn"
entweder
(lambda (Musik Pitch) ...) als eine procedure mit zwei Argumenten
oder
(lambda Musik ...) als `named-let', also eine rekursive Geschichte. Ich glaube aber nicht, daß Du das willst ...

(4)
  (define PitchListe
    (list
     (ly:make-pitch 0 0 NATURAL)
     (ly:make-pitch 0 1 NATURAL)
     (ly:make-pitch 0 2 NATURAL)

     )
    )

läßt sich einfacher definieren mit der LilyPond-eigenen procedure `event-chord-pitches'

(define PitchListe (event-chord-pitches #{ <c' d' e'> #}))

Soviel fürs erste.


Ich denke es ist Dir nicht geholfen, wenn ich eine Lösung für das Problem poste.
Insoweit wie weit soll ich gehen mit Verbesserungsvorschlägen?



Viel Erfolg,
  Harm
« Letzte Änderung: Donnerstag, 24. März 2016, 15:18 von harm6 »

fugenkomponist

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #2 am: Donnerstag, 24. März 2016, 15:58 »
Ich klinke mich mal ein, weil ich das Thema interessant finde und selbst auf keine Lösung komme … Vorausgesetzt, es ist so gemeint, dass mehrere Scores erzeugt werden sollen.
%% Um das Ergebnis auch gedruckt zu sehen, muß man es in sequentielle Musik
%% überführen:
$(make-sequential-music
Warum braucht man hier $ und nicht #? Ich kenn die Verwendung und Bedeutung der beiden innerhalb von Musikfunktionen, aber irgendwie wirds mir hier nicht ganz klar.
Zitat
(define PitchListe (event-chord-pitches #{ <c' d' e'> #}))
Interessant, das war mir neu. Aber vielleicht gut zu wissen in anderen Anwendungsfällen: Auch einzelne pitches muss man nicht mit (ly:make-pitch 0 0 NATURAL) ausschreiben, sondern kann die einfach als #{ c' #} schreiben (da braucht mann dann keine weitere Funktion, event-chord-pitches ist nur einfach dafür da, die pitches aus dem Akkord zu extrahieren).

Eigentlich lässt sich die Sache auch ohne die ganzen Funktionen TuWas und TuWasO hinschreiben. (Nachdem harm da nichts gesagt hat, halte ich mich auch mal zurück mit Code, sind aber ca. 5 Zeilen, wenn man mal die pitch-Liste als gegeben nimmt.) Man kriegt dann aber eine Liste von Scores und da bin auch ich überfragt: Wie krieg ich denn diese Scores jetzt ausgegeben? Hab mit make-bookpart und make-book rumprobiert, aber 1. glaub ich kaum, dass es so kompliziert sein muss und 2. hab ich das nicht auf die Reihe gekriegt …

Manuela

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #3 am: Donnerstag, 24. März 2016, 16:14 »


(lambda Musik Pitch ...)
ist tatsächlich "Blödsinn"
entweder
(lambda (Musik Pitch) ...) als eine procedure mit zwei Argumenten
oder
(lambda Musik ...) als `named-let', also eine rekursive Geschichte. Ich glaube aber nicht, daß Du das willst ...

(4)
  (define PitchListe
    (list
     (ly:make-pitch 0 0 NATURAL)
     (ly:make-pitch 0 1 NATURAL)
     (ly:make-pitch 0 2 NATURAL)

     )
    )

läßt sich einfacher definieren mit der LilyPond-eigenen procedure `event-chord-pitches'

(define PitchListe (event-chord-pitches #{ <c' d' e'> #}))

Soviel fürs erste.


Ich denke es ist Dir nicht geholfen, wenn ich eine Lösung für das Problem poste.
Insoweit wie weit soll ich gehen mit Verbesserungsvorschlägen?



Viel Erfolg,
  Harm

Hallo Harm,

du einsames Liliypond- und Scheme-Genie (wenn es einen Smiley "Thumbs up" oder "Klatschen" gäbe, würde ich ihn jetzt einfügen)  ,
danke für deine Vorschläge und Anregungen, die mir wieder Stoff zum Nachdenken geben  :D

Tatsächlich wäre mir mit einer Lösung schon sehr geholfen, ich bezwecke nämlich etwas ganz bestimmtes damit.

Trotz ausgiebigen Studiums diverser Scheme-Handbücher und Tutorials tue ich mir immer noch unglaublich schwer mit der Klammernsetzung, und dann geht sie wieder daneben wie in meinem Beispiel. Natürlich wollte ich eine Prozedur mit 2 Variablen haben.
« Letzte Änderung: Donnerstag, 24. März 2016, 16:23 von Manuela »

fugenkomponist

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #4 am: Donnerstag, 24. März 2016, 16:19 »
Könntest du harms erste Frage beantworten? Davon hängt ab, ob ich ne Lösung hätte ;)

Manuela

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #5 am: Donnerstag, 24. März 2016, 16:24 »
Könntest du harms erste Frage beantworten? Davon hängt ab, ob ich ne Lösung hätte ;)

O.k. klar  :D

es sollen verschiedene Scores werden

Im Idealfall würde ich auch noch Text innerhalb der Ausgabe abhängig von der verwendeten Tonart gestalten (wofür ich keine andere Lösung gefunden habe)

fugenkomponist

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #6 am: Donnerstag, 24. März 2016, 16:40 »
Hm, dann weiß ich leider nichts, da müssen wir wohl auf harm warten ;)

Was für ein Text denn genau? Bzw. wie soll der von der Tonart abhängen?

harm6

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #7 am: Donnerstag, 24. März 2016, 16:41 »
Zitat von: Manuela
Tatsächlich wäre mir mit einer Lösung schon sehr geholfen

Hier so einiges:
\version "2.18.2"

\markup "Basic, one Staff"

myMusik = \relative c' { e c d e }

%% Alles in einen Staff, basic :)
\new Staff
  $(make-sequential-music
    (map
      (lambda (p)
        #{ { \transpose c $p \myMusik } #})
      (event-chord-pitches #{ < f g > #})))
     
\markup "All new Scores"
     
%% Jeweils neue Scores:
%% Das ist 2.18.-code, für neuere lily-versionen muß `parser' gelöscht werden
%% `add-score' und `scorify-music' finden sich in lily-library.scm
%% `add-score' Kommentar:
%%    ;; Add a score to the current bookpart, book or toplevel
%% `scorify-music' verwendet `ly:make-score', doku dafür:
%%    "Return score with music encapsulated in it."
%% Man ist jetzt natürlich komplett auf scheme-level
%% Neue Elemente müssen dann auch via scheme eingeführt werden
%% Dazu gibt es einige weitere Funktionen in lily-library.scm
#(for-each
   (lambda (p)
     (add-score parser
       (scorify-music #{ { \transpose c $p \myMusik } #} parser)))
   (event-chord-pitches #{ < f g > #}))
   
\markup "Sophisticated `multipleTransposes'"

%% Thanks David Kastrup
multipleTransposes =
#(define-music-function (parser location m music)(ly:music? ly:music?)
   (music-clone m
    'elements
    (map (lambda (pitch)
  (ly:music-property #{ \transpose c $pitch $music #} 'element))
         (event-chord-pitches m))))

%% Examples

\new Staff
\multipleTransposes { c cis } \relative c'' { g a }

\new StaffGroup
\multipleTransposes << c cis >> \relative c'' \new Staff { g a }

\new Staff
\multipleTransposes <c cis> g''!

Zitat von: Manuela
Im Idealfall würde ich auch noch Text innerhalb der Ausgabe abhängig von der verwendeten Tonart gestalten

Was für Text?
Als \header? mark? markup? (im Staff oder toplevel?)


Gruß,
  Harm

Manuela

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #8 am: Donnerstag, 24. März 2016, 16:49 »

Hier so einiges:


Was für Text?
Als \header? mark? markup? (im Staff oder toplevel?)


Gruß,
  Harm

Hui, das geht ja in Windeseile  :)
Da hätte ich mich nicht tagelang plagen müssen...

Markup täte es, glaube ich.

Ganz herzlichen Dank  :-*

Ich sehe gerade, das ist so sophisticated, da wäre ich ohnehin chancenlos gewesen...
« Letzte Änderung: Donnerstag, 24. März 2016, 16:51 von Manuela »

harm6

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #9 am: Donnerstag, 24. März 2016, 16:58 »
Zitat von: fugenkomponist
Warum braucht man hier $ und nicht #?

#(make-sequential-music (list #{ c'1 d' #}))

ist ein scheme-Ausdruck, der erst noch Musik in einem .ly-file werden muß.
Das kann auf verschieden Weise passieren. Z.B.:

foo =
#(make-sequential-music (list #{ c'1 d' #}))
\new Staff \foo

Auch
\displayMusic
#(make-sequential-music (list #{ c'1 d' #}))
reicht schon, da \displayMusic auch die Musik ausgibt.

Aber die vielleicht simpelste Methode ist $ zu verwenden
$(make-sequential-music (list #{ c'1 d' #}))

HTH,
  Harm


« Letzte Änderung: Donnerstag, 24. März 2016, 17:00 von harm6 »

fugenkomponist

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #10 am: Donnerstag, 24. März 2016, 17:02 »
Zitat von: Harm
\version "2.18.2"

\markup "Basic, one Staff"

myMusik = \relative c' { e c d e }

%% Alles in einen Staff, basic :)
\new Staff
  $(make-sequential-music
    (map
      (lambda (p)
        #{ { \transpose c $p \myMusik } #})
      (event-chord-pitches #{ < f g > #})))
     
\markup "All new Scores"
     
%% Jeweils neue Scores:
%% Das ist 2.18.-code, für neuere lily-versionen muß `parser' gelöscht werden
%% `add-score' und `scorify-music' finden sich in lily-library.scm
%% `add-score' Kommentar:
%%    ;; Add a score to the current bookpart, book or toplevel
%% `scorify-music' verwendet `ly:make-score', doku dafür:
%%    "Return score with music encapsulated in it."
%% Man ist jetzt natürlich komplett auf scheme-level
%% Neue Elemente müssen dann auch via scheme eingeführt werden
%% Dazu gibt es einige weitere Funktionen in lily-library.scm
#(for-each
   (lambda (p)
     (add-score parser
       (scorify-music #{ { \transpose c $p \myMusik } #} parser)))
   (event-chord-pitches #{ < f g > #}))
   
\markup "Sophisticated `multipleTransposes'"

%% Thanks David Kastrup
multipleTransposes =
#(define-music-function (parser location m music)(ly:music? ly:music?)
   (music-clone m
    'elements
    (map (lambda (pitch)
  (ly:music-property #{ \transpose c $pitch $music #} 'element))
         (event-chord-pitches m))))

%% Examples

\new Staff
\multipleTransposes { c cis } \relative c'' { g a }

\new StaffGroup
\multipleTransposes << c cis >> \relative c'' \new Staff { g a }

\new Staff
\multipleTransposes <c cis> g''!
Wow. Woher weiß man sowas? Da hilft ja nichtmal die Internals Reference, hast du einfach den kompletten Code gelesen und intus? music-clone und add-score hab ich vorher noch nie gesehn.

Und eine Frage hab ich noch: Wie funktioniert multipleTransposes? Scheint ja 'elements von nem EventChord, SimultaneousMusic oder  SequentialMusic zu nehmen und jedes Element dieser Liste durch
(ly:music-property [mach was mit dem einzelnen pitch und dem Muster] 'element)zu ersetzen. Ich versteh nicht ganz, warum man da dieses 'element erstmal rausholt. Geht doch auch ohne bzw. warum funktioniert es überhaupt mit?

Das dritte Beispiel brauchts anscheinend, aber das kapier ich auch überhaupt nicht (weder, warum es überhaupt geht, noch, warum es nur mit diesem Trick geht) …

Edit: Danke für deine Erklärung zum Thema $. Ich glaub, ich habs verstanden :)

Manuela

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #11 am: Donnerstag, 24. März 2016, 17:05 »
Wieso finde ich event-chord-pitches nicht in der Internals-Referenz?

Könnte man damit folgendes machen: eine Liste von Akkorden, wobei jeder Akkord durch eine Liste von Pitches dargestellt wird.
Und eine Funktion, die als Argument eine Liste von Pitches hat und alle Akkorde aus obiger Liste auswirft, in denen die Pitches des Arguments vorkommen.

Das sollte wahrscheinlich nicht allzu schwierig ist, aber ich verrenne mich bestimmt wieder irgendwie.

Manuela

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #12 am: Donnerstag, 24. März 2016, 17:06 »


Wow. Woher weiß man sowas? Da hilft ja nichtmal die Internals Reference

Da kann ich mich nur anschließen  :D

harm6

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #13 am: Donnerstag, 24. März 2016, 17:11 »
Zitat von: Manuela
Markup täte es, glaube ich.

\version "2.18.2"

%% Mit hinzugefügtem toplevel-markup
#(for-each
   (lambda (p)
     (begin
       (add-text parser
         (format #f
           "tranposed to ~a"
           (cadr (string-split (format #f "~a" p) #\sp))))
       (add-score parser
         (scorify-music #{ { \transpose c $p \myMusik } #} parser))))
   (event-chord-pitches #{ < f g > #}))

HTH,
  Harm

P.S.
Für die anderen Fragen, ich brauch mal ne' Pause ;)

fugenkomponist

  • Gast
Re: Wieder mal Scheme - for-each und define-music-function
« Antwort #14 am: Donnerstag, 24. März 2016, 17:14 »
Für die anderen Fragen, ich brauch mal ne' Pause ;)
Die hast du dir verdient :) Aber schön, wie viel Neues man hier lernt ;)