Lilypond et les motifs rythmiques

Musique Assistée par Ordinateur
Avatar de l’utilisateur
EricW
Infidèle de la première heure
Messages : 10045
Inscription : 16 mai 2005, 22:38
Contact :

Lilypond et les motifs rythmiques

Message par EricW »

Salut les gazéléfilles,

Je vous propose un petit outil pour lilypond qui est bien pratique quand on doit saisir une partie dans laquelle un même motif rythmique se répète tout en étant sur des notes différentes.

L'idée est qu'on décrit la structure rythmique du motif une bonne fois pour toute, et ça génère une fonction qui s'applique ensuite à une séquence de notes quelconque.

Un petit exemple : j'ai un motif "croche, noire, croche, croche pointée, double croche" à utiliser je ne sais combien de fois dans un morceau.
Je commence par décrire le motif (peu importent les notes, ici c'est le rythme qui nous intéresse) :

Code : Tout sélectionner

monMotif = #(pattern-apply-factory #{ do8 do4 do8  do8. do16 #})
Et ensuite j'écris ma partie (ici ce sont les notes qui nous intéressent, le rythme a été décrit une fois pour toute) :

Code : Tout sélectionner

\score {
  \relative do' {
    \monMotif{ do re mi fa sol }
    \monMotif{ do, sol' mi do sib }
    ...
Petite limitation : la description du motif ne supporte pas encore les liaisons (un jour si j'ai le courage ... sinon s'il y a amateur de codage en scheme qui veut se lancer, ça doit se passer dans pattern-apply-factory, et apply pattern est probablement à modifier aussi).

Voici le code à inclure dans votre partition (avec une directive "\include"), et qui définit toute la mécanique du bidule :

Code : Tout sélectionner

\version "2.14.0"

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% pattern.ly
%%
%% A pattern generator for lilypond.
%%
%% The basic idea is to apply a rythmic pattern to a sequence of notes.
%% But instead of specifying each time the notes and the pattern (which would
%% be quite useless ...), the scheme macro defined below
%% creates a music function which applies the given pattern to any sequence of
%% notes. This is possible thanks to the scheme macro mechanism
%% "define-syntax" and "syntax rules" (see r5rs document for details about the
%% macro mechanism in scheme).
%%
%% For a usage example, see the file "test-pattern.ly"
%%
%%%%%%%%%
%%
%% Un générateur de motifs pour lilypond
%%
%% L'idée de base est d'appliquer un motif rythmique à une séquence de notes, 
%% mais au lieu de spécifier à chaque fois les notes et le motif (ce qui serait 
%% plutot inutile ...), la macro en scheme définie ci-dessous crée une 
%% fonction musicale lilypond (music-function) qui applique le motif à n'importe 
%% quelle séquence de notes. Ceci est rendu possible grace au mécanisme de macros
%% de scheme (define-syntax et les "syntax rules", voir r5rs pour plus de détails 
%% sur ce mécanisme).
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% scheme macro mechanism for guile (guile macros are a bit different, but
%% scheme macros are nicest and more clean).
#(use-syntax (ice-9 syncase))

                             
#(define (make-event-chord elements duration)
   (make-music
     'EventChord
     'elements
     (let loop ((elts elements))
       (if (null? elts)
           '()
           (cons
             (if (eqv? (ly:music-property (car elts) 'name) 'NoteEvent)
                 (make-music
                   'NoteEvent
                   'duration
                   duration
                   'pitch
                   (ly:music-property (car elts) 'pitch))
                 (car elts))
             (loop (cdr elts)))))))
                 



%% the `apply-pattern' macro must be called with a list of duration objects
%% composing a pattern. The result of the macro invocation is a
%% music function, which applies the given pattern to any sequence of
%% notes. If the sequence is longer than the pattern, the pattern is
%% applied again, until there are no more notes left in the sequence.
%%
%% You should not use this macro directly. Use the function
%% `pattern-apply-factory' instead (see belox).
#(define-syntax apply-pattern
  (syntax-rules ()
    ((_ x)
     (define-music-function (parser location notes) (ly:music?)
       (let ((elts (ly:music-property notes 'elements))
             (durations x))
         (make-music
           'SequentialMusic
           'elements
           (let loop ((nlist elts)
                      (dur   durations))
             (if (null? dur)
                 (loop nlist durations) 
                 (if (null? nlist)
                   '()
                   (cons
                     (make-event-chord (ly:music-property (car nlist) 'elements) (car dur))
                     (loop (cdr nlist) (cdr dur))))))))))))

%% the `pattern-apply-factory' must be called a sequence of notes which
%% represent a rythmic pattern. Only the durations are kept to form a
%% rythmic pattern.
%% The apply-pattern macro is then called on that pattern. The result of
%% the macro invocation is a music function which applies the given pattern
%% to any sequence of notes. If the sequence is longer than the pattern,
%% the pattern is applied again, until there are no more notes left in
%% the sequence.
#(define-public (pattern-apply-factory pattern)
   (if (not (ly:music? pattern))
       (ly:error "Parameter 1 of `pattern-apply-factory' must be a SequentialMusicObject: ~A" pattern)
       (if (not (eqv? (ly:music-property pattern 'name) 'SequentialMusic))
           (ly:error "Parameter 1 of `pattern-apply-factory' must be a SequentialMusicObject: ~A" pattern)
           (apply-pattern
             (let loop ((elts (ly:music-property pattern 'elements)))
               (if (null? elts)
                   '()
                   (let* ((evtch    (car elts))
                          (note-evt (car (ly:music-property evtch 'elements))))
                     (cons (ly:music-property note-evt 'duration) (loop (cdr elts))))))))))      

Et voici un exemple d'utilisation un peu plus exhaustif que le précédent, et qui montre que, quand on applique un motif, on peut ajouter des choses, comme du texte, des indications de nuance, etc.

Code : Tout sélectionner

\version "2.14.2"

\language italiano

\include "./pattern.ly"



%% create a function which, applied to a sequence of 4 notes,
%% assigns the duration pattern "dotted eighth, eighth, eighth, dotted eighth"
%% to these notes. The result is a new sequence
%% --
%% Crée une fonction qui, appliquée à une séquence de 4 notes, lui assigne 
%% le motif rythmique suivant : croche pointée, croche, croche, croche pointée.
%% Le résultat est une nouvelle séquence.
motifi = #(pattern-apply-factory #{ do8. do8 do do8. #})

%% create a function which, applied to a sequence of 4 notes,
%% assigns the duration pattern "eighth, dotted eighth, dotted eighth, eighth"
%% to these notes. The result is a new sequence
%% --
%% Crée une fonction qui, appliquée à une séquence de 4 notes, lui assigne 
%% le motif rythmique suivant : croche, croche pointée, croche pointée, croche.
%% Le résultat est une nouvelle séquence.
motifii = #(pattern-apply-factory #{ do8 do8. do do8 #})

\score {
  \relative do' {
    \time 10/16
    \motifi{ do re mi fa } |
    \motifi{ re mi fa mi } |
    \motifii{ sol fad mi si'} |
    \motifii{ la sol re' do} |
    \motifi{ si mi re dod } |
    \motifi{ si^\markup { \italic "plus vite !" } <mi sol> re dod } |
    \motifi{ sol fad mib re sol lab lab sib }
    \motifi{ sol-> \< sol' <fa, la do>\pp <re mi \! sold sib>-. }
  }
  \layout {}
}
Amusez vous bien !

E.
« Finalement, j’ai rencontré une brouette, et j’ai pensé qu’elle me prêterait une oreille attentive. » Lewis Carroll
Avatar de l’utilisateur
Pierolivier
Pithéclarinethantropus
Messages : 7080
Inscription : 21 oct. 2002, 08:13
Localisation : Là où naissent les cloches et les andouilles.

Message par Pierolivier »

Je sens que ça va être utile ce bidule, merci ô grand maître de la MAO ! :D

(je cire les pompes(et les orteils avec vu ton style de pompes) en prévision des rencontres intergalactiques :mrvert: )
Froid de novembre, range ton membre
P. Desproges
Le Plume
Touriste
Messages : 36
Inscription : 30 janv. 2011, 12:55
Localisation : Paris

pourquoi en macro..?

Message par Le Plume »

Question bête, vu que j'ai un peu de bagage en Scheme (de du temps que j'étais en DEUG, ça date un peu), et un peu en Lilypond, mais par contre je suis très novice à combiner les deux: pourquoi passer par une macro plutôt que par une fonction musicale à deux arguments?

genre, une fonction suivremotif dont le comportement serait :

Code : Tout sélectionner

motif={do4 do8. do16 do8 do do do}

\suivremotif \motif {sol fad la sol re mi fad}
qui donnerait:

Code : Tout sélectionner

 {sol4 fad8. la16 sol8 re mi fad}
Evidemment si le motif revient très très souvent, répéter la variable à chaque fois peut être un peu lourd, mais on n'est pas obligé de lui donner un nom compliqué.

Quoi? Comment? Je la code moi-même ou je me tais? Ah oui, ok, je vais essayer alors, mais ptet pas tout de suite... :)
Avatar de l’utilisateur
EricW
Infidèle de la première heure
Messages : 10045
Inscription : 16 mai 2005, 22:38
Contact :

Message par EricW »

Le Plume a écrit :Evidemment si le motif revient très très souvent, répéter la variable à chaque fois peut être un peu lourd, mais on n'est pas obligé de lui donner un nom compliqué.
Ben voilà, t'as trouvé la raison pour laquelle j'ai fait une macro :wink:
(et note au passage que ma macro génère une fonction musicale, en fait ... :wink: )

Mais on peut farpaitement faire comme tu dis, et d'ailleurs :
Le Plume a écrit :Quoi? Comment? Je la code moi-même ou je me tais? Ah oui, ok, je vais essayer alors, mais ptet pas tout de suite... :)


Ben voilà :mrvert: :mrvert:
(je ramasse la copie dans une semaine :mrvert: )

E.
« Finalement, j’ai rencontré une brouette, et j’ai pensé qu’elle me prêterait une oreille attentive. » Lewis Carroll
Répondre