@c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*-
@c This file is part of extending.tely
@ignore
    Translation of GIT committish: ba4e7ffd01ece9dc9662a035967f5a6e438f9cf9

    When revising a translation, copy the HEAD committish of the
    version that you are working on.  See TRANSLATION for details.
@end ignore

@c \version "2.23.6"


@node Interfaces for programmers
@chapter Interfaces para programadores

Se pueden realizar trucos avanzados mediante el uso de Scheme.
Si no está familiarizado con Scheme, le conviene leer nuestro
tutorial de Scheme, @ref{Scheme tutorial}.


@node LilyPond code blocks
@section Bloques de código de LilyPond

@cindex Bloques de código de LilyPond
@cindex LilyPond, bloques de código de
@funindex #@{ @dots{} #@}
@funindex $
@funindex #

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
  #@{ @var{código de LilyPond} #@}
@end example

He aquí un ejemplo trivial:

@lilypond[verbatim,quote]
ritpp = #(define-event-function () ()
  #{ ^"rit." \pp #}
)

{ c'4 e'4\ritpp g'2 }
@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 @samp{$} y @samp{#}.

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éxico 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 @samp{#}, pero
se puede acceder a ellas como variables de LilyPond, es decir,
precedidas de @samp{\}.

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 Scheme functions
@section Funciones de Scheme
@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
@samp{#} 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.


@node Scheme function definitions
@subsection Definición de funciones de Scheme
@funindex define-scheme-function

La forma general de la definición de una función de Scheme es:

@example
funcion =
#(define-scheme-function
     (@var{arg1} @var{arg2} @dots{})
     (@var{tipo1?} @var{tipo2?} @dots{})
   @var{cuerpo})
@end example

@noindent
donde

@indentedblock
@table @code
@item @var{argN}
@var{n}-ésimo argumento.

@item @var{typeN?}
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 @var{cuerpo}
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{LilyPond code blocks}.  Dentro de los bloques de
código de LilyPond, use el símbolo @samp{#} para hacer referencia
a argumentos de función (p.ej. @code{#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 @samp{#} no funcionan, podríamos
necesitar volver a expresiones de Scheme inmediatas que usan
@samp{$}, como por ejemplo @code{$music}.

Si nuestra función devuelve una expresión musical, recibe un
valor @code{origin} útil.
@end table
@end indentedblock

@noindent
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 @samp{#} 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 @rnotationnamed{Predefined type predicates, Predicados de tipo predefinidos}.

@morerefs
Referencia de la notación:
@rnotationnamed{Predefined type predicates, Predicados de tipo predefinidos}.

Archivos instalados:
@file{lily/music-scheme.cc},
@file{scm/c++.scm},
@file{scm/lily.scm}.
@endmorerefs


@node Scheme function usage
@subsection Uso de las funciones de Scheme

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{}@samp{#}.  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
@samp{#} 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{Void Scheme
functions}) 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. Los argumentos opcionales al final de una lista de
argumentos se pueden simplemente omitir sin más indicación cuando
se llaman a través de Scheme.

@node Void Scheme functions
@subsection Funciones de Scheme vacías
@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
noApuntarYPulsar =
#(define-void-function
     ()
     ()
   (ly:set-option 'point-and-click #f))
@dots{}
\noApuntarYPulsar   % desactivar la función de apuntar y pulsar
@end example

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
\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 Music functions
@section Funciones musicales

@cindex funciones musicales

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.


@node Music function definitions
@subsection Definiciones de funciones musicales
@cindex definición de funciones musicales
@funindex define-music-function

La forma general para definir funciones musicales es:

@example
funcion =
#(define-music-function
     (@var{arg1} @var{arg2} @dots{})
     (@var{tipo1?} @var{tipo2?} @dots{})
   @var{cuerpo})
@end example

@noindent
de forma bastante análoga a
@ref{Scheme function definitions}.  Lo más probable es que
el @var{cuerpo} sea un
@ref{LilyPond code blocks,bloque de código de LilyPond}.

Para ver una lista de los predicados de tipo disponibles,
consulte @rnotationnamed{Predefined type predicates, Predicados de tipo predefinidos}.

@morerefs
Referencia de la notación:
@rnotationnamed{Predefined type predicates, Predicados de tipo predefinidos}.

Archivos de inicio:
@file{lily/music-scheme.cc},
@file{scm/c++.scm},
@file{scm/lily.scm}.
@endmorerefs


@node Music function usage
@subsection Uso de las funciones musicales
Con respecto al manejo de la lista de argumentos, las funciones
musicales no son distintas de las funciones de Scheme, véase
@ref{Scheme function usage}.

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.

Si se usa una llamada a función musical dentro de otros
contextos, el contexto puede aplicar restricciones semánticas
adicionales.

@itemize
@item
En el nivel superior dentro de una expresión musical no se acepta
ningún post-evento.

@item
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
Como componente de un acorde.  La expresión devuelta debe ser del
tipo @code{rhythmic-event}, probablemente un @code{NoteEvent}.
@end itemize

@noindent
Se pueden aplicar funciones @q{polimórficas}, como @code{\tweak},
a los post-eventos, componentes de acordes y expresiones
musicales del nivel superior.

@node Simple substitution functions
@subsection Funciones de sustitución sencillas

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 @rnotationnamed{Substitution function examples,
Ejemplos de funciones de sustitución}.


@node Intermediate substitution functions
@subsection Funciones de sustitución intermedias

Las funciones de sustitución intermedias contienen una mezcla de
código de Scheme y de LilyPond dentro de la expresión musical que
se devuelve.

Algunas instrucciones @code{\override} requieren un argumento que
consiste en una pareja de números (llamada una @emph{célula cons}
en Scheme).

La pareja se puede pasar directamente dentro de la función
musical, usando una variable @code{pair?}:

@example
barraManual =
#(define-music-function
     (principio-final)
     (pair?)
   #@{
     \once \override Beam.positions = #principio-final
   #@})

\relative c' @{
  \barraManual #'(3 . 6) c8 d e f
@}
@end example

De forma alternativa, los números que componen la pareja se
pueden pasar como argumentos separados, y el código de Scheme que
se ha usado para crear la pareja se puede incluir dentro de la
expresión musical:

@lilypond[quote,verbatim,ragged-right]
manualBeam =
#(define-music-function
     (beg end)
     (number? number?)
   #{
     \once \override Beam.positions = #(cons beg end)
   #})

\relative c' {
  \manualBeam #3 #6 c8 d e f
}
@end lilypond

@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
\temporary \override @dots{}
@end example

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
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 Mathematics in functions
@subsection Matemáticas dentro de las funciones

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
     (mag)
     (number?)
   #{
     \override Stem.length = #(* 7.0 mag)
     \override NoteHead.font-size =
       #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag)))
   #})

AltOff = {
  \revert Stem.length
  \revert NoteHead.font-size
}

\relative {
  c'2 \AltOn #0.5 c4 c
  \AltOn #1.5 c c \AltOff c2
}
@end lilypond

@noindent
Este ejemplo se puede reescribir de forma que pase expresiones
musicales:

@lilypond[quote,verbatim,ragged-right]
withAlt =
#(define-music-function
     (mag music)
     (number? ly:music?)
   #{
     \override Stem.length = #(* 7.0 mag)
     \override NoteHead.font-size =
       #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag)))
     #music
     \revert Stem.length
     \revert NoteHead.font-size
   #})

\relative {
  c'2 \withAlt #0.5 { c4 c }
  \withAlt #1.5 { c c } c2
}
@end lilypond


@node Functions without arguments
@subsection Funciones sin argumentos

En casi todos los casos, una función sin argumentos se debe
escribir con una variable:

@example
dolce = \markup@{ \italic \bold dolce @}
@end example

Sin embargo, en raras ocasiones puede ser de utilidad crear una
función musical sin argumentos:

@example
mostrarNumeroDeCompas =
#(define-music-function
     ()
     ()
   (if (eq? #t (ly:get-option 'display-bar-numbers))
       #@{ \once \override Score.BarNumber.break-visibility = ##f #@}
       #@{#@}))
@end example

Para la impresión real de los números de compás donde se llama a
esta función, invoque a @command{lilypond} con

@example
lilypond -d display-bar-numbers ARCHIVO.ly
@end example


@node Void music functions
@subsection Funciones musicales vacías

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.


@node Event functions
@section Funciones de eventos
@funindex define-event-function
@cindex event functions

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:

@lilypond[quote,verbatim,ragged-right]
dyn=#(define-event-function (arg) (markup?)
         (make-dynamic-script arg))
\relative { c'\dyn pfsss }
@end lilypond

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}}.


@node Markup functions
@section Funciones de marcado

Los elementos de marcado están implementados como funciones de
Scheme especiales que producen un objeto @code{Stencil} dada una
serie de argumentos.


@node Markup construction in Scheme
@subsection Construcción de elementos de marcado en 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

Para ver una expresión de marcado en su forma de Scheme, utilice
la instrucción @code{\displayScheme}:

@example
\displayScheme
\markup @{
  \column @{
    \line @{ \bold \italic "hola" \raise #0.4 "mundo" @}
    \larger \line @{ fulano fulanito menganito @}
  @}
@}
@end example

@noindent
La compilación del código anterior envía a la consola lo
siguiente:

@example
(markup
  #:line
  (#:column
   (#:line
    (#:bold (#:italic "hola") #:raise 0.4 "mundo")
    #:larger
    (#:line ("fulano" "fulanito" "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{Displaying music expressions}.

@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.  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.

@need 800
@indentedblock
@multitable {@code{\markup @{ marcado1 marcado2 @dots{} @}}} {@code{(markup marcado1 marcado2 @dots{})}}
@item @b{LilyPond}
      @tab @b{Scheme}
@item @code{\markup marcado1}
      @tab @code{(markup marcado1)}
@item @code{\markup @{ marcado1 marcado2 @dots{} @}}
      @tab @code{(markup marcado1 marcado2 @dots{})}
@item @code{\instrucción}
      @tab @code{#:instrucción}
@item @code{\variable}
      @tab @code{variable}
@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 indentedblock

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{New markup command definition}).


@knownissues

El argumento markup-list de instrucciones como @code{#:line},
@code{#:center-column} y @code{#:column} no puede ser una variable
ni el resultado de la llamada a una función.

@lisp
(markup #:line (funcion-que-devuelve-marcados))
@end lisp

@noindent
no es válido.  Hay que usar las funciones @code{make-line-markup},
@code{make-center-column-markup} o @code{make-column-markup} en su
lugar:

@lisp
(markup (make-line-markup (funcion-que-devuelve-marcados)))
@end lisp


@node How markups work internally
@subsection Cómo funcionan internamente los elementos de marcado

En un elemento de marcado como

@example
\raise #0.5 "ejemplo de texto"
@end example

@noindent
@code{\raise} se representa en realidad por medio de la función
@code{raise-markup}.  La expresión de marcado se almacena como

@example
(list raise-markup 0.5 "ejemplo de texto")
@end example

Cuando el marcado se convierte en objetos imprimibles (Stencils o
sellos), se llama la función @code{raise-markup} como

@example
(apply raise-markup
       @var{\objeto de marcado}
       @var{lista de listas asociativas de propiedades}
       0.5
       @var{el marcado "ejemplo de texto"})
@end example

Primero la función @code{raise-markup} crea el sello para la
cadena @code{ejemplo de texto}, y después eleva el sello Stencil
en 0.5 espacios de pentagrama.  Este es un ejemplo bastante
simple; en el resto de la sección podrán verse ejemplos más
complejos, así como en @file{scm/define-markup-commands.scm}.


@node New markup command definition
@subsection Definición de una instrucción de marcado nueva

Esta sección trata sobre la definición de nuevas instrucciones de
marcado.


@node Markup command definition syntax
@unnumberedsubsubsec Sintaxis de la definición de instrucciones de marcado

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} @dots{})
    (@var{tipo-de-arg1?} @var{tipo-de-arg2?} @dots{})
    [ #:properties ((@var{propiedad1} @var{valor-predeterminado1})
                    @dots{}) ]
    [ #:as-string @var{expresion} ]
  @dots{}command body@dots{})
@end lisp

Los argumentos son

@table @code
@item @var{nombre-de-la-instruccion}
nombre de la instrucción de marcado
@item layout
la definición de @q{layout} (disposición).
@item props
una lista de listas asociativas, que contienen todas las propiedades
activas.
@item @var{argi}
argumento @var{i}-ésimo de la instrucción
@item @var{tipo-de-argi?}
predicado de tipo para el argumento @var{i}-ésimo
@end table

Si la instrucción utiliza propiedades de los argumentos
@code{props}, se puede usar la palabra clave @code{#:properties}
para especificar qué propiedades se usan, así como sus valores
predeterminados.

Los argumentos se distinguen según su tipo:
@itemize
@item un marcado, que corresponde al predicado de tipo @code{markup?};
@item una lista de marcados, que corresponde al predicado de tipo
@code{markup-list?};
@item cualquier otro objeto de Scheme, que corresponde a predicados de tipo como
@code{list?}, @code{number?}, @code{boolean?}, etc.
@end itemize

No existe ninguna limitación en el orden de los argumentos
(después de los argumentos estándar @code{layout} y
@code{props}).  Sin embargo, las funciones de marcado que toman
un elemento de marcado como su último argumento son un poco
especiales porque podemos aplicarlas a una lista de marcados y el
resultado es una lista de marcados donde la función de marcado
(con los argumentos antecedentes especificados) se ha aplicado a
todos los elementos de la lista de marcados original.

Dado que la replicación de los argumentos precedentes para
aplicar una función de marcado a una lista de marcados es poco
costosa principalmente por los argumentos de Scheme, se evitan
las caídas de 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 On properties
@unnumberedsubsubsec Acerca de las propiedades

Los argumentos @code{layout} y @code{props} de las instrucciones
de marcado traen a escena un contexto para la interpretación del
marcado: tamaño de la tipografía, grueso de línea, etc.

El argumento @code{layout} permite el acceso a las propiedades
definidas en los bloques @code{paper}, usando la función
@code{ly:output-def-lookup}.  Por ejemplo, el grueso de línea (el
mismo que el que se usa en las partituras) se lee usando:

@example
(ly:output-def-lookup layout 'line-width)
@end example

El argumento @code{props} hace accesibles algunas propiedades a
las instrucciones de marcado.  Por ejemplo, cuando se interpreta
el marcado del título de un libro, todas las variables definidas
dentro del bloque @code{\header} se añaden automáticamente a
@code{props}, de manera que el marcado del título del libro puede
acceder al título del libro, el autor, etc.  También es una forma
de configurar el comportamiento de una instrucción de marcado:
por ejemplo, cuando una instrucción utiliza tamaños de tipografía
durante el procesado, el tamaño se lee de @code{props} en vez de
tener un argumento @code{font-size}.  El que llama a una
instrucción de marcado puede cambiar el valor de la propiedad del
tamaño de la tipografía con el objeto de modificar el
comportamiento.  Utilice la palabra clave @code{#:properties} de
@code{define-markup-command} para especificar qué propiedades se
deben leer a partir de los argumentos de @code{props}.

El ejemplo de la sección siguiente ilustra cómo acceder y
sobreescribir las propiedades de una instrucción de marcado.


@node A complete example
@unnumberedsubsubsec Un ejemplo completo

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 @rnotationnamed{Text markup commands, 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

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

@noindent
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

@noindent
o, de forma equivalente,

@lisp
#(define-markup-command (double-box layout props text) (markup?)
  "Trazar un rectángulo doble rodeando el texto."
  (interpret-markup layout props
    (markup #:override '(box-padding . 0.4) #:box
            #:override '(box-padding . 0.6) #:box text)))
@end lisp

@code{text} es el nombre del argumento de la instrucción, y
@code{markup?} es el tipo: lo identifica como un elemento de
marcado.  La función @code{interpret-markup} se usa en casi todas
las instrucciones de marcado: construye un sello, usando
@code{layout}, @code{props}, y un elemento de marcado.  En el
segundo caso, la marca se construye usando el macro de Scheme
@code{markup}, véase @ref{Markup construction in Scheme}.  La transformación de una expresión @code{\markup} en
una expresión de marcado de Scheme es directa.

La instrucción nueva se puede usar como sigue:

@example
\markup \double-box A
@end example

Sería 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
    #@{\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 #:override `(box-padding . ,inter-box-padding) #:box
            #:override `(box-padding . ,box-padding) #:box text)))
@end lisp

Aquí, la palabra clave @code{#:properties} se usa de manera que
las propiedades @code{inter-box-padding} y @code{box-padding} se
leen a partir del argumento @code{props}, y se les proporcionan
unos valores predeterminados si las propiedades no están
definidas.

Después estos valores se usan para sobreescribir las propiedades
@code{box-padding} usadas por las dos instrucciones @code{\box}.
Observe el apóstrofo invertido y la coma en el argumento de
@code{\override}: nos permiten introducir un valor de variable
dentro de una expresión literal.

Ahora, la instrucción se puede usar dentro de un elemento de
marcado, y el relleno de los rectángulos se puede personalizar:

@lilypond[quote,verbatim,ragged-right]
#(define-markup-command (double-box layout props text) (markup?)
  #:properties ((inter-box-padding 0.4)
                (box-padding 0.6))
  "Draw a double box around text."
  (interpret-markup layout props
    #{\markup \override #`(box-padding . ,inter-box-padding) \box
              \override #`(box-padding . ,box-padding) \box
              { #text } #}))

\markup \double-box A
\markup \override #'(inter-box-padding . 0.8) \double-box A
\markup \override #'(box-padding . 1.0) \double-box A
@end lilypond


@node Adapting builtin commands
@unnumberedsubsubsec Adaptación de instrucciones incorporadas

Una buena manera de comenzar a escribir una instrucción de
marcado nueva, es seguir el ejemplo de otra instrucción ya
incorporada.  Casi todas las instrucciones de marcado que están
incorporadas en LilyPond se pueden encontrar en el archivo
@file{scm/define-markup-commands.scm}.

Por ejemplo, querríamos adaptar la instrucción @code{\draw-line},
para que trace una línea doble.  La instrucción @code{\draw-line}
está definida como sigue (se han suprimido los comentarios de
documentación):

@lisp
(define-markup-command (draw-line layout props dest)
  (number-pair?)
  #:category graphic
  #:properties ((thickness 1))
  "@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

Para definir una instrucción nueva basada en otra existente,
copie la definición y cámbiele el nombre.  La palabra clave
@code{#:category} se puede eliminar sin miedo, pues sólo se
utiliza para generar documentación de LilyPond, y no tiene
ninguna utilidad para las instrucciones de marcado definidas por
el usuario.

@lisp
(define-markup-command (draw-double-line layout props dest)
  (number-pair?)
  #:properties ((thickness 1))
  "@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

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 Converting markups to strings
@unnumberedsubsubsec Convertir elementos de marcado en cadenas

@cindex marcado, a cadena
@funindex markup->string

Los elementos de marcado se convierten a veces en cadenas normales
por ejemplo cuando se producen metadatos de PDF basados en el
campo @code{title} del encabezamiento o para convertir la letra de
las canciones a MIDI.  Esta conversión conlleva inherentemente
pérdidas, pero intenta hacerlo de la forma más fiel que sea
posible.  La función que se usa para ello es
@code{markup->string}.

@lilypond[verbatim,quote]
composerName = \markup \box "Arnold Schönberg"

\markup \composerName

\markup \typewriter #(markup->string composerName)
@end lilypond

Cuando se trata de instrucciones de marcado personalizadas, el
comportamiento por omisión es convertir en primer lugar todos los
argumentos de marcados, o de listas de marcados, y concatenar los
resultados con espacios.

@lilypond[verbatim,quote]
#(define-markup-command (authors-and layout props authorA authorB)
                        (markup? markup?)
   (interpret-markup layout props
    #{
      \markup \fill-line { \box #authorA and \box #authorB }
    #}))

defaultBehavior = \markup \authors-and "Bertolt Brecht" "Kurt Weill"

\markup \defaultBehavior

\markup \typewriter #(markup->string defaultBehavior)
@end lilypond

@code{markup->string} también puede recibir los argumentos con
nombre @code{#:layout @var{layout}} y @code{#:props @var{props}},
con el mismo significado que en la definición de una instrucción
de marcado.  Sin embargo, son opcionales porque no siempre pueden
aportarse (como el argumento @code{layout} durante la conversión a
MIDI).

Para contemplar las conversiones especiales dentro de
instrucciones de marcado personalizadas, se puede dar el parámetro
@code{#:as-string} a @code{define-markup-command}.  Espera como
argumento una expresión, que se evalúa por parte de
@code{markup->string} para dar el resultado en forma de cadena.

@lilypond[verbatim,quote]
#(define-markup-command (authors-and layout props authorA authorB)
                        (markup? markup?)
   #:as-string (format #f "~a and ~a"
                       (markup->string authorA #:layout layout #:props props)
                       (markup->string authorB #:layout layout #:props props))
   (interpret-markup layout props
    #{
      \markup \fill-line { \box #authorA and \box #authorB }
    #}))

customized = \markup \authors-and "Bertolt Brecht" "Kurt Weill"

\markup \customized

\markup \typewriter #(markup->string customized)
@end lilypond

Dentro de la expresión, están disponibles las mismas relaciones de
enlace que en el cuerpo de la instrucción de marcado principal,
concretamente @code{layout} y @code{props}, el argumento de la
instrucción, y opcionalmente las propiedades.

@lilypond[verbatim,quote]
#(define-markup-command (authors-and layout props authorA authorB)
                        (markup? markup?)
   #:properties ((author-separator " and "))
   #:as-string (format #f "~a~a~a"
                       (markup->string authorA #:layout layout #:props props)
                       (markup->string author-separator #:layout layout #:props props)
                       (markup->string authorB #:layout layout #:props props))
   (interpret-markup layout props
    #{
      \markup { \box #authorA #author-separator \box #authorB }
    #}))

customized = \markup \override #'(author-separator . ", ")
                     \authors-and "Bertolt Brecht" "Kurt Weill"

\markup \customized

\markup \typewriter #(markup->string customized)
@end lilypond

Lo más frecuente es que una rutina procesadora solamente necesite
llamar recursivamente a @code{markup->string} sobre ciertos
argumentos, como se ha mostrado arriba.  Sin embargo, también
puede hacer uso directamente de @code{layout} y de @code{props},
de la misma manera que en el cuerpo principal.  Hay que tener
cuidado de que el argumento @code{layout} sea @code{#f} si no se
le ha dado ningún @code{#:layout} a la función
@code{markup->string}.  El argumento @code{props} es, por omisión,
una lista vacía.


@node New markup list command definition
@subsection Definición de nuevas instrucciones de lista de marcado
@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{New markup command
definition}, excepto que donde éste devuelve un sello único, aquél
devuelve una lista de sellos.

De forma parecida, se usa @code{interpret-markup-list} en lugar de
@code{interpret-markup} para convertir una lista de marcado en 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


La versión que usa solamente Scheme es más compleja:
@example
#(define-markup-list-command (paragraph layout props args) (markup-list?)
   #:properties ((par-indent 2))
   (interpret-markup-list layout props
     (make-justified-lines-markup-list (cons (make-hspace-markup par-indent)
                                             args))))
@end example

Aparte de los argumentos usuales @code{layout} y @code{props}, la
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
\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.
    hace sólo algunas décadas, las partituras se hacían cortando y estampando
    la música en una plancha de zinc o lata en una imagen invertida.
  @}
  \override-lines #'(par-indent . 4) \paragraph @{
    La plancha se tenía que entintar, y las depresiones causadas por los cortes
    y estampados retienen la tinta.  Se formaba una imagen presionando el papel
    contra la plancha.  El estampado y cortado se hacía completamente
    a mano.
  @}
@}
@end example


@need 1500
@node Contexts for programmers
@section Contextos para programadores


@node Context evaluation
@subsection Evaluación de contextos

@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.  Dentro de un bloque de código de LilyPond, la
sintaxis para esto es:

@example
\applyContext @var{función}
@end example

En código de Scheme, la sintaxis es:

@example
(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 Running a function on all layout objects
@subsection Ejecutar una función sobre todos los objetos de la presentación

@cindex código, llamar sobre objetos de presentación
@funindex \applyOutput

La manera más versátil de realizar el ajuste fino de un objeto es
@code{\applyOutput}, que funciona insertando un evento dentro del
contexto especificado (@rinternals{ApplyOutputEvent}).  Su
sintaxis es o bien

@example
\applyOutput @var{Contexto} @var{proc}
@end example

o bien

@example
\applyOutput @var{Context}.@var{Grob} @var{proc}
@end example

@noindent
donde @code{@var{proc}} es una función de Scheme que toma tres
argumentos.

Al interpretarse, la función @code{@var{proc}} se llama para cada
objeto de presentación (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,
@item el contexto en que se creó el objeto de presentación, y
@item el contexto en que se procesa @code{\applyOutput}.
@end itemize


Además, la causa del objeto de presentación, es decir el objeto o
expresión musical que es responsable de haberlo creado, está en la
propiedad @code{cause} del objeto.  Por ejemplo, para la cabeza de
una nota, éste es un evento @rinternals{NoteHead}, y para un
objeto plica, éste es un objeto @rinternals{Stem}.

He aquí una función que usar para @code{\applyOutput}; borra las
cabezas de las notas que están sobre la línea central y junto a
ella:

@lilypond[quote,verbatim,ragged-right]
#(define (blanker grob grob-origin context)
   (if (< (abs (ly:grob-property grob 'staff-position)) 2)
       (set! (ly:grob-property grob 'transparent) #t)))

\relative {
  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 Callback functions
@section Funciones de callback

Las propiedades (como @code{thickness} (grosor), @code{direction}
(dirección), etc.@:) se pueden establecer a valores fijos con
\override, p. ej.:

@example
\override Stem.thickness = #2.0
@end example

Las propiedades pueden fijarse también a un procedimiento de
Scheme:

@lilypond[fragment,verbatim,quote]
\override Stem.thickness = #(lambda (grob)
    (if (= UP (ly:grob-property grob 'direction))
        2.0
        7.0))
\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.

Casi todo el motor de tipografiado está manejado por estos
@emph{callbacks}.  Entre las propiedades que usan normalmente
@emph{callbacks} están

@table @code
@item stencil
  La rutina de impresión, que construye un dibujo para el símbolo
@item X-offset
  La rutina que establece la posición horizontal
@item X-extent
  La rutina que calcula la anchura de un objeto
@end table

El procedimiento siempre toma un argumento único, que es el grob
(el objeto gráfico).

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
\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

También es posible obtener el valor del valor predeterminado
existente, empleando la función @code{grob-transformer}:

@lilypond[verbatim,quote]
\relative {
  \override Flag.X-offset = #(grob-transformer 'X-offset
    (lambda (flag default) (* default 4.0)))
  c''4. d8 a4. g8
}
@end lilypond


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

@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.

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 (o
más bien: así lo hacía en algún momento del pasado):

@example
F = \tweak font-size #-3 -\flageolet

\relative @{
  c''4^\F c4_\F
@}
@end example

@noindent
Usando Scheme, se puede dar un rodeo a este problema.  La ruta hacia
el resultado se da en @ref{Adding articulation to notes (example)}, especialmente cómo usar @code{\displayMusic} como guía de
ayuda.

@example
F = #(let ((m (make-music 'ArticulationEvent
                          'articulation-type 'flageolet)))
       (set! (ly:music-property m 'tweaks)
             (acons 'font-size -3
                    (ly:music-property m 'tweaks)))
       m)

\relative @{
  c''4^\F c4_\F
@}
@end example

@noindent
Aquí, las propiedades @code{tweaks} del objeto flageolet @code{m}
(creado con @code{make-music}) se extraen con
@code{ly:music-property}, se antepone un nuevo par clave-valor para
cambiar el tamaño de la tipografía a la lista de propiedades con la
función de Scheme @code{acons}, y finalmente el resultado se escribe
de nuevo con @code{set!}.  El último elemento del bloque @code{let} es
el valor de retorno, el propio @code{m}.

@end ignore


@node Unpure-pure containers
@section Contenedores Unpure-pure

@c See issue #3512.
@warning{Si bien esta subsección refleja la situación actual, el
ejemplo dado es irrelevante y no muestra ningún efecto.}

@cindex Scheme, contenedor pure
@cindex Scheme, contenedor unpure
@cindex pure, contenedor, Scheme
@cindex unpure, contenedor, Scheme
@cindex horizontal, espaciado, sobreescritura

Los contenedores unpure-pure son útiles para sobreescribir los
cálculos de espaciado en @emph{Y-axis}, el eje Y (específicamente
@code{Y-offset} y @code{Y-extent}) con una función de Scheme en
lugar de un valor literal, como un número o una pareja de números.

Para determinados objetos gráficos, las dimensiones verticales
@code{Y-extent} están basadas en la propiedad @code{stencil}
(sello): la sobreescritura de la propiedad sello de uno de estos
objetos necesitaría otra sobreescritura de @code{Y-extent} con un
contenedor unpure-pure.  Cuando una función sobreescribe el
desplazamiento @code{Y-offset} y/o las dimensiones verticales
@code{Y-extent}, se supone que ello dispara los álculos de los
saltos de línea demasiado pronro durante la compilación.  Por ello
la función no se evalúa en absoluto (devolviendo por lo general un
valor de @samp{0} o de @samp{'(0 . 0)}) lo que puede dar
colisiones como resultado.  Una función @q{pure} no afecta a las
propiedades, los objetos se suicidan y por tanto siempre tendrán
evaluado correctamente su valor relacionado con el eje Y.

En este momento existen aproximadamente 30 funciones que ya se
conbsideran @q{pure} y los contenedores Unpure-pure son una manera
de establecer como @q{pure} funciones que no están en esta lista.
La función @q{pure} se evalúa @emph{antes} de cualquier salto de
línea y así el espaciado horizontal se puede ajustar @q{a tiempo}.
La función @q{unpure} se evalúa entonces @emph{después} del salto
de línea.

@warning{Dado que es difícil saber en todo momento qué funciones
están en esta lista, recomendamos que cualquier función @q{pure}
que usted cree, no utilicen los objetos gráficos @code{Beam} ni
@code{VerticalAlignment}.}

Un contenedor unpure-pure se construye como sigue:

@example
(ly:make-unpure-pure-container f0 f1)
@end example

@noindent
donde @code{f0} es una función que toma @var{n} argumentos (@var{n
>= 1}) y el primer argumento debe ser siempre el grob.  Esta es la
función que da el resultado real.  @var{f1} es la función que se
está etiquetando como @q{pure} que toma @var{n + 2} argumentos.
De nuevo, el primer argumento siempre debe ser el grob, pero el
segundo y el tercero son los argumentos de @q{inicio} y @q{fin}.

@var{inicio} y @var{fin} son, a todos los efectos, valores mudos
que solo tienen importancia para los objetos de extensión
(@code{Spanners} como @code{Hairpin}, reguladores, o @code{Beam},
barras), que pueden devolver diferentes estimaciones de altura
basadas en una columna de inicio y de final.

El resto son los otros argumentos para la primera función (que
pueden no ser ninguno si @var{n = 1}).

Los resultados de la segunda función se usan como aproximación del
valor requerido cuando se usa después por parte de la primera
función para obtener el valor real que se usa entonces para el
ajuste fino mucho tiempo después, durante el proceso de espaciado.

@c TODO: The following example supposedly showing a collision no longer
@c 'works' since 2.18.x. Another example of a collision is needed.
@c Issue #3512

@lilypond[verbatim,quote,ragged-right]
#(define (square-line-circle-space grob)
(let* ((pitch (ly:event-property (ly:grob-property grob 'cause)
                                 'pitch))
      (notename (ly:pitch-notename pitch)))
 (if (= 0 (modulo notename 2))
     (make-circle-stencil 0.5 0.0 #t)
     (make-filled-box-stencil '(0 . 1.0)
                              '(-0.5 . 0.5)))))

squareLineCircleSpace = {
  \override NoteHead.stencil = #square-line-circle-space
}

smartSquareLineCircleSpace = {
  \squareLineCircleSpace
  \override NoteHead.Y-extent =
   #(ly:make-unpure-pure-container
      ly:grob::stencil-height
      (lambda (grob start end) (ly:grob::stencil-height grob)))
}

\new Voice \with { \remove Stem_engraver }
\relative c'' {
  \squareLineCircleSpace
  cis4 ces disis d
  \smartSquareLineCircleSpace
  cis4 ces disis d
}
@end lilypond

@noindent
En el primer compás, sin un contenedor unpure-pure, el motor de
espaciado no conoce la anchura de la cabeza de la nota ydeja que
choque con las alteraciones accidentales.  En el segundo compás,
con contenedores unpure-pure, el motor de espaciado conoce el
ancho de las cabezas de nota y evita la colisión alargando la
línea adecuadamente.

Normalmente, para cálculos sencillos se pueden usar funciones casi
idénticas para las dos partes @q{unpure} y @q{pure} , solo
cambiando el número de los argumentos que se pasan a, y el ámbito
de, la función.  Este ejemplo de utilización es lo bastante
frecuente como para que @code{ly:make-unpure-pure-container}
construya una segunda función de forma predeterminada cuando se
llama con solo un argumento de función.

@warning{Si una función se etiqueta como @q{pure} y después
resulta que no lo es, los resultados pueden ser inesperados.}


@node Difficult tweaks
@section Trucos difíciles

Hay un cierto número de tipos de ajustes difíciles.

@itemize


@item
Un tipo de ajuste difícil es la apariencia de los objetos de
extensión, como las ligaduras de expresión y de unión.
Inicialmente, sólo se crea uno de estos objetos, y pueden
ajustarse con el mecanismo normal.  Sin embargo, en ciertos casos
los objetos extensores cruzan los saltos de línea.  Si esto
ocurre, estos objetos se clonan.  Se crea un objeto distinto por
cada sistema en que se encuentra.  Éstos son clones del objeto
original y heredan todas sus propiedades, incluidos los
@code{\override}s.

En otras palabras, un @code{\override} siempre afecta a todas las
piezas de un objeto de extensión fragmentado.  Para cambiar sólo
una parte de un extensor en el salto de línea, es necesario
inmiscuirse en el proceso de formateado.  El @emph{callback}
@code{after-line-breaking} contiene el procedimiento Scheme que se
llama después de que se han determinado los saltos de línea, y los
objetos de presentación han sido divididos sobre los distintos
sistemas.

En el ejemplo siguiente, definimos un procedimiento
@code{my-callback}.  Este procedimiento

@itemize @minus{}
@item
determina si hemos sido divididos por los saltos de línea
@item
en caso afirmativo, reúne todos los objetos divididos
@item
comprueba si somos el último de los objetos divididos
@item
en caso afirmativo, establece @code{extra-offset}.
@end itemize

Este procedimiento se instala en @rinternals{Tie} (ligadura de
unión), de forma que la última parte de la ligadura dividida se
traslada hacia arriba.

@lilypond[quote,verbatim,ragged-right]
#(define (my-callback grob)
   (let* (
          ;; have we been split?
          (orig (ly:grob-original grob))

          ;; if yes, get the split pieces (our siblings)
          (siblings (if (ly:grob? orig)
                        (ly:spanner-broken-into orig)
                        '())))

     (if (and (>= (length siblings) 2)
              (eq? (car (last-pair siblings)) grob))
         (ly:grob-set-property! grob 'extra-offset '(1 . -4)))))

\relative {
  \override Tie.after-line-breaking =
  #my-callback
  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, si
existe este valor predeterminado.  Por ejemplo, si se usa con
@code{Hairpin}, se debe llamar también a
@code{ly:spanner::kill-zero-spanned-time}.


@item Algunos objetos no se pueden cambiar con @code{\override} por
razones técnicas.  Son ejemplos @code{NonMusicalPaperColumn} y
@code{PaperColumn}.  Se pueden cambiar con la función
@code{\overrideProperty} que funciona de forma similar a
@code{\once \override}, pero usa una sintaxis
distinta.@footnote{Con el paso del tiempo,
@code{\overrideProperty} se está sustituyendo con la instrucción
más usual @code{\once \override}.  Si aún necesita
@code{\overrideProperty}, agradeceríamos un informe de bug.}

@example
\overrideProperty [@var{NombreDelContexto}].@var{NombreDelGrob}.@var{NombreDeLaPropiedad}[.@var{NombreDeLaSubpropiedad}] @var{valor}
@end example


@end itemize


@node LilyPond Scheme interfaces
@chapter Interfaces de Scheme de LilyPond

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.

(Próximamente)

@c HACER @c TODO -- figure out what goes in here and how to organize it
