From: Francisco Vila Date: Sat, 27 Feb 2010 17:39:05 +0000 (+0100) Subject: Doc-es: update of Programming Interfaces. X-Git-Tag: release/2.13.16-1~43^2~17 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=641edd4d4027d09484c00386ec827afb25244f3a;p=lilypond.git Doc-es: update of Programming Interfaces. --- diff --git a/Documentation/es/extending/programming-interface.itely b/Documentation/es/extending/programming-interface.itely index d175bda285..f08d2650ad 100644 --- a/Documentation/es/extending/programming-interface.itely +++ b/Documentation/es/extending/programming-interface.itely @@ -1,11 +1,10 @@ @c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- - +@c This file is part of extending.tely @ignore - Translation of GIT committish: d4f58bb3ad4e7fe1967a6b48f25e3addffc8aa14 + Translation of GIT committish: 3dd778f33e8681d58716b08e52a167ce5347aa84 When revising a translation, copy the HEAD committish of the - version that you are working on. For details, see the Contributors' - Guide, node Updating translation committishes.. + version that you are working on. See TRANSLATION for details. @end ignore @c \version "2.12.0" @@ -16,90 +15,113 @@ Se pueden realizar trucos avanzados mediante el uso de Scheme. Si no está familiarizado con Scheme, le conviene leer nuestro tutorial de -Scheme, @rlearning{Tutorial de Scheme}. +Scheme, @ref{Tutorial de Scheme}. + @menu * Funciones musicales:: -* Interfaces para el programador:: -* Interfaz de marcado para el programador:: +* Funciones de marcado:: * Contextos para programadores:: -* Procedimientos de Scheme como propiedades:: -* Usar código de Scheme en lugar de \tweak:: +* Funciones de callback:: +* Código de Scheme en línea:: * Trucos difíciles:: @end menu - @node Funciones musicales @section Funciones musicales @translationof Music functions -Esta sección trata sobre cómo crear funciones musicales dentro de -LilyPond. +Las funciones musicales son funciones de Scheme que se utilizan para +crear automáticamente expresiones musicales. Se pueden usar para +simplificar enormemente el archivo de entrada. @menu -* Panorámica de las funciones musicales:: +* Sintaxis de las funciones musicales:: * Funciones de sustitución sencillas:: -* Funciones de sustitutión en parejas:: +* Funciones de sustitución intermedias:: * Matemáticas dentro de las funciones:: * Funciones vacías:: * Funciones sin argumentos:: -* Panorámica de las funciones musicales disponibles:: @end menu -@node Panorámica de las funciones musicales -@subsection Panorámica de las funciones musicales -@translationof Overview of music functions +@node Sintaxis de las funciones musicales +@subsection Sintaxis de las funciones musicales +@translationof Music function syntax -Es fácil hacer una función que sustituya a una variable en código de -LilyPond. La forma general de estas funciones es: +La sintaxis general de una función musical es: @example -function = -#(define-music-function (parser location @var{var1} @var{var2}...@var{vari}... ) - (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...) - #@{ - @emph{...música...} - #@}) +miFuncion = +#(define-music-function (parser location @var{var_1} @var{var_2}...@var{var_n}) + (@var{var_1-type?} @var{var_2-type?}...@var{var_n-type?}) + @var{...expresión musical válida...}) @end example @noindent donde @multitable @columnfractions .33 .66 -@item @var{vari} @tab @var{i}-ésima variable -@item @var{vari-type?} @tab tipo de la @var{i}-ésima variable -@item @var{...música...} @tab entrada normal de LilyPond, usando las variables como @code{#$var1}, etc. +@item @var{var_i} @tab @var{i}-ésima variable +@item @var{var_i-type?} @tab tipo de la @var{i}-ésima variable +@item @var{...expresión musical válida...} @tab expresión que devuelve +música válida, generalmente en la forma de una expresión de Scheme. +También hay una sintaxis especial que permite la existencia de código +de entrada de LilyPond dentro de esta expresión musical. @end multitable -Los siguientes tipos de entrada se pueden usar como variables en una -función musical. Esta lista no es exhaustiva; consulte otros lugares -de la documentación específica de Scheme para ver otros tipos de -variables. +Los comprobadores de tipo de variable son procedimientos de Scheme que +devuelven @code{#t} si una variable es de un tipo dado. Se muestran +algunos tipos comunes en la tabla de abajo. Hay más tipos en los +archivos @file{lily/music-scheme.cc} y @file{scm/c++.scm}. @multitable @columnfractions .33 .66 -@headitem Tipo de entrada @tab notación de @var{vari-type?} -@item Entero @tab @code{integer?} -@item Flotante (número decimal) @tab @code{number?} -@item Cadena de texto @tab @code{string?} -@item Marcado @tab @code{markup?} -@item Expresión musical @tab @code{ly:music?} -@item Pareja de variables @tab @code{pair?} +@headitem Tipo de entrada @tab notación de @var{vari-type?} +@item Entero @tab @code{integer?} +@item Flotante (número decimal) @tab @code{number?} +@item Cadena de texto @tab @code{string?} +@item Marcado @tab @code{markup?} +@item Expresión musical @tab @code{ly:music?} +@item Pareja de variables @tab @code{pair?} @end multitable -Los argumentos @code{parser} y @code{location} son obligatorios, y se -usan en ciertas situaciones avanzadas. El argumento @code{parser} se -usa para tener acceso al valor de otra variable de LilyPond. El -argumento @code{location} se usa para establecer el @q{origen} de la -expresión musical que construye la función musical, de forma que en -caso de producirse un error de sintaxis LilyPond pueda informar al -usuario de un lugar adecuado donde buscar en el archivo de entrada. +Los argumentos @code{parser} y @code{location} son obligatorios. El +argumento @code{parser} se usa en el cuerpo de la función para tener +acceso al valor de otra variable de LilyPond. El argumento +@code{location} se usa para establecer el @q{origen} de la expresión +musical que se construye por parte de la función musical, de forma que +en caso de un error de sintaxis LilyPond pueda comunicar al usuario el +lugar adecuado del archivo de entrada en que buscar. @node Funciones de sustitución sencillas @subsection Funciones de sustitución sencillas @translationof Simple substitution functions -He aquí un ejemplo sencillo: +Una función de sustitución sencilla es una función musical cuya +expresión musical de salida está escrita en código de LilyPond, pero +con una variable de entrada sustituida en el código de LilyPond. La +forma general de estas funciones es: + +@example +miFuncion = +#(define-music-function (parser location @var{var1}) + (@var{var1-type?}) + #@{ + @emph{... código de entrada de LilyPond con} @code{#$var1} @emph{para sustituir ...} + #@}) +@end example + +Observe que los caracteres especiales @code{#@{} y @code{#@}} +encierran la música de LilyPond. + +@multitable @columnfractions .33 .66 +@item @var{vari} @tab @var{i}-ésima variable +@item @var{vari-type?} @tab tipo de la @var{i}-ésima variable +@item @var{...música...} @tab código de entrada normal de LilyPond, que utiliza variables como @code{#$var1}, etc. +@end multitable + +Por ejemplo, se puede definir una función que simplifique el +establecimiento de un relleno para un guión de texto TextScript: @lilypond[quote,verbatim,ragged-right] padText = #(define-music-function (parser location padding) (number?) @@ -116,7 +138,8 @@ padText = #(define-music-function (parser location padding) (number?) } @end lilypond -También se pueden sustituir las expresiones musicales: +Además de números, podemos usar expresiones musicales, como por +ejemplo notas, como argumentos de las funciones musicales: @lilypond[quote,verbatim,ragged-right] custosNote = #(define-music-function (parser location note) @@ -129,55 +152,42 @@ custosNote = #(define-music-function (parser location note) \once \override Voice.Stem #'stencil = ##f $note #}) - -{ c' d' e' f' \custosNote g' } @end lilypond -Se puede usar más de una variable: - -@lilypond[quote,verbatim,ragged-right] -tempoPadded = #(define-music-function (parser location padding tempotext) - (number? string?) -#{ - \once \override Score.MetronomeMark #'padding = $padding - \tempo \markup { \bold $tempotext } -#}) -\relative c'' { - \tempo \markup { "Low tempo" } - c4 d e f g1 - \tempoPadded #4.0 #"High tempo" - g4 f e d c1 -} -@end lilypond +@node Funciones de sustitución intermedias +@subsection Funciones de sustitución intermedias +@translationof Intermediate substitution functions +Algo más complicadas que las funciones de sustitución sencillas, las +funciones de sustitución intermedias contienen una mezcla de código de +Scheme y de LilyPond dentro de la expresión musical que se devuelve. -@node Funciones de sustitutión en parejas -@subsection Funciones de sustitutión en parejas -@translationof Paired substitution functions +Algunas instrucciones @code{\override} requieren un argumento que +consiste en una pareja de números (llamada una @code{célula cons} en +Scheme). -Algunas instrucciones @code{\override} requieren un par de números -(llamados en Scheme una @code{célula cons}). Para pasar estos números -a una función, usamos una variable @code{pair?} o bien insertamos el -@code{cons} en la función musical. +La pareja se puede pasar directamente dentro de la función musical, +usando una variable @code{pair?}: @quotation @example -manualBeam = -#(define-music-function (parser location beg-end) +barraManual = +#(define-music-function (parser location principio-final) (pair?) #@{ - \once \override Beam #'positions = #$beg-end + \once \override Beam #'positions = #$principio-final #@}) \relative @{ - \manualBeam #'(3 . 6) c8 d e f + \barraManual #'(3 . 6) c8 d e f @} @end example @end quotation -@noindent -o bien +De forma alternativa, los números que componen la pareja se pueden +pasar como argumentos separados, y el código de Scheme que se ha usado +para crear la pareja se puede incluir dentro de la expresión musical: @lilypond[quote,verbatim,ragged-right] manualBeam = @@ -250,12 +260,12 @@ musical vacía es el proceso realizado por la función, no la expresión musical que se devuelve. @example -noPointAndClick = +noApuntarYPulsar = #(define-music-function (parser location) () (ly:set-option 'point-and-click #f) (make-music 'SequentialMusic 'void #t)) ... -\noPointAndClick % desactivar la funcionalidad Apuntar y Pulsar. +\noApuntarYPulsar % desactivar la funcionalidad Apuntar y Pulsar. @end example @@ -274,7 +284,7 @@ Sin embargo, en raras ocasiones puede ser de utilidad crear una función musical sin argumentos: @example -displayBarNum = +mostrarNumeroDeCompas = #(define-music-function (parser location) () (if (eq? #t (ly:get-option 'display-bar-numbers)) #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} @@ -289,195 +299,24 @@ lilypond -d display-bar-numbers ARCHIVO.ly @end example -@node Panorámica de las funciones musicales disponibles -@subsection Panorámica de las funciones musicales disponibles -@translationof Overview of available music functions - -@c fixme ; this should be move somewhere else? -Las siguientes instrucciones son funciones musicales: - -@include identifiers.tely - - -@node Interfaces para el programador -@section Interfaces para el programador -@translationof Programmer interfaces - -Esta sección contiene información sobre cómo mezclar LilyPond y -Scheme. - -@menu -* Variables de entrada y Scheme:: -* Representación interna de la música:: -@end menu - -@node Variables de entrada y Scheme -@subsection Variables de entrada y Scheme -@translationof Input variables and Scheme - -El formato de entrada contempla la noción de variables: en el ejemplo -siguiente, se asigna una expresión musical a una variable con el -nombre @code{traLaLa}. - -@example -traLaLa = @{ c'4 d'4 @} -@end example - -@noindent - -También existe una forma de ámbito léxico: en el ejemplo siguiente, el -bloque @code{\layout} también contiene una variable @code{traLaLa}, -que es independiente de la @code{\traLaLa} exterior. - -@example -traLaLa = @{ c'4 d'4 @} -\layout @{ traLaLa = 1.0 @} -@end example -@c -De hecho, cada archivo de entrada es un ámbito léxico, y todos los -bloques @code{\header}, @code{\midi} y @code{\layout} son ámbitos -anidados dentro de dicho ámbito de nivel superior. - -Tanto el ámbito léxico como las variables están implementados en el -sistema de módulos GUILE. Se adjunta un módulo anónimo de Scheme a -cada ámbito. Una asignación de la forma -@example -traLaLa = @{ c'4 d'4 @} -@end example - -@noindent -se convierte internamente a una definición de Scheme -@example -(define traLaLa @var{Scheme value of `@code{... }'}) -@end example - -Esto supone que las variables de entrada y las variables de Scheme se -pueden entremezclar con libertad. En el ejemplo siguiente, se -almacena un fragmento musical en la variable @code{traLaLa}, y se -duplica utilizando Scheme. El resultado se importa en un bloque -@code{\score} por medio de una segunda variable @code{twice}: - -@lilypond[verbatim] -traLaLa = { c'4 d'4 } - -%% dummy action to deal with parser lookahead -#(display "this needs to be here, sorry!") - -#(define newLa (map ly:music-deep-copy - (list traLaLa traLaLa))) -#(define twice - (make-sequential-music newLa)) - -{ \twice } -@end lilypond - -@c Due to parser lookahead - -En este ejemplo, la asignación se produce después de que el analizador -sintáctico ha verificado que no ocurre nada interesante después de -@code{traLaLa = @{ ... @}}. Sin el argumento mudo del ejemplo, la -definición @code{newLa} se ejecuta antes de que se defina -@code{traLaLa}, conduciendo a un error de sintaxis. - -El ejemplo anterior muestra cómo @q{exportar} expresiones musicales -desde la entrada hasta el intérprete de Scheme. También es posible lo -contrario. Envolviendo un valor de Scheme en la función -@code{ly:export}, un valor de Scheme se interpreta como si hubiera -sido introducido en sintaxis de LilyPond. En vez de definir -@code{\twice}, el ejemplo anterior podría también haberse escrito como - -@example -... -@{ #(ly:export (make-sequential-music (list newLa))) @} -@end example - -El código de Scheme se evalúa tan pronto como el analizador sintáctico -lo encuentra. Para definir código de Scheme en un macro (para -llamarlo con posterioridad), use @ref{Funciones vacías}, o bien - -@example -#(define (nopc) - (ly:set-option 'point-and-click #f)) - -... -#(nopc) -@{ c'4 @} -@end example - -@knownissues - -No es posible mezclar variables de Scheme y de LilyPond con la opción -@code{--safe}. - - -@node Representación interna de la música -@subsection Representación interna de la música -@translationof Internal music representation - -Cuando se analiza sintácticamente una expresión musical, se convierte -en un conjunto de objetos musicales de Scheme. La propiedad que -define a un objeto musical es que tiene una cierta duración. El -tiempo es un número racional que mide la longitud de un fragmento de -música en unidades del valor de una redonda. - -Un objeto musical tiene tres clases de tipos: -@itemize -@item -nombre musical: cada expresión musical tiene un nombre. Por ejemplo, -una nota conduce a un evento @rinternals{NoteEvent}, y -@code{\simultaneous} conduce a @rinternals{SimultaneousMusic}. Hay -una lista de todas las expresiones que están disponibles en el Manual -de referencia de funcionamiento interno, bajo @rinternals{Music -expressions}. - -@item -@q{tipo} o interface: cada nombre de música tiene varios @q{tipos} o -interfaces, por ejemplo una nota es un @code{event}, pero también es -un @code{note-event}, un @code{rhythmic-event} y un -@code{melodic-event}. Todas las clases musicales se encuentran -relacionadas en la Referencia de funcionamiento interno bajo -@rinternals{Music classes}. - -@item -Objeto de C++: cada objeto musical está representado por un objeto de -la clase de C++ @code{Music}. -@end itemize +@node Funciones de marcado +@section Funciones de marcado +@translationof Markup functions -La información real de una expresión musical se almacena en forma de -propiedades. Por ejemplo, un evento @rinternals{NoteEvent} tiene -propiedades @code{pitch} y @code{duration} que almacenan la altura y -duración de la nota. Hay una lista completa de las propiedades que -están disponibles en la Referencia de funcionamiento interno, bajo -@rinternals{Music properties}. +Los elementos de marcado están implementados como funciones de Scheme +especiales que producen un objeto @code{Stencil} dada una serie de +argumentos. -Una expresión musical compuesta es un objeto musical que contiene -otros objetos musicales en sus propiedades. Se puede almacenar una -lista de objetos en la propiedad @code{elements} de un objeto musical, -o un solo objeto musical @q{hijo} en la propiedad @code{element}. Por -ejemplo, @rinternals{SequentialMusic} tiene sus hijos en -@code{elements}, y @rinternals{GraceMusic} tiene su elemento único en -@code{element}. El cuerpo de una repetición se almacena en la -propiedad @code{element} de @rinternals{RepeatedMusic}, y las -alternativas en @code{elements}. - - - -@node Interfaz de marcado para el programador -@section Interfaz de marcado para el programador -@translationof Markup programmer interface - -Los marcados están implementados como funciones de Scheme especiales -que producen un elemento Stencil (sello) dado un número de argumentos. @menu -* Construcción del marcado en Scheme:: -* Cómo funciona internamente el marcado:: +* Construcción de elementos de marcado en Scheme:: +* Cómo funcionan internamente los elementos de marcado:: * Definición de una instrucción de marcado nueva:: * Definición de nuevas instrucciones de lista de marcado:: @end menu -@node Construcción del marcado en Scheme -@subsection Construcción del marcado en Scheme +@node Construcción de elementos de marcado en Scheme +@subsection Construcción de elementos de marcado en Scheme @translationof Markup construction in Scheme @cindex marcado, definir instrucciones de @@ -521,10 +360,11 @@ Por ejemplo, podemos usar llamadas a funciones dentro de @code{markup} para así manipular cadenas de caracteres. Esto es útil si se están definiendo instrucciones de marcado nuevas (véase @ref{Definición de una instrucción de marcado nueva}). + @knownissues El argumento markup-list de instrucciones como @code{#:line}, -@code{#:center} y @code{#:column} no pueden se una variable o el +@code{#:center} y @code{#:column} no puede ser una variable ni el resultado de la llamada a una función. @lisp @@ -540,8 +380,8 @@ no es válido. Hay que usar las funciones @code{make-line-markup}, @end lisp -@node Cómo funciona internamente el marcado -@subsection Cómo funciona internamente el marcado +@node Cómo funcionan internamente los elementos de marcado +@subsection Cómo funcionan internamente los elementos de marcado @translationof How markups work internally En un elemento de marcado como @@ -580,218 +420,342 @@ resto de la sección podrán verse ejemplos más complejos, así como en @subsection Definición de una instrucción de marcado nueva @translationof New markup command definition -Las instrucciones de marcado nuevas se pueden definir con el macro de -Scheme @code{define-markup-command}. +Esta sección trata sobre la definición de nuevas instrucciones de +marcado. + + +@menu +* Sintaxis de la definición de instrucciones de marcado:: +* Acerca de las propiedades:: +* Un ejemplo completo:: +* Adaptación de instrucciones incorporadas:: +@end menu + +@node Sintaxis de la definición de instrucciones de marcado +@unnumberedsubsubsec Sintaxis de la definición de instrucciones de marcado +@translationof Markup command definition syntax + +Se pueden definir instrucciones de marcado nuevas usando el macro de +Scheme @code{define-markup-command}, en el nivel sintáctico superior. @lisp (define-markup-command (@var{nombre-de-la-instruccion} @var{layout} @var{props} @var{arg1} @var{arg2} ...) - (@var{arg1-type?} @var{arg2-type?} ...) + (@var{tipo-de-arg1?} @var{tipo-de-arg2?} ...) + [ #:properties ((@var{propiedad1} @var{valor-predeterminado1}) + ...) ] ..command body..) @end lisp Los argumentos son @table @var -@item argi -@var{i}-ésimo argumento de la instrucción -@item argi-type? -predicado de tipo para el argumento @var{i}-ésimo +@item nombre-de-la-instruccion +nombre de la instrucción de marcado @item layout -la definición de @q{presentación} +la definición de @q{layout} (disposición). @item props -lista de listas asociativas, que contiene todas las propiedades +una lista de listas asociativas, que contienen todas las propiedades activas. +@item argi +argumento @var{i}-ésimo de la instrucción +@item tipo-de-argi? +predicado de tipo para el argumento @var{i}-ésimo @end table -Como ejemplo sencillo, mostramos cómo añadir una instrucción -@code{\smallcaps}, que selecciona una tipografía de versalitas. -Normalmente podríamos seleccionar la tipografía de versalitas, +Si la instrucción utiliza propiedades de los argumentos @var{props}, +se puede usar la palabra clave @code{#:properties} para especificar +qué propiedades se usan, y sus valores predeterminados. -@example -\markup @{ \override #'(font-shape . caps) Texto-en-versalitas @} -@end example +@knownissues +Existen algunas restricciones sobre los argumentos posibles de una +instrucción de marcado. -@noindent -Esto selecciona la tipografía de versalitas mediante el -establecimiento de la propiedad @code{font-shape} a @code{#'caps} para -la interpretación de @code{Texto-en-versalitas}. +Los argumentos se distinguen según su tipo: +@itemize +@item un marcado, que corresponde al predicado de tipo @code{markup?}; +@item una lista de marcados, que corresponde al predicado de tipo +@code{markup-list?}; +@item cualquier otro objeto de Scheme, que corresponde a predicados de tipo como +@code{list?}, @code{number?}, @code{boolean?}, etc. +@end itemize -Para poner lo anterior disponible como la instrucción -@code{\smallcaps}, tenemos que definir una función utilizando -@code{define-markup-command}. La instrucción ha de tomar un argumento -del tipo @code{markup}. Por tanto, el inicio de la definición ha de -ser +Actualmente las combinaciones de argumentos que hay disponibles +(después de los argumentos estándar @var{layout} y @var{props}) para +una instrucción de marcado definida con @code{define-markup-command} +se limitan a la siguiente lista: -@example -(define-markup-command (smallcaps layout props argument) (markup?) -@end example +@table @asis +@item (sin argumentos) +@itemx @var{markup-list} +@itemx @var{markup} +@itemx @var{markup markup} +@itemx @var{scheme} +@itemx @var{scheme markup} +@itemx @var{scheme scheme} +@itemx @var{scheme scheme markup} +@itemx @var{scheme scheme markup markup} +@itemx @var{scheme markup markup} +@itemx @var{scheme scheme scheme} +@end table @noindent - -Lo que aparece a continuación es el contenido de la instrucción: -debemos interpretar el @code{argument} como un marcado, es decir: +Esto significa que no es posible definir con p.ej. tres argumentos de +Scheme y un argumento de marcado, como: @example -(interpret-markup layout @dots{} argument) +#(define-markup-command (fulanito layout props + num1 num2 lista marcado) + (number? number? list? markup?) + ...) @end example @noindent -Esta interpretación tiene que añadir @code{'(font-shape . caps)} a las -propiedades activas, por lo que sustituimos lo siguiente por los -@dots{} en el ejemplo anterior: +Si la aplicamos como, digamos, @example -(cons (list '(font-shape . caps) ) props) +\markup \fulanito #1 #2 #'(mengano zutano) Loquesea @end example +@cindex firma de Scheme +@cindex Scheme, firma de @noindent -La variable @code{props} es una lista de a-listas, y se lo anteponemos -haciendo la operación cons de una lista con el ajuste adicional. +@command{lilypond} protesta diciendo que no puede analizar +@code{fulanito} debido a su firma de Scheme desconocida. -Supongamos que estamos tipografiando un recitativo de una ópera y nos -gustaría definir una instrucción que presente los nombres de los -personajes de una forma personalizada. Queremos que los nombres se -impriman con versalitas y se desplacen un poco a la izquierda y hacia -arriba. Definimos una instrucción @code{\character} que toma en -cuenta la traslación necesaria y utiliza la instrucción -@code{\smallcaps} recién definida: + +@node Acerca de las propiedades +@unnumberedsubsubsec Acerca de las propiedades +@translationof On properties + +Los argumentos @code{layout} y @code{props} de las instrucciones de +marcado traen a escena un contexto para la interpretación del marcado: +tamaño de la tipografía, grueso de línea, etc. + +El argumento @code{layout} permite el acceso a las propiedades +definidas en los bloques @code{paper}, usando la función +@code{ly:output-def-lookup}. Por ejemplo, el grueso de línea (el +mismo que el que se usa en las partituras) se lee usando: @example -#(define-markup-command (character layout props nombre) (string?) - "Imprimir el nombre del personaje en versalitas, desplazado a la izquierda y hacia - arriba. Sintaxis: \\character #\"nombre\"" - (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps nombre))) +(ly:output-def-lookup layout 'line-width) @end example -Esta es una complicación que requiere una explicación: los textos por -encima y por debajo del pentagrama se mueven verticalmente de forma -que estén a una cierta distancia (la propiedad @code{padding}) del -pentagrama y de las notas. Para asegurar que este mecanismo no anula -el efecto de nuestro @code{#:translate}, añadimos una cadena vacía -(@code{#:hspace 0}) antes del texto trasladado. Ahora el -@code{#:hspace 0} se pone encima de las notas, y el @code{nombre} se -mueve en relación a dicha cadena vacía. El efecto neto es que el -texto se mueve hacia la izquierda y hacia arriba. +El argumento @code{props} hace accesibles algunas propiedades a las +instrucciones de marcado. Por ejemplo, cuando se interpreta el +marcado del título de un libro, todas las variables definidas dentro +del bloque @code{\header} se añaden automáticamente a @code{props}, de +manera que el marcado del título del libro puede acceder al título del +libro, el autor, etc. También es una forma de configurar el +comportamiento de una instrucción de marcado: por ejemplo, cuando una +instrucción utiliza tamaños de tipografía durante el procesado, el +tamaño se lee de @code{props} en vez de tener un argumento +@code{font-size}. El que llama a una instrucción de marcado puede +cambiar el valor de la propiedad del tamaño de la tipografía con el +objeto de modificar el comportamiento. Utilice la palabra clave +@code{#:properties} de @code{define-markup-command} para especificar +qué propiedades se deben leer a partir de los argumentos de +@code{props}. + +El ejemplo de la sección siguiente ilustra cómo acceder y +sobreescribir las propiedades de una instrucción de marcado. + + +@node Un ejemplo completo +@unnumberedsubsubsec Un ejemplo completo +@translationof A complete example + +El ejemplo siguiente define una instrucción de marcado para trazar un +rectángulo doble alrededor de un fragmento de texto. + +En primer lugar, necesitamos construir un resultado aproximado +utilizando marcados. Una consulta a @ruser{Text markup commands} nos +muestra que es útil la instrucción @code{\box}: + +@lilypond[quote,verbatim,ragged-right] +\markup \box \box HELLO +@end lilypond -El resultado final es como sigue: +Ahora, consideramos que es preferible tener más separación entre el +texto y los rectángulos. Según la documentación de @code{\box}, esta +instrucción usa una propiedad @code{box-padding}, cuyo valor +predeterminado es 0.2. La documentación también menciona cómo +sobreescribir este valor: + +@lilypond[quote,verbatim,ragged-right] +\markup \box \override #'(box-padding . 0.6) \box A +@end lilypond + +Después, el relleno o separación entre los dos rectángulos nos parece +muy pequeño, así que lo vamos a sobreescribir también: + +@lilypond[quote,verbatim,ragged-right] +\markup \override #'(box-padding . 0.4) \box \override #'(box-padding . 0.6) \box A +@end lilypond + +Repetir esta extensa instrucción de marcado una y otra vez sería un +quebradero de cabeza. Aquí es donde se necesita una instrucción de +marcado. Así pues, escribimos una instrucción de marcado +@code{double-box}, que toma un argumento (el texto). Dibuja los dos +rectángulos y añade una separación. + +@lisp +#(define-markup-command (double-box layout props text) (markup?) + "Trazar un rectángulo doble rodeando el texto." + (interpret-markup layout props + (markup #:override '(box-padding . 0.4) #:box + #:override '(box-padding . 0.6) #:box text))) +@end lisp + +@code{text} es el nombre del argumento de la instrucción, y +@code{markup?} es el tipo: lo identifica como un elemento de marcado. +La función @code{interpret-markup} se usa en casi todas las +instrucciones de marcado: construye un sello, usando @code{layout}, +@code{props}, y un elemento de marcado. Aquí, la marca se construye +usando el macro de Scheme @code{markup}, véase @ref{Construcción de +elementos de marcado en Scheme}. La transformación de una expresión +@code{\markup} en una expresión de marcado de Scheme es directa. + +La instrucción nueva se puede usar como sigue: @example -@{ - c''^\markup \character #"Cleopatra" - e'^\markup \character #"Giulio Cesare" -@} +\markup \double-box A @end example -@lilypond[quote,ragged-right] -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps. Syntax: \\smallcaps #\"string\"" - (interpret-markup layout props - (make-line-markup - (map (lambda (s) - (if (= (string-length s) 0) - s - (markup #:large (string-upcase (substring s 0 1)) - #:translate (cons -0.6 0) - #:tiny (string-upcase (substring s 1))))) - (string-split str #\Space))))) - -#(define-markup-command (character layout props name) (string?) - "Print the character name in small caps, translated to the left and - top. Syntax: \\character #\"name\"" +Sería buen hacer que la instrucción @code{double-box} fuera +personalizable: aquí, los valores de relleno @code{box-padding} son +fijos, y no se pueden cambiar por parte del usuario. Además, sería +mejor distinguir la separación entre los dos rectángulos, del relleno +entre el rectángulo interno y el texto. Así pues, introducimos una +nueva propiedad, @code{inter-box-padding}, para el relleno entre los +rectángulos. El @code{box-padding} se usará para el relleno interno. +Ahora el código nuevo es como se ve a continuación: + +@lisp +#(define-markup-command (double-box layout props text) (markup?) + #:properties ((inter-box-padding 0.4) + (box-padding 0.6)) + "Trazar un rectángulo doble rodeando el texto." (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) + (markup #:override `(box-padding . ,inter-box-padding) #:box + #:override `(box-padding . ,box-padding) #:box text))) +@end lisp -{ - c''^\markup \character #"Cleopatra" c'' c'' c'' - e'^\markup \character #"Giulio Cesare" e' e' e' -} -@end lilypond +Aquí, la palabra clave @code{#:properties} se usa de manera que las +propiedades @code{inter-box-padding} y @code{box-padding} se leen a +partir del argumento @code{props}, y se les proporcionan unos valores +predeterminados si las propiedades no están definidas. -Hemos usado la forma de fuente tipográfica @code{caps}, pero -supongamos que nuestra fuente no tiene la variante de versalitas. En -ese caso tenemos que hacer una falsa fuente de mayúsculas pequeñas -haciendo que la cadena en mayúsculas tenga la primera legra un poco -mayor: +Después estos valores se usan para sobreescribir las propiedades +@code{box-padding} usadas por las dos instrucciones @code{\box}. +Observe el apóstrofo invertido y la coma en el argumento de +@code{\override}: nos permiten introducir un valor de variable dentro +de una expresión literal. -@example -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps." +Ahora, la instrucción se puede usar dentro de un elemento de marcado, +y el relleno de los rectángulos se puede personalizar: + +@lilypond[quote,verbatim,ragged-right] +#(define-markup-command (double-box layout props text) (markup?) + #:properties ((inter-box-padding 0.4) + (box-padding 0.6)) + "Draw a double box around text." (interpret-markup layout props - (make-line-markup - (map (lambda (s) - (if (= (string-length s) 0) - s - (markup #:large (string-upcase (substring s 0 1)) - #:translate (cons -0.6 0) - #:tiny (string-upcase (substring s 1))))) - (string-split str #\Space))))) -@end example + (markup #:override `(box-padding . ,inter-box-padding) #:box + #:override `(box-padding . ,box-padding) #:box text))) -La instrucción @code{smallcaps} primero divide su argumento de cadena -en unidades o palabras separadas por espacios (@code{(string-split str -#\Space)}); para cada unidad o palabra, se construye un marcado con la -primera letra agrandada y en mayúscula (@code{#:large (string-upcase -(substring s 0 1))}), y un segundo marcado construido con las letras -siguientes reducidas de tamaño y en mayúsculas (@code{#:tiny -(string-upcase (substring s 1))}). Como LilyPond introduce un espacio -entre los marcados de una misma línea, el segundo marcado se traslada -a la izquierda (@code{#:translate (cons -0.6 0) ...}). Después, los -marcados construidos para cada palabra se ponen en una línea mediante -@code{(make-line-markup ...)}. Finalmente, el marcado resultante se -pasa a la función @code{interpret-markup}, con los argumentos -@code{layout} y @code{props}. - -Nota: ahora existe una instrucción interna @code{\smallCaps} que se -puede usar para poner texto en versalitas. Consulte @ref{Text markup commands}, para ver más detalles. +\markup \double-box A +\markup \override #'(inter-box-padding . 0.8) \double-box A +\markup \override #'(box-padding . 1.0) \double-box A +@end lilypond -@knownissues -Actualmente las combinaciones de argumentos que hay disponibles -(después de los argumentos estándar @var{layout} y @var{props}) para -una instrucción de marcado definida con @code{define-markup-command} -se limitan a la siguiente lista: +@node Adaptación de instrucciones incorporadas +@unnumberedsubsubsec Adaptación de instrucciones incorporadas +@translationof Adapting builtin commands -@table @asis -@item (ningún argumento) -@itemx @var{list} -@itemx @var{markup} -@itemx @var{markup markup} -@itemx @var{scm} -@itemx @var{scm markup} -@itemx @var{scm scm} -@itemx @var{scm scm markup} -@itemx @var{scm scm markup markup} -@itemx @var{scm markup markup} -@itemx @var{scm scm scm} -@end table +Una buena manera de comenzar a escribir una instrucción de marcado +nueva, es seguir el ejemplo de otra instrucción ya incorporada. Casi +todas las instrucciones de marcado que están incorporadas en LilyPond +se pueden encontrar en el archivo +@file{scm/@/define@/-markup@/-commands@/.scm}. -@noindent -En la tabla de arriba, @var{scm} representa los tipos de datos nativos -de Scheme como @q{number} (número) o @q{string} (cadena). +Por ejemplo, querríamos adaptar la instrucción @code{\draw-line}, para +que trace una línea doble. La instrucción @code{\draw-line} está +definida como sigue (se han suprimido los comentarios de +documentación): -Como ejemplo, no es posible usar una instrucción de marcado -@code{fulanito} con cuatro argumentos definida como +@lisp +(define-markup-command (draw-line layout props dest) + (number-pair?) + #:category graphic + #:properties ((thickness 1)) + "...documentación..." + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) +@end lisp -@example -#(define-markup-command (fulanito layout props - num1 str1 num2 str2) - (number? string? number? string?) - ...) -@end example +Para definir una instrucción nueva basada en otra existente, copie la +definición y cámbiele el nombre. La palabra clave @code{#:category} +se puede eliminar sin miedo, pues sólo se utiliza para generar +documentación de LilyPond, y no tiene ninguna utilidad para las +instrucciones de marcado definidas por el usuario. -@noindent -Si la aplicamos como, digamos, +@lisp +(define-markup-command (draw-double-line layout props dest) + (number-pair?) + #:properties ((thickness 1)) + "...documentación..." + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) +@end lisp -@example -\markup \fulanito #1 #"mengano" #2 #"zutano" -@end example +A continuación se añade una propiedad para establecer la separación +entre las dos líneas, llamada @code{line-gap}, con un valor +predeterminado de p.ej. 0.6: -@cindex Scheme signature -@cindex signature, Scheme -@noindent -@command{lilypond} protesta diciendo que no puede analizar -@code{fulanito} debido a su firma de Scheme desconocida. +@lisp +(define-markup-command (draw-double-line layout props dest) + (number-pair?) + #:properties ((thickness 1) + (line-gap 0.6)) + "...documentación..." + ... +@end lisp + +Finalmente, se añade el código para trazar las dos líneas. Se usan +dos llamadas a @code{make-line-stencil} para trazar las líneas, y los +sellos resultantes se combinan usando @code{ly:stencil-add}: + +@lilypond[quote,verbatim,ragged-right] +#(define-markup-command (my-draw-line layout props dest) + (number-pair?) + #:properties ((thickness 1) + (line-gap 0.6)) + "..documentation.." + (let* ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (dx (car dest)) + (dy (cdr dest)) + (w (/ line-gap 2.0)) + (x (cond ((= dx 0) w) + ((= dy 0) 0) + (else (/ w (sqrt (+ 1 (* (/ dx dy) (/ dx dy)))))))) + (y (* (if (< (* dx dy) 0) 1 -1) + (cond ((= dy 0) w) + ((= dx 0) 0) + (else (/ w (sqrt (+ 1 (* (/ dy dx) (/ dy dx)))))))))) + (ly:stencil-add (make-line-stencil th x y (+ dx x) (+ dy y)) + (make-line-stencil th (- x) (- y) (- dx x) (- dy y))))) + +\markup \my-draw-line #'(4 . 3) +\markup \override #'(line-gap . 1.2) \my-draw-line #'(4 . 3) +@end lilypond @node Definición de nuevas instrucciones de lista de marcado @@ -800,8 +764,9 @@ Si la aplicamos como, digamos, Las instrucciones de listas de marcado se definen con el macro de Scheme @code{define-markup-list-command}, que es similar al macro -@code{define-markup-command} descrito en @ref{Definición de una instrucción de marcado nueva}, excepto que donde éste devuelve un sello único, aquél -devuelve una lista de sellos. +@code{define-markup-command} descrito en @ref{Definición de una +instrucción de marcado nueva}, excepto que donde éste devuelve un +sello único, aquél devuelve una lista de sellos. En el siguiente ejemplo se define una instrucción de lista de marcado @code{\paragraph}, que devuelve una lista de líneas justificadas, @@ -810,10 +775,10 @@ del argumento @code{props}. @example #(define-markup-list-command (paragraph layout props args) (markup-list?) - (let ((indent (chain-assoc-get 'par-indent props 2))) - (interpret-markup-list layout props - (make-justified-lines-markup-list (cons (make-hspace-markup indent) - args))))) + #:properties ((par-indent 2)) + (interpret-markup-list layout props + (make-justified-lines-markup-list (cons (make-hspace-markup par-indent) + args)))) @end example Aparte de los argumentos usuales @code{layout} y @code{props}, la @@ -892,7 +857,6 @@ la compilación: @subsection Ejecutar una función sobre todos los objetos de la presentación @translationof Running a function on all layout objects - @cindex código, llamar sobre objetos de presentación @funindex \applyOutput @@ -917,6 +881,7 @@ siguientes argumentos: @item el contexto en que se procesa @code{\applyOutput}. @end itemize + Además, la causa del objeto de presentación, es decir el objeto o expresión musical que es responsable de haberlo creado, está en la propiedad @code{cause} del objeto. Por ejemplo, para la cabeza de una @@ -939,12 +904,13 @@ cabezas de las notas que están sobre la línea central: @end lilypond -@node Procedimientos de Scheme como propiedades -@section Procedimientos de Scheme como propiedades -@translationof Scheme procedures as properties +@node Funciones de callback +@section Funciones de callback +@translationof Callback functions -Las propiedades (como el grosor, la dirección, etc.) se pueden -establecer a valores fijos con \override, p. ej. +Las propiedades (como @code{thickness} (grosor), @code{direction} +(dirección), etc.) se pueden establecer a valores fijos con \override, +p. ej.: @example \override Stem #'thickness = #2.0 @@ -985,7 +951,7 @@ puede insertar con una cerradura de grob. He aquí un ajuste procedente de @code{AccidentalSuggestion}, @example -(X-offset . +`(X-offset . ,(ly:make-simple-closure `(,+ ,(ly:make-simple-closure @@ -1015,10 +981,18 @@ argumento de @var{proc}, el exterior asegura que el resultado de la función es lo que se devuelve, en lugar del objeto @code{simple-closure}. +Desde dentro de un callback, el método más fácil para evaluar un +elemento de marcado es usar grob-interpret-markup. Por ejemplo: + +@example +mi-callback = #(lambda (grob) + (grob-interpret-markup grob (markup "fulanito"))) +@end example + -@node Usar código de Scheme en lugar de \tweak -@section Usar código de Scheme en lugar de @code{\tweak} -@translationof Using Scheme code instead of \tweak +@node Código de Scheme en línea +@section Código de Scheme en línea +@translationof Inline Scheme code La principal desventaja de @code{\tweak} es su inflexibilidad sintáctica. Por ejemplo, lo siguiente produce un error de sintaxis. @@ -1062,6 +1036,7 @@ función de Scheme @code{acons}, y finalmente el resultado se escribe de nuevo con @code{set!}. El último elemento del bloque @code{let} es el valor de retorno, el propio @code{m}. + @node Trucos difíciles @section Trucos difíciles @translationof Difficult tweaks @@ -1070,6 +1045,7 @@ Hay un cierto número de tipos de ajustes difíciles. @itemize + @item Un tipo de ajuste difícil es la apariencia de los objetos de extensión, como las ligaduras de expresión y de unión. Inicialmente, @@ -1160,4 +1136,8 @@ como se espera dentro de los bloques @code{\context}. @chapter Interfaces de Scheme de LilyPond @translationof LilyPond Scheme interfaces -@untranslated +Este capítulo cubre las diversas herramientas proporcionadas por +LilyPond como ayuda a los programadores de Scheme a extraer e +introducir información de los flujos musicales. + +HACER @c TODO -- figure out what goes in here and how to organize it