Autor Thema: Scheme  (Gelesen 10403 mal)

iugin

  • Member
Scheme
« am: Donnerstag, 1. Mai 2014, 08:39 »
Liebe alle

ich weiss nicht, ob dieser Thema hier gehört, ich versuche es mal... :)
Ich finde wirklich erstaunlich, was manche von euch mit Scheme machen, und möchte in dem Bereich ein bisschen selbständig werden. Es ist mir langsam ein bisschen peinlich, dass ich immer wieder hier in Forum für jede Kleinigkeit fragen muss, ich möchte irgendwann auch selber etwas basteln (und beitragen) können.
Ich programmiere Java, und ein bisschen C++. Scheme ist mir aber ein Rätsel. Überall steht sogar, dass es eine Sprache für Anfänger ist!
Ich habe die Tutorials im Lilypond-Handbuch gelesen, aber sobald ich versuche selber etwas zu schreiben, verliere ich mich total.

Ich bin sicher, ich bin in guter Gesellschaft :)

Ich möchte am liebsten eine Scheme-Sektion öffnen, etwas for dummies, ich weiss aber nicht, ob es Sinn machen würde.

Deswegen meine Frage: wie habt ihr euch Scheme beigebracht? Sind die Infos auf der Homepage von Lilypond tatsächlich knapp, oder bin ich einfach blöd? Ist die einzige Lösung, einfache Beispiele zu studieren, und was verändern, und schauen, was sie produzieren?

Bin gespannt.... :)

Liebe Grüsse

Eugenio

Ps: Falls viele jetzt schreiben "Ja, ich habe dasselbe Problem", machen wir eine Scheme-Selbsthilfsgruppe. So etwas wie im Kreis sitzen und sagen: "Hallo, mein Name ist Eugenio, ich habe ein Problem mit Scheme". "Hallo Eugenio..." usw.  :D

trulli

  • Member
Re: Scheme
« Antwort #1 am: Donnerstag, 1. Mai 2014, 12:50 »
[...]machen wir eine Scheme-Selbsthilfsgruppe.

Da bin ich dabei.  :)

Mir geht es auch so, dass ich gerne Scheme können möchte. Leider ist für mich die Anwendung nur hier in LilyPond gegeben und alle Probleme, die ich mal hatte, wurden hier wunderbar im Forum gelöst. Ich glaube deshalb, dass ich es nie richtig lernen werde, weil mir die tägliche Anwendung fehlt.

Aber ich kann ja als "passives" Mitglied dabei sein.  :)

Wir hatten hier schon mal einige Links und Tutorials zum Thema Scheme. Davon habe ich leider nicht viel kapiert. Vielleicht können uns die Experten hier noch ein paar Tipps für die ganz blutigen Anfänger geben....

Grüße von Trulli

harm6

  • Member
Re: Scheme
« Antwort #2 am: Donnerstag, 1. Mai 2014, 13:43 »
Hallo,

tatsächlich habe ich scheme, oder genauer guile, nur gelernt um LilyPond besser an meine Bedürfnisse anpassen zu können.
Das Extending-maual ist allerdings tatsächlich sehr knapp gehalten, aber viel besser geworden. Es gibt jedoch zahlreiche Manuals online...
Ich habe aber tatsächlich geübt die Beispiele aus dem Extending-manual zu manipulieren, z.B. markup-commands zu schreiben, music-functions etc
Neben dem Problem guile zu lernen, muß man es ja auch in LilyPond anwenden. Das ist manchmal das größere Problem, da einige vorgefertigte tools schlecht zu finden und/oder schlecht dokumentiert sind.

Ganz generell ist es leichter/unkomplizierter layout-Objekte (grobs) zu manipulieren, als die Musik.
Das wäre auch mein Rat für den Beginn.
markup-commands sind (meistens) auch nicht so problematisch.

Wenn Fragen/Probleme auftauchen, helfe ich gerne.
Aber bitte nur ein kleines Problem pro post. Ansonsten ist zu viel Erklärung notwendig.
(Jeden einzelnen Schritt aus meinem Coding hier zu erklären wäre ein Riesen Aufwand ...)

Gruß,
  Harm

Zitat
Ps: Falls viele jetzt schreiben "Ja, ich habe dasselbe Problem", machen wir eine Scheme-Selbsthilfsgruppe. So etwas wie im Kreis sitzen und sagen: "Hallo, mein Name ist Eugenio, ich habe ein Problem mit Scheme". "Hallo Eugenio..."
LMAO

infranator

  • Member
Re: Scheme
« Antwort #3 am: Donnerstag, 1. Mai 2014, 14:17 »
Zitat
Ich bin sicher, ich bin in guter Gesellschaft
So einer Selbsthilfegruppe würde ich mich auf jeden Fall anschließen!

Es gibt auf www.lilypondblog.org eine seht gute Einführung in die Benutzung von Scheme in Lilypond. Wenn es um die Syntax von Scheme selbst geht, habe ich viel in dem Tutorial hier http://www.shido.info/lisp/idx_scm_e.html gelernt (Kapitel 2-7).
Besonders das Verstehen des Prinzips der sich selbst aufrufenden Funktionen (Rekursion), trägt glaube ich sehr zum Verständnis von Scheme bei.
Das schwierigste sind für mich aber die hunderten von vordefinierten Befehle die es bei Guile/Lilypond gibt.

Sind die Infos auf der Homepage von Lilypond tatsächlich knapp, oder bin ich einfach blöd?Das ist schon sehr knapp, ansonsten bin ich auch blöd ;-)






trulli

  • Member
Re: Scheme
« Antwort #4 am: Donnerstag, 1. Mai 2014, 17:29 »
Die Selbsthilfegruppe bedankt sich für die Links.



iugin

  • Member
Re: Scheme
« Antwort #5 am: Samstag, 3. Mai 2014, 15:00 »
Hallo miteinander

erstens: danke infranator für die Links, die sind sehr hilfsreich :)
Ich komme jetzt mit einer konkreten Frage: ich möchte die Hemiolen in einem Stück mit Klammern markieren, und ich weiss, ich kann \startGroup und \stopGroup benutzen.
Ich habe mich alledings gefragt, ob ich eine Scheme-Funktion schreiben kann, mit der ich einfach z.B. \klammer{c d e} schreiben kann.
Das erste das ich gemacht habe ist zu schauen, wie die Musik in Scheme übersetzt wird.
Dieser Code
\version "2.18.0"

\layout {
  \context {
    \Voice
    \consists "Horizontal_bracket_engraver"
  }
}

\displayMusic
\relative c'' {
  c4\startGroup d
  e\stopGroup
}
ergibt
(make-music
  'RelativeOctaveMusic
  'element
  (make-music
    'SequentialMusic
    'elements
    (list (make-music
            'NoteEvent
            'articulations
            (list (make-music
                    'NoteGroupingEvent
                    'span-direction
                    -1))
            'duration
            (ly:make-duration 2 0 1)
            'pitch
            (ly:make-pitch 1 0 0))
          (make-music
            'NoteEvent
            'pitch
            (ly:make-pitch 1 1 0)
            'duration
            (ly:make-duration 2 0 1))
          (make-music
            'NoteEvent
            'articulations
            (list (make-music
                    'NoteGroupingEvent
                    'span-direction
                    1))
            'pitch
            (ly:make-pitch 1 2 0)
            'duration
            (ly:make-duration 2 0 1)))))
Jetzt glaube ich, ich sollte, in meinem Befehl \klammer{c d e} die Musik durchlaufen können, so dass ich bei der ersten Note folgendes hinfügen kann:
'articulations
            (list (make-music
                    'NoteGroupingEvent
                    'span-direction
                    -1))
und bei der letzten dasselbe einfach mit dem Wert 'span-direction 1.
Wie ich eine Artikulation hinfügen kann, sehe ich hier: http://lilypond.org/doc/v2.19/Documentation/extending/adding-articulation-to-notes-_0028example_0029.de.html
Das funktioniert aber nur mit einer Note, und nicht mit einer Sequenz.

Erstens: Eine Note ist anscheinend ein music-event. Ist eine Sequenz eine List aus music-events? Es scheint aus dem obigen Code so zu sein: 'SequentialMusic hat 'elements der eine Liste aus NoteEvents ist.
Zweitens: Wenn schon, wie kann ich die Sequenz durchlaufen (ich habe hier http://lilypondblog.org/2014/04/music-functions-3-reusing-code/ von maps gelesen, und habe das Gefühl, es geht in die Richtung), und nur das erste und das letzte Element rausnehmen?

Ich wünsche der ganzen Scheme-Selbsthilfegruppe einen schönen Tag

Liebe Grüsse

Eugenio

 

infranator

  • Member
Re: Scheme
« Antwort #6 am: Sonntag, 4. Mai 2014, 00:57 »
Zitat
Erstens: Eine Note ist anscheinend ein music-event. Ist eine Sequenz eine List aus music-events? Es scheint aus dem obigen Code so zu sein: 'SequentialMusic hat 'elements der eine Liste aus NoteEvents ist.
Genauso ist es!
Zitat
Zweitens: Wenn schon, wie kann ich die Sequenz durchlaufen (ich habe hier http://lilypondblog.org/2014/04/music-functions-3-reusing-code/ von maps gelesen, und habe das Gefühl, es geht in die Richtung), und nur das erste und das letzte Element rausnehmen?
Vielleicht geht es irgendwie mit maps, das habe ich bis jetzt aber noch nie benutzt. Ich glaube aber, maps ist eher dazu geeignet, music-events unabhängig voneinander zu bearbeiten.
Mit Rekursion weiß ich aber wie es geht.

\version "2.19.5"

\layout {
  \context {
    \Voice
    \consists "Horizontal_bracket_engraver"
  }
}

#(define (add-grouping dir note-event)
   "Add an NoteGroupingEvent to the articulations of `note-event',
  which is supposed to be a NoteEvent expression."
   (set! (ly:music-property note-event 'articulations)
         (cons (make-music 'NoteGroupingEvent
                 'span-direction dir)
           (ly:music-property note-event 'articulations)))
   note-event)

#(define (helper ls1 ls2)
   "Add a NoteGroupingEvent with the direction -1 to the first
    and one with the direction 1 to the last NoteEvent of
    a SequentialMusic expression"
   (if (eq? 1 (length ls1))
       ; wenn ls1 nur noch aus einem element besteht
       ; Schluss mit der Selbstaufrufung, das Ende von der Klammer
       ; an die letzte Note hängen und das ganze umdrehen
       (reverse (cons (add-grouping 1 (car ls1)) ls2))
       (if (null? ls2)
           ; ls2 ist noch leer, das heißt (car ls1) ist das
           ; erste Element in der Liste. Start der klammer an die
           ; Note hängen und weiter
           (helper
            (cdr ls1)
            (cons (add-grouping -1 (car ls1)) ls2))
           ; (car ls1) ist weder das letzte noch das erste
           ; Element in der Liste. Nichts verändern und ein
           ; Element weiter gehen
           (helper
            (cdr ls1)
            (cons (car ls1) ls2)))))

klammer =
#(define-music-function (parser location music) (ly:music?)
   (make-music
    'SequentialMusic
    'elements
    (helper (ly:music-property music 'elements) '())))

{
  c'4 \klammer { d' e' f' }
  a' b'2.
}

Die Funktion add-grouping ist eine Bearbeitung von der add-accent Funktion aus dem Handbuch. Jetzt fügt sie aber den Start oder das Ende einer einer Grouping Klammer hinzu. Je nachdem, ob sie mit -1 oder 1 aufgerufen wird.

Die helper Funktion geht ein Element nach dem anderen in der Liste durch. Nur das erste und das letzte wird verändert.

Die klammer Funktion ruft die helper Funktion auf.
Man muss die Elemente von SequentialMusic mit (ly:music-property x 'elements) aufrufen, damit man die einzelnen music-events mit car und cdr e.t.c.  ansteuern, und dann bearbeiten kann.

infranator

  • Member
Re: Scheme
« Antwort #7 am: Sonntag, 4. Mai 2014, 01:07 »
Es geht auch viel einfacher..

https://liarchiv.joonet.de/index.php?topic=1747.0

mit (last LISTE) oder (car (reverse LISTE)) kann man natürlich auch das letzte element direkt ansteuern, ohne die ganze Geschichte mit der Rekursion.

Wie war das nochmal mit dem Wald und den Bäumen? ;-)

harm6

  • Member
Re: Scheme
« Antwort #8 am: Sonntag, 4. Mai 2014, 15:36 »
Zitat von: infranator
Es geht auch viel einfacher..

https://liarchiv.joonet.de/index.php?topic=1747.0

mit (last LISTE) oder (car (reverse LISTE)) kann man natürlich auch das letzte element direkt ansteuern, ohne die ganze Geschichte mit der Rekursion.

Hallo infranator,

ich finde Deinen Code richtig gut.
Das Problem ist jedoch, er funktioniert nicht immer:

\version "2.18.0"

\layout {
  \context {
    \Voice
    \consists "Horizontal_bracket_engraver"
  }
}

#(define (add-grouping dir note-event)
   "Add an NoteGroupingEvent to the articulations of `note-event',
  which is supposed to be a NoteEvent expression."
   (set! (ly:music-property note-event 'articulations)
         (cons (make-music 'NoteGroupingEvent
                 'span-direction dir)
           (ly:music-property note-event 'articulations)))
   note-event)

#(define (helper ls1 ls2)
   "Add a NoteGroupingEvent with the direction -1 to the first
    and one with the direction 1 to the last NoteEvent of
    a SequentialMusic expression"
   (if (eq? 1 (length ls1))
       ; wenn ls1 nur noch aus einem element besteht
       ; Schluss mit der Selbstaufrufung, das Ende von der Klammer
       ; an die letzte Note hängen und das ganze umdrehen
       (reverse (cons (add-grouping 1 (car ls1)) ls2))
       (if (null? ls2)
           ; ls2 ist noch leer, das heißt (car ls1) ist das
           ; erste Element in der Liste. Start der klammer an die
           ; Note hängen und weiter
           (helper
            (cdr ls1)
            (cons (add-grouping -1 (car ls1)) ls2))
           ; (car ls1) ist weder das letzte noch das erste
           ; Element in der Liste. Nichts verändern und ein
           ; Element weiter gehen
           (helper
            (cdr ls1)
            (cons (car ls1) ls2)))))

klammer =
#(define-music-function (parser location music) (ly:music?)
   (make-music
    'SequentialMusic
    'elements
    (helper (ly:music-property music 'elements) '())))

 
\relative c' {
  c4
  \klammer { d \times 2/3 { c d c } }
  \klammer { <d f>2 \repeat volta 2 { e4 f } }
  b1
}

In diese Falle bin ich schon selbst gelaufen.
Siehe Diskussion hier.

Die Tipps die David Kastrup gab, führen hier zu folgendem:

\version "2.19.4"

% see:
% http://lilypond.1069038.n5.nabble.com/review-of-a-Mutopia-file-why-TabStaff-gives-error-here-td136690.html
% http://lsr.dsi.unimi.it/LSR/Item?id=857

#(define (group-start-stop mus)
  (let ((elts (extract-typed-music mus '(rhythmic-event event-chord))))
    (for-each
      (lambda (sel)
        (let ((m (sel elts)))
          (if (music-is-of-type? m 'event-chord)
              (set! (ly:music-property m 'elements)
                    (cons (make-music 'NoteGroupingEvent
                                      'span-direction (sel '(-1 1)))
                          (ly:music-property m 'elements)))
              (set! (ly:music-property m 'articulations)
                    (cons (make-music 'NoteGroupingEvent
                                      'span-direction (sel '(-1 1)))
                          (ly:music-property m 'articulations))))))
      (list last first)))
  mus)

grouping =
#(define-music-function (parser location music) (ly:music?)
  (group-start-stop music))

\relative c' {
  c4
  \grouping { d4 \times 2/3 { c d c } }
  \grouping { <d f>2 \repeat volta 2 { e4 f } }
  b1
}

Zusätzlich habe ich im Falle eines EventChord das 'NoteGroupingEvent in die 'elements gepackt und nicht in die 'articulations.
Es macht tatsächlich keinen Unterschied, aber die manuelle Eingabe mit \startGroup, etc würde so verfahren.
Falls sich die interne Struktur von LilyPond mal ändern sollte, ist es auf jeden Fall richtig. ;)

Ich habe auch versucht
\grouping { \repeat unfold 4 c''4 }
möglich zu machen, bin aber bislang gescheitert.
Wäre schön, denn mit \repeat unfold ... klappt selbst die manuelle Eingabe via \startGroup, \stopGroup derzeit nicht.

HTH,
  Harm

iugin

  • Member
Re: Scheme
« Antwort #9 am: Sonntag, 4. Mai 2014, 19:10 »
Hallo miteinander

ihr werdet mich aus dem Forum rausschmeissen...  ;D

Ich habe den Code von Infranator ziemlich genau angeschaut, und mit grosser Mühe habe etwas verstanden, auch dank den guten Kommentaren.
Jetzt, abgesehen davon, ob es immer funktioniert oder nicht, sind mir ein paar grundlegende Fragen in den Sinn gekommen.
- (define-music-function) ist nur die Funktion die vom normalen Lilypond Code aufgerufen wird, oder? Alle andere sind nur mit (define) definiert.
- (make-music) ist immer gefolgt von einem Namen gross geschrieben (wie zb. 'SequentialMusic) und 'elements oder 'articulations oder so. Das Apostroph bedeutet, dass sie Liste sind.
'SequentialMusic finde ich in der IR bei der Music expression, 'elements in den Music properties. Ungefähr sollte es heissen: Mach Sequentielle Musik mit folgenden Eigenschaften. Heisst es, dass (make-music) nur zwei Argumente (Listen) nimmt, eine Music Expression und eine Music property, wobei die properties sich auf die expressions beziehen?

Wie ihr seht, sind meine Probleme sehr grundlegend, ich bin aber schon froh, dass ich die Programme zu verstehen beginne (die einfache).

Liebe Grüsse und Danke :)

Eugenio

infranator

  • Member
Re: Scheme
« Antwort #10 am: Mittwoch, 7. Mai 2014, 13:34 »
Zitat
- (make-music) ist immer gefolgt von einem Namen gross geschrieben (wie zb. 'SequentialMusic) und 'elements oder 'articulations oder so. Das Apostroph bedeutet, dass sie Liste sind.
Soweit ich weiß sind das Symbols. Das Apostroph verhindert, dass 'SequentialMusic oder 'elemtents e.t.c. von Scheme für Variablen oder Funktionen gehalten werden.
Ich kann das leider auch nicht besser erklären, aber gib mal folgendes in der scheme-sandbox ein:

(define ls '(1 2 3 4))

guile> ls
(1 2 3 4)

guile> 'ls
ls

guile> 'WurstBrot
WurstBrot

Wenn Du bei WurstBrot das Apostroph weglässt gibt's Beschwerden.

infranator

  • Member
Re: Scheme
« Antwort #11 am: Donnerstag, 8. Mai 2014, 11:11 »
Hallo alle miteinander!
#(define (group-start-stop mus)
  (let ((elts (extract-typed-music mus '(rhythmic-event event-chord))))
    (for-each
      (lambda (sel)
        (let ((m (sel elts)))
          (if (music-is-of-type? m 'event-chord)
              (set! (ly:music-property m 'elements)
                    (cons (make-music 'NoteGroupingEvent
                                      'span-direction (sel '(-1 1)))
                          (ly:music-property m 'elements)))
              (set! (ly:music-property m 'articulations)
                    (cons (make-music 'NoteGroupingEvent
                                      'span-direction (sel '(-1 1)))
                          (ly:music-property m 'articulations))))))
      (list last first)))
  mus)

Das ist mal wieder eine große Herausforderung hier!
Ich habe nach der Funktion "extract-typed-music" in music-functions.scm gesucht:
#(define-public (extract-typed-music music type)
   "Return a flat list of all music with @var{type} (either a single
type symbol or a list of alternatives) inside of @var{music}, not
recursing into matches themselves."
   (extract-music
    music
    (if (cheap-list? type)
        (lambda (m)
          (any (lambda (t) (music-is-of-type? m t)) type))
        (lambda (m) (music-is-of-type? m type)))))

Das heißt, bei (extract-typed-music mus '(rhythmic-event event-chord))wird eine nicht verschachtelte Liste von allen rhythmic-events und event-chords in "mus" ausgegeben. Cool!
Davon wird im led-Block nur das letzte und das erste Element bearbeitet.
Was ich noch nicht verstehe ist, wie daraus die resultierende Liste wird.
Ich würde jetzt denken, die Funktion gibt erst das aus, was im led-Block steht, also das bearbeitete erste Element und das bearbeitete letzte Element, und danach die unveränderte "mus"-Liste.
Zum Glück tut sie das nicht, dann würde es ja gar nicht funktionieren  :)

Übrigens finde ich die Konstruktionen mit lambda ich immer schwer zu verstehen. Im Prinzip ist "sel = (list last first)", oder?
Könnte man das nicht auch mit let machen?
vg,
infranator
« Letzte Änderung: Samstag, 10. Mai 2014, 14:32 von infranator »

Manuela

  • Member
Re: Scheme
« Antwort #12 am: Montag, 6. April 2015, 22:38 »

Ich habe die Tutorials im Lilypond-Handbuch gelesen, aber sobald ich versuche selber etwas zu schreiben, verliere ich mich total.

Ich bin sicher, ich bin in guter Gesellschaft :)

Ich weiß nicht, wie gut meine Gesellschaft ist  ;) aber mir geht es haargenau so

iugin

  • Member
Re: Scheme
« Antwort #13 am: Dienstag, 7. April 2015, 12:15 »
Hallo Manuela

ich konnte inzwischen mit Scheme etwas anfangen (habe natürlich schon alles wieder vergessen, da ich seit Dezember nichts mehr gebastelt habe). Geholfen haben mir die viele Erklärungen im Forum, aber auch das.
So konnte ich für meine Bedürfnisse immer was machen. Vielleicht hilft dir das ein bisschen.

Liebe Grüsse

Eugenio

Arnold

  • Member
Re: Scheme
« Antwort #14 am: Mittwoch, 8. April 2015, 09:30 »
Hallo,

nachdem ich schon vor längerer Zeit mich einmal geäußert habe, welche Kapitel des Guile-Handbuchs ich am meisten konsultiere, jetzt noch eine allgemeinere Information, denn für dieses Thema sind zwei Blickwinkel wichtig:
1. Scheme als allgemeines Werkzeug
2. Wie wird Scheme (Erweiterungen mittels Scheme) in Lilypond eingebunden.

Zu diesem zweiten Punkt ein kurzer Abriß über die einzelnen Schritte einer PDF-Erstellung mittels LilyPond:
  • Parsen der Eingabedatei, dabei werden vor allem Datenstrukturen angelegt, welche die Musik beschreiben
    Hier greifen viele Scheme-Erweiterungen an, auch die musicMap-Funktion.
  • Die Musikevents werden abgespielt, und die Engraver erstellen ein »Netzwerk von Grobs (Grafikobjekten)«
    Mittlerweile können Engraver auch in Scheme und nicht nur in C programmiert werden. Insgesamt ist das ein Themenbereich, um den man sich eher später kümmert.
  • Spezelle Callback-Einsprungpunkte: before-line-breaking und after-line-breaking
    diese werden an Grobs angehängt
  • Callback-Funktionen für Grob-Eigenschaften
  • Backend patchen - wird auch nur äußerst selten nützlich anzuwenden sein
    z. Bsp. am Schuß der PDF-Erzeugung in dieser Routine noch ein externes Programm aufrufen, welches den gegenwärtigen Arbeitsspeicherbedarf vom Lilypond-Prozess anzeigt, oder zwei PDF-Dateien erstellen (eine mit und eine ohne Point-And-Click)

Arnold