]> git.donarmstrong.com Git - lilypond.git/blobdiff - Documentation/es/extending/programming-interface.itely
resolve merge
[lilypond.git] / Documentation / es / extending / programming-interface.itely
diff --git a/Documentation/es/extending/programming-interface.itely b/Documentation/es/extending/programming-interface.itely
new file mode 100644 (file)
index 0000000..a1f552d
--- /dev/null
@@ -0,0 +1,1085 @@
+@c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*-
+@c This file is part of extending.tely
+@ignore
+    Translation of GIT committish: 7ba0a22641cb0c7f5949d66a06d1e2e1fd0b3033
+
+    When revising a translation, copy the HEAD committish of the
+    version that you are working on.  See TRANSLATION for details.
+@end ignore
+
+@c \version "2.14.0"
+
+@node Interfaces para programadores
+@chapter Interfaces para programadores
+@translationof Interfaces for programmers
+
+Se pueden realizar trucos avanzados mediante el uso de Scheme.  Si no
+está familiarizado con Scheme, le conviene leer nuestro tutorial de
+Scheme, @ref{Tutorial de Scheme}.
+
+
+@menu
+* Funciones musicales::
+* Funciones de marcado::
+* Contextos para programadores::
+* Funciones de callback::
+* Código de Scheme en línea::
+* Trucos difíciles::
+@end menu
+
+@node Funciones musicales
+@section Funciones musicales
+@translationof Music functions
+
+Las @emph{funciones musicales} son procedimientos de Scheme
+que pueden crear automáticamente expresiones musicales, y se
+pueden usar para simplificar enormemente el archivo de entrada.
+
+@menu
+* Sintaxis de las funciones musicales::
+* Funciones de sustitución sencillas::
+* Funciones de sustitución intermedias::
+* Matemáticas dentro de las funciones::
+* Funciones sin argumentos::
+* Funciones vacías::
+@end menu
+
+@node Sintaxis de las funciones musicales
+@subsection Sintaxis de las funciones musicales
+@translationof Music function syntax
+
+La forma general de una función musical es:
+
+@example
+funcion =
+#(define-music-function
+     (parser location @var{arg1} @var{arg2} @dots{})
+     (@var{type1?} @var{type2?} @dots{})
+   @var{música})
+@end example
+
+@noindent
+donde
+
+@multitable @columnfractions .33 .66
+@item @code{@var{argN}}
+@tab @var{n}-ésimo argumento
+
+@item @code{@var{typeN?}}
+@tab un @emph{predicado de tipo} de Scheme para el que @code{@var{argN}}
+deve devolver @code{#t}.
+
+@item @code{@var{música}}
+@tab una expresión musical, opcionalmente escrita en Scheme, con
+el código de LilyPond que pudiera tener, encerrado entre llaves
+con almohadilla
+(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}).  Dentro de los bloques
+de código de LilyPond, use @code{$} para referenciar a los argumentos
+de la función (p. ej. @samp{$arg1})
+o para iniciar una expresión en línea de Scheme
+que contenga argumentos de función
+(p.ej., @w{@samp{$(cons arg1 arg2)}}).
+
+@end multitable
+
+@noindent
+Para ver una lista de los predicados de tipo disponibles, consulte
+@ruser{Predicados de tipo predefinidos}.
+También se permiten predicados de tipo definidos por el usuario.
+
+
+
+@seealso
+
+Referencia de la notación:
+@ruser{Predicados de tipo predefinidos}.
+
+Archivos de inicio:
+@file{lily/music-scheme.cc},
+@file{scm/c++.scm},
+@file{scm/lily.scm}.
+
+
+@node Funciones de sustitución sencillas
+@subsection Funciones de sustitución sencillas
+@translationof Simple substitution functions
+
+Una función de sustitución sencilla es una función musical cuya
+expresión musical de salida está escrita en código de LilyPond
+y contiene argumentos de la función en la expresión de salida.
+Están descritas en @ruser{Ejemplos de funciones de sustitución}.
+
+
+@node Funciones de sustitución intermedias
+@subsection Funciones de sustitución intermedias
+@translationof Intermediate substitution functions
+
+Las funciones de sustitución intermedias contienen una
+mezcla de código de Scheme y de LilyPond
+dentro de la expresión musical que se devuelve.
+
+Algunas instrucciones @code{\override} requieren un argumento que
+consiste en una pareja de números (llamada una @emph{célula cons} en
+Scheme).
+
+La pareja se puede pasar directamente dentro de la función musical,
+usando una variable @code{pair?}:
+
+@example
+barraManual =
+#(define-music-function
+     (parser location principio-final)
+     (pair?)
+   #@{
+     \once \override Beam #'positions = $principio-final
+   #@})
+
+\relative c' @{
+  \barraManual #'(3 . 6) c8 d e f
+@}
+@end example
+
+De forma alternativa, los números que componen la pareja se pueden
+pasar como argumentos separados, y el código de Scheme que se ha usado
+para crear la pareja se puede incluir dentro de la expresión musical:
+
+@lilypond[quote,verbatim,ragged-right]
+manualBeam =
+#(define-music-function
+     (parser location beg end)
+     (number? number?)
+   #{
+     \once \override Beam #'positions = $(cons beg end)
+   #})
+
+\relative c' {
+  \manualBeam #3 #6 c8 d e f
+}
+@end lilypond
+
+
+@node Matemáticas dentro de las funciones
+@subsection Matemáticas dentro de las funciones
+@translationof Mathematics in functions
+
+Las funciones musicales pueden contar con programación de Scheme
+además de la simple sustitución:
+
+@lilypond[quote,verbatim,ragged-right]
+AltOn =
+#(define-music-function
+     (parser location mag)
+     (number?)
+   #{
+     \override Stem #'length = $(* 7.0 mag)
+     \override NoteHead #'font-size =
+       $(inexact->exact (* (/ 6.0 (log 2.0)) (log mag)))
+   #})
+
+AltOff = {
+  \revert Stem #'length
+  \revert NoteHead #'font-size
+}
+
+\relative c' {
+  c2 \AltOn #0.5 c4 c
+  \AltOn #1.5 c c \AltOff c2
+}
+@end lilypond
+
+@noindent
+Este ejemplo se puede reescribir de forma que pase expresiones
+musicales:
+
+@lilypond[quote,verbatim,ragged-right]
+withAlt =
+#(define-music-function
+     (parser location mag music)
+     (number? ly:music?)
+   #{
+     \override Stem #'length = $(* 7.0 mag)
+     \override NoteHead #'font-size =
+       $(inexact->exact (* (/ 6.0 (log 2.0)) (log mag)))
+     $music
+     \revert Stem #'length
+     \revert NoteHead #'font-size
+   #})
+
+\relative c' {
+  c2 \withAlt #0.5 { c4 c }
+  \withAlt #1.5 { c c } c2
+}
+@end lilypond
+
+
+@node Funciones sin argumentos
+@subsection Funciones sin argumentos
+@translationof Functions without arguments
+
+En casi todos los casos, una función sin argumentos se debe escribir
+con una variable:
+
+@example
+dolce = \markup@{ \italic \bold dolce @}
+@end example
+
+Sin embargo, en raras ocasiones puede ser de utilidad crear una
+función musical sin argumentos:
+
+@example
+mostrarNumeroDeCompas =
+#(define-music-function
+     (parser location)
+     ()
+   (if (eq? #t (ly:get-option 'display-bar-numbers))
+       #@{ \once \override Score.BarNumber #'break-visibility = ##f #@}
+       #@{#@}))
+@end example
+
+Para la impresión real de los números de compás donde se llama a esta
+función, invoque a @command{lilypond} con
+
+@example
+lilypond -d display-bar-numbers ARCHIVO.ly
+@end example
+
+
+@node Funciones vacías
+@subsection Funciones vacías
+@translationof Void functions
+
+Una función musical debe devolver una expresión musical, pero a veces
+podemos necesitar una función en la que no hay música en juego (como
+la desactivación de la funcionalidad Apuntar y Pulsar).  Para hacerlo,
+devolvemos una expresión musical @code{void} (vacía).
+
+Este es el motivo por el que la forma que se devuelve es
+@code{(make-music ...)}.  Con el valor de la propiedad @code{'void}
+establecido a @code{#t}, le decimos al analizador que descarte la
+expresión musical devuelta.  así, la parte importante de la función
+musical vacía es el proceso realizado por la función, no la expresión
+musical que se devuelve.
+
+@example
+noApuntarYPulsar =
+#(define-music-function (parser location) ()
+   (ly:set-option 'point-and-click #f)
+   (make-music 'SequentialMusic 'void #t))
+...
+\noApuntarYPulsar   % desactivar la funcionalidad Apuntar y Pulsar.
+@end example
+
+
+@node Funciones de marcado
+@section Funciones de marcado
+@translationof Markup functions
+
+Los elementos de marcado están implementados como funciones de Scheme
+especiales que producen un objeto @code{Stencil} dada una serie de
+argumentos.
+
+
+@menu
+* Construcción de elementos de marcado en Scheme::
+* Cómo funcionan internamente los elementos de marcado::
+* Definición de una instrucción de marcado nueva::
+* Definición de nuevas instrucciones de lista de marcado::
+@end menu
+
+@node Construcción de elementos de marcado en Scheme
+@subsection Construcción de elementos de marcado en Scheme
+@translationof Markup construction in Scheme
+
+@cindex marcado, definir instrucciones de
+
+El macro @code{markup} construye expresiones de marcado en Scheme,
+proporcionando una sintaxis similar a la de LilyPond.  Por ejemplo:
+
+@example
+(markup #:column (#:line (#:bold #:italic "hola" #:raise 0.4 "mundo")
+                  #:larger #:line ("fulano" "fulanito" "menganito")))
+@end example
+
+@noindent
+equivale a:
+@example
+\markup \column @{ \line @{ \bold \italic "hola" \raise #0.4 "mundo" @}
+                  \larger \line @{ fulano fulanito menganito @} @}
+@end example
+
+@noindent
+Este ejemplo muestra las principales reglas de traducción entre la
+sintaxis del marcado normal de LilyPond y la sintaxis del marcado de
+Scheme.
+
+@quotation
+@multitable @columnfractions .3 .3
+@item @b{LilyPond} @tab @b{Scheme}
+@item @code{\markup marcado1} @tab @code{(markup marcado1)}
+@item @code{\markup @{ marcado1 marcado2 ... @}} @tab
+        @code{(markup marcado1 marcado2 ... )}
+@item @code{\instruccion} @tab @code{#:instruccion}
+@item @code{\variable} @tab @code{variable}
+@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )}
+@item @code{cadena} @tab @code{"cadena"}
+@item @code{#argumento-de-scheme} @tab @code{argumento-de-scheme}
+@end multitable
+@end quotation
+
+Todo el lenguaje Scheme está accesible dentro del macro @code{markup}.
+Por ejemplo, podemos usar llamadas a funciones dentro de @code{markup}
+para así manipular cadenas de caracteres.  Esto es útil si se están
+definiendo instrucciones de marcado nuevas (véase @ref{Definición de una instrucción de marcado nueva}).
+
+
+@knownissues
+
+El argumento markup-list de instrucciones como @code{#:line},
+@code{#:center} y @code{#:column} no puede ser una variable ni el
+resultado de la llamada a una función.
+
+@lisp
+(markup #:line (funcion-que-devuelve-marcados))
+@end lisp
+
+@noindent
+no es válido.  Hay que usar las funciones @code{make-line-markup},
+@code{make-center-markup} o @code{make-column-markup} en su lugar:
+
+@lisp
+(markup (make-line-markup (funcion-que-devuelve-marcados)))
+@end lisp
+
+
+@node Cómo funcionan internamente los elementos de marcado
+@subsection Cómo funcionan internamente los elementos de marcado
+@translationof How markups work internally
+
+En un elemento de marcado como
+
+@example
+\raise #0.5 "ejemplo de texto"
+@end example
+
+@noindent
+@code{\raise} se representa en realidad por medio de la función
+@code{raise-markup}.  La expresión de marcado se almacena como
+
+@example
+(list raise-markup 0.5 (list simple-markup "ejemplo de texto"))
+@end example
+
+Cuando el marcado se convierte en objetos imprimibles (Stencils o
+sellos), se llama la función @code{raise-markup} como
+
+@example
+(apply raise-markup
+       @var{\objeto de marcado}
+       @var{lista de listas asociativas de propiedades}
+       0.5
+       @var{el marcado "ejemplo de texto"})
+@end example
+
+Primero la función @code{raise-markup} crea el sello para la cadena
+@code{ejemplo de texto}, y después eleva el sello Stencil en 0.5
+espacios de pentagrama.  Este es un ejemplo bastante simple; en el
+resto de la sección podrán verse ejemplos más complejos, así como en
+@file{scm/define-markup-commands.scm}.
+
+
+@node Definición de una instrucción de marcado nueva
+@subsection Definición de una instrucción de marcado nueva
+@translationof New markup command definition
+
+Esta sección trata sobre la definición de nuevas instrucciones de
+marcado.
+
+
+@menu
+* Sintaxis de la definición de instrucciones de marcado::
+* Acerca de las propiedades::
+* Un ejemplo completo::
+* Adaptación de instrucciones incorporadas::
+@end menu
+
+@node Sintaxis de la definición de instrucciones de marcado
+@unnumberedsubsubsec Sintaxis de la definición de instrucciones de marcado
+@translationof Markup command definition syntax
+
+Se pueden definir instrucciones de marcado nuevas usando el macro de
+Scheme @code{define-markup-command}, en el nivel sintáctico superior.
+
+@lisp
+(define-markup-command (@var{nombre-de-la-instruccion} @var{layout} @var{props} @var{arg1} @var{arg2} ...)
+    (@var{tipo-de-arg1?} @var{tipo-de-arg2?} ...)
+    [ #:properties ((@var{propiedad1} @var{valor-predeterminado1})
+                    ...) ]
+  ..command body..)
+@end lisp
+
+Los argumentos son
+
+@table @code
+@item @var{nombre-de-la-instruccion}
+nombre de la instrucción de marcado
+@item layout
+la definición de @q{layout} (disposición).
+@item props
+una lista de listas asociativas, que contienen todas las propiedades
+activas.
+@item @var{argi}
+argumento @var{i}-ésimo de la instrucción
+@item @var{tipo-de-argi?}
+predicado de tipo para el argumento @var{i}-ésimo
+@end table
+
+Si la instrucción utiliza propiedades de los argumentos @code{props},
+se puede usar la palabra clave @code{#:properties} para especificar
+qué propiedades se usan, así como sus valores predeterminados.
+
+Los argumentos se distinguen según su tipo:
+@itemize
+@item un marcado, que corresponde al predicado de tipo @code{markup?};
+@item una lista de marcados, que corresponde al predicado de tipo
+@code{markup-list?};
+@item cualquier otro objeto de Scheme, que corresponde a predicados de tipo como
+@code{list?}, @code{number?}, @code{boolean?}, etc.
+@end itemize
+
+No existe ninguna limitación en el orden de los argumentos (después de
+los argumentos estándar @code{layout} y @code{props}).  Sin embargo, las
+funciones de marcado que toman un elemento de marcado como su último
+argumento son un poco especiales porque podemos aplicarlas a una lista
+de marcados y el resultado es una lista de marcados donde la función
+de marcado (con los argumentos antecedentes especificados) se ha
+aplicado a todos los elementos de la lista de marcados original.
+
+Dado que la replicación de los argumentos precedentes para aplicar una
+función de marcado a una lista de marcados es poco costosa
+principalmente por los argumentos de Scheme, se evitan las caídas de
+reindimiento simplemente mediante la utilización de argumentos de
+Scheme para los argumentos antecedentes de las funciones de marcado
+que toman un marcado como su último argumento.
+
+@node Acerca de las propiedades
+@unnumberedsubsubsec Acerca de las propiedades
+@translationof On properties
+
+Los argumentos @code{layout} y @code{props} de las instrucciones de
+marcado traen a escena un contexto para la interpretación del marcado:
+tamaño de la tipografía, grueso de línea, etc.
+
+El argumento @code{layout} permite el acceso a las propiedades
+definidas en los bloques @code{paper}, usando la función
+@code{ly:output-def-lookup}.  Por ejemplo, el grueso de línea (el
+mismo que el que se usa en las partituras) se lee usando:
+
+@example
+(ly:output-def-lookup layout 'line-width)
+@end example
+
+El argumento @code{props} hace accesibles algunas propiedades a las
+instrucciones de marcado.  Por ejemplo, cuando se interpreta el
+marcado del título de un libro, todas las variables definidas dentro
+del bloque @code{\header} se añaden automáticamente a @code{props}, de
+manera que el marcado del título del libro puede acceder al título del
+libro, el autor, etc.  También es una forma de configurar el
+comportamiento de una instrucción de marcado: por ejemplo, cuando una
+instrucción utiliza tamaños de tipografía durante el procesado, el
+tamaño se lee de @code{props} en vez de tener un argumento
+@code{font-size}.  El que llama a una instrucción de marcado puede
+cambiar el valor de la propiedad del tamaño de la tipografía con el
+objeto de modificar el comportamiento.  Utilice la palabra clave
+@code{#:properties} de @code{define-markup-command} para especificar
+qué propiedades se deben leer a partir de los argumentos de
+@code{props}.
+
+El ejemplo de la sección siguiente ilustra cómo acceder y
+sobreescribir las propiedades de una instrucción de marcado.
+
+
+@node Un ejemplo completo
+@unnumberedsubsubsec Un ejemplo completo
+@translationof A complete example
+
+El ejemplo siguiente define una instrucción de marcado para trazar un
+rectángulo doble alrededor de un fragmento de texto.
+
+En primer lugar, necesitamos construir un resultado aproximado
+utilizando marcados.  Una consulta a @ruser{Text markup commands} nos
+muestra que es útil la instrucción @code{\box}:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \box HELLO
+@end lilypond
+
+Ahora, consideramos que es preferible tener más separación entre el
+texto y los rectángulos.  Según la documentación de @code{\box}, esta
+instrucción usa una propiedad @code{box-padding}, cuyo valor
+predeterminado es 0.2.  La documentación también menciona cómo
+sobreescribir este valor:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \override #'(box-padding . 0.6) \box A
+@end lilypond
+
+Después, el relleno o separación entre los dos rectángulos nos parece
+muy pequeño, así que lo vamos a sobreescribir también:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \override #'(box-padding . 0.4) \box \override #'(box-padding . 0.6) \box A
+@end lilypond
+
+Repetir esta extensa instrucción de marcado una y otra vez sería un
+quebradero de cabeza.  Aquí es donde se necesita una instrucción de
+marcado.  Así pues, escribimos una instrucción de marcado
+@code{double-box}, que toma un argumento (el texto).  Dibuja los dos
+rectángulos y añade una separación.
+
+@lisp
+#(define-markup-command (double-box layout props text) (markup?)
+  "Trazar un rectángulo doble rodeando el texto."
+  (interpret-markup layout props
+    (markup #:override '(box-padding . 0.4) #:box
+            #:override '(box-padding . 0.6) #:box text)))
+@end lisp
+
+@code{text} es el nombre del argumento de la instrucción, y
+@code{markup?} es el tipo: lo identifica como un elemento de marcado.
+La función @code{interpret-markup} se usa en casi todas las
+instrucciones de marcado: construye un sello, usando @code{layout},
+@code{props}, y un elemento de marcado.  Aquí, la marca se construye
+usando el macro de Scheme @code{markup}, véase @ref{Construcción de
+elementos de marcado en Scheme}.  La transformación de una expresión
+@code{\markup} en una expresión de marcado de Scheme es directa.
+
+La instrucción nueva se puede usar como sigue:
+
+@example
+\markup \double-box A
+@end example
+
+Sería buen hacer que la instrucción @code{double-box} fuera
+personalizable: aquí, los valores de relleno @code{box-padding} son
+fijos, y no se pueden cambiar por parte del usuario.  Además, sería
+mejor distinguir la separación entre los dos rectángulos, del relleno
+entre el rectángulo interno y el texto.  Así pues, introducimos una
+nueva propiedad, @code{inter-box-padding}, para el relleno entre los
+rectángulos.  El @code{box-padding} se usará para el relleno interno.
+Ahora el código nuevo es como se ve a continuación:
+
+@lisp
+#(define-markup-command (double-box layout props text) (markup?)
+  #:properties ((inter-box-padding 0.4)
+                (box-padding 0.6))
+  "Trazar un rectángulo doble rodeando el texto."
+  (interpret-markup layout props
+    (markup #:override `(box-padding . ,inter-box-padding) #:box
+            #:override `(box-padding . ,box-padding) #:box text)))
+@end lisp
+
+Aquí, la palabra clave @code{#:properties} se usa de manera que las
+propiedades @code{inter-box-padding} y @code{box-padding} se leen a
+partir del argumento @code{props}, y se les proporcionan unos valores
+predeterminados si las propiedades no están definidas.
+
+Después estos valores se usan para sobreescribir las propiedades
+@code{box-padding} usadas por las dos instrucciones @code{\box}.
+Observe el apóstrofo invertido y la coma en el argumento de
+@code{\override}: nos permiten introducir un valor de variable dentro
+de una expresión literal.
+
+Ahora, la instrucción se puede usar dentro de un elemento de marcado,
+y el relleno de los rectángulos se puede personalizar:
+
+@lilypond[quote,verbatim,ragged-right]
+#(define-markup-command (double-box layout props text) (markup?)
+  #:properties ((inter-box-padding 0.4)
+                (box-padding 0.6))
+  "Draw a double box around text."
+  (interpret-markup layout props
+    (markup #:override `(box-padding . ,inter-box-padding) #:box
+            #:override `(box-padding . ,box-padding) #:box text)))
+
+\markup \double-box A
+\markup \override #'(inter-box-padding . 0.8) \double-box A
+\markup \override #'(box-padding . 1.0) \double-box A
+@end lilypond
+
+
+@node Adaptación de instrucciones incorporadas
+@unnumberedsubsubsec Adaptación de instrucciones incorporadas
+@translationof Adapting builtin commands
+
+Una buena manera de comenzar a escribir una instrucción de marcado
+nueva, es seguir el ejemplo de otra instrucción ya incorporada.  Casi
+todas las instrucciones de marcado que están incorporadas en LilyPond
+se pueden encontrar en el archivo
+@file{scm/define-markup-commands.scm}.
+
+Por ejemplo, querríamos adaptar la instrucción @code{\draw-line}, para
+que trace una línea doble.  La instrucción @code{\draw-line} está
+definida como sigue (se han suprimido los comentarios de
+documentación):
+
+@lisp
+(define-markup-command (draw-line layout props dest)
+  (number-pair?)
+  #:category graphic
+  #:properties ((thickness 1))
+  "...documentación..."
+  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
+               thickness))
+        (x (car dest))
+        (y (cdr dest)))
+    (make-line-stencil th 0 0 x y)))
+@end lisp
+
+Para definir una instrucción nueva basada en otra existente, copie la
+definición y cámbiele el nombre.  La palabra clave @code{#:category}
+se puede eliminar sin miedo, pues sólo se utiliza para generar
+documentación de LilyPond, y no tiene ninguna utilidad para las
+instrucciones de marcado definidas por el usuario.
+
+@lisp
+(define-markup-command (draw-double-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1))
+  "...documentación..."
+  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
+               thickness))
+        (x (car dest))
+        (y (cdr dest)))
+    (make-line-stencil th 0 0 x y)))
+@end lisp
+
+A continuación se añade una propiedad para establecer la separación
+entre las dos líneas, llamada @code{line-gap}, con un valor
+predeterminado de p.ej. 0.6:
+
+@lisp
+(define-markup-command (draw-double-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1)
+                (line-gap 0.6))
+  "...documentación..."
+  ...
+@end lisp
+
+Finalmente, se añade el código para trazar las dos líneas.  Se usan
+dos llamadas a @code{make-line-stencil} para trazar las líneas, y los
+sellos resultantes se combinan usando @code{ly:stencil-add}:
+
+@lilypond[quote,verbatim,ragged-right]
+#(define-markup-command (my-draw-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1)
+                (line-gap 0.6))
+  "..documentation.."
+  (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
+                thickness))
+         (dx (car dest))
+         (dy (cdr dest))
+         (w (/ line-gap 2.0))
+         (x (cond ((= dx 0) w)
+                  ((= dy 0) 0)
+                  (else (/ w (sqrt (+ 1 (* (/ dx dy) (/ dx dy))))))))
+         (y (* (if (< (* dx dy) 0) 1 -1)
+               (cond ((= dy 0) w)
+                     ((= dx 0) 0)
+                     (else (/ w (sqrt (+ 1 (* (/ dy dx) (/ dy dx))))))))))
+     (ly:stencil-add (make-line-stencil th x y (+ dx x) (+ dy y))
+                     (make-line-stencil th (- x) (- y) (- dx x) (- dy y)))))
+
+\markup \my-draw-line #'(4 . 3)
+\markup \override #'(line-gap . 1.2) \my-draw-line #'(4 . 3)
+@end lilypond
+
+
+@node Definición de nuevas instrucciones de lista de marcado
+@subsection Definición de nuevas instrucciones de lista de marcado
+@translationof New markup list command definition
+
+Las instrucciones de listas de marcado se definen con el macro de
+Scheme @code{define-markup-list-command}, que es similar al macro
+@code{define-markup-command} descrito en @ref{Definición de una
+instrucción de marcado nueva}, excepto que donde éste devuelve un
+sello único, aquél devuelve una lista de sellos.
+
+En el siguiente ejemplo se define una instrucción de lista de marcado
+@code{\paragraph}, que devuelve una lista de líneas justificadas,
+estando la primera de ellas sangrada.  La anchura del sangrado se toma
+del argumento @code{props}.
+
+@example
+#(define-markup-list-command (paragraph layout props args) (markup-list?)
+   #:properties ((par-indent 2))
+   (interpret-markup-list layout props
+     (make-justified-lines-markup-list (cons (make-hspace-markup par-indent)
+                                             args))))
+@end example
+
+Aparte de los argumentos usuales @code{layout} y @code{props}, la
+instrucción de lista de marcados @code{paragraph} toma un argumento de
+lista de marcados, llamado @code{args}.  El predicado para listas de
+marcados es @code{markup-list?}.
+
+En primer lugar, la función toma el ancho del sangrado, una propiedad
+llamada aquí @code{par-indent}, de la lista de propiedades
+@code{props}.  Si no se encuentra la propiedad, el valor
+predeterminado es @code{2}.  Después, se hace una lista de líneas
+justificadas usando la función
+@code{make-justified-lines-markup-list}, que está relacionada con la
+instrucción incorporada de lista de marcados @code{\justified-lines}.
+Se añade un espacio horizontal al principio usando la función
+@code{make-hspace-markup}.  Finalmente, la lista de marcados se
+interpreta usando la función @code{interpret-markup-list}.
+
+Esta nueva instrucción de lista de marcados se puede usar como sigue:
+
+@example
+\markuplines @{
+  \paragraph @{
+    El arte de la tipografía musical se llama  \italic @{grabado (en plancha).@}
+    El término deriva del proceso tradicional de impresión de música.
+    hace sólo algunas décadas, las partituras se hacían cortando y estampando
+    la música en una plancha de zinc o lata en una imagen invertida.
+  @}
+  \override-lines #'(par-indent . 4) \paragraph @{
+    La plancha se tenía que entintar, y las depresiones causadas por los cortes
+    y estampados retienen la tinta.  Se formaba una imagen presionando el papel
+    contra la plancha.  El estampado y cortado se hacía completamente
+    a mano.
+  @}
+@}
+@end example
+
+
+@node Contextos para programadores
+@section Contextos para programadores
+@translationof Contexts for programmers
+
+@menu
+* Evaluación de contextos::
+* Ejecutar una función sobre todos los objetos de la presentación::
+@end menu
+
+@node Evaluación de contextos
+@subsection Evaluación de contextos
+@translationof Context evaluation
+
+@cindex código, llamadas durante la interpretación
+@funindex \applyContext
+
+Se pueden modificar los contextos durante la interpretación con código
+de Scheme.  La sintaxis para esto es
+
+@example
+\applyContext @var{función}
+@end example
+
+@code{@var{función}} debe ser una función de Scheme que toma un único
+argumento, que es el contexto al que aplicarla.  El código siguiente
+imprime el número del compás actual sobre la salida estándar durante
+la compilación:
+
+@example
+\applyContext
+  #(lambda (x)
+    (format #t "\nSe nos ha llamado en el compás número ~a.\n"
+     (ly:context-property x 'currentBarNumber)))
+@end example
+
+
+@node Ejecutar una función sobre todos los objetos de la presentación
+@subsection Ejecutar una función sobre todos los objetos de la presentación
+@translationof Running a function on all layout objects
+
+@cindex código, llamar sobre objetos de presentación
+@funindex \applyOutput
+
+
+La manera más versátil de realizar el ajuste fino de un objeto es
+@code{\applyOutput}, que
+funciona insertando un evento dentro del contexto especificado
+(@rinternals{ApplyOutputEvent}).  Su sintaxis es
+
+@example
+\applyOutput @var{contexto} @var{proc}
+@end example
+
+@noindent
+donde @code{@var{proc}} es una función de Scheme que toma tres argumentos.
+
+Al interpretarse, la función @code{@var{proc}} se llama para cada objeto de
+presentación que se encuentra en el contexto @code{@var{contexto}}
+en el tiempo actual, con los siguientes argumentos:
+
+@itemize
+@item el propio objeto de presentación,
+@item el contexto en que se creó el objeto de presentación, y
+@item el contexto en que se procesa @code{\applyOutput}.
+@end itemize
+
+
+Además, la causa del objeto de presentación, es decir el objeto o
+expresión musical que es responsable de haberlo creado, está en la
+propiedad @code{cause} del objeto.  Por ejemplo, para la cabeza de una
+nota, éste es un evento @rinternals{NoteHead}, y para un objeto
+plica, éste es un objeto @rinternals{Stem}.
+
+He aquí una función que usar para @code{\applyOutput}; borra las
+cabezas de las notas que están sobre la línea central y junto a ella:
+
+@lilypond[quote,verbatim,ragged-right]
+#(define (blanker grob grob-origin context)
+   (if (and (memq 'note-head-interface (ly:grob-interfaces grob))
+            (< (abs (ly:grob-property grob 'staff-position)) 2))
+       (set! (ly:grob-property grob 'transparent) #t)))
+
+\relative c' {
+  a'4 e8 <<\applyOutput #'Voice #blanker a c d>> b2
+}
+@end lilypond
+
+
+@node Funciones de callback
+@section Funciones de callback
+@translationof Callback functions
+
+Las propiedades (como @code{thickness} (grosor), @code{direction}
+(dirección), etc.) se pueden establecer a valores fijos con \override,
+p. ej.:
+
+@example
+\override Stem #'thickness = #2.0
+@end example
+
+Las propiedades pueden fijarse también a un procedimiento de scheme,
+
+@lilypond[fragment,verbatim,quote,relative=2]
+\override Stem #'thickness = #(lambda (grob)
+    (if (= UP (ly:grob-property grob 'direction))
+        2.0
+        7.0))
+c b a g b a g b
+@end lilypond
+
+@noindent
+En este caso, el procedimiento se ejecuta tan pronto como el valor de
+la propiedad se reclama durante el proceso de formateo.
+
+Casi todo el motor de tipografiado está manejado por estos
+@emph{callbacks}.  Entre las propiedades que usan normalmente
+@emph{callbacks} están
+
+@table @code
+@item stencil
+  La rutina de impresión, que construye un dibujo para el símbolo
+@item X-offset
+  La rutina que establece la posición horizontal
+@item X-extent
+  La rutina que calcula la anchura de un objeto
+@end table
+
+El procedimiento siempre toma un argumento único, que es el grob (el
+objeto gráfico).
+
+Si se deben llamar rutinas con varios argumentos, el grob actual se
+puede insertar con una cerradura de grob.  He aquí un ajuste
+procedente de @code{AccidentalSuggestion},
+
+@example
+`(X-offset .
+  ,(ly:make-simple-closure
+    `(,+
+        ,(ly:make-simple-closure
+           (list ly:self-alignment-interface::centered-on-x-parent))
+      ,(ly:make-simple-closure
+           (list ly:self-alignment-interface::x-aligned-on-self)))))
+@end example
+
+@noindent
+En este ejemplo, tanto
+@code{ly:self-alignment-interface::x-aligned-on-self} como
+@code{ly:self-alignment-interface::centered-on-x-parent} se llaman con
+el grob como argumento.  El resultado se añade con la función
+@code{+}.  Para asegurar que esta adición se ejecuta adecuadamente,
+todo ello se encierra dentro de @code{ly:make-simple-closure}.
+
+De hecho, usar un solo procedimiento como valor de una propiedad
+equivale a
+
+@example
+(ly:make-simple-closure (ly:make-simple-closure (list @var{proc})))
+@end example
+
+@noindent
+El @code{ly:make-simple-closure} interior aporta el grob como
+argumento de @var{proc}, el exterior asegura que el resultado de la
+función es lo que se devuelve, en lugar del objeto
+@code{simple-closure}.
+
+Desde dentro de un callback, el método más fácil para evaluar un
+elemento de marcado es usar grob-interpret-markup.  Por ejemplo:
+
+@example
+mi-callback = #(lambda (grob)
+                 (grob-interpret-markup grob (markup "fulanito")))
+@end example
+
+
+@node Código de Scheme en línea
+@section Código de Scheme en línea
+@translationof Inline Scheme code
+
+La principal desventaja de @code{\tweak} es su inflexibilidad
+sintáctica.  Por ejemplo, lo siguiente produce un error de sintaxis.
+
+@example
+F = \tweak #'font-size #-3 -\flageolet
+
+\relative c'' @{
+  c4^\F c4_\F
+@}
+@end example
+
+@noindent
+En otras palabras, @code{\tweak} no se comporta como una articulación
+en cuando a la sintaxis; concretamente, no se puede adjuntar con
+@code{^} y @code{_}.
+
+Usando Scheme, se puede dar un rodeo a este problema.  La ruta hacia
+el resultado se da en @ref{Añadir articulaciones a las notas
+(ejemplo)}, especialmente cómo usar @code{\displayMusic} como guía de
+ayuda.
+
+@example
+F = #(let ((m (make-music 'ArticulationEvent
+                          'articulation-type "flageolet")))
+       (set! (ly:music-property m 'tweaks)
+             (acons 'font-size -3
+                    (ly:music-property m 'tweaks)))
+       m)
+
+\relative c'' @{
+  c4^\F c4_\F
+@}
+@end example
+
+@noindent
+Aquí, las propiedades @code{tweaks} del objeto flageolet @code{m}
+(creado con @code{make-music}) se extraen con
+@code{ly:music-property}, se antepone un nuevo par clave-valor para
+cambiar el tamaño de la tipografía a la lista de propiedades con la
+función de Scheme @code{acons}, y finalmente el resultado se escribe
+de nuevo con @code{set!}.  El último elemento del bloque @code{let} es
+el valor de retorno, el propio @code{m}.
+
+
+@node Trucos difíciles
+@section Trucos difíciles
+@translationof Difficult tweaks
+
+Hay un cierto número de tipos de ajustes difíciles.
+
+@itemize
+
+
+@item
+Un tipo de ajuste difícil es la apariencia de los objetos de
+extensión, como las ligaduras de expresión y de unión.  Inicialmente,
+sólo se crea uno de estos objetos, y pueden ajustarse con el mecanismo
+normal.  Sin embargo, en ciertos casos los objetos extensores cruzan
+los saltos de línea.  Si esto ocurre, estos objetos se clonan.  Se
+crea un objeto distinto por cada sistema en que se encuentra.  Éstos
+son clones del objeto original y heredan todas sus propiedades,
+incluidos los @code{\override}s.
+
+En otras palabras, un @code{\override} siempre afecta a todas las
+piezas de un objeto de extensión fragmentado.  Para cambiar sólo una
+parte de un extensor en el salto de línea, es necesario inmiscuirse en
+el proceso de formateado.  El @emph{callback}
+@code{after-line-breaking} contiene el procedimiento Scheme que se
+llama después de que se han determinado los saltos de línea, y los
+objetos de presentación han sido divididos sobre los distintos
+sistemas.
+
+En el ejemplo siguiente, definimos un procedimiento
+@code{my-callback}.  Este procedimiento
+
+@itemize
+@item
+determina si hemos sido divididos por los saltos de línea
+@item
+en caso afirmativo, reúne todos los objetos divididos
+@item
+comprueba si somos el último de los objetos divididos
+@item
+en caso afirmativo, establece @code{extra-offset}.
+@end itemize
+
+Este procedimiento se instala en @rinternals{Tie} (ligadura de unión),
+de forma que la última parte de la ligadura dividida se traslada hacia
+arriba.
+
+@lilypond[quote,verbatim,ragged-right]
+#(define (my-callback grob)
+   (let* (
+          ;; have we been split?
+          (orig (ly:grob-original grob))
+
+          ;; if yes, get the split pieces (our siblings)
+          (siblings (if (ly:grob? orig)
+                        (ly:spanner-broken-into orig)
+                        '())))
+
+     (if (and (>= (length siblings) 2)
+              (eq? (car (last-pair siblings)) grob))
+         (ly:grob-set-property! grob 'extra-offset '(-2 . 5)))))
+
+\relative c'' {
+  \override Tie #'after-line-breaking =
+  #my-callback
+  c1 ~ \break
+  c2 ~ c
+}
+@end lilypond
+
+@noindent
+Al aplicar este truco, la nueva función de callback
+@code{after-line-breaking} también debe llamar a la antigua,
+si existe este valor predeterminado.  Por ejemplo, si se usa con
+@code{Hairpin}, se debe llamar también a
+@code{ly:spanner::kill-zero-spanned-time}.
+
+
+@item Algunos objetos no se pueden cambiar con @code{\override} por
+razones técnicas.  Son ejemplos @code{NonMusicalPaperColumn} y
+@code{PaperColumn}.  Se pueden cambiar con la función
+@code{\overrideProperty} que funciona de forma similar a @code{\once
+\override}, pero usa una sintaxis distinta.
+
+@example
+\overrideProperty
+#"Score.NonMusicalPaperColumn"  % Nombre del grob
+#'line-break-system-details     % Nombre de la propiedad
+#'((next-padding . 20))         % Valor
+@end example
+
+Observe, sin embargo, que @code{\override}, aplicado a
+@code{NonMusicalPaperColumn} y a @code{PaperColumn}, aún funciona
+como se espera dentro de los bloques @code{\context}.
+
+@end itemize
+
+
+@node Interfaces de Scheme de LilyPond
+@chapter Interfaces de Scheme de LilyPond
+@translationof LilyPond Scheme interfaces
+
+Este capítulo cubre las diversas herramientas proporcionadas por
+LilyPond como ayuda a los programadores de Scheme a extraer e
+introducir información de los flujos musicales.
+
+HACER @c TODO -- figure out what goes in here and how to organize it