]> git.donarmstrong.com Git - lilypond.git/blobdiff - Documentation/es/extending/programming-interface.itely
Doc-es: update Extending/Programming.
[lilypond.git] / Documentation / es / extending / programming-interface.itely
index ad66d172cf708624cd60b893ed580f1af3874f5e..b2552e8eb6c0a94c38ba70a587f12d002dc0c364 100644 (file)
 @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: 708aa920d682cf9aa3ed647cd129afd8509760f4
 
     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.24"
 
 @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, @rlearning{Tutorial de Scheme}.
+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
+* 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::
 * 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::
-* Panorá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.
+He aquí un ejemplo trivial:
 
+@lilypond[verbatim,quote]
+ritpp = #(define-event-function () ()
+  #{ ^"rit." \pp #}
+)
 
-@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
-
-También se pueden sustituir las expresiones musicales:
-
-@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{#}.
+
+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{\}.
+
+Toda la música generada dentro del bloque de código tiene su
+@samp{origin} establecido a la localización actual del puntero de
+entrada.
+
+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
+     (@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{@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} a la ubicación actual del
+cursor de entrada.
+
+@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.
-
-@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.
-@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:
+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.
+
+LilyPond resuelve algunas 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
+siguen inmediatamente, cambian dicha interpretación.  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.
+
+Por conveniencia, las funciones de Scheme también se pueden
+llamar directamente desde Scheme, puenteando al analizador
+sintáctico de LilyPond.  Su nombre puede utilizarse como el
+nombre de una función corriente.  La comprobación de tipo de los
+argumentos y el salto de los argumentos opcionales tiene lugar de
+la misma forma que cuando se llama desde dentro de LilyPond,
+tomando el valor de Scheme @code{*unspecified*} el papel de la
+palabra reservada @code{\default} para saltar explícitamente
+argumentos opcionales.
+
+@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
-displayBarNum =
-#(define-music-function (parser location) ()
-   (if (eq? #t (ly:get-option 'display-bar-numbers))
-       #@{ \once \override Score.BarNumber #'break-visibility = ##f #@}
-       #@{#@}))
+noApuntarYPulsar =
+#(define-void-function
+     ()
+     ()
+   (ly:set-option 'point-and-click #f))
+@dots{}
+\noApuntarYPulsar   % desactivar la función de apuntar y pulsar
 @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 Panorámica de las funciones musicales disponibles
-@subsection Panorá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}.
-
-@example
-traLaLa = @{ c'4 d'4 @}
-@end example
 
-@noindent
+@node Definiciones de funciones musicales
+@subsection Definiciones de funciones musicales
+@translationof Music function definitions
+@cindex definición de funciones musicales
+@funindex define-music-function
 
-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
+     (@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
+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}.
 
-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}:
+Para ver una lista de los predicados de tipo disponibles,
+consulte @ruser{Predicados de tipo predefinidos}.
 
-@lilypond[verbatim]
-traLaLa = { c'4 d'4 }
+@seealso
 
-%% dummy action to deal with parser lookahead
-#(display "this needs to be here, sorry!")
+Referencia de la notación:
+@ruser{Predicados de tipo predefinidos}.
 
-#(define newLa (map ly:music-deep-copy
-  (list traLaLa traLaLa)))
-#(define twice
-  (make-sequential-music newLa))
+Archivos de inicio:
+@file{lily/music-scheme.cc},
+@file{scm/c++.scm},
+@file{scm/lily.scm}.
 
-{ \twice }
-@end lilypond
-
-@c Due to parser lookahead
-
-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.
-
-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
-
-@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
-
-@example
-#(define (nopc)
-  (ly:set-option 'point-and-click #f))
-
-...
-#(nopc)
-@{ c'4 @}
-@end example
-
-@knownissues
-
-No es posible mezclar variables de Scheme y de LilyPond con la opción
-@code{--safe}.
 
+@node Uso de las funciones musicales
+@subsection Uso de las funciones musicales
+@translationof Music function usage
 
-@node Representación interna de la música
-@subsection Representación interna de la música
-@translationof Internal music representation
+Una @q{función musical} debe devolver una expresión que se
+corresponda con el predicado @code{ly:music?}.  Esto hace que las
+llamadas a funciones musicales sean aproopiadas como argumentos
+del tipo @code{ly:music?} para otra llamada a una función
+musical.
 
-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.
+Si se usa una llamada a función musical dentro de otros
+contextos, el contexto puede aplicar restricciones semánticas
+adicionales.
 
-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 no se acepta
+ningún post-evento.
 
 @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}.
+Cuando una función musical (a diferencia de una función de
+evento) devuelve una expresión del tipo post-event, LilyPond
+requiere uno de los indicadores de dirección con nombre
+(@code{-}, @code{^}, @w{y @code{_}}) para poder integrar
+adecuadamente el post-evento producido por la llamada a la
+función musical dentro de la expresión circundante.
 
 @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:
-
-@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.
+Se pueden aplicar funciones @q{polimórficas}, como @code{\tweak},
+a los post-eventos, componentes de acordes y expresiones
+musicales del nivel superior.
 
-@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
+     (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
+     (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 valor
+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 (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
+     (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'2 \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:
+Este ejemplo se puede reescribir de forma que pase expresiones
+musicales:
 
-@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
+@lilypond[quote,verbatim,ragged-right]
+withAlt =
+#(define-music-function
+     (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
+   #})
 
-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}.
+\relative {
+  c'2 \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
+     ()
+     ()
+   (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 (arg) (markup?)
+         (make-dynamic-script arg))
+\relative { 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
+
+Las expresiones de marcado se representan internamente en Scheme
+usando el macro @code{markup}:
+
+@example
+(markup @var{expr})
+@end example
 
-El macro @code{markup} construye expresiones de marcado en Scheme,
-proporcionando una sintaxis similar a la de LilyPond.  Por ejemplo:
+Para ver una expresión de marcado en su forma de Scheme, utilice
+la instrucción @code{\displayScheme}:
 
 @example
-(markup #:column (#:line (#:bold #:italic "hola" #:raise 0.4 "mundo")
-                  #:larger #:line ("fulano" "fulanito" "menganito")))
+\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.
+Este ejemplo muestra las principales reglas de traducción entre
+la sintaxis del marcado normal de LilyPond y la sintaxis del
+marcado de 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
 @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}).
+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 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
@@ -938,16 +756,17 @@ resultado de la llamada a una función.
 @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:
+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 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
@@ -975,273 +794,439 @@ sellos), se llama la función @code{raise-markup} como
        @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}.
+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
 
-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}:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \box HELLO
+@end lilypond
 
-Lo que aparece a continuación es el contenido de la instrucción:
-debemos interpretar el @code{argument} como un marcado, es decir:
+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:
 
-@example
-(interpret-markup layout @dots{} argument)
-@end example
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \override #'(box-padding . 0.6) \box A
+@end lilypond
 
-@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:
+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:
 
-@example
-(cons (list '(font-shape . caps) ) props)
-@end example
+@lilypond[quote,verbatim,ragged-right]
+\markup \override #'(box-padding . 0.4) \box
+     \override #'(box-padding . 0.6) \box A
+@end lilypond
 
-@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.
+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
 
-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:
+o, de forma equivalente,
 
-@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.
+@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.
 
-El resultado final es como sigue:
+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 bueno 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, 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
+     #@{\markuplist \justified-lines @{ \hspace #par-indent #args @} #@}))
+@end example
 
-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}.
 
+La versión que usa solamente Scheme es más compleja:
 @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
+     (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:
+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 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.
@@ -1273,49 +1258,172 @@ Esta nueva instrucción de lista de marcados se puede usar como sigue:
 
 @cindex código, llamadas durante la interpretación
 @funindex \applyContext
+@funindex make-apply-context
+@funindex ly:context-property
+@funindex ly:context-set-property!
+@funindex ly:context-grob-definition
+@funindex ly:assoc-get
+@funindex ly:context-pushpop-property
 
-Se pueden modificar los contextos durante la interpretación con código
-de Scheme.  La sintaxis para esto es
+Se pueden modificar los contextos durante la interpretación con
+código de Scheme.  Dentro de un bloque de código de LilyPond, la
+sintaxis para esto es:
 
 @example
 \applyContext @var{función}
 @end example
 
-@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:
+En código de Scheme, la sintaxis es:
 
 @example
-\applyContext
-  #(lambda (x)
-    (format #t "\nSe nos ha llamado en el compás número ~a.\n"
-     (ly:context-property x 'currentBarNumber)))
+(make-apply-context @var{function})
 @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.  La función
+puede acceder a, así como sobreescribir u establecer propiedades
+de grobs s y propiedades de contextos.  Cualquier acción tomada
+por la función que dependa del estado del contexto, está limitada
+al estado del contexto @emph{en el momento de llamar a la
+función}.  Asimismo, los cambios efectuados por una llamada a
+@code{\applyContext} permanecen en efecto hasta que se modifican
+de nuevo directamente, o se revierten, incluso si han cambiado las
+condiciones iniciales sobre las que dependen.
+
+Las siguientes funciones de Scheme son útiles cuando se utiliza
+@code{\applyContext}:
+
+@table @code
+@item ly:context-property
+recuperar el valor de una propiedad de contexto
+
+@item ly:context-set-property!
+establecer el valor de una propiedad de contexto
+
+@item ly:context-grob-definition
+@itemx ly:assoc-get
+recuperar el valor de una propiedad de un grob
+
+@item ly:context-pushpop-property
+hacer una sobreescritura temporal
+(@code{\temporary@tie{}\override}) o una reversión
+(@code{\revert}) sobre una propiedad de un grob
+@end table
+
+El ejemplo siguiente recupera el valor actual de @code{fontSize},
+y a continuación lo dobla:
+
+@lilypond[quote,verbatim]
+doubleFontSize =
+\applyContext
+  #(lambda (context)
+     (let ((fontSize (ly:context-property context 'fontSize)))
+       (ly:context-set-property! context 'fontSize (+ fontSize 6))))
+
+{
+  \set fontSize = -3
+  b'4
+  \doubleFontSize
+  b'
+}
+@end lilypond
+
+
+El ejemplo siguiente recupera los colores actuales de los grobs
+@code{NoteHead}, @code{Stem} y @code{Beam}, y a continuación los
+modifica para que tengan un matiz menos saturado.
+
+@lilypond[quote,verbatim]
+desaturate =
+\applyContext
+  #(lambda (context)
+     (define (desaturate-grob grob)
+       (let* ((grob-def (ly:context-grob-definition context grob))
+              (color (ly:assoc-get 'color grob-def black))
+              (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color)))
+         (ly:context-pushpop-property context grob 'color new-color)))
+     (for-each desaturate-grob '(NoteHead Stem Beam)))
+
+\relative {
+  \time 3/4
+  g'8[ g] \desaturate g[ g] \desaturate g[ g]
+  \override NoteHead.color = #darkred
+  \override Stem.color = #darkred
+  \override Beam.color = #darkred
+  g[ g] \desaturate g[ g] \desaturate g[ g]
+}
+@end lilypond
+
+
+Esto puede implementarse también como una función musical, con el
+objeto de restringir las modificaciones a un único bloque de
+música.  Observe cómo se usa @code{ly:context-pushpop-property}
+tanto como una sobreescritura temporal
+(@code{\temporary@tie{}\override}) como una reversión
+(@code{\revert}):
+
+@lilypond[quote,verbatim]
+desaturate =
+#(define-music-function
+   (music) (ly:music?)
+   #{
+     \applyContext
+     #(lambda (context)
+        (define (desaturate-grob grob)
+          (let* ((grob-def (ly:context-grob-definition context grob))
+                 (color (ly:assoc-get 'color grob-def black))
+                 (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color)))
+            (ly:context-pushpop-property context grob 'color new-color)))
+        (for-each desaturate-grob '(NoteHead Stem Beam)))
+     #music
+     \applyContext
+     #(lambda (context)
+        (define (revert-color grob)
+          (ly:context-pushpop-property context grob 'color))
+        (for-each revert-color '(NoteHead Stem Beam)))
+   #})
+
+\relative {
+  \override NoteHead.color = #darkblue
+  \override Stem.color = #darkblue
+  \override Beam.color = #darkblue
+  g'8 a b c
+  \desaturate { d c b a }
+  g b d b g2
+}
+@end lilypond
+
 
 @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}.  Su sintaxis es
+@code{\applyOutput}, que funciona insertando un evento dentro del
+contexto especificado (@rinternals{ApplyOutputEvent}).  Su
+sintaxis es o bien
 
 @example
-\applyOutput @var{contexto} @var{proc}
+\applyOutput @var{Contexto} @var{proc}
+@end example
+
+o bien
+
+@example
+\applyOutput @var{Context}.@var{Grob} @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 (con el nombre del grob @var{Grob} si se
+especifica) 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,52 +1431,62 @@ 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
+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:
+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))
+   (if (< (abs (ly:grob-property grob 'staff-position)) 2)
        (set! (ly:grob-property grob 'transparent) #t)))
 
 \relative {
-  e4 g8 \applyOutput #'Voice #blanker b d2
+  a'4 e8 <<\applyOutput Voice.NoteHead #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:
+
+@example
+\applyOutput Score@dots{}
+\applyOutput Staff@dots{}
+@end example
+
 
-@node Procedimientos de Scheme como propiedades
-@section Procedimientos de Scheme como propiedades
-@translationof Scheme procedures as properties
+@node Funciones de callback
+@section Funciones de callback
+@translationof Callback functions
 
-Las propiedades (como el grosor, la dirección, etc.) se pueden
-establecer a valores fijos con \override, p. ej.
+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)
+@lilypond[fragment,verbatim,quote]
+\override Stem.thickness = #(lambda (grob)
     (if (= UP (ly:grob-property grob 'direction))
         2.0
         7.0))
-c b a g b a g b
+\relative { 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.
+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
@@ -1383,68 +1501,60 @@ Casi todo el motor de tipografiado está manejado por estos
   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).
+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},
+Dicho procedimiento puede acceder al valor usual de la propiedad,
+llamando en primer lugar a la función que es el @q{callback} usual
+para esa propiedad, y que puede verse en el manual de referencia
+interna o en el archivo 'define-grobs.scm':
 
 @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)))))
+\relative @{
+  \override Flag.X-offset = #(lambda (flag)
+    (let ((default (ly:flag::calc-x-offset flag)))
+      (* default 4.0)))
+  c''4. d8 a4. g8
+@}
 @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
+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
-(ly:make-simple-closure (ly:make-simple-closure (list @var{proc})))
+mi-callback = #(lambda (grob)
+                 (grob-interpret-markup grob (markup "fulanito")))
 @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}.
+@ignore
+
+@n ode Código de Scheme en línea
+@s ection Código de Scheme en línea
+@t ranslationof Inline Scheme code
 
+TODO: after this section had been written, LilyPond has improved
+to the point that finding a @emph{simple} example where one would
+@emph{have} to revert to Scheme has become rather hard.
 
-@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
+Until this section gets a rewrite, let's pretend we don't know.
 
 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
+\relative @{
+  c''4^\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 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
@@ -1454,8 +1564,8 @@ F = #(let ((m (make-music 'ArticulationEvent
                     (ly:music-property m 'tweaks)))
        m)
 
-\relative c'' @{
-  c4^\F c4_\F
+\relative @{
+  c''4^\F c4_\F
 @}
 @end example
 
@@ -1468,6 +1578,9 @@ 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}.
 
+@end ignore
+
+
 @node Trucos difíciles
 @section Trucos difíciles
 @translationof Difficult tweaks
@@ -1476,20 +1589,22 @@ 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.
+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}
+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
@@ -1509,50 +1624,53 @@ comprueba si somos el último de los objetos divididos
 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.
+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))
+   (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 =
+\relative {
+  \override Tie.after-line-breaking =
   #my-callback
-  c1 ~ \break c2 ~ c
+  c''1 ~ \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
 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.
+@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
+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 +1684,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