| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Building complicated functions
Esta sección explica cómo reunir la información necesaria para crear funciones musicales complicadas.
| A.3.1 Presentación de las expresiones musicales | ||
| A.3.2 Propiedades musicales | ||
| A.3.3 Duplicar una nota con ligaduras (ejemplo) | ||
| A.3.4 Añadir articulaciones a las notas (ejemplo) |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Displaying music expressions
Si se está escribiendo una función musical, puede ser muy
instructivo examinar cómo se almacena internamente una expresión
musical. Esto se puede hacer con la función musical
\displayMusic.
{
\displayMusic { c'4\f }
}
|
imprime lo siguiente:
(make-music
'SequentialMusic
'elements
(list (make-music
'NoteEvent
'articulations
(list (make-music
'AbsoluteDynamicEvent
'text
"f"))
'duration
(ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 0 0))))
|
De forma predeterminada, LilyPond imprime estos mensajes sobre la
consola junto al resto de los mensajes. Para separar estos
mensajes y guardar el resultado de \display{LOQUESEA},
puede especificar que se use un puerto de salida opcional:
{
\displayMusic #(open-output-file "display.txt") { c'4\f }
}
|
Esto sobreescribe el archivo de salida anterior cada vez ques e llama; si necesitamos escribir más de una expresión, debemos usar una variable para el puerto y reutilizarla:
{
port = #(open-output-file "display.txt")
\displayMusic \port { c'4\f }
\displayMusic \port { d'4 }
#(close-output-port port)
}
|
El manual de Guile describe los puertos detalladamente. Solo es realmente necesario cerrar el puerto si necesitamos leer el archivo antes de que LilyPond termine; en el primer ejemplo, no nos hemos molestado en hacerlo.
Un poco de reformateo hace a la información anterior más fácil de leer:
(make-music 'SequentialMusic
'elements (list
(make-music 'NoteEvent
'articulations (list
(make-music 'AbsoluteDynamicEvent
'text
"f"))
'duration (ly:make-duration 2 0 1/1)
'pitch (ly:make-pitch 0 0 0))))
|
Una secuencia musical { … } tiene el nombre
SequentialMusic, y sus expresiones internas se almacenan
coma una lista dentro de su propiedad 'elements. Una nota
se representa como un objeto NoteEvent (que almacena las
propiedades de duración y altura) con información adjunta (en este
caso, un evento AbsoluteDynamicEvent con una propiedad
"f" de texto) almacenada en su propiedad
articulations.
\displayMusic devuelve la música que imprime en la consola,
y por ello se interpretará al tiempo que se imprime en la consola.
Para evitar la interpretación, escriba \void antes de
\displayMusic.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Music properties
Veamos un ejemplo:
someNote = c' \displayMusic \someNote ===> (make-music 'NoteEvent 'duration (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 0 0)) |
El objeto NoteEvent es la representación de
someNote. Sencillo. ¿Y si ponemos el c’ dentro de un
acorde?
someNote = <c'>
\displayMusic \someNote
===>
(make-music
'EventChord
'elements
(list (make-music
'NoteEvent
'duration
(ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 0 0))))
|
Ahora el objeto NoteEvent es el primer objeto de la
propiedad 'elements de someNote.
La función display-scheme-music es la función que se usa
por parte de \displayMusic para imprimir la representación
de Scheme de una expresión musical.
#(display-scheme-music (first (ly:music-property someNote 'elements))) ===> (make-music 'NoteEvent 'duration (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 0 0)) |
Después se accede a la altura de la nota a través de la propiedad
'pitch del objeto NoteEvent:
#(display-scheme-music
(ly:music-property (first (ly:music-property someNote 'elements))
'pitch))
===>
(ly:make-pitch 0 0 0)
|
La altura de la nota se puede cambiar estableciendo el valor de
esta propiedad 'pitch.
#(set! (ly:music-property (first (ly:music-property someNote 'elements))
'pitch)
(ly:make-pitch 0 1 0)) ;; establecer la altura a d'.
\displayLilyMusic \someNote
===>
d'4
|
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Doubling a note with slurs (example)
Supongamos que queremos crear una función que convierte una
entrada como a en { a( a) }. Comenzamos
examinando la representación interna de la música con la que
queremos terminar.
\displayMusic{ a'( a') }
===>
(make-music
'SequentialMusic
'elements
(list (make-music
'NoteEvent
'articulations
(list (make-music
'SlurEvent
'span-direction
-1))
'duration
(ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 5 0))
(make-music
'NoteEvent
'articulations
(list (make-music
'SlurEvent
'span-direction
1))
'duration
(ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 5 0))))
|
La mala noticia es que las expresiones SlurEvent se deben
añadir ‘dentro’ de la nota (dentro de la propiedad
articulations).
Ahora examinamos la entrada.
\displayMusic a' ===> (make-music 'NoteEvent 'duration (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 5 0)))) |
Así pues, en nuestra función, tenemos que clonar esta expresión
(de forma que tengamos dos notas para construir la secuencia),
añadir SlurEvent a la propiedad 'articulations de
cada una de ellas, y por último hacer una secuencia
SequentialMusic con los dos elementos NoteEvent.
Para añadir a una propiedad, es útil saber que una propiedad no
establecida se lee como '(), la lista vacía, así que no se
requiere ninguna comprobación especial antes de que pongamos otro
elemento delante de la propiedad articulations.
doubleSlur = #(define-music-function (note) (ly:music?)
"Return: { note ( note ) }.
`note' is supposed to be a single note."
(let ((note2 (ly:music-deep-copy note)))
(set! (ly:music-property note 'articulations)
(cons (make-music 'SlurEvent 'span-direction -1)
(ly:music-property note 'articulations)))
(set! (ly:music-property note2 'articulations)
(cons (make-music 'SlurEvent 'span-direction 1)
(ly:music-property note2 'articulations)))
(make-music 'SequentialMusic 'elements (list note note2))))
|
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Adding articulation to notes (example)
La manera fácil de añadir articulación a las notas es juxtaponer dos expresiones musicales. Sin embargo, supongamos que queremos escribir una función musical que lo haga.
Una $variable dentro de la notación #{…#} es
como una \variable normal en la notación clásica de
LilyPond. Podríamos escribir
{ \music -. -> }
|
pero a los efectos de este ejemplo, aprenderemos ahora cómo hacerlo en Scheme. Empezamos examinando nuestra entrada y la salida deseada.
% input
\displayMusic c4
===>
(make-music
'NoteEvent
'duration
(ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch -1 0 0))))
=====
% desired output
\displayMusic c4->
===>
(make-music
'NoteEvent
'articulations
(list (make-music
'ArticulationEvent
'articulation-type
"accent"))
'duration
(ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch -1 0 0))
|
Vemos que una nota (c4) se representa como una expresión
NoteEvent. Para añadir una articulación de acento, se debe
añadir una expresión ArticulationEvent a la propiedad
articulations de la expresión NoteEvent.
Para construir esta función, empezamos con
(define (add-accent note-event)
"Add an accent ArticulationEvent to the articulations of `note-event',
which is supposed to be a NoteEvent expression."
(set! (ly:music-property note-event 'articulations)
(cons (make-music 'ArticulationEvent
'articulation-type "accent")
(ly:music-property note-event 'articulations)))
note-event)
|
La primera línea es la forma de definir una función en Scheme: el
nombre de la función es add-accent, y tiene una variable
llamada note-event. En Scheme, el tipo de variable suele
quedar claro a partir de su nombre (¡esto también es una buena
práctica en otros lenguajes de programación!)
"Add an accent…" |
es una descripción de lo que hace la función. No es estrictamente necesaria, pero de igual forma que los nombres claros de variable, es una buena práctica.
Se preguntará por qué modificamos el evento de nota directamente
en lugar de trabajar sobre una copia (se puede usar
ly:music-deep-copy para ello). La razón es un contrato
silencioso: se permite que las funciones musicales modifiquen sus
argumentos; o bien se generan partiendo de cero (como la entrada
del usuario) o están ya copiadas (referenciar una variable de
música con ‘\name’ o la música procedente de expresiones de
Scheme inmediatas ‘$(…)’ proporcionan una copia). Dado
que sería ineficiente crear copias innecesarias, el valor devuelto
de una función musical no se copia. Así pues, para cumplir
dicho contrato, no debemos usar ningún argumento más de una vez, y
devolverlo cuenta como una vez.
En un ejemplo anterior, hemos construido música mediante la
repetición de un argumento musical dado. En tal caso, al menos
una repetidión tuvo que ser una copia de sí misma. Si no lo
fuese, podrían ocurrir cosas muy extrañas. Por ejemplo, si usamos
\relative o \transpose sobre la música resultante
que contiene los mismos elementos varias veces, estarían sujetos
varias veces a la relativización o al transporte. Si los
asignamos a una variable de música, se rompe el curso porque hacer
referencia a ‘\name’ creará de nuevo una copia que no retiene
la identidad de los elementos repetidos.
Ahora bien, aun cuando la función anterior no es una función
musical, se usará normalmente dentro de funciones musicales. Así
pues, tiene sentido obedecer el mismo convenio que usamos para las
funciones musicales: la entrada puede modificarse para producir la
salida, y el código que llama es responsable de crear las copias
si aún necesita el propio argumento sin modificar. Si observamos
las propias funciones de LilyPond como music-map, veremos
que se atienen a los mismos principios.
¿En qué punto nos encontramos? Ahora tenemos un note-event
que podemos modificar, no a causa de la utilización de
ly:music-deep-copy sino por una explicación muy
desarrollada. Añadimos el acento a su propiedad de lista
'articulations.
(set! place new-value) |
Aquí, lo que queremos establecer (el ‘place’) es la propiedad
'articulations de la expresión note-event.
(ly:music-property note-event 'articulations) |
ly:music-property es la función ustilizada para acceder a las
propiedades musicales (las 'articulations, 'duration,
'pitch, etc, que vemos arriba en la salida de
\displayMusic). El nuevo valor es la antigua propiedad
'articulations, con un elemento adicional: la expresión
ArticulationEvent, que copiamos a partir de la salida de
\displayMusic,
(cons (make-music 'ArticulationEvent
'articulation-type "accent")
(ly:music-property result-event-chord 'articulations))
|
Se usa cons para añadir un elemento a la parte delantera de
una lista sin modificar la lista original. Esto es lo que
queremos: la misma lista de antes, más la nueva expresión
ArticulationEvent. El orden dentro de la propiedad
'articulations no tiene importancia aquí.
Finalmente, una vez hemos añadido la articulación de acento a su
propiedad articulations, podemos devolver
note-event, de aquí la última línea de la función.
Ahora transformamos la función add-accent en una función
musical (es cuestión de un poco de aderezo sintáctico y una
declaración del tipo de su argumento).
addAccent = #(define-music-function (note-event)
(ly:music?)
"Add an accent ArticulationEvent to the articulations of `note-event',
which is supposed to be a NoteEvent expression."
(set! (ly:music-property note-event 'articulations)
(cons (make-music 'ArticulationEvent
'articulation-type "accent")
(ly:music-property note-event 'articulations)))
note-event)
|
A continuación verificamos que esta función musical funciona correctamente:
\displayMusic \addAccent c4 |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] |
Este documento ha sido generado por gub el el 13 julio 2020 utilizando texi2html 1.82.
Otros idiomas: English, deutsch, français.
Acerca de la selección automática del idioma.