]> git.donarmstrong.com Git - lilypond.git/blobdiff - Documentation/es/extending/programming-interface.itely
Merge remote-tracking branch 'origin/translation' into staging
[lilypond.git] / Documentation / es / extending / programming-interface.itely
index db86c8cada3fdde1c77d0cac41f98bdfc7617bbd..0f5a87038598d4d7b5a75e02e72345772d17b6d8 100644 (file)
@@ -1,14 +1,13 @@
 @c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*-
-
+@c This file is part of extending.tely
 @ignore
-    Translation of GIT committish: d4f58bb3ad4e7fe1967a6b48f25e3addffc8aa14
+    Translation of GIT committish: 6bbc01872dd4e9cced2524c378628d9219ac08ae
 
     When revising a translation, copy the HEAD committish of the
-    version that you are working on.  For details, see the Contributors'
-    Guide, node Updating translation committishes..
+    version that you are working on.  See TRANSLATION for details.
 @end ignore
 
-@c \version "2.12.0"
+@c \version "2.19.2"
 
 @node Interfaces para programadores
 @chapter Interfaces para programadores
 
 Se pueden realizar trucos avanzados mediante el uso de Scheme.  Si no
 está familiarizado con Scheme, le conviene leer nuestro tutorial de
-Scheme, @rlearning{Tutorial de Scheme}.
+Scheme, @ref{Tutorial de Scheme}.
+
 
 @menu
+* Bloques de código de LilyPond::
+* Funciones de Scheme::
 * Funciones musicales::
-* Interfaces para el programador::
-* Construcción de funciones complejas::
-* Interfaz de marcado para el programador::
+* Funciones de eventos::
+* Funciones de marcado::
 * Contextos para programadores::
-* Procedimientos de Scheme como propiedades::
-* Usar código de Scheme en lugar de \tweak::
+* Funciones de callback::
+* Código de Scheme en línea::
 * Trucos difíciles::
 @end menu
 
+@node Bloques de código de LilyPond
+@section Bloques de código de LilyPond
+@translationof LilyPond code blocks
 
-@node Funciones musicales
-@section Funciones musicales
-@translationof Music functions
-
-Esta sección trata sobre cómo crear funciones musicales dentro de
-LilyPond.
-
-@menu
-* Panorámica de las funciones musicales::
-* Funciones de sustitución sencillas::
-* Funciones de sustitutión en parejas::
-* Matemáticas dentro de las funciones::
-* Funciones vacías::
-* Funciones sin argumentos::
-* Pranorámica de las funciones musicales disponibles::
-@end menu
-
-@node Panorámica de las funciones musicales
-@subsection Panorámica de las funciones musicales
-@translationof Overview of music functions
+@cindex Bloques de código de LilyPond
+@cindex LilyPond, bloques de código de
+@funindex #@{ @dots{} #@}
+@funindex $
+@funindex #
 
-Es fácil hacer una función que sustituya a una variable en código de
-LilyPond.  La forma general de estas funciones es:
+La creación de expresiones musicales en Scheme puede ser una tarea
+tediosa porque a veces presentan muchos niveles de profundidad de
+anidamiento y el código resultante es grande.  Para algunas tareas
+sencillas, esto puede evitarse utilizando bloques de código de
+LilyPond, que permiten usar la sintaxis ordinaria de LilyPond
+dentro de Scheme.
 
+Los bloques de código de LilyPond tienen el siguiente aspecto:
 @example
-function =
-#(define-music-function (parser location @var{var1} @var{var2}...@var{vari}... )
-                        (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...)
-  #@{
-    @emph{...música...}
-  #@})
+  #@{ @var{código de LilyPond} #@}
 @end example
 
-@noindent
-donde
-
-@multitable @columnfractions .33 .66
-@item @var{vari}         @tab @var{i}-ésima variable
-@item @var{vari-type?}   @tab tipo de la @var{i}-ésima variable
-@item @var{...música...}  @tab entrada normal de LilyPond, usando las variables como @code{#$var1}, etc.
-@end multitable
-
-Los siguientes tipos de entrada se pueden usar como variables en una
-función musical.  Esta lista no es exhaustiva; consulte otros lugares
-de la documentación específica de Scheme para ver otros tipos de
-variables.
-
-@multitable @columnfractions .33 .66
-@headitem Tipo de entrada       @tab notación de @var{vari-type?}
-@item Entero                    @tab @code{integer?}
-@item Flotante (número decimal) @tab @code{number?}
-@item Cadena de texto           @tab @code{string?}
-@item Marcado                   @tab @code{markup?}
-@item Expresión musical         @tab @code{ly:music?}
-@item Pareja de variables          @tab @code{pair?}
-@end multitable
-
-Los argumentos @code{parser} y @code{location} son obligatorios, y se
-usan en ciertas situaciones avanzadas.  El argumento @code{parser} se
-usa para tener acceso al valor de otra variable de LilyPond.  El
-argumento @code{location} se usa para establecer el @q{origen} de la
-expresión musical que construye la función musical, de forma que en
-caso de producirse un error de sintaxis LilyPond pueda informar al
-usuario de un lugar adecuado donde buscar en el archivo de entrada.
-
-
-@node Funciones de sustitución sencillas
-@subsection Funciones de sustitución sencillas
-@translationof Simple substitution functions
-
-He aquí un ejemplo sencillo:
-
-@lilypond[quote,verbatim,ragged-right]
-padText = #(define-music-function (parser location padding) (number?)
-  #{
-    \once \override TextScript #'padding = #$padding
-  #})
-
-\relative c''' {
-  c4^"piu mosso" b a b
-  \padText #1.8
-  c4^"piu mosso" d e f
-  \padText #2.6
-  c4^"piu mosso" fis a g
-}
-@end lilypond
+He aquí un ejemplo trivial:
 
-También se pueden sustituir las expresiones musicales:
+@lilypond[verbatim,quote]
+ritpp = #(define-event-function (parser location) ()
+  #{ ^"rit." \pp #}
+)
 
-@lilypond[quote,verbatim,ragged-right]
-custosNote = #(define-music-function (parser location note)
-                                     (ly:music?)
-  #{
-    \once \override Voice.NoteHead #'stencil =
-      #ly:text-interface::print
-    \once \override Voice.NoteHead #'text =
-      \markup \musicglyph #"custodes.mensural.u0"
-    \once \override Voice.Stem #'stencil = ##f
-    $note
-  #})
-
-{ c' d' e' f' \custosNote g' }
+{ c'4 e'4\ritpp g'2 }
 @end lilypond
 
-Se puede usar más de una variable:
-
-@lilypond[quote,verbatim,ragged-right]
-tempoPadded = #(define-music-function (parser location padding tempotext)
-  (number? string?)
-#{
-  \once \override Score.MetronomeMark #'padding = $padding
-  \tempo \markup { \bold $tempotext }
-#})
-
-\relative c'' {
-  \tempo \markup { "Low tempo" }
-  c4 d e f g1
-  \tempoPadded #4.0 #"High tempo"
-  g4 f e d c1
-}
-@end lilypond
+Los bloques de código de LilyPond se pueden usar en cualquier
+lugar en el que se pueda escribir código de Scheme.  El lector de
+Scheme en efecto se modifica para que pueda incorporar bloques de
+código de LilyPond y pueda ocuparse de las expresiones de Scheme
+incrustadas que comienzan por @code{$} y@w{ }@code{#}.
+
+@cindex parser (function argument)
+@cindex location
+
+El lector extrae el bloque de código de LilyPond y genera una
+llamada en tiempo de ejecución al analizador sintáctico para que
+interprete el código de LilyPond.  Las expresiones de Scheme
+incrustadas en el código de LilyPond se evalúan dentro del entorno
+lóexico del bloque de código de LilyPond, de manera que puede
+accederse a todas las variables locales y los parámetros de
+función que están disponibles en el punto en que se escribe el
+bloque de código de LilyPond.  Las variables definidas en otros
+módulos de Scheme, como los módulos que contienen bloques
+@code{\header} y @code{\layout}, no están accesibles como
+variables de Scheme, es decir, precedidas de@tie{}@code{#}, pero
+se puede acceder a ellas como variables de LilyPond, es decir,
+precedidas de@tie{}@code{\}.
+
+Si @code{location} (véase @ref{Funciones de Scheme}) se refiere a una
+posición de entrada válida (como lo hace normalmente dentro de las
+funciones musicales o de Scheme), toda la música generada dentro
+del bloque de código tiene su @samp{origin} establecido a
+@code{location}.
+
+Un bloque de código de LilyPond puede contener cualquier cosa que
+podríamos utilizar en la parte derecha de una asignación.  Además, un
+bloque de LilyPond vacío corresponde a una expresión musical vacía, y
+un bloque de LilyPond que contiene varios eventos musicales se
+convierte en una expresión de música secuencial.
+
+@node Funciones de Scheme
+@section Funciones de Scheme
+@translationof Scheme functions
+@cindex Scheme, funciones de (sintaxis de LilyPond)
+
+Las @emph{funciones de Scheme} son procedimientos de Scheme que pueden
+crear expresiones de Scheme a partir de código de entrada escrito en
+la sintaxis de LilyPond.  Se pueden llamar desde prácticamente
+cualquier lugar en el que se permita el uso de @code{#} para la
+especificación de un valor en sintaxis de Scheme.  Mientras que Scheme
+tiene funciones propias, este capítulo se ocupa de las funciones
+@emph{sintácticas}, funciones que reciben argumentos especificados en
+la sintaxis de LilyPond.
 
+@menu
+* Definición de funciones de Scheme::
+* Uso de las funciones de Scheme::
+* Funciones de Scheme vacías::
+@end menu
 
-@node Funciones de sustitutión en parejas
-@subsection Funciones de sustitutión en parejas
-@translationof Paired substitution functions
+@node Definición de funciones de Scheme
+@subsection Definición de funciones de Scheme
+@translationof Scheme function definitions
+@funindex define-scheme-function
 
-Algunas instrucciones @code{\override} requieren un par de números
-(llamados en Scheme una @code{célula cons}).  Para pasar estos números
-a una función, usamos una variable @code{pair?} o bien insertamos el
-@code{cons} en la función musical.
+La forma general de la definición de una función de Scheme es:
 
-@quotation
 @example
-manualBeam =
-#(define-music-function (parser location beg-end)
-                        (pair?)
-#@{
-  \once \override Beam #'positions = #$beg-end
-#@})
-
-\relative @{
-  \manualBeam #'(3 . 6) c8 d e f
-@}
+funcion =
+#(define-scheme-function
+     (parser location @var{arg1} @var{arg2} @dots{})
+     (@var{tipo1?} @var{tipo2?} @dots{})
+   @var{cuerpo})
 @end example
-@end quotation
 
 @noindent
-o bien
-
-@lilypond[quote,verbatim,ragged-right]
-manualBeam =
-#(define-music-function (parser location beg end)
-                        (number? number?)
-#{
-  \once \override Beam #'positions = #(cons $beg $end)
-#})
-
-\relative {
-  \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
-}
+donde
 
-{ c'2 \AltOn #0.5 c'4 c'
-  \AltOn #1.5 c' c' \AltOff c'2 }
-@end lilypond
+@multitable @columnfractions .33 .66
+@item @code{parser}
+@tab tiene que ser literalmente @code{parser} para dar a los bloques de código
+de LilyPond (@code{#@{}@dots{}@code{#@}}) acceso al analizador
+sintáctico.
+
+@item @code{location}
+@tab tiene que ser literalmente @code{location} para ofrecer acceso al
+objeto de situación de la entrada, que se usa para ofrecer
+menssajes de error con nombres de archivo y números de línea.
+
+@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}}
+debe devolver @code{#t}.
+
+También existe una forma especial @code{(@emph{predicate?}
+@emph{default})} para especificar argumentos opcionales.  Si el
+argumento actual no está presente cuando se ll ama a la función, el
+valor predeterminado se emplea en sustitución.  Los valores
+predeterminados se evalúan en tiempo de definición (¡incluyendo los
+bloques de código de LilyPond!), de manera que se necesitamos un valor
+por omisión calculado en tiempo de ejecución, debemos escribir en su
+lugar un valor especial que podamos reconocer fácilmente.  Si
+escribimos el predicado entre paréntesis pero no lo seguimos por el
+valor predeterminado, se usa @code{#f} como valor por omisión.  Los
+valores por omisión no se verifican con @emph{predicate?} en tiempo de
+definición ni en tiempo de ejecución: es nuestra responsabilidad
+tratar con los valores que especifiquemos.  Los valores por omisión
+que son expresiones musicales se copian mientras se establece
+@code{origin} al parámetro @code{location}.
+
+@item @code{@var{cuerpo}}
+@tab una secuencia de formas de Scheme que se evalúan ordenadamente; la
+última forma de la secuencia se usa como el valor de retorno de la
+función de Scheme. Puede contener bloques de código de LilyPond
+encerrados entre llaves con almohadillas
+(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}), como se describe en
+@ref{Bloques de código de LilyPond}.  Dentro de los bloques de código
+de LilyPond, use el símbolo @code{#} para hacer referencia a
+argumentos de 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)}}).  Donde las expresiones de Scheme
+normales que usan @code{#} no funcionan, podríamos necesitar volver a
+expresiones de Scheme inmediatas que usan @code{$}, como por ejemplo
+@samp{$music}.
+
+Si nuestra función devuelve una expresión musical, recibe un valor
+@code{origin} útil.
+@end multitable
 
 @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 #})
-
-{ c'2 \withAlt #0.5 {c'4 c'}
-  \withAlt #1.5 {c' c'} c'2 }
-@end lilypond
-
-
-@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.
+La idoneidad de los argumentos para los predicados viene determinada
+mediante llamadas reales al predicado después de que LilyPond ya las
+ha convertido en una expresión de Scheme.  Como consecuencia, el
+argumento se puede especificar en la sintaxis de Scheme si se desea
+(precedido de @code{#} o como resultado de haber llamado a una función
+de Scheme), pero LilyPond también convierte algunas construcciones de
+LilyPond en Scheme antes de hacer efectivamente la comprobación del
+predicado sobre ellas.  Actualmente se encuentran entre ellas la
+música, los post-eventos, las cadenas simples (entrecomilladas o no),
+los números, los elementos de marcado y de listas de marcado, score
+(partitura), book (libro), bookpart (parte de libro), las definiciones
+de contexto y los bloques de definición de salida.
+
+Para ciertos tipos de expresión (como la mayor parte de la música que
+no está encerrada entre llaves) LilyPond necesita más allá de la
+expresión misma para poder determinar su final.  Si tal expresión se
+considerase un argumento opcional mediante la evaluación de su
+predicado, LilyPond no podría recuperarse después de decidir que la
+expresión no se corresponde con el parámetro.  Así, ciertas formas de
+música necesitan ir encerradas entre llaves para poder considerarlas
+como aceptables bajo algunas circunstancias.  LilyPond resuelve
+algunas otras ambigüedades mediante la comprobación con funciones de
+predicado: ¿es @samp{-3} un post-evento de digitación o un número
+negativo?  ¿Es @code{"a" 4} en el modo de letra una cadena seguida por
+un número, o un evento de letra con la duración @code{4}?  LilyPond
+prueba el predicado del argumento sobre diversas interpretaciones
+sucesivas hasta que lo consigue, con un orden diseñado para minimizar
+las interpretaciones poco consistentes y la lectura por adelantado.
+
+Por ejemplo, un predicado que acepta tanto expresiones musicales como
+alturas consideraría que @code{c''} es una altura en lugar de una
+expresión musical.  Las duraciones o post-eventos que siguieran
+inmediatamente podrían no funcionar con dicha interpretación.  Así
+pues, es mejor evitar los predicados excesivamente permisivos como
+@code{scheme?} cuando la aplicación requeriría tipos de argumento más
+específicos.
+
+Para ver una lista de los predicados de tipo disponibles, consulte
+@ruser{Predicados de tipo predefinidos}.
+
+@seealso
+
+Referencia de la notación:
+@ruser{Predicados de tipo predefinidos}.
+
+Archivos instalados:
+@file{lily/music-scheme.cc},
+@file{scm/c++.scm},
+@file{scm/lily.scm}.
+
+
+@node Uso de las funciones de Scheme
+@subsection Uso de las funciones de Scheme
+@translationof Scheme function usage
+
+Las funciones de Scheme se pueden llamar casi desde cualquier lugar en
+que puede escribirse una expresión de Scheme que comience con la
+almohadilla@tie{}@code{#}.  Llamamos a una función de Scheme
+escribiendo su nombre precedido de la barra invertida@tie{}@code{\}, y
+seguido por sus argumentos.  Una vez que un argumento opcional no
+corresponde a ningún argumento, LilyPond se salta este argumento y
+todos los que le siguen, sustituyéndolos por su valor por omisión
+especificado, y @q{recupera} el argumento que no correspondía al lugar
+del siguiente argumento obligatorio.  Dado que el argumento recuperado
+necesita ir a algún lugar, los argumentos opcionales no se consideran
+realmente opcionales a no ser que vayan seguidos de un argumento
+obligatorio.
+
+Existe una excepción: si escribimos @code{\default} en el lugar de un
+argumento opcional, este argumento y todos los argumentos opcionales
+que le siguen se saltan y se sustituyen por sus valores
+predeterminados.  Esto funciona incluso si no sigue ningún argumento
+obligatorio porque @code{\default} no necesita recuperarse.  Las
+instrucciones @code{mark} y @code{key} hacen uso de este truco para
+ofrecer su comportamiento predeterminado cuando van seguidas solamente
+por @code{\default}.
+
+Aparte de los lugares en que se requiere un valor de Scheme hay
+ciertos sitios en que se aceptan expresiones de almohadilla @code{#} y
+se evalúan por sus efectos secundarios, pero por lo demás se ignoran.
+Son, mayormente, los lugares en que también sería aceptable colocar
+una asignación.
+
+Dado que no es buena idea devolver valores que puedan malinterpretarse
+en algún contexto, debería usar funciones de Scheme normales solo para
+los casos en que siempre se devuelve un valor útil, y usar funciones
+de Scheme vacías (@pxref{Funciones de Scheme vacías}) en caso
+contrario.
+
+
+@node Funciones de Scheme vacías
+@subsection Funciones de Scheme vacías
+@translationof Void scheme functions
+@funindex define-void-function
+@funindex \void
+
+En ocasiones, un procedimiento se ejecuta con el objeto de llevar a
+cabo alguna acción más que para devolver un valor.  Algunos lenguajes
+de programación (como C y Scheme) usan las funciones para los dos
+conceptos y se limitan a descartar el valor devuelto (usualmente
+haciendo que cualquier expresión pueda actuar como instrucción,
+ignorando el resultado devuelto).  Esto puede parecer inteligente pero
+es propenso a errores: casi todos los compiladores de C de hoy en día
+emiten advertencias cuando se descarta una expresión no vacía.  Para
+muchas funciones que ejecutan una acción, los estándares de Scheme
+declaran que el valor de retorno sea no especificado.  Guile, el
+intérprete de Scheme de LilyPond, tiene un valor único
+@code{*unspecified*} que en tales casos devuelve de forma usual (como
+cuando se usa directamente @code{set!} sobre una variable), pero
+desgraciadamente no de forma consistente.
+
+Definir una función de LilyPond con @code{define-void-function}
+asegura que se devuelve este valor especial, el único valor que
+satisface el predicado @code{void?}.
 
 @example
-noPointAndClick =
-#(define-music-function (parser location) ()
-   (ly:set-option 'point-and-click #f)
-   (make-music 'SequentialMusic 'void #t))
-...
-\noPointAndClick   % desactivar la funcionalidad Apuntar y Pulsar.
+noApuntarYPulsar =
+#(define-void-function
+     (parser location)
+     ()
+   (ly:set-option 'point-and-click #f))
+@dots{}
+\noApuntarYPulsar   % desactivar la función de apuntar y pulsar
 @end example
 
-
-@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
-displayBarNum =
-#(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
+Si queremos evaluar una expresión sólo por su efecto colateral y no
+queremos que se interprete ningún valor que pueda devolver, podemos
+hacerlo anteponiendo el prefijo @code{\void}:
 
 @example
-lilypond -d display-bar-numbers ARCHIVO.ly
+\void #(hashq-set! some-table some-key some-value)
 @end example
 
+De esta forma podemos asegurar que LilyPond no asignará ningún
+significado al valor devuelto, independientemente de dónde lo
+encuentre.  También funciona para funciones musicales como
+@code{\displayMusic}.
 
-@node Pranorámica de las funciones musicales disponibles
-@subsection Pranorámica de las funciones musicales disponibles
-@translationof Overview of available music functions
-
-@c fixme ; this should be move somewhere else?
-Las siguientes instrucciones son funciones musicales:
-
-@include identifiers.tely
-
+@node Funciones musicales
+@section Funciones musicales
+@translationof Music functions
 
-@node Interfaces para el programador
-@section Interfaces para el programador
-@translationof Programmer interfaces
+@cindex funciones musicales
 
-Esta sección contiene información sobre cómo mezclar LilyPond y
-Scheme.
+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
-* Variables de entrada y Scheme::
-* Representación interna de la música::
+* Definiciones de funciones musicales::
+* Uso de las funciones musicales::
+* Funciones de sustitución sencillas::
+* Funciones de sustitución intermedias::
+* Matemáticas dentro de las funciones::
+* Funciones sin argumentos::
+* Funciones musicales vacías::
 @end menu
 
-@node Variables de entrada y Scheme
-@subsection Variables de entrada y Scheme
-@translationof Input variables and Scheme
 
-El formato de entrada contempla la noción de variables: en el ejemplo
-siguiente, se asigna una expresión musical a una variable con el
-nombre @code{traLaLa}.
+@node Definiciones de funciones musicales
+@subsection Definiciones de funciones musicales
+@translationof Music function definitions
+@cindex definición de funciones musicales
+@funindex define-music-function
 
-@example
-traLaLa = @{ c'4 d'4 @}
-@end example
-
-@noindent
-
-También existe una forma de ámbito léxico: en el ejemplo siguiente, el
-bloque @code{\layout} también contiene una variable @code{traLaLa},
-que es independiente de la @code{\traLaLa} exterior.
+La forma general para definir funciones musicales es:
 
 @example
-traLaLa = @{ c'4 d'4 @}
-\layout @{ traLaLa = 1.0 @}
-@end example
-@c
-De hecho, cada archivo de entrada es un ámbito léxico, y todos los
-bloques @code{\header}, @code{\midi} y @code{\layout} son ámbitos
-anidados dentro de dicho ámbito de nivel superior.
-
-Tanto el ámbito léxico como las variables están implementados en el
-sistema de módulos GUILE.  Se adjunta un módulo anónimo de Scheme a
-cada ámbito.  Una asignación de la forma
-@example
-traLaLa = @{ c'4 d'4 @}
+funcion =
+#(define-music-function
+     (parser location @var{arg1} @var{arg2} @dots{})
+     (@var{tipo1?} @var{tipo2?} @dots{})
+   @var{cuerpo})
 @end example
 
 @noindent
-se convierte internamente a una definición de Scheme
-@example
-(define traLaLa @var{Scheme value of `@code{... }'})
-@end example
-
-Esto supone que las variables de entrada y las variables de Scheme se
-pueden entremezclar con libertad.  En el ejemplo siguiente, se
-almacena un fragmento musical en la variable @code{traLaLa}, y se
-duplica utilizando Scheme.  El resultado se importa en un bloque
-@code{\score} por medio de una segunda variable @code{twice}:
-
-@lilypond[verbatim]
-traLaLa = { c'4 d'4 }
-
-%% dummy action to deal with parser lookahead
-#(display "this needs to be here, sorry!")
-
-#(define newLa (map ly:music-deep-copy
-  (list traLaLa traLaLa)))
-#(define twice
-  (make-sequential-music newLa))
-
-{ \twice }
-@end lilypond
-
-@c Due to parser lookahead
+de forma bastante análoga a @ref{Definición de funciones de Scheme}.
+Lo más probable es que el @var{cuerpo} sea un
+@ref{Bloques de código de LilyPond,bloque de código de LilyPond}.
 
-En este ejemplo, la asignación se produce después de que el analizador
-sintáctico ha verificado que no ocurre nada interesante después de
-@code{traLaLa = @{ ... @}}.  Sin el argumento mudo del ejemplo, la
-definición @code{newLa} se ejecuta antes de que se defina
-@code{traLaLa}, conduciendo a un error de sintaxis.
+Para ver una lista de los predicados de tipo disponibles, consulte
+@ruser{Predicados de tipo predefinidos}.
 
-El ejemplo anterior muestra cómo @q{exportar} expresiones musicales
-desde la entrada hasta el intérprete de Scheme.  También es posible lo
-contrario.  Envolviendo un valor de Scheme en la función
-@code{ly:export}, un valor de Scheme se interpreta como si hubiera
-sido introducido en sintaxis de LilyPond.  En vez de definir
-@code{\twice}, el ejemplo anterior podría también haberse escrito como
+@seealso
 
-@example
-...
-@{ #(ly:export (make-sequential-music (list newLa))) @}
-@end example
-
-El código de Scheme se evalúa tan pronto como el analizador sintáctico
-lo encuentra.  Para definir código de Scheme en un macro (para
-llamarlo con posterioridad), use @ref{Funciones vacías}, o bien
+Referencia de la notación:
+@ruser{Predicados de tipo predefinidos}.
 
-@example
-#(define (nopc)
-  (ly:set-option 'point-and-click #f))
+Archivos de inicio:
+@file{lily/music-scheme.cc},
+@file{scm/c++.scm},
+@file{scm/lily.scm}.
 
-...
-#(nopc)
-@{ c'4 @}
-@end example
 
-@knownissues
+@node Uso de las funciones musicales
+@subsection Uso de las funciones musicales
+@translationof Music function usage
 
-No es posible mezclar variables de Scheme y de LilyPond con la opción
-@code{--safe}.
+Las funciones musicales se pueden actualmente utilizar en varios
+lugares.  Dependiendo de dónde se usan, son de aplicación ciertas
+restricciones para que sea posible su análisis sintáctico de forma
+no ambigua.  El resultado que devuelve una función musical debe ser
+compatible con el contexto desde el que se la llama.
 
-
-@node Representación interna de la música
-@subsection Representación interna de la música
-@translationof Internal music representation
-
-Cuando se analiza sintácticamente una expresión musical, se convierte
-en un conjunto de objetos musicales de Scheme.  La propiedad que
-define a un objeto musical es que tiene una cierta duración.  El
-tiempo es un número racional que mide la longitud de un fragmento de
-música en unidades del valor de una redonda.
-
-Un objeto musical tiene tres clases de tipos:
 @itemize
 @item
-nombre musical: cada expresión musical tiene un nombre.  Por ejemplo,
-una nota conduce a un evento @rinternals{NoteEvent}, y
-@code{\simultaneous} conduce a @rinternals{SimultaneousMusic}.  Hay
-una lista de todas las expresiones que están disponibles en el Manual
-de referencia de funcionamiento interno, bajo @rinternals{Music
-expressions}.
+En el nivel superior dentro de una expresión musical.  Aquí
+no se aplica ninguna restricción.
 
 @item
-@q{tipo} o interface: cada nombre de música tiene varios @q{tipos} o
-interfaces, por ejemplo una nota es un @code{event}, pero también es
-un @code{note-event}, un @code{rhythmic-event} y un
-@code{melodic-event}.  Todas las clases musicales se encuentran
-relacionadas en la Referencia de funcionamiento interno bajo
-@rinternals{Music classes}.
+Como un post-evento, que comienza explícitamente con un indicador de
+dirección (a elegir entre @code{-}, @code{^} @w{y @code{_}}).
+
+En este caso, no podemos usar una expresión musical @emph{abierta}
+como último argumento, que terminaría en una expresión musical
+capaz de aceptar post-eventos adicionales.
 
 @item
-Objeto de C++: cada objeto musical está representado por un objeto de
-la clase de C++ @code{Music}.
+Como componente de un acorde.  La expresión devuelta debe ser
+del tipo @code{rhythmic-event}, probablemente un @code{NoteEvent}.
 @end itemize
 
-La información real de una expresión musical se almacena en forma de
-propiedades.  Por ejemplo, un evento @rinternals{NoteEvent} tiene
-propiedades @code{pitch} y @code{duration} que almacenan la altura y
-duración de la nota.  Hay una lista completa de las propiedades que
-están disponibles en la Referencia de funcionamiento interno, bajo
-@rinternals{Music properties}.
-
-Una expresión musical compuesta es un objeto musical que contiene
-otros objetos musicales en sus propiedades.  Se puede almacenar una
-lista de objetos en la propiedad @code{elements} de un objeto musical,
-o un solo objeto musical @q{hijo} en la propiedad @code{element}.  Por
-ejemplo, @rinternals{SequentialMusic} tiene sus hijos en
-@code{elements}, y @rinternals{GraceMusic} tiene su elemento único en
-@code{element}.  El cuerpo de una repetición se almacena en la
-propiedad @code{element} de @rinternals{RepeatedMusic}, y las
-alternativas en @code{elements}.
-
-
-@node Construcción de funciones complejas
-@section Construcción de funciones complejas
-@translationof Building complicated functions
-
-Esta sección explica cómo reunir la información necesaria para crear
-funciones musicales complejas.
-
-
-@menu
-* Presentación de expresiones musicales::
-* Propiedades de la música::
-* Doblar una nota con ligaduras (ejemplo)::
-* Añadir articulación a las notas (ejemplo)::
-@end menu
-
-@node Presentación de expresiones musicales
-@subsection Presentación de expresiones musicales
-@translationof Displaying music expressions
-
-@cindex interno, almacenamiento
-@cindex mostrar expresiones musicales
-@cindex interna, representación, mostrar
-
-@funindex \displayMusic
-
-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 @code{\displayMusic}:
-
-@example
-@{
-  \displayMusic @{ c'4\f @}
-@}
-@end example
-
 @noindent
-imprime lo siguiente:
+Las reglas especiales para los argumentos del final hacen posible
+escribir funciones polimórficas como @code{\tweak} que se pueden
+aplicar a construcciones distintas.
 
-@example
-(make-music
-  'SequentialMusic
-  'elements
-  (list (make-music
-          'EventChord
-          'elements
-          (list (make-music
-                  'NoteEvent
-                  'duration
-                  (ly:make-duration 2 0 1 1)
-                  'pitch
-                  (ly:make-pitch 0 0 0))
-                (make-music
-                  'AbsoluteDynamicEvent
-                  'text
-                  "f")))))
-@end example
-
-De forma predeterminada, LilyPond imprime estos mensajes en la consola
-junto al resto de los mensajes.  Para discernir entre estos mensajes y
-guardar el resultado de @code{\display@{MATERIAL@}}, redirija la
-salida hacia un archivo.
-
-@example
-lilypond archivo.ly >resultado.txt
-@end example
-
-Con la aplicación de un poco de formato, la información anterior es
-fácil de leer:
-
-@example
-(make-music 'SequentialMusic
-  'elements (list (make-music 'EventChord
-                    'elements (list (make-music 'NoteEvent
-                                      'duration (ly:make-duration 2 0 1 1)
-                                      'pitch (ly:make-pitch 0 0 0))
-                                    (make-music 'AbsoluteDynamicEvent
-                                      'text "f")))))
-@end example
-
-Una secuencia musical @code{@{ ... @}} tiene el nombre
-@code{SequentialMusic}, y sus expresiones internas se almacenan como
-una lista en su propiedad @code{'elements}.  Una nota se representa
-como una expresión @code{EventChord} que contiene un objeto
-@code{NoteEvent} (que almacena las propiedades de duración y altura) y
-cualquier otra información adicional (en este caso, un evento
-@code{AbsoluteDynamicEvent} con una propiedad de texto @code{"f"}.
-
-
-@node Propiedades de la música
-@subsection Propiedades de la música
-@translationof Music properties
-
-El objeto @code{NoteEvent} es el primer objeto de la propiedad
-@code{'elements} de @code{someNote}.
-
-@example
-unaNota = c'
-\displayMusic \unaNota
-===>
-(make-music
-  'EventChord
-  'elements
-  (list (make-music
-          'NoteEvent
-          'duration
-          (ly:make-duration 2 0 1 1)
-          'pitch
-          (ly:make-pitch 0 0 0))))
-@end example
+@node Funciones de sustitución sencillas
+@subsection Funciones de sustitución sencillas
+@translationof Simple substitution functions
 
-La función @code{display-scheme-music} es la función utilizada por
-@code{\displayMusic} para imprimir la representación de Scheme de una
-expresión musical.
+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}.
 
-@example
-#(display-scheme-music (first (ly:music-property unaNota 'elements)))
-===>
-(make-music
-  'NoteEvent
-  'duration
-  (ly:make-duration 2 0 1 1)
-  'pitch
-  (ly:make-pitch 0 0 0))
-@end example
 
-Después se accede a la altura de la nota a través de la propiedad
-@code{'pitch} del objeto @code{NoteEvent}:
+@node Funciones de sustitución intermedias
+@subsection Funciones de sustitución intermedias
+@translationof Intermediate substitution functions
 
-@example
-#(display-scheme-music
-   (ly:music-property (first (ly:music-property unaNota 'elements))
-                      'pitch))
-===>
-(ly:make-pitch 0 0 0)
-@end example
+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.
 
-La altura de la nota se puede cambiar estableciendo el valor de esta
-propiedad 'pitch:
+Algunas instrucciones @code{\override} requieren un argumento que
+consiste en una pareja de números (llamada una @emph{célula cons} en
+Scheme).
 
-@funindex \displayLilyMusic
+La pareja se puede pasar directamente dentro de la función musical,
+usando una variable @code{pair?}:
 
 @example
-#(set! (ly:music-property (first (ly:music-property unaNota 'elements))
-                          'pitch)
-       (ly:make-pitch 0 1 0)) ;; fijar la altura a d'.
-\displayLilyMusic \unaNota
-===>
-d'
+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:
 
-@node Doblar una nota con ligaduras (ejemplo)
-@subsection Doblar una nota con ligaduras (ejemplo)
-@translationof Doubling a note with slurs (example)
-
-Supongamos que queremos crear una función que traduce una entrada como
-@code{a} a algo como @code{a( a)}.  Empezamos examinando la
-representación interna de la música con la que queremos terminar.
-
-@example
-\displayMusic@{ a'( a') @}
-===>
-(make-music
-  'SequentialMusic
-  'elements
-  (list (make-music
-          'EventChord
-          'elements
-          (list (make-music
-                  'NoteEvent
-                  'duration
-                  (ly:make-duration 2 0 1 1)
-                  'pitch
-                  (ly:make-pitch 0 5 0))
-                (make-music
-                  'SlurEvent
-                  'span-direction
-                  -1)))
-        (make-music
-          'EventChord
-          'elements
-          (list (make-music
-                  'NoteEvent
-                  'duration
-                  (ly:make-duration 2 0 1 1)
-                  'pitch
-                  (ly:make-pitch 0 5 0))
-                (make-music
-                  'SlurEvent
-                  'span-direction
-                  1)))))
-@end example
-
-Las malas noticias son que las expresiones @code{SlurEvent} se deben
-añadir @q{dentro} de la nota (o más concretamente, dentro de la
-expresión @code{EventChord}).
+@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
 
-Ahora observamos la entrada:
+@funindex \temporary
+@cindex sobreescrituras temporales
+@cindex temporales, sobreescrituras
+@cindex propiedades, recuperar valor anterior
+
+Las propiedades se mantienen conceptualmente utilizando una pila
+por cada propiedad, por cada grob y por cada contexto.  Las
+funciones musicales pueden requerir la sobreescritura de una o
+varias propiedades durante el tiempo de duración de la función,
+restaurándolas a sus valores previos antes de salir.  Sin embargo,
+las sobreescrituras normales extraen y descartan la cima de la
+pila de propiedades actual antes de introducir un valor en ella,
+de manera que el valor anterior de la propiedad se pierde cuando
+se sobreescribe.  Si se quiere preservar el valor anterior, hay
+que preceder la instrucción @code{\override} con la palabra clave
+@code{\temporary}, así:
 
 @example
-(make-music
-  'SequentialMusic
-  'elements
-  (list (make-music
-          'EventChord
-          'elements
-          (list (make-music
-                  'NoteEvent
-                  'duration
-                  (ly:make-duration 2 0 1 1)
-                  'pitch
-                  (ly:make-pitch 0 5 0))))))
+\temporary \override @dots{}
 @end example
 
-Así pues, en nuestra función, tenemos que clonar esta expresión (de
-forma que tengamos dos notas para construir la secuencia), añadir
-@code{SlurEvents} a la propiedad @code{'elements} de cada una de
-ellas, y por último hacer una secuencia @code{SequentialMusic} con los
-dos @code{EventChords}.
+El uso de @code{\temporary} hace que se borre la propiedad
+(normalmente fijada a un cierto valor) @code{pop-first} de la
+sobreescritura, de forma que el valor anterior no se extrae de la
+pila de propiedades antes de poner en ella el valor nuevo.  Cuando
+una instrucción @code{\revert} posterior extrae el avlor
+sobreescrito temporalmente, volverá a emerger el valor anterior.
+
+En otras palabras, una llamada a @code{\temporary \override} y a
+continuación otra a @code{\revert} sobre la misma propiedad, tiene
+un valor neto que es nulo.  De forma similar, la combinación en
+secuencia de @code{\temporary} y @code{\undo} sobre la misma
+música que contiene las sobreescrituras, tiene un efecto neto
+nulo.
+
+He aquí un ejemplo de una función musical que utiliza lo expuesto
+anteriormente.  El uso de @code{\temporary} asegura que los
+valores de las propiedades @code{cross-staff} y @code{style} se
+restauran a la salida a los valores que tenían cuando se llamó a
+la función @code{crossStaff}.  Sin @code{\temporary}, a la salida
+se habrían fijado los valores predeterminados.
 
 @example
-doubleSlur = #(define-music-function (parser location note) (ly:music?)
-         "Return: @{ note ( note ) @}.
-         `note' is supposed to be an EventChord."
-         (let ((note2 (ly:music-deep-copy note)))
-           (set! (ly:music-property note 'elements)
-                 (cons (make-music 'SlurEvent 'span-direction -1)
-                       (ly:music-property note 'elements)))
-           (set! (ly:music-property note2 'elements)
-                 (cons (make-music 'SlurEvent 'span-direction 1)
-                       (ly:music-property note2 'elements)))
-           (make-music 'SequentialMusic 'elements (list note note2))))
+crossStaff =
+#(define-music-function (parser location notes) (ly:music?)
+  (_i "Create cross-staff stems")
+  #@{
+  \temporary \override Stem.cross-staff = #cross-staff-connect
+  \temporary \override Flag.style = #'no-flag
+  #notes
+  \revert Stem.cross-staff
+  \revert Flag.style
+#@})
 @end example
 
 
-@node Añadir articulación a las notas (ejemplo)
-@subsection Añadir articulación a las notas (ejemplo)
-@translationof Adding articulation to notes (example)
-
-La manera fácil de añadir articulación a las notas es fundir dos
-expresiones musicales en un contexto único, como está explicado en
-@ref{Crear contextos}.  Sin embargo, suponga que queremos escribir
-una función musical que haga esto.
+@node Matemáticas dentro de las funciones
+@subsection Matemáticas dentro de las funciones
+@translationof Mathematics in functions
 
-Una @code{$variable} dentro de la notación @code{#@{...#@}} es como
-usar una @code{\variable} normal en la notación clásica de LilyPond.
-Sabemos que
+Las funciones musicales pueden contar con programación de Scheme
+además de la simple sustitución:
 
-@example
-@{ \musica -. -> @}
-@end example
+@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)))
+   #})
 
-@noindent
-no funciona en LilyPond.  Podemos evitar este problema adjuntando la
-articulación a una nota de mentira,
+AltOff = {
+  \revert Stem.length
+  \revert NoteHead.font-size
+}
 
-@example
-@{ << \musica s1*0-.-> @}
-@end example
+\relative c' {
+  c2 \AltOn #0.5 c4 c
+  \AltOn #1.5 c c \AltOff c2
+}
+@end lilypond
 
 @noindent
-pero a los efectos de este ejemplo, aprenderemos ahora cómo hacerlo en
-Scheme.  Comenzamos examinando nuestra entrada y la salida deseada:
-
-@example
-%  entrada
-\displayMusic c4
-===>
-(make-music
-  'EventChord
-  'elements
-  (list (make-music
-          'NoteEvent
-          'duration
-          (ly:make-duration 2 0 1 1)
-          'pitch
-          (ly:make-pitch -1 0 0))))
-=====
-%  salida deseada
-\displayMusic c4->
-===>
-(make-music
-  'EventChord
-  'elements
-  (list (make-music
-          'NoteEvent
-          'duration
-          (ly:make-duration 2 0 1 1)
-          'pitch
-          (ly:make-pitch -1 0 0))
-        (make-music
-          'ArticulationEvent
-          'articulation-type
-          "marcato")))
-@end example
+Este ejemplo se puede reescribir de forma que pase expresiones
+musicales:
 
-Vemos que una nota (@code{c4}) se representa como una expresión
-@code{EventChord}, con una expresión @code{NoteEvent} en su lista de
-elementos.  Para añadir una articulación marcato, se debe añadir una
-expresión @code{ArticulationEvent} a la propiedad elementos de la
-expresión @code{EventChord}.
+@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
 
-Para construir esta función, empezamos con
 
-@example
-(define (add-marcato event-chord)
-  "Añadir una ArticulationEvent de marcato a los elementos de `event-chord',
-  que se supone que es una expresión EventChord."
-  (let ((result-event-chord (ly:music-deep-copy event-chord)))
-    (set! (ly:music-property result-event-chord 'elements)
-          (cons (make-music 'ArticulationEvent
-                  'articulation-type "marcato")
-                (ly:music-property result-event-chord 'elements)))
-    result-event-chord))
-@end example
+@node Funciones sin argumentos
+@subsection Funciones sin argumentos
+@translationof Functions without arguments
 
-La primera línea es la forma de definir una función en Scheme: el
-nombre de la función es @code{add-marcato}, y tiene una variable
-llamada @code{event-chord}.  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!).
+En casi todos los casos, una función sin argumentos se debe escribir
+con una variable:
 
 @example
-"Añadir una ArticulationEvent de marcato..."
+dolce = \markup@{ \italic \bold dolce @}
 @end example
 
-@noindent
-es una descripción de lo que hace la función.  No es estrictamente
-necesario, pero como los nombres de variable claros, es una buena
-práctica.
+Sin embargo, en raras ocasiones puede ser de utilidad crear una
+función musical sin argumentos:
 
 @example
-(let ((result-event-chord (ly:music-deep-copy event-chord)))
+mostrarNumeroDeCompas =
+#(define-music-function
+     (parser location)
+     ()
+   (if (eq? #t (ly:get-option 'display-bar-numbers))
+       #@{ \once \override Score.BarNumber.break-visibility = ##f #@}
+       #@{#@}))
 @end example
 
-@code{let} se usa para declarar variables locales.  Aquí usamos una
-variable local, llamada @code{result-event-chord}, a la que le damos
-el valor @code{(ly:music-deep-copy event-chord)}.
-@code{ly:music-deep-copy} es una función específica de LilyPond, como
-todas las funciones que comienzan por @code{ly:}.  Se usa para hacer
-una copia de una expresión musical.  Aquí, copiamos @code{event-chord}
-(el parámetro de la función).  Recuerde que el propósito es añadir un
-marcato a una expresión @code{EventChord}.  Es mejor no modificar el
-@code{EventChord} que se dio como argumento, porque podría utilizarse
-en algún otro lugar.
-
-Ahora tenemos un @code{result-event-chord}, que es una expresión
-@code{NoteEventChord} y es una copia de @code{event-chord}.  Añadimos
-el marcato a su propiedad lista de elementos.
+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
-(set! lugar valor-nuevo)
+lilypond -d display-bar-numbers ARCHIVO.ly
 @end example
 
-Aquí, lo que queremos establecer (el @q{lugar}) es la propiedad
-@q{elements} de la expresión @code{result-event-chord}.
 
-@example
-(ly:music-property result-event-chord 'elements)
-@end example
-
-@code{ly:music-property} es la función que se usa para acceder a las
-propiedades musicales (los @code{'elements}, @code{'duration},
-@code{'pitch}, etc., que vemos en la salida de @code{\displayMusic}
-más arriba).  El nuevo valor es la anterior propiedad elements, con un
-elemento adicional: la expresión @code{ArticulationEvent}, que
-copiamos a partir de la salida de @code{\displayMusic},
+@node Funciones musicales vacías
+@subsection Funciones musicales vacías
+@translationof Void music functions
 
-@example
-(cons (make-music 'ArticulationEvent
-        'articulation-type "marcato")
-      (ly:music-property result-event-chord 'elements))
-@end example
+Una función musical debe devolver una expresión musical.  Si quiere
+ejecutar una función exclusivamente por sus efectos secundarios,
+debería usar @code{define-void-function}.  Pero
+puede haber casos en los que a veces queremos producir una expresión
+musical, y a veces no (como en el ejemplo anterior).  Devolver una
+expresión musical @code{void} (vacía) por medio de @code{#@{ #@}} lo
+hace posible.
 
-@code{cons} se usa para añadir un elemento a una lista sin modificar
-la lista original.  Esto es lo que queremos: la misma lista que antes,
-más la nueva expresión @code{ArticulationEvent}.  El orden dentro de
-la propiedad elements no es importante aquí.
 
-Finalmente, una vez añadida la articulación marcato a su propiedad
-@code{elements}, podemos devolver @code{result-event-chord}, de aquí
-la última línea de la función.
+@node Funciones de eventos
+@section Funciones de eventos
+@translationof Event functions
+@funindex define-event-function
+@cindex event functions
 
-Ahora transformamos la función @code{add-marcato} en una función
-musical,
+Para usar una función musical en el lugar de un evento, tenemos que
+escribir un indicador de dirección antes de ella.  Pero a veces, ello
+hace que se pierda la correspondencia con la sintaxis de las
+construcciones que queremos sustituir.  Por ejemplo, si queremos
+escribir instrucciones de matiz dinámico, éstos se adjuntan
+habitualmente sin indicador de dirección, como @code{c'\pp}.  He aquí
+una forma de escribir indicaciones dinámicas arbitrarias:
 
-@example
-addMarcato = #(define-music-function (parser location event-chord)
-                                     (ly:music?)
-    "Añadir un ArticulationEvent de marcato a los elementos de `event-chord',
-    que se supone que es una expresión EventChord."
-    (let ((result-event-chord (ly:music-deep-copy event-chord)))
-      (set! (ly:music-property result-event-chord 'elements)
-            (cons (make-music 'ArticulationEvent
-                    'articulation-type "marcato")
-                  (ly:music-property result-event-chord 'elements)))
-      result-event-chord))
-@end example
+@lilypond[quote,verbatim,ragged-right]
+dyn=#(define-event-function (parser location arg) (markup?)
+         (make-dynamic-script arg))
+\relative c' { c\dyn pfsss }
+@end lilypond
 
-Podemos verificar que esta función musical funciona correctamente,
+Podríamos hacer lo mismo usando una función musical, pero entonces
+tendríamos que escribir siempre un indicador de dirección antes de
+llamarla, como @code{@w{c-\dyn pfsss}}.
 
-@example
-\displayMusic \addMarcato c4
-@end example
 
+@node Funciones de marcado
+@section Funciones de marcado
+@translationof Markup functions
 
-@node Interfaz de marcado para el programador
-@section Interfaz de marcado para el programador
-@translationof Markup programmer interface
+Los elementos de marcado están implementados como funciones de Scheme
+especiales que producen un objeto @code{Stencil} dada una serie de
+argumentos.
 
-Los marcados están implementados como funciones de Scheme especiales
-que producen un elemento Stencil (sello) dado un número de argumentos.
 
 @menu
-* Construcción del marcado en Scheme::
-* Cómo funciona internamente el marcado::
+* 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 del marcado en Scheme
-@subsection Construcción del marcado en Scheme
+@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
+@funindex \displayScheme
 
-El macro @code{markup} construye expresiones de marcado en Scheme,
-proporcionando una sintaxis similar a la de LilyPond.  Por ejemplo:
+Las expresiones de marcado se representan internamente en Scheme
+usando el macro @code{markup}:
 
 @example
-(markup #:column (#:line (#:bold #:italic "hola" #:raise 0.4 "mundo")
-                  #:larger #:line ("fulano" "fulanito" "menganito")))
+(markup @var{expr})
+@end example
+
+Para ver una expresión de marcado en su forma de Scheme, utilice
+la instrucción @code{\displayScheme}:
+
+@example
+\displayScheme
+\markup @{
+  \column @{
+    \line @{ \bold \italic "hola" \raise #0.4 "mundo" @}
+    \larger \line @{ fulano fulanito menganito @}
+  @}
+@}
 @end example
 
 @noindent
-equivale a:
+La compilación del código anterior envía a la consola lo
+siguiente:
+
 @example
-\markup \column @{ \line @{ \bold \italic "hola" \raise #0.4 "mundo" @}
-                  \larger \line @{ fulano fulanito menganito @} @}
+(markup
+  #:line
+  (#:column
+   (#:line
+    (#:bold (#:italic "hola") #:raise 0.4 "mundo")
+    #:larger
+    (#:line
+     (#:simple "fulano" #:simple "fulanito" #:simple "menganito")))))
 @end example
 
+Para evitar que el marcado se imprima en la página, use
+@w{@samp{\void \displayScheme @var{marcado}}}.  Asimismo, como
+ocurre con la instrucción @code{\displayMusic}, la salida de
+@code{\displayScheme} se puede guardar en un archivo externo.
+Véase @ref{Presentación de las expresiones musicales}.
+
 @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.
+Scheme.  La utilización de @code{#@{ @dots{} #@}} para escribir en la
+sintaxis de LilyPond será con frecuencia lo más conveniente, pero
+explicamos cómo usar la macro @code{markup} para obtener una solución
+sólo con 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{\markup @{ marcado1 marcado2 @dots{} @}} @tab
+        @code{(markup marcado1 marcado2 @dots{} )}
 @item @code{\instruccion} @tab @code{#:instruccion}
 @item @code{\variable} @tab @code{variable}
-@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )}
+@item @code{\center-column @{ @dots{} @}} @tab
+        @code{#:center-column ( @dots{} )}
 @item @code{cadena} @tab @code{"cadena"}
 @item @code{#argumento-de-scheme} @tab @code{argumento-de-scheme}
 @end multitable
@@ -925,12 +743,14 @@ Scheme.
 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}).
+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 pueden se una variable o el
+@code{#:center} y @code{#:column} no puede ser una variable ni el
 resultado de la llamada a una función.
 
 @lisp
@@ -946,8 +766,8 @@ no es válido.  Hay que usar las funciones @code{make-line-markup},
 @end lisp
 
 
-@node Cómo funciona internamente el marcado
-@subsection Cómo funciona internamente el marcado
+@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
@@ -979,235 +799,379 @@ 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}.
+@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
 
-Las instrucciones de marcado nuevas se pueden definir con el macro de
-Scheme @code{define-markup-command}.
+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{arg1-type?} @var{arg2-type?} ...)
-  ..command body..)
+(define-markup-command (@var{nombre-de-la-instruccion} @var{layout} @var{props} @var{arg1} @var{arg2} @dots{})
+    (@var{tipo-de-arg1?} @var{tipo-de-arg2?} @dots{})
+    [ #:properties ((@var{propiedad1} @var{valor-predeterminado1})
+                    @dots{}) ]
+  @dots{}command body@dots{})
 @end lisp
 
 Los argumentos son
 
-@table @var
-@item argi
-@var{i}-ésimo argumento de la instrucción
-@item argi-type?
-predicado de tipo para el argumento @var{i}-ésimo
+@table @code
+@item @var{nombre-de-la-instruccion}
+nombre de la instrucción de marcado
 @item layout
-la definición de @q{presentación}
+la definición de @q{layout} (disposición).
 @item props
-lista de listas asociativas, que contiene todas las propiedades
+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
 
-Como ejemplo sencillo, mostramos cómo añadir una instrucción
-@code{\smallcaps}, que selecciona una tipografía de versalitas.
-Normalmente podríamos seleccionar la tipografía de versalitas,
-
-@example
-\markup @{ \override #'(font-shape . caps) Texto-en-versalitas @}
-@end example
+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.
 
-@noindent
-Esto selecciona la tipografía de versalitas mediante el
-establecimiento de la propiedad @code{font-shape} a @code{#'caps} para
-la interpretación de @code{Texto-en-versalitas}.
+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
 
-Para poner lo anterior disponible como la instrucción
-@code{\smallcaps}, tenemos que definir una función utilizando
-@code{define-markup-command}.  La instrucción ha de tomar un argumento
-del tipo @code{markup}.  Por tanto, el inicio de la definición ha de
-ser
+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
+rendimiento 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.
+
+@funindex \markup
+@cindex markup macro
+@funindex interpret-markup
+Las instrucciones de marcado tienen un ciclo de vida más bien
+complejo.  El cuerpo de la definición de una instrucción de marcado es
+responsable de la conversión de los argumentos de la instrucción de
+marcado en una expresión de sello que se devuelve.  Muy a menudo esto
+se lleva a cabo llamando a la función @code{interpret-markup} sobre
+una expresión de marcado, pasándole los argumentos @var{layout} y
+@var{props}.  Por lo general, estos argumentos se conocen solamente en
+una fase muy tardía de la composición tipográfica.  Las expresiones de
+marcado ya tienen sus componentes ensamblados dentro de expresiones de
+marcado cuando se expanden las instrucciones @code{\markup} (dentro de
+una expresión de LilyPond) o la macro @code{markup} (dentro de
+Scheme).  La evaluación y la comprobación de tipos de los argumentos
+de la instrucción de marcado tiene lugar en el momento en que se
+interpretan @code{\markup} o @code{markup}.
+
+Pero la conversión real de expresiones de marcado en expresiones de
+sello mediante la ejecución de los cuerpos de función de marcado solo
+tienen lugar cuando se llama a @code{interpret-markup} sobre una
+expresión de marcado.
+
+@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
-(define-markup-command (smallcaps layout props argument) (markup?)
+(ly:output-def-lookup layout 'line-width)
 @end example
 
-@noindent
+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{Instrucciones de marcado
+de texto} nos muestra que es útil la instrucción @code{\box}:
 
-Lo que aparece a continuación es el contenido de la instrucción:
-debemos interpretar el @code{argument} como un marcado, es decir:
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \box HELLO
+@end lilypond
 
-@example
-(interpret-markup layout @dots{} argument)
-@end example
+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:
 
-@noindent
-Esta interpretación tiene que añadir @code{'(font-shape . caps)} a las
-propiedades activas, por lo que sustituimos lo siguiente por los
-@dots{} en el ejemplo anterior:
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \override #'(box-padding . 0.6) \box A
+@end lilypond
 
-@example
-(cons (list '(font-shape . caps) ) props)
-@end example
+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:
 
-@noindent
-La variable @code{props} es una lista de a-listas, y se lo anteponemos
-haciendo la operación cons de una lista con el ajuste adicional.
+@lilypond[quote,verbatim,ragged-right]
+\markup \override #'(box-padding . 0.4) \box
+     \override #'(box-padding . 0.6) \box A
+@end lilypond
 
-Supongamos que estamos tipografiando un recitativo de una ópera y nos
-gustaría definir una instrucción que presente los nombres de los
-personajes de una forma personalizada.  Queremos que los nombres se
-impriman con versalitas y se desplacen un poco a la izquierda y hacia
-arriba.  Definimos una instrucción @code{\character} que toma en
-cuenta la traslación necesaria y utiliza la instrucción
-@code{\smallcaps} recién definida:
+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.
 
-@example
-#(define-markup-command (character layout props nombre) (string?)
-  "Imprimir el nombre del personaje en versalitas, desplazado a la izquierda y hacia
-  arriba.  Sintaxis: \\character #\"nombre\""
+@lisp
+#(define-markup-command (double-box layout props text) (markup?)
+  "Trazar un rectángulo doble rodeando el texto."
   (interpret-markup layout props
-   (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps nombre)))
-@end example
+    #@{\markup \override #'(box-padding . 0.4) \box
+            \override #'(box-padding . 0.6) \box @{ #text @}#@}))
+@end lisp
 
-Esta es una complicación que requiere una explicación: los textos por
-encima y por debajo del pentagrama se mueven verticalmente de forma
-que estén a una cierta distancia (la propiedad @code{padding}) del
-pentagrama y de las notas.  Para asegurar que este mecanismo no anula
-el efecto de nuestro @code{#:translate}, añadimos una cadena vacía
-(@code{#:hspace 0}) antes del texto trasladado.  Ahora el
-@code{#:hspace 0} se pone encima de las notas, y el @code{nombre} se
-mueve en relación a dicha cadena vacía.  El efecto neto es que el
-texto se mueve hacia la izquierda y hacia arriba.
+o, de forma equivalente,
 
-El resultado final es como sigue:
+@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.  En el segundo caso, 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
-@{
-  c''^\markup \character #"Cleopatra"
-  e'^\markup \character #"Giulio Cesare"
-@}
+\markup \double-box A
 @end example
 
-@lilypond[quote,ragged-right]
-#(define-markup-command (smallcaps layout props str) (string?)
-  "Print the string argument in small caps.  Syntax: \\smallcaps #\"string\""
+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
-   (make-line-markup
-    (map (lambda (s)
-          (if (= (string-length s) 0)
-              s
-              (markup #:large (string-upcase (substring s 0 1))
-                      #:translate (cons -0.6 0)
-                      #:tiny (string-upcase (substring s 1)))))
-         (string-split str #\Space)))))
-
-#(define-markup-command (character layout props name) (string?)
-  "Print the character name in small caps, translated to the left and
-  top.  Syntax: \\character #\"name\""
+    #@{\markup \override #`(box-padding . ,inter-box-padding) \box
+               \override #`(box-padding . ,box-padding) \box
+               @{ #text @} #@}))
+@end lisp
+
+De nuevo, la versión equivalente que utiliza la macro de marcado sería:
+
+@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 #:hspace 0 #:translate (cons -3 1) #:smallcaps name)))
+    (markup #:override `(box-padding . ,inter-box-padding) #:box
+            #:override `(box-padding . ,box-padding) #:box text)))
+@end lisp
 
-{
-  c''^\markup \character #"Cleopatra" c'' c'' c''
-  e'^\markup \character #"Giulio Cesare" e' e' e'
-}
-@end lilypond
+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.
 
-Hemos usado la forma de fuente tipográfica @code{caps}, pero
-supongamos que nuestra fuente no tiene la variante de versalitas.  En
-ese caso tenemos que hacer una falsa fuente de mayúsculas pequeñas
-haciendo que la cadena en mayúsculas tenga la primera legra un poco
-mayor:
+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.
 
-@example
-#(define-markup-command (smallcaps layout props str) (string?)
-  "Print the string argument in small caps."
+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
-   (make-line-markup
-    (map (lambda (s)
-          (if (= (string-length s) 0)
-              s
-              (markup #:large (string-upcase (substring s 0 1))
-                      #:translate (cons -0.6 0)
-                      #:tiny (string-upcase (substring s 1)))))
-         (string-split str #\Space)))))
-@end example
+    #{\markup \override #`(box-padding . ,inter-box-padding) \box
+              \override #`(box-padding . ,box-padding) \box
+              { #text } #}))
 
-La instrucción @code{smallcaps} primero divide su argumento de cadena
-en unidades o palabras separadas por espacios (@code{(string-split str
-#\Space)}); para cada unidad o palabra, se construye un marcado con la
-primera letra agrandada y en mayúscula (@code{#:large (string-upcase
-(substring s 0 1))}), y un segundo marcado construido con las letras
-siguientes reducidas de tamaño y en mayúsculas (@code{#:tiny
-(string-upcase (substring s 1))}).  Como LilyPond introduce un espacio
-entre los marcados de una misma línea, el segundo marcado se traslada
-a la izquierda (@code{#:translate (cons -0.6 0) ...}).  Después, los
-marcados construidos para cada palabra se ponen en una línea mediante
-@code{(make-line-markup ...)}.  Finalmente, el marcado resultante se
-pasa a la función @code{interpret-markup}, con los argumentos
-@code{layout} y @code{props}.
-
-Nota: ahora existe una instrucción interna @code{\smallCaps} que se
-puede usar para poner texto en versalitas.  Consulte @ref{Text markup commands}, para ver más detalles.
+\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
 
-@knownissues
 
-Actualmente las combinaciones de argumentos que hay disponibles
-(después de los argumentos estándar @var{layout} y @var{props}) para
-una instrucción de marcado definida con @code{define-markup-command}
-se limitan a la siguiente lista:
-
-@table @asis
-@item (ningún argumento)
-@itemx @var{list}
-@itemx @var{markup}
-@itemx @var{markup markup}
-@itemx @var{scm}
-@itemx @var{scm markup}
-@itemx @var{scm scm}
-@itemx @var{scm scm markup}
-@itemx @var{scm scm markup markup}
-@itemx @var{scm markup markup}
-@itemx @var{scm scm scm}
-@end table
+@node Adaptación de instrucciones incorporadas
+@unnumberedsubsubsec Adaptación de instrucciones incorporadas
+@translationof Adapting builtin commands
 
-@noindent
-En la tabla de arriba, @var{scm} representa los tipos de datos nativos
-de Scheme como @q{number} (número) o @q{string} (cadena).
+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}.
 
-Como ejemplo, no es posible usar una instrucción de marcado
-@code{fulanito} con cuatro argumentos definida como
+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):
 
-@example
-#(define-markup-command (fulanito layout props
-                         num1    str1    num2    str2)
-                        (number? string? number? string?)
-  ...)
-@end example
+@lisp
+(define-markup-command (draw-line layout props dest)
+  (number-pair?)
+  #:category graphic
+  #:properties ((thickness 1))
+  "@dots{}documentación@dots{}"
+  (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
 
-@noindent
-Si la aplicamos como, digamos,
+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.
 
-@example
-\markup \fulanito #1 #"mengano" #2 #"zutano"
-@end example
+@lisp
+(define-markup-command (draw-double-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1))
+  "@dots{}documentación@dots{}"
+  (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
 
-@cindex Scheme signature
-@cindex signature, Scheme
-@noindent
-@command{lilypond} protesta diciendo que no puede analizar
-@code{fulanito} debido a su firma de Scheme desconocida.
+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))
+  "@dots{}documentación@dots{}"
+  @dots{}
+@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
 
+@funindex define-markup-list-command
+@funindex interpret-markup-list
+
 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.
+@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,
@@ -1216,10 +1180,19 @@ del argumento @code{props}.
 
 @example
 #(define-markup-list-command (paragraph layout props args) (markup-list?)
-   (let ((indent (chain-assoc-get 'par-indent props 2)))
-     (interpret-markup-list layout props
-       (make-justified-lines-markup-list (cons (make-hspace-markup indent)
-                                               args)))))
+   #:properties ((par-indent 2))
+   (interpret-markup-list layout props
+     #@{\markuplist \justified-lines @{ \hspace #par-indent #args @} #@}))
+@end example
+
+
+La versión que usa solamente Scheme es más compleja:
+@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
@@ -1231,17 +1204,17 @@ 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
+justificadas usando la instrucción incorporada de lista de marcados
+@code{\justified-lines}, que está relacionada con la función
+@code{make-justified-lines-markup-list}.  Se añade un espacio
+horizontal al principio usando @code{\hspace} (o 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 @{
+\markuplist @{
   \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.
@@ -1281,7 +1254,7 @@ de Scheme.  La sintaxis para esto es
 \applyContext @var{función}
 @end example
 
-@var{función} debe ser una función de Scheme que toma un único
+@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:
@@ -1298,24 +1271,25 @@ la compilació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}.  Su sintaxis es
+@code{\applyOutput}, que
+funciona insertando un evento dentro del contexto especificado
+(@rinternals{ApplyOutputEvent}).  Su sintaxis es
 
 @example
-\applyOutput @var{contexto} @var{proc}
+\applyOutput @var{Contexto} @var{proc}
 @end example
 
 @noindent
-donde @var{proc} es una función de Scheme, que toma tres argumentos.
+donde @code{@var{proc}} es una función de Scheme que toma tres argumentos.
 
-Al interpretarse, la función @var{proc} se llama para cada objeto de
-presentación que se encuentra en el contexto @var{contexto}, con los
-siguientes 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,
@@ -1323,43 +1297,52 @@ siguientes argumentos:
 @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
-@rinternals{Stem} (plica), éste es un objeto @rinternals{Stem}.
-@c Impossible - changed to Stem --FV
+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:
+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))
-            (eq? (ly:grob-property grob 'staff-position) 0))
+            (< (abs (ly:grob-property grob 'staff-position)) 2))
        (set! (ly:grob-property grob 'transparent) #t)))
 
-\relative {
-  e4 g8 \applyOutput #'Voice #blanker b d2
+\relative c' {
+  a'4 e8 <<\applyOutput #'Voice #blanker a c d>> b2
 }
 @end lilypond
 
+Para que @var{función} se interprete en los niveles de @code{Score} o de @code{Staff}
+utilice estas formas:
 
-@node Procedimientos de Scheme como propiedades
-@section Procedimientos de Scheme como propiedades
-@translationof Scheme procedures as properties
+@example
+\applyOutput #'Score #@var{función}
+\applyOutput #'Staff #@var{función}
+@end example
 
-Las propiedades (como el grosor, la dirección, etc.) se pueden
-establecer a valores fijos con \override, p. ej.
+
+@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
+\override Stem.thickness = #2.0
 @end example
 
-Las propiedades pueden fijarse también a un procedimiento de scheme,
+Las propiedades pueden fijarse también a un procedimiento de Scheme,
 
 @lilypond[fragment,verbatim,quote,relative=2]
-\override Stem #'thickness = #(lambda (grob)
+\override Stem.thickness = #(lambda (grob)
     (if (= UP (ly:grob-property grob 'direction))
         2.0
         7.0))
@@ -1391,7 +1374,7 @@ puede insertar con una cerradura de grob.  He aquí un ajuste
 procedente de @code{AccidentalSuggestion},
 
 @example
-(X-offset .
+`(X-offset .
   ,(ly:make-simple-closure
     `(,+
         ,(ly:make-simple-closure
@@ -1421,16 +1404,25 @@ 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 Usar código de Scheme en lugar de \tweak
-@section Usar código de Scheme en lugar de @code{\tweak}
-@translationof Using Scheme code instead of \tweak
+@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.
+sintáctica.  Por ejemplo, lo siguiente produce un error de sintaxis (o
+más bien: así lo hacía en algún momento del pasado):
 
 @example
-F = \tweak #'font-size #-3 -\flageolet
+F = \tweak font-size #-3 -\flageolet
 
 \relative c'' @{
   c4^\F c4_\F
@@ -1438,13 +1430,10 @@ F = \tweak #'font-size #-3 -\flageolet
 @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 articulación a las notas (ejemplo)},
-especialmente cómo usar @code{\displayMusic} como guía de ayuda.
+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
@@ -1468,6 +1457,7 @@ 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
@@ -1476,6 +1466,7 @@ 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,
@@ -1515,31 +1506,33 @@ arriba.
 
 @lilypond[quote,verbatim,ragged-right]
 #(define (my-callback grob)
-  (let* (
-         ; have we been split?
-         (orig (ly:grob-original 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 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)))))
+     (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 =
+  \override Tie.after-line-breaking =
   #my-callback
-  c1 ~ \break c2 ~ c
+  c1 ~ \break
+  c2 ~ 2
 }
 @end lilypond
 
 @noindent
 Al aplicar este truco, la nueva función de callback
-@code{after-line-breaking} también debe llamar a la antigua
-@code{after-line-breaking}, si existe.  Por ejemplo, si se usa con
+@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:hairpin::after-line-breaking}.
+@code{ly:spanner::kill-zero-spanned-time}.
 
 
 @item Algunos objetos no se pueden cambiar con @code{\override} por
@@ -1550,9 +1543,10 @@ razones técnicas.  Son ejemplos @code{NonMusicalPaperColumn} y
 
 @example
 \overrideProperty
-#"Score.NonMusicalPaperColumn"  % Nombre del grob
-#'line-break-system-details     % Nombre de la propiedad
-#'((next-padding . 20))         % Valor
+Score.NonMusicalPaperColumn      % Nombre del grob
+  . line-break-system-details    % Nombre de la propiedad
+  . next-padding                 % Nombre de la subpropiedad, opcional
+  #20                            % Valor
 @end example
 
 Observe, sin embargo, que @code{\override}, aplicado a
@@ -1566,4 +1560,8 @@ como se espera dentro de los bloques @code{\context}.
 @chapter Interfaces de Scheme de LilyPond
 @translationof LilyPond Scheme interfaces
 
-@untranslated
+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