X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=Documentation%2Fes%2Fextending%2Fprogramming-interface.itely;h=b2552e8eb6c0a94c38ba70a587f12d002dc0c364;hb=530857ca80db51aad52eb1c92ad5f23bfdcfdd4a;hp=f71652981391362470e350e2179050e882fe04e4;hpb=95a4237d0aca94993bd3b91afc4ff0e4e2daec9f;p=lilypond.git diff --git a/Documentation/es/extending/programming-interface.itely b/Documentation/es/extending/programming-interface.itely index f716529813..b2552e8eb6 100644 --- a/Documentation/es/extending/programming-interface.itely +++ b/Documentation/es/extending/programming-interface.itely @@ -1,61 +1,130 @@ @c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- @c This file is part of extending.tely @ignore - Translation of GIT committish: 10bd5cc93870ac4b884b8cb938cfc6a19c768097 + Translation of GIT committish: 708aa920d682cf9aa3ed647cd129afd8509760f4 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.13.36" +@c \version "2.19.24" @node Interfaces para programadores @chapter Interfaces para programadores @translationof Interfaces for programmers -Se pueden realizar trucos avanzados mediante el uso de Scheme. Si no -está familiarizado con Scheme, le conviene leer nuestro tutorial de -Scheme, @ref{Tutorial de Scheme}. +Se pueden realizar trucos avanzados mediante el uso de Scheme. +Si no está familiarizado con Scheme, le conviene leer nuestro +tutorial de Scheme, @ref{Tutorial de Scheme}. @menu +* Bloques de código de LilyPond:: +* Funciones de Scheme:: * Funciones musicales:: +* Funciones de eventos:: * Funciones de marcado:: * Contextos para programadores:: * Funciones de callback:: -* Código de Scheme en línea:: * Trucos difíciles:: @end menu -@node Funciones musicales -@section Funciones musicales -@translationof Music functions +@node Bloques de código de LilyPond +@section Bloques de código de LilyPond +@translationof LilyPond code blocks + +@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 -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. +Los bloques de código de LilyPond se pueden usar en cualquier +lugar en el que se pueda escribir código de Scheme. El lector de +Scheme en efecto se modifica para que pueda incorporar bloques de +código de LilyPond y pueda ocuparse de las expresiones de Scheme +incrustadas que comienzan por @code{$} y@w{ }@code{#}. + +El lector extrae el bloque de código de LilyPond y genera una +llamada en tiempo de ejecución al analizador sintáctico para que +interprete el código de LilyPond. Las expresiones de Scheme +incrustadas en el código de LilyPond se evalúan dentro del +entorno lóexico del bloque de código de LilyPond, de manera que +puede accederse a todas las variables locales y los parámetros de +función que están disponibles en el punto en que se escribe el +bloque de código de LilyPond. Las variables definidas en otros +módulos de Scheme, como los módulos que contienen bloques +@code{\header} y @code{\layout}, no están accesibles como +variables de Scheme, es decir, precedidas de@tie{}@code{#}, pero +se puede acceder a ellas como variables de LilyPond, es decir, +precedidas de@tie{}@code{\}. + +Toda la música generada dentro del bloque de código tiene su +@samp{origin} establecido a la localización actual del puntero de +entrada. + +Un bloque de código de LilyPond puede contener cualquier cosa que +podríamos utilizar en la parte derecha de una asignación. +Además, un bloque de LilyPond vacío corresponde a una expresión +musical vacía, y un bloque de LilyPond que contiene varios +eventos musicales se convierte en una expresión de música +secuencial. + +@node Funciones de Scheme +@section Funciones de Scheme +@translationof Scheme functions +@cindex Scheme, funciones de (sintaxis de LilyPond) + +Las @emph{funciones de Scheme} son procedimientos de Scheme que +pueden crear expresiones de Scheme a partir de código de entrada +escrito en la sintaxis de LilyPond. Se pueden llamar desde +prácticamente cualquier lugar en el que se permita el uso de +@code{#} para la especificación de un valor en sintaxis de +Scheme. Mientras que Scheme tiene funciones propias, este +capítulo se ocupa de las funciones @emph{sintácticas}, funciones +que reciben argumentos especificados en la sintaxis de LilyPond. @menu -* Sintaxis de las funciones musicales:: -* Funciones de sustitución sencillas:: -* Funciones de sustitución intermedias:: -* Matemáticas dentro de las funciones:: -* Funciones sin argumentos:: -* Funciones vacías:: +* Definición de funciones de Scheme:: +* Uso de las funciones de Scheme:: +* Funciones de Scheme vacías:: @end menu -@node Sintaxis de las funciones musicales -@subsection Sintaxis de las funciones musicales -@translationof Music function syntax +@node Definición de funciones de Scheme +@subsection Definición de funciones de Scheme +@translationof Scheme function definitions +@funindex define-scheme-function -La forma general de una función musical es: +La forma general de la definición de una función de Scheme es: @example funcion = -#(define-music-function - (parser location @var{arg1} @var{arg2} @dots{}) - (@var{type1?} @var{type2?} @dots{}) - @var{música}) +#(define-scheme-function + (@var{arg1} @var{arg2} @dots{}) + (@var{tipo1?} @var{tipo2?} @dots{}) + @var{cuerpo}) @end example @noindent @@ -63,31 +132,236 @@ donde @multitable @columnfractions .33 .66 @item @code{@var{argN}} -@tab @var{n}-ésimo argumento +@tab @var{n}-ésimo argumento. @item @code{@var{typeN?}} -@tab un @emph{predicado de tipo} de Scheme para el que @code{@var{argN}} -deve devolver @code{#t}. - -@item @code{@var{música}} -@tab una expresión musical, opcionalmente escrita en Scheme, con -el código de LilyPond que pudiera tener, encerrado entre llaves -con almohadilla -(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}). Dentro de los bloques -de código de LilyPond, use @code{$} para referenciar a los argumentos -de la función (p. ej. @samp{$arg1}) -o para iniciar una expresión en línea de Scheme -que contenga argumentos de función -(p.ej., @w{@samp{$(cons arg1 arg2)}}). - +@tab Un @emph{predicado de tipo} de Scheme para el que @code{@var{argN}} +debe devolver @code{#t}. También existe una forma especial +@code{(@emph{predicate?} @emph{default})} para especificar +argumentos opcionales. Si el argumento actual no está presente +cuando se ll ama a la función, el valor predeterminado se emplea +en sustitución. Los valores predeterminados se evalúan en tiempo +de definición (¡incluyendo los bloques de código de LilyPond!), +de manera que se necesitamos un valor por omisión calculado en +tiempo de ejecución, debemos escribir en su lugar un valor +especial que podamos reconocer fácilmente. Si escribimos el +predicado entre paréntesis pero no lo seguimos por el valor +predeterminado, se usa @code{#f} como valor por omisión. Los +valores por omisión no se verifican con @emph{predicate?} en +tiempo de definición ni en tiempo de ejecución: es nuestra +responsabilidad tratar con los valores que especifiquemos. Los +valores por omisión que son expresiones musicales se copian +mientras se establece @code{origin} a la ubicación actual del +cursor de entrada. + +@item @code{@var{cuerpo}} +@tab una secuencia de formas de Scheme que se evalúan ordenadamente; la +última forma de la secuencia se usa como el valor de retorno de +la función de Scheme. Puede contener bloques de código de +LilyPond encerrados entre llaves con almohadillas +(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}), como se describe en +@ref{Bloques de código de LilyPond}. Dentro de los bloques de +código de LilyPond, use el símbolo @code{#} para hacer referencia +a argumentos de función (p.ej. @samp{#arg1}) o para iniciar una +expresión en línea de Scheme que contenga argumentos de función +(p.ej. @w{@samp{#(cons arg1 arg2)}}). Donde las expresiones de +Scheme normales que usan @code{#} no funcionan, podríamos +necesitar volver a expresiones de Scheme inmediatas que usan +@code{$}, como por ejemplo @samp{$music}. + +Si nuestra función devuelve una expresión musical, recibe un +valor @code{origin} útil. @end multitable @noindent -Para ver una lista de los predicados de tipo disponibles, consulte +La idoneidad de los argumentos para los predicados viene +determinada mediante llamadas reales al predicado después de que +LilyPond ya las ha convertido en una expresión de Scheme. Como +consecuencia, el argumento se puede especificar en la sintaxis de +Scheme si se desea (precedido de @code{#} o como resultado de +haber llamado a una función de Scheme), pero LilyPond también +convierte algunas construcciones de LilyPond en Scheme antes de +hacer efectivamente la comprobación del predicado sobre ellas. +Actualmente se encuentran entre ellas la música, los +post-eventos, las cadenas simples (entrecomilladas o no), los +números, los elementos de marcado y de listas de marcado, score +(partitura), book (libro), bookpart (parte de libro), las +definiciones de contexto y los bloques de definición de salida. + +LilyPond resuelve algunas ambigüedades mediante la comprobación +con funciones de predicado: ¿es @samp{-3} un post-evento de +digitación o un número negativo? ¿Es @code{"a" 4} en el modo de +letra una cadena seguida por un número, o un evento de letra con +la duración @code{4}? LilyPond prueba el predicado del argumento +sobre diversas interpretaciones sucesivas hasta que lo consigue, +con un orden diseñado para minimizar las interpretaciones poco +consistentes y la lectura por adelantado. + +Por ejemplo, un predicado que acepta tanto expresiones musicales +como alturas consideraría que @code{c''} es una altura en lugar +de una expresión musical. Las duraciones o post-eventos que +siguen inmediatamente, cambian dicha interpretación. Es mejor +evitar los predicados excesivamente permisivos como +@code{scheme?} cuando la aplicación requeriría tipos de argumento +más específicos. + +Para ver una lista de los predicados de tipo disponibles, +consulte @ruser{Predicados de tipo predefinidos}. + +@seealso + +Referencia de la notación: @ruser{Predicados de tipo predefinidos}. -También se permiten predicados de tipo definidos por el usuario. + +Archivos instalados: +@file{lily/music-scheme.cc}, +@file{scm/c++.scm}, +@file{scm/lily.scm}. + + +@node Uso de las funciones de Scheme +@subsection Uso de las funciones de Scheme +@translationof Scheme function usage + +Las funciones de Scheme se pueden llamar casi desde cualquier +lugar en que puede escribirse una expresión de Scheme que +comience con la almohadilla@tie{}@code{#}. Llamamos a una +función de Scheme escribiendo su nombre precedido de la barra +invertida@tie{}@code{\}, y seguido por sus argumentos. Una vez +que un argumento opcional no corresponde a ningún argumento, +LilyPond se salta este argumento y todos los que le siguen, +sustituyéndolos por su valor por omisión especificado, y +@q{recupera} el argumento que no correspondía al lugar del +siguiente argumento obligatorio. Dado que el argumento +recuperado necesita ir a algún lugar, los argumentos opcionales +no se consideran realmente opcionales a no ser que vayan seguidos +de un argumento obligatorio. + +Existe una excepción: si escribimos @code{\default} en el lugar +de un argumento opcional, este argumento y todos los argumentos +opcionales que le siguen se saltan y se sustituyen por sus +valores predeterminados. Esto funciona incluso si no sigue +ningún argumento obligatorio porque @code{\default} no necesita +recuperarse. Las instrucciones @code{mark} y @code{key} hacen +uso de este truco para ofrecer su comportamiento predeterminado +cuando van seguidas solamente por @code{\default}. + +Aparte de los lugares en que se requiere un valor de Scheme hay +ciertos sitios en que se aceptan expresiones de almohadilla +@code{#} y se evalúan por sus efectos secundarios, pero por lo +demás se ignoran. Son, mayormente, los lugares en que también +sería aceptable colocar una asignación. + +Dado que no es buena idea devolver valores que puedan +malinterpretarse en algún contexto, debería usar funciones de +Scheme normales solo para los casos en que siempre se devuelve un +valor útil, y usar funciones de Scheme vacías (@pxref{Funciones +de Scheme vacías}) en caso contrario. + +Por conveniencia, las funciones de Scheme también se pueden +llamar directamente desde Scheme, puenteando al analizador +sintáctico de LilyPond. Su nombre puede utilizarse como el +nombre de una función corriente. La comprobación de tipo de los +argumentos y el salto de los argumentos opcionales tiene lugar de +la misma forma que cuando se llama desde dentro de LilyPond, +tomando el valor de Scheme @code{*unspecified*} el papel de la +palabra reservada @code{\default} para saltar explícitamente +argumentos opcionales. + +@node Funciones de Scheme vacías +@subsection Funciones de Scheme vacías +@translationof Void scheme functions +@funindex define-void-function +@funindex \void + +En ocasiones, un procedimiento se ejecuta con el objeto de llevar +a cabo alguna acción más que para devolver un valor. Algunos +lenguajes de programación (como C y Scheme) usan las funciones +para los dos conceptos y se limitan a descartar el valor devuelto +(usualmente haciendo que cualquier expresión pueda actuar como +instrucción, ignorando el resultado devuelto). Esto puede +parecer inteligente pero es propenso a errores: casi todos los +compiladores de C de hoy en día emiten advertencias cuando se +descarta una expresión no vacía. Para muchas funciones que +ejecutan una acción, los estándares de Scheme declaran que el +valor de retorno sea no especificado. Guile, el intérprete de +Scheme de LilyPond, tiene un valor único @code{*unspecified*} que +en tales casos devuelve de forma usual (como cuando se usa +directamente @code{set!} sobre una variable), pero +desgraciadamente no de forma consistente. + +Definir una función de LilyPond con @code{define-void-function} +asegura que se devuelve este valor especial, el único valor que +satisface el predicado @code{void?}. + +@example +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 Funciones musicales +@section Funciones musicales +@translationof Music functions + +@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. + +@menu +* Definiciones de funciones musicales:: +* Uso de las funciones musicales:: +* Funciones de sustitución sencillas:: +* Funciones de sustitución intermedias:: +* Matemáticas dentro de las funciones:: +* Funciones sin argumentos:: +* Funciones musicales vacías:: +@end menu +@node Definiciones de funciones musicales +@subsection Definiciones de funciones musicales +@translationof Music function definitions +@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{Definición de funciones de Scheme}. Lo más probable es que +el @var{cuerpo} sea un +@ref{Bloques de código de LilyPond,bloque de código de LilyPond}. + +Para ver una lista de los predicados de tipo disponibles, +consulte @ruser{Predicados de tipo predefinidos}. @seealso @@ -100,13 +374,50 @@ Archivos de inicio: @file{scm/lily.scm}. +@node Uso de las funciones musicales +@subsection Uso de las funciones musicales +@translationof Music 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 Funciones de sustitución sencillas @subsection Funciones de sustitución sencillas @translationof Simple substitution functions 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. +expresión musical de salida está escrita en código de LilyPond y +contiene argumentos de la función en la expresión de salida. Están descritas en @ruser{Ejemplos de funciones de sustitución}. @@ -114,24 +425,24 @@ Están descritas en @ruser{Ejemplos de funciones de sustitución}. @subsection Funciones de sustitución intermedias @translationof Intermediate substitution functions -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. +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). +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?}: +La pareja se puede pasar directamente dentro de la función +musical, usando una variable @code{pair?}: @example barraManual = #(define-music-function - (parser location principio-final) + (principio-final) (pair?) #@{ - \once \override Beam #'positions = $principio-final + \once \override Beam.positions = #principio-final #@}) \relative c' @{ @@ -139,17 +450,18 @@ barraManual = @} @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: +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 - (parser location beg end) + (beg end) (number? number?) #{ - \once \override Beam #'positions = $(cons beg end) + \once \override Beam.positions = #(cons beg end) #}) \relative c' { @@ -157,6 +469,61 @@ manualBeam = } @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 Matemáticas dentro de las funciones @subsection Matemáticas dentro de las funciones @@ -168,21 +535,21 @@ además de la simple sustitución: @lilypond[quote,verbatim,ragged-right] AltOn = #(define-music-function - (parser location mag) + (mag) (number?) #{ - \override Stem #'length = $(* 7.0 mag) - \override NoteHead #'font-size = - $(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) + \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 + \revert Stem.length + \revert NoteHead.font-size } -\relative c' { - c2 \AltOn #0.5 c4 c +\relative { + c'2 \AltOn #0.5 c4 c \AltOn #1.5 c c \AltOff c2 } @end lilypond @@ -194,19 +561,19 @@ musicales: @lilypond[quote,verbatim,ragged-right] withAlt = #(define-music-function - (parser location mag music) + (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 + \override Stem.length = #(* 7.0 mag) + \override NoteHead.font-size = + #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) + #music + \revert Stem.length + \revert NoteHead.font-size #}) -\relative c' { - c2 \withAlt #0.5 { c4 c } +\relative { + c'2 \withAlt #0.5 { c4 c } \withAlt #1.5 { c c } c2 } @end lilypond @@ -216,8 +583,8 @@ withAlt = @subsection Funciones sin argumentos @translationof Functions without arguments -En casi todos los casos, una función sin argumentos se debe escribir -con una variable: +En casi todos los casos, una función sin argumentos se debe +escribir con una variable: @example dolce = \markup@{ \italic \bold dolce @} @@ -229,54 +596,67 @@ función musical sin argumentos: @example mostrarNumeroDeCompas = #(define-music-function - (parser location) + () () (if (eq? #t (ly:get-option 'display-bar-numbers)) - #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} + #@{ \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 +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 Funciones vacías -@subsection Funciones vacías -@translationof Void functions +@node Funciones musicales vacías +@subsection Funciones musicales vacías +@translationof Void music functions -Una función musical debe devolver una expresión musical, pero a veces -podemos necesitar una función en la que no hay música en juego (como -la desactivación de la funcionalidad Apuntar y Pulsar). Para hacerlo, -devolvemos una expresión musical @code{void} (vacía). +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. -Este es el motivo por el que la forma que se devuelve es -@code{(make-music ...)}. Con el valor de la propiedad @code{'void} -establecido a @code{#t}, le decimos al analizador que descarte la -expresión musical devuelta. así, la parte importante de la función -musical vacía es el proceso realizado por la función, no la expresión -musical que se devuelve. -@example -noApuntarYPulsar = -#(define-music-function (parser location) () - (ly:set-option 'point-and-click #f) - (make-music 'SequentialMusic 'void #t)) -... -\noApuntarYPulsar % desactivar la funcionalidad Apuntar y Pulsar. -@end example +@node Funciones de eventos +@section Funciones de eventos +@translationof Event functions +@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 Funciones de marcado @section Funciones de marcado @translationof Markup functions -Los elementos de marcado están implementados como funciones de Scheme -especiales que producen un objeto @code{Stencil} dada una serie de -argumentos. +Los elementos de marcado están implementados como funciones de +Scheme especiales que producen un objeto @code{Stencil} dada una +serie de argumentos. @menu @@ -291,45 +671,78 @@ argumentos. @translationof Markup construction in Scheme @cindex marcado, definir instrucciones de +@funindex \displayScheme + +Las expresiones de marcado se representan internamente en Scheme +usando el macro @code{markup}: + +@example +(markup @var{expr}) +@end example -El macro @code{markup} construye expresiones de marcado en Scheme, -proporcionando una sintaxis similar a la de LilyPond. Por ejemplo: +Para ver una expresión de marcado en su forma de Scheme, utilice +la instrucción @code{\displayScheme}: @example -(markup #:column (#:line (#:bold #:italic "hola" #:raise 0.4 "mundo") - #:larger #:line ("fulano" "fulanito" "menganito"))) +\displayScheme +\markup @{ + \column @{ + \line @{ \bold \italic "hola" \raise #0.4 "mundo" @} + \larger \line @{ fulano fulanito menganito @} + @} +@} @end example @noindent -equivale a: +La compilación del código anterior envía a la consola lo +siguiente: + @example -\markup \column @{ \line @{ \bold \italic "hola" \raise #0.4 "mundo" @} - \larger \line @{ fulano fulanito menganito @} @} +(markup + #:line + (#:column + (#:line + (#:bold (#:italic "hola") #:raise 0.4 "mundo") + #:larger + (#:line + (#:simple "fulano" #:simple "fulanito" #:simple "menganito"))))) @end example +Para evitar que el marcado se imprima en la página, use +@w{@samp{\void \displayScheme @var{marcado}}}. Asimismo, como +ocurre con la instrucción @code{\displayMusic}, la salida de +@code{\displayScheme} se puede guardar en un archivo externo. +Véase @ref{Presentación de las expresiones musicales}. + @noindent -Este ejemplo muestra las principales reglas de traducción entre la -sintaxis del marcado normal de LilyPond y la sintaxis del marcado de -Scheme. +Este ejemplo muestra las principales reglas de traducción entre +la sintaxis del marcado normal de LilyPond y la sintaxis del +marcado de Scheme. La utilización de @code{#@{ @dots{} #@}} para +escribir en la sintaxis de LilyPond será con frecuencia lo más +conveniente, pero explicamos cómo usar la macro @code{markup} +para obtener una solución sólo con Scheme. @quotation @multitable @columnfractions .3 .3 @item @b{LilyPond} @tab @b{Scheme} @item @code{\markup marcado1} @tab @code{(markup marcado1)} -@item @code{\markup @{ marcado1 marcado2 ... @}} @tab - @code{(markup marcado1 marcado2 ... )} +@item @code{\markup @{ marcado1 marcado2 @dots{} @}} @tab + @code{(markup marcado1 marcado2 @dots{} )} @item @code{\instruccion} @tab @code{#:instruccion} @item @code{\variable} @tab @code{variable} -@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} +@item @code{\center-column @{ @dots{} @}} @tab + @code{#:center-column ( @dots{} )} @item @code{cadena} @tab @code{"cadena"} @item @code{#argumento-de-scheme} @tab @code{argumento-de-scheme} @end multitable @end quotation -Todo el lenguaje Scheme está accesible dentro del macro @code{markup}. -Por ejemplo, podemos usar llamadas a funciones dentro de @code{markup} -para así manipular cadenas de caracteres. Esto es útil si se están -definiendo instrucciones de marcado nuevas (véase @ref{Definición de una instrucción de marcado nueva}). +Todo el lenguaje Scheme está accesible dentro del macro +@code{markup}. Por ejemplo, podemos usar llamadas a funciones +dentro de @code{markup} para así manipular cadenas de caracteres. +Esto es útil si se están definiendo instrucciones de marcado +nuevas (véase @ref{Definición de una instrucción de marcado +nueva}). @knownissues @@ -343,8 +756,9 @@ resultado de la llamada a una función. @end lisp @noindent -no es válido. Hay que usar las funciones @code{make-line-markup}, -@code{make-center-markup} o @code{make-column-markup} en su lugar: +no es válido. Hay que usar las funciones +@code{make-line-markup}, @code{make-center-markup} o +@code{make-column-markup} en su lugar: @lisp (markup (make-line-markup (funcion-que-devuelve-marcados))) @@ -380,11 +794,11 @@ sellos), se llama la función @code{raise-markup} como @var{el marcado "ejemplo de texto"}) @end example -Primero la función @code{raise-markup} crea el sello para la cadena -@code{ejemplo de texto}, y después eleva el sello Stencil en 0.5 -espacios de pentagrama. Este es un ejemplo bastante simple; en el -resto de la sección podrán verse ejemplos más complejos, así como en -@file{scm/define-markup-commands.scm}. +Primero la función @code{raise-markup} crea el sello para la +cadena @code{ejemplo de texto}, y después eleva el sello Stencil +en 0.5 espacios de pentagrama. Este es un ejemplo bastante +simple; en el resto de la sección podrán verse ejemplos más +complejos, así como en @file{scm/define-markup-commands.scm}. @node Definición de una instrucción de marcado nueva @@ -406,15 +820,16 @@ 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. +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{tipo-de-arg1?} @var{tipo-de-arg2?} ...) +(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}) - ...) ] - ..command body..) + @dots{}) ] + @dots{}command body@dots{}) @end lisp Los argumentos son @@ -433,9 +848,10 @@ argumento @var{i}-ésimo de la instrucción 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. +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 @@ -446,28 +862,54 @@ Los argumentos se distinguen según su tipo: @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 -reindimiento 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. +No existe ninguna limitación en el orden de los argumentos +(después de los argumentos estándar @code{layout} y +@code{props}). Sin embargo, las funciones de marcado que toman +un elemento de marcado como su último argumento son un poco +especiales porque podemos aplicarlas a una lista de marcados y el +resultado es una lista de marcados donde la función de marcado +(con los argumentos antecedentes especificados) se ha aplicado a +todos los elementos de la lista de marcados original. + +Dado que la replicación de los argumentos precedentes para +aplicar una función de marcado a una lista de marcados es poco +costosa principalmente por los argumentos de Scheme, se evitan +las caídas de rendimiento simplemente mediante la utilización de +argumentos de Scheme para los argumentos antecedentes de las +funciones de marcado que toman un marcado como su último +argumento. + +@funindex \markup +@cindex markup macro +@funindex interpret-markup +Las instrucciones de marcado tienen un ciclo de vida más bien +complejo. El cuerpo de la definición de una instrucción de +marcado es responsable de la conversión de los argumentos de la +instrucción de marcado en una expresión de sello que se devuelve. +Muy a menudo esto se lleva a cabo llamando a la función +@code{interpret-markup} sobre una expresión de marcado, pasándole +los argumentos @var{layout} y @var{props}. Por lo general, estos +argumentos se conocen solamente en una fase muy tardía de la +composición tipográfica. Las expresiones de marcado ya tienen +sus componentes ensamblados dentro de expresiones de marcado +cuando se expanden las instrucciones @code{\markup} (dentro de +una expresión de LilyPond) o la macro @code{markup} (dentro de +Scheme). La evaluación y la comprobación de tipos de los +argumentos de la instrucción de marcado tiene lugar en el momento +en que se interpretan @code{\markup} o @code{markup}. + +Pero la conversión real de expresiones de marcado en expresiones +de sello mediante la ejecución de los cuerpos de función de +marcado solo tienen lugar cuando se llama a +@code{interpret-markup} sobre una expresión de marcado. @node Acerca de las propiedades @unnumberedsubsubsec Acerca de las propiedades @translationof On properties -Los argumentos @code{layout} y @code{props} de las instrucciones de -marcado traen a escena un contexto para la interpretación del marcado: -tamaño de la tipografía, grueso de línea, etc. +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 @@ -478,21 +920,21 @@ mismo que el que se usa en las partituras) se lee usando: (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 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. @@ -502,39 +944,51 @@ sobreescribir las propiedades de una instrucción de marcado. @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. +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}: +utilizando marcados. Una consulta a @ruser{Instrucciones de +marcado de texto} nos muestra que es útil la instrucción +@code{\box}: @lilypond[quote,verbatim,ragged-right] \markup \box \box HELLO @end lilypond -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: +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: +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 +\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. +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 + +o, de forma equivalente, @lisp #(define-markup-command (double-box layout props text) (markup?) @@ -545,13 +999,14 @@ rectángulos y añade una separación. @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. +@code{markup?} es el tipo: lo identifica como un elemento de +marcado. La función @code{interpret-markup} se usa en casi todas +las instrucciones de marcado: construye un sello, usando +@code{layout}, @code{props}, y un elemento de marcado. En el +segundo caso, la marca se construye usando el macro de Scheme +@code{markup}, véase @ref{Construcción de elementos de marcado en +Scheme}. La transformación de una expresión @code{\markup} en +una expresión de marcado de Scheme es directa. La instrucción nueva se puede usar como sigue: @@ -559,14 +1014,29 @@ La instrucción nueva se puede usar como sigue: \markup \double-box A @end example -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: +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?) @@ -578,19 +1048,20 @@ Ahora el código nuevo es como se ve a continuación: #: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. +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. +@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: +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?) @@ -598,8 +1069,9 @@ y el relleno de los rectángulos se puede personalizar: (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 \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 @@ -611,15 +1083,15 @@ y el relleno de los rectángulos se puede personalizar: @unnumberedsubsubsec Adaptación de instrucciones incorporadas @translationof Adapting builtin commands -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 +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 +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 @@ -627,7 +1099,7 @@ documentación): (number-pair?) #:category graphic #:properties ((thickness 1)) - "...documentación..." + "@dots{}documentación@dots{}" (let ((th (* (ly:output-def-lookup layout 'line-thickness) thickness)) (x (car dest)) @@ -635,17 +1107,18 @@ documentación): (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. +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)) - "...documentación..." + "@dots{}documentación@dots{}" (let ((th (* (ly:output-def-lookup layout 'line-thickness) thickness)) (x (car dest)) @@ -653,22 +1126,23 @@ instrucciones de marcado definidas por el usuario. (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: +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)) - "...documentación..." - ... + "@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}: +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) @@ -700,17 +1174,29 @@ sellos resultantes se combinan usando @code{ly:stencil-add}: @subsection Definición de nuevas instrucciones de lista de marcado @translationof New markup list command definition +@funindex define-markup-list-command +@funindex interpret-markup-list + Las instrucciones de listas de marcado se definen con el macro de Scheme @code{define-markup-list-command}, que es similar al macro @code{define-markup-command} descrito en @ref{Definición de una instrucción de marcado nueva}, excepto que donde éste devuelve un sello único, aquél devuelve una lista de sellos. -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}. +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)) @@ -720,25 +1206,27 @@ del argumento @code{props}. @end example Aparte de los argumentos usuales @code{layout} y @code{props}, la -instrucción de lista de marcados @code{paragraph} toma un argumento de -lista de marcados, llamado @code{args}. El predicado para listas de -marcados es @code{markup-list?}. - -En primer lugar, la función toma el ancho del sangrado, una propiedad -llamada aquí @code{par-indent}, de la lista de propiedades -@code{props}. Si no se encuentra la propiedad, el valor -predeterminado es @code{2}. Después, se hace una lista de líneas -justificadas usando la función -@code{make-justified-lines-markup-list}, que está relacionada con la -instrucción incorporada de lista de marcados @code{\justified-lines}. -Se añade un espacio horizontal al principio usando la función -@code{make-hspace-markup}. Finalmente, la lista de marcados se -interpreta usando la función @code{interpret-markup-list}. - -Esta nueva instrucción de lista de marcados se puede usar como sigue: +instrucción de lista de marcados @code{paragraph} toma un +argumento de lista de marcados, llamado @code{args}. El +predicado para listas de marcados es @code{markup-list?}. + +En primer lugar, la función toma el ancho del sangrado, una +propiedad llamada aquí @code{par-indent}, de la lista de +propiedades @code{props}. Si no se encuentra la propiedad, el +valor predeterminado es @code{2}. Después, se hace una lista de +líneas justificadas usando la instrucción incorporada de lista de +marcados @code{\justified-lines}, que está relacionada con la +función @code{make-justified-lines-markup-list}. Se añade un +espacio horizontal al principio usando @code{\hspace} (o la +función @code{make-hspace-markup}). Finalmente, la lista de +marcados se interpreta usando la función +@code{interpret-markup-list}. + +Esta nueva instrucción de lista de marcados se puede usar como +sigue: @example -\markuplines @{ +\markuplist @{ \paragraph @{ El arte de la tipografía musical se llama \italic @{grabado (en plancha).@} El término deriva del proceso tradicional de impresión de música. @@ -770,26 +1258,141 @@ Esta nueva instrucción de lista de marcados se puede usar como sigue: @cindex código, llamadas durante la interpretación @funindex \applyContext +@funindex make-apply-context +@funindex ly:context-property +@funindex ly:context-set-property! +@funindex ly:context-grob-definition +@funindex ly:assoc-get +@funindex ly:context-pushpop-property -Se pueden modificar los contextos durante la interpretación con código -de Scheme. La sintaxis para esto es +Se pueden modificar los contextos durante la interpretación con +código de Scheme. Dentro de un bloque de código de LilyPond, la +sintaxis para esto es: @example \applyContext @var{función} @end example -@code{@var{función}} debe ser una función de Scheme que toma un único -argumento, que es el contexto al que aplicarla. El código siguiente -imprime el número del compás actual sobre la salida estándar durante -la compilación: +En código de Scheme, la sintaxis es: @example -\applyContext - #(lambda (x) - (format #t "\nSe nos ha llamado en el compás número ~a.\n" - (ly:context-property x 'currentBarNumber))) +(make-apply-context @var{function}) @end example +@code{@var{función}} debe ser una función de Scheme que toma un +único argumento, que es el contexto al que aplicarla. La función +puede acceder a, así como sobreescribir u establecer propiedades +de grobs s y propiedades de contextos. Cualquier acción tomada +por la función que dependa del estado del contexto, está limitada +al estado del contexto @emph{en el momento de llamar a la +función}. Asimismo, los cambios efectuados por una llamada a +@code{\applyContext} permanecen en efecto hasta que se modifican +de nuevo directamente, o se revierten, incluso si han cambiado las +condiciones iniciales sobre las que dependen. + +Las siguientes funciones de Scheme son útiles cuando se utiliza +@code{\applyContext}: + +@table @code +@item ly:context-property +recuperar el valor de una propiedad de contexto + +@item ly:context-set-property! +establecer el valor de una propiedad de contexto + +@item ly:context-grob-definition +@itemx ly:assoc-get +recuperar el valor de una propiedad de un grob + +@item ly:context-pushpop-property +hacer una sobreescritura temporal +(@code{\temporary@tie{}\override}) o una reversión +(@code{\revert}) sobre una propiedad de un grob +@end table + +El ejemplo siguiente recupera el valor actual de @code{fontSize}, +y a continuación lo dobla: + +@lilypond[quote,verbatim] +doubleFontSize = +\applyContext + #(lambda (context) + (let ((fontSize (ly:context-property context 'fontSize))) + (ly:context-set-property! context 'fontSize (+ fontSize 6)))) + +{ + \set fontSize = -3 + b'4 + \doubleFontSize + b' +} +@end lilypond + + +El ejemplo siguiente recupera los colores actuales de los grobs +@code{NoteHead}, @code{Stem} y @code{Beam}, y a continuación los +modifica para que tengan un matiz menos saturado. + +@lilypond[quote,verbatim] +desaturate = +\applyContext + #(lambda (context) + (define (desaturate-grob grob) + (let* ((grob-def (ly:context-grob-definition context grob)) + (color (ly:assoc-get 'color grob-def black)) + (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color))) + (ly:context-pushpop-property context grob 'color new-color))) + (for-each desaturate-grob '(NoteHead Stem Beam))) + +\relative { + \time 3/4 + g'8[ g] \desaturate g[ g] \desaturate g[ g] + \override NoteHead.color = #darkred + \override Stem.color = #darkred + \override Beam.color = #darkred + g[ g] \desaturate g[ g] \desaturate g[ g] +} +@end lilypond + + +Esto puede implementarse también como una función musical, con el +objeto de restringir las modificaciones a un único bloque de +música. Observe cómo se usa @code{ly:context-pushpop-property} +tanto como una sobreescritura temporal +(@code{\temporary@tie{}\override}) como una reversión +(@code{\revert}): + +@lilypond[quote,verbatim] +desaturate = +#(define-music-function + (music) (ly:music?) + #{ + \applyContext + #(lambda (context) + (define (desaturate-grob grob) + (let* ((grob-def (ly:context-grob-definition context grob)) + (color (ly:assoc-get 'color grob-def black)) + (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color))) + (ly:context-pushpop-property context grob 'color new-color))) + (for-each desaturate-grob '(NoteHead Stem Beam))) + #music + \applyContext + #(lambda (context) + (define (revert-color grob) + (ly:context-pushpop-property context grob 'color)) + (for-each revert-color '(NoteHead Stem Beam))) + #}) + +\relative { + \override NoteHead.color = #darkblue + \override Stem.color = #darkblue + \override Beam.color = #darkblue + g'8 a b c + \desaturate { d c b a } + g b d b g2 +} +@end lilypond + @node Ejecutar una función sobre todos los objetos de la presentación @subsection Ejecutar una función sobre todos los objetos de la presentación @@ -798,21 +1401,28 @@ la compilació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 +@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{contexto} @var{proc} +\applyOutput @var{Context}.@var{Grob} @var{proc} @end example @noindent -donde @code{@var{proc}} es una función de Scheme que toma tres argumentos. +donde @code{@var{proc}} es una función de Scheme que toma tres +argumentos. -Al interpretarse, la función @code{@var{proc}} se llama para cada objeto de -presentación que se encuentra en el contexto @code{@var{contexto}} +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 @@ -824,50 +1434,59 @@ en el tiempo actual, con los siguientes argumentos: 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}. +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: +cabezas de las notas que están sobre la línea central y junto a +ella: @lilypond[quote,verbatim,ragged-right] #(define (blanker grob grob-origin context) - (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) - (< (abs (ly:grob-property grob 'staff-position)) 2)) + (if (< (abs (ly:grob-property grob 'staff-position)) 2) (set! (ly:grob-property grob 'transparent) #t))) -\relative c' { - a'4 e8 <<\applyOutput #'Voice #blanker a c d>> b2 +\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 Funciones de callback @section Funciones de callback @translationof Callback functions Las propiedades (como @code{thickness} (grosor), @code{direction} -(dirección), etc.) se pueden establecer a valores fijos con \override, -p. ej.: +(dirección), etc.) se pueden establecer a valores fijos con +\override, p. ej.: @example -\override Stem #'thickness = #2.0 +\override Stem.thickness = #2.0 @end example -Las propiedades pueden fijarse también a un procedimiento de scheme, +Las propiedades pueden fijarse también a un procedimiento de +Scheme: -@lilypond[fragment,verbatim,quote,relative=2] -\override Stem #'thickness = #(lambda (grob) +@lilypond[fragment,verbatim,quote] +\override Stem.thickness = #(lambda (grob) (if (= UP (ly:grob-property grob 'direction)) 2.0 7.0)) -c b a g b a g b +\relative { c'' b a g b a g b } @end lilypond @noindent -En este caso, el procedimiento se ejecuta tan pronto como el valor de -la propiedad se reclama durante el proceso de formateo. +En este caso, el procedimiento se ejecuta tan pronto como el valor +de la propiedad se reclama durante el proceso de formateo. Casi todo el motor de tipografiado está manejado por estos @emph{callbacks}. Entre las propiedades que usan normalmente @@ -882,44 +1501,23 @@ Casi todo el motor de tipografiado está manejado por estos La rutina que calcula la anchura de un objeto @end table -El procedimiento siempre toma un argumento único, que es el grob (el -objeto gráfico). +El procedimiento siempre toma un argumento único, que es el grob +(el objeto gráfico). -Si se deben llamar rutinas con varios argumentos, el grob actual se -puede insertar con una cerradura de grob. He aquí un ajuste -procedente de @code{AccidentalSuggestion}, +Dicho procedimiento puede acceder al valor usual de la propiedad, +llamando en primer lugar a la función que es el @q{callback} usual +para esa propiedad, y que puede verse en el manual de referencia +interna o en el archivo 'define-grobs.scm': @example -`(X-offset . - ,(ly:make-simple-closure - `(,+ - ,(ly:make-simple-closure - (list ly:self-alignment-interface::centered-on-x-parent)) - ,(ly:make-simple-closure - (list ly:self-alignment-interface::x-aligned-on-self))))) -@end example - -@noindent -En este ejemplo, tanto -@code{ly:self-alignment-interface::x-aligned-on-self} como -@code{ly:self-alignment-interface::centered-on-x-parent} se llaman con -el grob como argumento. El resultado se añade con la función -@code{+}. Para asegurar que esta adición se ejecuta adecuadamente, -todo ello se encierra dentro de @code{ly:make-simple-closure}. - -De hecho, usar un solo procedimiento como valor de una propiedad -equivale a - -@example -(ly:make-simple-closure (ly:make-simple-closure (list @var{proc}))) +\relative @{ + \override Flag.X-offset = #(lambda (flag) + (let ((default (ly:flag::calc-x-offset flag))) + (* default 4.0))) + c''4. d8 a4. g8 +@} @end example -@noindent -El @code{ly:make-simple-closure} interior aporta el grob como -argumento de @var{proc}, el exterior asegura que el resultado de la -función es lo que se devuelve, en lugar del objeto -@code{simple-closure}. - 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: @@ -928,27 +1526,31 @@ mi-callback = #(lambda (grob) (grob-interpret-markup grob (markup "fulanito"))) @end example +@ignore -@node Código de Scheme en línea -@section Código de Scheme en línea -@translationof Inline Scheme code +@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. +sintáctica. Por ejemplo, lo siguiente produce un error de sintaxis (o +más bien: así lo hacía en algún momento del pasado): @example -F = \tweak #'font-size #-3 -\flageolet +F = \tweak font-size #-3 -\flageolet -\relative c'' @{ - c4^\F c4_\F +\relative @{ + c''4^\F c4_\F @} @end example @noindent -En otras palabras, @code{\tweak} no se comporta como una articulación -en cuando a la sintaxis; concretamente, no se puede adjuntar con -@code{^} y @code{_}. - Usando Scheme, se puede dar un rodeo a este problema. La ruta hacia el resultado se da en @ref{Añadir articulaciones a las notas (ejemplo)}, especialmente cómo usar @code{\displayMusic} como guía de @@ -962,8 +1564,8 @@ F = #(let ((m (make-music 'ArticulationEvent (ly:music-property m 'tweaks))) m) -\relative c'' @{ - c4^\F c4_\F +\relative @{ + c''4^\F c4_\F @} @end example @@ -976,6 +1578,8 @@ función de Scheme @code{acons}, y finalmente el resultado se escribe de nuevo con @code{set!}. El último elemento del bloque @code{let} es el valor de retorno, el propio @code{m}. +@end ignore + @node Trucos difíciles @section Trucos difíciles @@ -988,18 +1592,19 @@ Hay un cierto número de tipos de ajustes difíciles. @item Un tipo de ajuste difícil es la apariencia de los objetos de -extensión, como las ligaduras de expresión y de unión. Inicialmente, -sólo se crea uno de estos objetos, y pueden ajustarse con el mecanismo -normal. Sin embargo, en ciertos casos los objetos extensores cruzan -los saltos de línea. Si esto ocurre, estos objetos se clonan. Se -crea un objeto distinto por cada sistema en que se encuentra. Éstos -son clones del objeto original y heredan todas sus propiedades, -incluidos los @code{\override}s. +extensión, como las ligaduras de expresión y de unión. +Inicialmente, sólo se crea uno de estos objetos, y pueden +ajustarse con el mecanismo normal. Sin embargo, en ciertos casos +los objetos extensores cruzan los saltos de línea. Si esto +ocurre, estos objetos se clonan. Se crea un objeto distinto por +cada sistema en que se encuentra. Éstos son clones del objeto +original y heredan todas sus propiedades, incluidos los +@code{\override}s. En otras palabras, un @code{\override} siempre afecta a todas las -piezas de un objeto de extensión fragmentado. Para cambiar sólo una -parte de un extensor en el salto de línea, es necesario inmiscuirse en -el proceso de formateado. El @emph{callback} +piezas de un objeto de extensión fragmentado. Para cambiar sólo +una parte de un extensor en el salto de línea, es necesario +inmiscuirse en el proceso de formateado. El @emph{callback} @code{after-line-breaking} contiene el procedimiento Scheme que se llama después de que se han determinado los saltos de línea, y los objetos de presentación han sido divididos sobre los distintos @@ -1019,9 +1624,9 @@ comprueba si somos el último de los objetos divididos en caso afirmativo, establece @code{extra-offset}. @end itemize -Este procedimiento se instala en @rinternals{Tie} (ligadura de unión), -de forma que la última parte de la ligadura dividida se traslada hacia -arriba. +Este procedimiento se instala en @rinternals{Tie} (ligadura de +unión), de forma que la última parte de la ligadura dividida se +traslada hacia arriba. @lilypond[quote,verbatim,ragged-right] #(define (my-callback grob) @@ -1038,18 +1643,18 @@ arriba. (eq? (car (last-pair siblings)) grob)) (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) -\relative c'' { - \override Tie #'after-line-breaking = +\relative { + \override Tie.after-line-breaking = #my-callback - c1 ~ \break - c2 ~ c + c''1 ~ \break + c2 ~ 2 } @end lilypond @noindent Al aplicar este truco, la nueva función de callback -@code{after-line-breaking} también debe llamar a la antigua, -si existe este valor predeterminado. Por ejemplo, si se usa con +@code{after-line-breaking} también debe llamar a la antigua, si +existe este valor predeterminado. Por ejemplo, si se usa con @code{Hairpin}, se debe llamar también a @code{ly:spanner::kill-zero-spanned-time}. @@ -1057,14 +1662,15 @@ si existe este valor predeterminado. Por ejemplo, si se usa con @item Algunos objetos no se pueden cambiar con @code{\override} por razones técnicas. Son ejemplos @code{NonMusicalPaperColumn} y @code{PaperColumn}. Se pueden cambiar con la función -@code{\overrideProperty} que funciona de forma similar a @code{\once -\override}, pero usa una sintaxis distinta. +@code{\overrideProperty} que funciona de forma similar a +@code{\once \override}, pero usa una sintaxis distinta. @example \overrideProperty -#"Score.NonMusicalPaperColumn" % Nombre del grob -#'line-break-system-details % Nombre de la propiedad -#'((next-padding . 20)) % Valor +Score.NonMusicalPaperColumn % Nombre del grob + . line-break-system-details % Nombre de la propiedad + . next-padding % Nombre de la subpropiedad, opcional + #20 % Valor @end example Observe, sin embargo, que @code{\override}, aplicado a