@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: ee7518558c4c46cd59030ca8e343cefe01037a67
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?)
}
@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)
\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 =
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
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 #@}
@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
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
@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
@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
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,
@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
@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
@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
@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
procedente de @code{AccidentalSuggestion},
@example
-(X-offset .
+`(X-offset .
,(ly:make-simple-closure
`(,+
,(ly:make-simple-closure
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.
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
@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,
@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