]> git.donarmstrong.com Git - lilypond.git/commitdiff
Doc-es: update of Programming Interfaces.
authorFrancisco Vila <francisco.vila@hispalinux.es>
Sat, 27 Feb 2010 17:39:05 +0000 (18:39 +0100)
committerFrancisco Vila <francisco.vila@hispalinux.es>
Sat, 27 Feb 2010 19:12:24 +0000 (20:12 +0100)
Documentation/es/extending/programming-interface.itely

index d175bda285d67905f47a8240bc33f755e6c1023c..f08d2650ad41216604d1544a3f4170e20626b733 100644 (file)
@@ -1,11 +1,10 @@
 @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: 3dd778f33e8681d58716b08e52a167ce5347aa84
 
     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"
 
 Se pueden realizar trucos avanzados mediante el uso de Scheme.  Si no
 está familiarizado con Scheme, le conviene leer nuestro tutorial de
-Scheme, @rlearning{Tutorial de Scheme}.
+Scheme, @ref{Tutorial de Scheme}.
+
 
 @menu
 * Funciones musicales::
-* Interfaces para el programador::
-* Interfaz de marcado para el programador::
+* Funciones de marcado::
 * Contextos para programadores::
-* Procedimientos de Scheme como propiedades::
-* Usar código de Scheme en lugar de \tweak::
+* Funciones de callback::
+* Código de Scheme en línea::
 * Trucos difíciles::
 @end menu
 
-
 @node Funciones musicales
 @section Funciones musicales
 @translationof Music functions
 
-Esta sección trata sobre cómo crear funciones musicales dentro de
-LilyPond.
+Las funciones musicales son funciones de Scheme que se utilizan para
+crear automáticamente expresiones musicales.  Se pueden usar para
+simplificar enormemente el archivo de entrada.
 
 @menu
-* Panorámica de las funciones musicales::
+* Sintaxis de las funciones musicales::
 * Funciones de sustitución sencillas::
-* Funciones de sustitutión en parejas::
+* Funciones de sustitución intermedias::
 * 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
+@node Sintaxis de las funciones musicales
+@subsection Sintaxis de las funciones musicales
+@translationof Music function syntax
 
-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 sintaxis general de una función musical es:
 
 @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...}
-  #@})
+miFuncion =
+#(define-music-function (parser location @var{var_1} @var{var_2}...@var{var_n})
+                        (@var{var_1-type?} @var{var_2-type?}...@var{var_n-type?})
+    @var{...expresión musical válida...})
 @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.
+@item @var{var_i}         @tab @var{i}-ésima variable
+@item @var{var_i-type?}   @tab tipo de la @var{i}-ésima variable
+@item @var{...expresión musical válida...}  @tab expresión que devuelve
+música válida, generalmente en la forma de una expresión de Scheme.
+También hay una sintaxis especial que permite la existencia de código
+de entrada de LilyPond dentro de esta expresión musical.
 @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.
+Los comprobadores de tipo de variable son procedimientos de Scheme que
+devuelven @code{#t} si una variable es de un tipo dado.  Se muestran
+algunos tipos comunes en la tabla de abajo.  Hay más tipos en los
+archivos @file{lily/music-scheme.cc} y @file{scm/c++.scm}.
 
 @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?}
+@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.
+Los argumentos @code{parser} y @code{location} son obligatorios.  El
+argumento @code{parser} se usa en el cuerpo de la función 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 se construye por parte de la función musical, de forma que
+en caso de un error de sintaxis LilyPond pueda comunicar al usuario el
+lugar adecuado del archivo de entrada en que buscar.
 
 
 @node Funciones de sustitución sencillas
 @subsection Funciones de sustitución sencillas
 @translationof Simple substitution functions
 
-He aquí un ejemplo sencillo:
+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, pero
+con una variable de entrada sustituida en el código de LilyPond.  La
+forma general de estas funciones es:
+
+@example
+miFuncion =
+#(define-music-function (parser location @var{var1})
+                        (@var{var1-type?})
+  #@{
+    @emph{... código de entrada de LilyPond con} @code{#$var1} @emph{para sustituir ...}
+  #@})
+@end example
+
+Observe que los caracteres especiales @code{#@{} y @code{#@}}
+encierran la música de LilyPond.
+
+@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 código de entrada normal de LilyPond, que utiliza variables como @code{#$var1}, etc.
+@end multitable
+
+Por ejemplo, se puede definir una función que simplifique el
+establecimiento de un relleno para un guión de texto TextScript:
 
 @lilypond[quote,verbatim,ragged-right]
 padText = #(define-music-function (parser location padding) (number?)
@@ -116,7 +138,8 @@ padText = #(define-music-function (parser location padding) (number?)
 }
 @end lilypond
 
-También se pueden sustituir las expresiones musicales:
+Además de números, podemos usar expresiones musicales, como por
+ejemplo notas, como argumentos de las funciones musicales:
 
 @lilypond[quote,verbatim,ragged-right]
 custosNote = #(define-music-function (parser location note)
@@ -129,55 +152,42 @@ custosNote = #(define-music-function (parser location note)
     \once \override Voice.Stem #'stencil = ##f
     $note
   #})
-
-{ c' d' e' f' \custosNote g' }
 @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
+@node Funciones de sustitución intermedias
+@subsection Funciones de sustitución intermedias
+@translationof Intermediate substitution functions
 
+Algo más complicadas que las funciones de sustitución sencillas, 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.
 
-@node Funciones de sustitutión en parejas
-@subsection Funciones de sustitutión en parejas
-@translationof Paired substitution functions
+Algunas instrucciones @code{\override} requieren un argumento que
+consiste en una pareja de números (llamada una @code{célula cons} en
+Scheme).
 
-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 pareja se puede pasar directamente dentro de la función musical,
+usando una variable @code{pair?}:
 
 @quotation
 @example
-manualBeam =
-#(define-music-function (parser location beg-end)
+barraManual =
+#(define-music-function (parser location principio-final)
                         (pair?)
 #@{
-  \once \override Beam #'positions = #$beg-end
+  \once \override Beam #'positions = #$principio-final
 #@})
 
 \relative @{
-  \manualBeam #'(3 . 6) c8 d e f
+  \barraManual #'(3 . 6) c8 d e f
 @}
 @end example
 @end quotation
 
-@noindent
-o bien
+De forma alternativa, los números que componen la pareja se pueden
+pasar como argumentos separados, y el código de Scheme que se ha usado
+para crear la pareja se puede incluir dentro de la expresión musical:
 
 @lilypond[quote,verbatim,ragged-right]
 manualBeam =
@@ -250,12 +260,12 @@ musical vacía es el proceso realizado por la función, no la expresión
 musical que se devuelve.
 
 @example
-noPointAndClick =
+noApuntarYPulsar =
 #(define-music-function (parser location) ()
    (ly:set-option 'point-and-click #f)
    (make-music 'SequentialMusic 'void #t))
 ...
-\noPointAndClick   % desactivar la funcionalidad Apuntar y Pulsar.
+\noApuntarYPulsar   % desactivar la funcionalidad Apuntar y Pulsar.
 @end example
 
 
@@ -274,7 +284,7 @@ Sin embargo, en raras ocasiones puede ser de utilidad crear una
 función musical sin argumentos:
 
 @example
-displayBarNum =
+mostrarNumeroDeCompas =
 #(define-music-function (parser location) ()
    (if (eq? #t (ly:get-option 'display-bar-numbers))
        #@{ \once \override Score.BarNumber #'break-visibility = ##f #@}
@@ -289,195 +299,24 @@ lilypond -d display-bar-numbers ARCHIVO.ly
 @end example
 
 
-@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 Interfaces para el programador
-@section Interfaces para el programador
-@translationof Programmer interfaces
-
-Esta sección contiene información sobre cómo mezclar LilyPond y
-Scheme.
-
-@menu
-* Variables de entrada y Scheme::
-* Representación interna de la música::
-@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
-
-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.
-
-@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 @}
-@end example
-
-@noindent
-se convierte internamente a una definición de Scheme
-@example
-(define traLaLa @var{Scheme value of `@code{... }'})
-@end example
-
-Esto supone que las variables de entrada y las variables de Scheme se
-pueden entremezclar con libertad.  En el ejemplo siguiente, se
-almacena un fragmento musical en la variable @code{traLaLa}, y se
-duplica utilizando Scheme.  El resultado se importa en un bloque
-@code{\score} por medio de una segunda variable @code{twice}:
-
-@lilypond[verbatim]
-traLaLa = { c'4 d'4 }
-
-%% dummy action to deal with parser lookahead
-#(display "this needs to be here, sorry!")
-
-#(define newLa (map ly:music-deep-copy
-  (list traLaLa traLaLa)))
-#(define twice
-  (make-sequential-music newLa))
-
-{ \twice }
-@end lilypond
-
-@c Due to parser lookahead
-
-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 Representación interna de la música
-@subsection Representación interna de la música
-@translationof Internal music representation
-
-Cuando se analiza sintácticamente una expresión musical, se convierte
-en un conjunto de objetos musicales de Scheme.  La propiedad que
-define a un objeto musical es que tiene una cierta duración.  El
-tiempo es un número racional que mide la longitud de un fragmento de
-música en unidades del valor de una redonda.
-
-Un objeto musical tiene tres clases de tipos:
-@itemize
-@item
-nombre musical: cada expresión musical tiene un nombre.  Por ejemplo,
-una nota conduce a un evento @rinternals{NoteEvent}, y
-@code{\simultaneous} conduce a @rinternals{SimultaneousMusic}.  Hay
-una lista de todas las expresiones que están disponibles en el Manual
-de referencia de funcionamiento interno, bajo @rinternals{Music
-expressions}.
-
-@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}.
-
-@item
-Objeto de C++: cada objeto musical está representado por un objeto de
-la clase de C++ @code{Music}.
-@end itemize
+@node Funciones de marcado
+@section Funciones de marcado
+@translationof Markup functions
 
-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}.
+Los elementos de marcado están implementados como funciones de Scheme
+especiales que producen un objeto @code{Stencil} dada una serie de
+argumentos.
 
-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 Interfaz de marcado para el programador
-@section Interfaz de marcado para el programador
-@translationof Markup programmer interface
-
-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
@@ -521,10 +360,11 @@ 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
@@ -540,8 +380,8 @@ no es válido.  Hay que usar las funciones @code{make-line-markup},
 @end lisp
 
 
-@node Cómo funciona internamente el marcado
-@subsection Cómo funciona internamente el marcado
+@node Cómo funcionan internamente los elementos de marcado
+@subsection Cómo funcionan internamente los elementos de marcado
 @translationof How markups work internally
 
 En un elemento de marcado como
@@ -580,218 +420,342 @@ resto de la sección podrán verse ejemplos más complejos, así como en
 @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?} ...)
+    (@var{tipo-de-arg1?} @var{tipo-de-arg2?} ...)
+    [ #:properties ((@var{propiedad1} @var{valor-predeterminado1})
+                    ...) ]
   ..command body..)
 @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
+@item 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 argi
+argumento @var{i}-ésimo de la instrucción
+@item 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,
+Si la instrucción utiliza propiedades de los argumentos @var{props},
+se puede usar la palabra clave @code{#:properties} para especificar
+qué propiedades se usan, y sus valores predeterminados.
 
-@example
-\markup @{ \override #'(font-shape . caps) Texto-en-versalitas @}
-@end example
+@knownissues
+Existen algunas restricciones sobre los argumentos posibles de una
+instrucción de marcado.
 
-@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
+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:
 
-@example
-(define-markup-command (smallcaps layout props argument) (markup?)
-@end example
+@table @asis
+@item (sin argumentos)
+@itemx @var{markup-list}
+@itemx @var{markup}
+@itemx @var{markup markup}
+@itemx @var{scheme}
+@itemx @var{scheme markup}
+@itemx @var{scheme scheme}
+@itemx @var{scheme scheme markup}
+@itemx @var{scheme scheme markup markup}
+@itemx @var{scheme markup markup}
+@itemx @var{scheme scheme scheme}
+@end table
 
 @noindent
-
-Lo que aparece a continuación es el contenido de la instrucción:
-debemos interpretar el @code{argument} como un marcado, es decir:
+Esto significa que no es posible definir con p.ej. tres argumentos de
+Scheme y un argumento de marcado, como:
 
 @example
-(interpret-markup layout @dots{} argument)
+#(define-markup-command (fulanito layout props
+                         num1    num2    lista  marcado)
+                        (number? number? list?  markup?)
+  ...)
 @end example
 
 @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:
+Si la aplicamos como, digamos,
 
 @example
-(cons (list '(font-shape . caps) ) props)
+\markup \fulanito #1 #2 #'(mengano zutano) Loquesea
 @end example
 
+@cindex firma de Scheme
+@cindex Scheme, firma de
 @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.
+@command{lilypond} protesta diciendo que no puede analizar
+@code{fulanito} debido a su firma de Scheme desconocida.
 
-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:
+
+@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 (character layout props nombre) (string?)
-  "Imprimir el nombre del personaje en versalitas, desplazado a la izquierda y hacia
-  arriba.  Sintaxis: \\character #\"nombre\""
-  (interpret-markup layout props
-   (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps nombre)))
+(ly:output-def-lookup layout 'line-width)
 @end example
 
-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.
+El argumento @code{props} hace accesibles algunas propiedades a las
+instrucciones de marcado.  Por ejemplo, cuando se interpreta el
+marcado del título de un libro, todas las variables definidas dentro
+del bloque @code{\header} se añaden automáticamente a @code{props}, de
+manera que el marcado del título del libro puede acceder al título del
+libro, el autor, etc.  También es una forma de configurar el
+comportamiento de una instrucción de marcado: por ejemplo, cuando una
+instrucción utiliza tamaños de tipografía durante el procesado, el
+tamaño se lee de @code{props} en vez de tener un argumento
+@code{font-size}.  El que llama a una instrucción de marcado puede
+cambiar el valor de la propiedad del tamaño de la tipografía con el
+objeto de modificar el comportamiento.  Utilice la palabra clave
+@code{#:properties} de @code{define-markup-command} para especificar
+qué propiedades se deben leer a partir de los argumentos de
+@code{props}.
+
+El ejemplo de la sección siguiente ilustra cómo acceder y
+sobreescribir las propiedades de una instrucción de marcado.
+
+
+@node Un ejemplo completo
+@unnumberedsubsubsec Un ejemplo completo
+@translationof A complete example
+
+El ejemplo siguiente define una instrucción de marcado para trazar un
+rectángulo doble alrededor de un fragmento de texto.
+
+En primer lugar, necesitamos construir un resultado aproximado
+utilizando marcados.  Una consulta a @ruser{Text markup commands} nos
+muestra que es útil la instrucción @code{\box}:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \box HELLO
+@end lilypond
 
-El resultado final es como sigue:
+Ahora, consideramos que es preferible tener más separación entre el
+texto y los rectángulos.  Según la documentación de @code{\box}, esta
+instrucción usa una propiedad @code{box-padding}, cuyo valor
+predeterminado es 0.2.  La documentación también menciona cómo
+sobreescribir este valor:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \override #'(box-padding . 0.6) \box A
+@end lilypond
+
+Después, el relleno o separación entre los dos rectángulos nos parece
+muy pequeño, así que lo vamos a sobreescribir también:
+
+@lilypond[quote,verbatim,ragged-right]
+\markup \override #'(box-padding . 0.4) \box \override #'(box-padding . 0.6) \box A
+@end lilypond
+
+Repetir esta extensa instrucción de marcado una y otra vez sería un
+quebradero de cabeza.  Aquí es donde se necesita una instrucción de
+marcado.  Así pues, escribimos una instrucción de marcado
+@code{double-box}, que toma un argumento (el texto).  Dibuja los dos
+rectángulos y añade una separación.
+
+@lisp
+#(define-markup-command (double-box layout props text) (markup?)
+  "Trazar un rectángulo doble rodeando el texto."
+  (interpret-markup layout props
+    (markup #:override '(box-padding . 0.4) #:box
+            #:override '(box-padding . 0.6) #:box text)))
+@end lisp
+
+@code{text} es el nombre del argumento de la instrucción, y
+@code{markup?} es el tipo: lo identifica como un elemento de marcado.
+La función @code{interpret-markup} se usa en casi todas las
+instrucciones de marcado: construye un sello, usando @code{layout},
+@code{props}, y un elemento de marcado.  Aquí, la marca se construye
+usando el macro de Scheme @code{markup}, véase @ref{Construcción de
+elementos de marcado en Scheme}.  La transformación de una expresión
+@code{\markup} en una expresión de marcado de Scheme es directa.
+
+La instrucción nueva se puede usar como sigue:
 
 @example
-@{
-  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\""
-  (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\""
+Sería buen hacer que la instrucción @code{double-box} fuera
+personalizable: aquí, los valores de relleno @code{box-padding} son
+fijos, y no se pueden cambiar por parte del usuario.  Además, sería
+mejor distinguir la separación entre los dos rectángulos, del relleno
+entre el rectángulo interno y el texto.  Así pues, introducimos una
+nueva propiedad, @code{inter-box-padding}, para el relleno entre los
+rectángulos.  El @code{box-padding} se usará para el relleno interno.
+Ahora el código nuevo es como se ve a continuación:
+
+@lisp
+#(define-markup-command (double-box layout props text) (markup?)
+  #:properties ((inter-box-padding 0.4)
+                (box-padding 0.6))
+  "Trazar un rectángulo doble rodeando el texto."
   (interpret-markup layout props
-   (markup #: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:
+@node Adaptación de instrucciones incorporadas
+@unnumberedsubsubsec Adaptación de instrucciones incorporadas
+@translationof Adapting builtin commands
 
-@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
+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}.
 
-@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).
+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):
 
-Como ejemplo, no es posible usar una instrucción de marcado
-@code{fulanito} con cuatro argumentos definida como
+@lisp
+(define-markup-command (draw-line layout props dest)
+  (number-pair?)
+  #:category graphic
+  #:properties ((thickness 1))
+  "...documentación..."
+  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
+               thickness))
+        (x (car dest))
+        (y (cdr dest)))
+    (make-line-stencil th 0 0 x y)))
+@end lisp
 
-@example
-#(define-markup-command (fulanito layout props
-                         num1    str1    num2    str2)
-                        (number? string? number? string?)
-  ...)
-@end example
+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.
 
-@noindent
-Si la aplicamos como, digamos,
+@lisp
+(define-markup-command (draw-double-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1))
+  "...documentación..."
+  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
+               thickness))
+        (x (car dest))
+        (y (cdr dest)))
+    (make-line-stencil th 0 0 x y)))
+@end lisp
 
-@example
-\markup \fulanito #1 #"mengano" #2 #"zutano"
-@end example
+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:
 
-@cindex Scheme signature
-@cindex signature, Scheme
-@noindent
-@command{lilypond} protesta diciendo que no puede analizar
-@code{fulanito} debido a su firma de Scheme desconocida.
+@lisp
+(define-markup-command (draw-double-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1)
+                (line-gap 0.6))
+  "...documentación..."
+  ...
+@end lisp
+
+Finalmente, se añade el código para trazar las dos líneas.  Se usan
+dos llamadas a @code{make-line-stencil} para trazar las líneas, y los
+sellos resultantes se combinan usando @code{ly:stencil-add}:
+
+@lilypond[quote,verbatim,ragged-right]
+#(define-markup-command (my-draw-line layout props dest)
+  (number-pair?)
+  #:properties ((thickness 1)
+                (line-gap 0.6))
+  "..documentation.."
+  (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
+                thickness))
+         (dx (car dest))
+         (dy (cdr dest))
+         (w (/ line-gap 2.0))
+         (x (cond ((= dx 0) w)
+                  ((= dy 0) 0)
+                  (else (/ w (sqrt (+ 1 (* (/ dx dy) (/ dx dy))))))))
+         (y (* (if (< (* dx dy) 0) 1 -1)
+               (cond ((= dy 0) w)
+                     ((= dx 0) 0)
+                     (else (/ w (sqrt (+ 1 (* (/ dy dx) (/ dy dx))))))))))
+     (ly:stencil-add (make-line-stencil th x y (+ dx x) (+ dy y))
+                     (make-line-stencil th (- x) (- y) (- dx x) (- dy y)))))
+
+\markup \my-draw-line #'(4 . 3)
+\markup \override #'(line-gap . 1.2) \my-draw-line #'(4 . 3)
+@end lilypond
 
 
 @node Definición de nuevas instrucciones de lista de marcado
@@ -800,8 +764,9 @@ Si la aplicamos como, digamos,
 
 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,
@@ -810,10 +775,10 @@ del argumento @code{props}.
 
 @example
 #(define-markup-list-command (paragraph layout props args) (markup-list?)
-   (let ((indent (chain-assoc-get 'par-indent props 2)))
-     (interpret-markup-list layout props
-       (make-justified-lines-markup-list (cons (make-hspace-markup indent)
-                                               args)))))
+   #:properties ((par-indent 2))
+   (interpret-markup-list layout props
+     (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
@@ -892,7 +857,6 @@ la compilación:
 @subsection Ejecutar una función sobre todos los objetos de la presentación
 @translationof Running a function on all layout objects
 
-
 @cindex código, llamar sobre objetos de presentación
 @funindex \applyOutput
 
@@ -917,6 +881,7 @@ 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
@@ -939,12 +904,13 @@ cabezas de las notas que están sobre la línea central:
 @end lilypond
 
 
-@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
@@ -985,7 +951,7 @@ puede insertar con una cerradura de grob.  He aquí un ajuste
 procedente de @code{AccidentalSuggestion},
 
 @example
-(X-offset .
+`(X-offset .
   ,(ly:make-simple-closure
     `(,+
         ,(ly:make-simple-closure
@@ -1015,10 +981,18 @@ argumento de @var{proc}, el exterior asegura que el resultado de la
 función es lo que se devuelve, en lugar del objeto
 @code{simple-closure}.
 
+Desde dentro de un callback, el método más fácil para evaluar un
+elemento de marcado es usar grob-interpret-markup.  Por ejemplo:
+
+@example
+mi-callback = #(lambda (grob)
+                 (grob-interpret-markup grob (markup "fulanito")))
+@end example
+
 
-@node Usar código de Scheme en lugar de \tweak
-@section Usar código de Scheme en lugar de @code{\tweak}
-@translationof Using Scheme code instead of \tweak
+@node Código de Scheme en línea
+@section Código de Scheme en línea
+@translationof Inline Scheme code
 
 La principal desventaja de @code{\tweak} es su inflexibilidad
 sintáctica.  Por ejemplo, lo siguiente produce un error de sintaxis.
@@ -1062,6 +1036,7 @@ función de Scheme @code{acons}, y finalmente el resultado se escribe
 de nuevo con @code{set!}.  El último elemento del bloque @code{let} es
 el valor de retorno, el propio @code{m}.
 
+
 @node Trucos difíciles
 @section Trucos difíciles
 @translationof Difficult tweaks
@@ -1070,6 +1045,7 @@ Hay un cierto número de tipos de ajustes difíciles.
 
 @itemize
 
+
 @item
 Un tipo de ajuste difícil es la apariencia de los objetos de
 extensión, como las ligaduras de expresión y de unión.  Inicialmente,
@@ -1160,4 +1136,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