X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fes%2Fextending%2Fprogramming-interface.itely;h=726f316dca0bb50be996b35a9d612911d8e27fef;hb=058370efc7e9710f149d0f444328bb1fcd7bdec1;hp=7a5ef591670c6427da9cdce3363caf51cd809510;hpb=b01ca49c05566b73d690ae84fda6040b24fcf73f;p=lilypond.git diff --git a/Documentation/es/extending/programming-interface.itely b/Documentation/es/extending/programming-interface.itely index 7a5ef59167..726f316dca 100644 --- a/Documentation/es/extending/programming-interface.itely +++ b/Documentation/es/extending/programming-interface.itely @@ -1,13 +1,13 @@ @c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- @c This file is part of extending.tely @ignore - Translation of GIT committish: 2055f35c47a045a50a01ff4dba8524322cfc3b48 + Translation of GIT committish: 41c8bf63a7cc180746eace9b9e5278f541be0229 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.14.0" +@c \version "2.19.2" @node Interfaces para programadores @chapter Interfaces para programadores @@ -19,7 +19,10 @@ 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:: @@ -27,67 +30,347 @@ Scheme, @ref{Tutorial de Scheme}. * 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: -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. +@lilypond[verbatim,quote] +ritpp = #(define-event-function (parser location) () + #{ ^"rit." \pp #} +) + +{ c'4 e'4\ritpp g'2 } +@end lilypond + +Los bloques de código de LilyPond se pueden usar en cualquier +lugar en el que se pueda escribir código de Scheme. El lector de +Scheme en efecto se modifica para que pueda incorporar bloques de +código de LilyPond y pueda ocuparse de las expresiones de Scheme +incrustadas que comienzan por @code{$} y@w{ }@code{#}. + +@cindex parser (function argument) +@cindex location + +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{\}. + +Si @code{location} (véase @ref{Funciones de Scheme}) se refiere a una +posición de entrada válida (como lo hace normalmente dentro de las +funciones musicales o de Scheme), toda la música generada dentro +del bloque de código tiene su @samp{origin} establecido a +@code{location}. + +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 +#(define-scheme-function (parser location @var{arg1} @var{arg2} @dots{}) - (@var{type1?} @var{type2?} @dots{}) - @var{música}) + (@var{tipo1?} @var{tipo2?} @dots{}) + @var{cuerpo}) @end example @noindent donde @multitable @columnfractions .33 .66 +@item @code{parser} +@tab tiene que ser literalmente @code{parser} para dar a los bloques de código +de LilyPond (@code{#@{}@dots{}@code{#@}}) acceso al analizador +sintáctico. + +@item @code{location} +@tab tiene que ser literalmente @code{location} para ofrecer acceso al +objeto de situación de la entrada, que se usa para ofrecer +menssajes de error con nombres de archivo y números de línea. + @item @code{@var{argN}} @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)}}). - +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} al parámetro @code{location}. + +@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 +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. + +Para ciertos tipos de expresión (como la mayor parte de la música que +no está encerrada entre llaves) LilyPond necesita más allá de la +expresión misma para poder determinar su final. Si tal expresión se +considerase un argumento opcional mediante la evaluación de su +predicado, LilyPond no podría recuperarse después de decidir que la +expresión no se corresponde con el parámetro. Así, ciertas formas de +música necesitan ir encerradas entre llaves para poder considerarlas +como aceptables bajo algunas circunstancias. LilyPond resuelve +algunas otras 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 siguieran +inmediatamente podrían no funcionar con dicha interpretación. Así +pues, 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}. -También se permiten predicados de tipo definidos por el usuario. +@seealso + +Referencia de la notación: +@ruser{Predicados de tipo predefinidos}. + +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. + + +@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 + (parser location) + () + (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 + (parser location @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,6 +383,39 @@ Archivos de inicio: @file{scm/lily.scm}. +@node Uso de las funciones musicales +@subsection Uso de las funciones musicales +@translationof Music function usage + +Las funciones musicales se pueden actualmente utilizar en varios +lugares. Dependiendo de dónde se usan, son de aplicación ciertas +restricciones para que sea posible su análisis sintáctico de forma +no ambigua. El resultado que devuelve una función musical debe ser +compatible con el contexto desde el que se la llama. + +@itemize +@item +En el nivel superior dentro de una expresión musical. Aquí +no se aplica ninguna restricción. + +@item +Como un post-evento, que comienza explícitamente con un indicador de +dirección (a elegir entre @code{-}, @code{^} @w{y @code{_}}). + +En este caso, no podemos usar una expresión musical @emph{abierta} +como último argumento, que terminaría en una expresión musical +capaz de aceptar post-eventos adicionales. + +@item +Como componente de un acorde. La expresión devuelta debe ser +del tipo @code{rhythmic-event}, probablemente un @code{NoteEvent}. +@end itemize + +@noindent +Las reglas especiales para los argumentos del final hacen posible +escribir funciones polimórficas como @code{\tweak} que se pueden +aplicar a construcciones distintas. + @node Funciones de sustitución sencillas @subsection Funciones de sustitución sencillas @translationof Simple substitution functions @@ -131,7 +447,7 @@ barraManual = (parser location principio-final) (pair?) #@{ - \once \override Beam #'positions = $principio-final + \once \override Beam.positions = #principio-final #@}) \relative c' @{ @@ -149,7 +465,7 @@ manualBeam = (parser location beg end) (number? number?) #{ - \once \override Beam #'positions = $(cons beg end) + \once \override Beam.positions = #(cons beg end) #}) \relative c' { @@ -157,6 +473,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 avlor +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 (parser location 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 @@ -171,14 +542,14 @@ AltOn = (parser location 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' { @@ -197,12 +568,12 @@ withAlt = (parser location 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' { @@ -232,7 +603,7 @@ mostrarNumeroDeCompas = (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 @@ -244,30 +615,42 @@ 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 (parser location arg) (markup?) + (make-dynamic-script arg)) +\relative c' { 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 @@ -291,36 +674,67 @@ 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. +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 @@ -329,7 +743,8 @@ Scheme. 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}). +definiendo instrucciones de marcado nuevas (véase +@ref{Definición de una instrucción de marcado nueva}). @knownissues @@ -410,11 +825,11 @@ 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 @@ -457,10 +872,33 @@ 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 +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 @@ -506,8 +944,8 @@ 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 @@ -527,7 +965,8 @@ 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 @@ -536,6 +975,16 @@ 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?) "Trazar un rectángulo doble rodeando el texto." @@ -548,10 +997,11 @@ rectángulos y añade una separación. @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{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: @@ -568,6 +1018,19 @@ nueva propiedad, @code{inter-box-padding}, para el relleno entre los rectángulos. El @code{box-padding} se usará para el relleno interno. Ahora el código nuevo es como se ve a continuación: +@lisp +#(define-markup-command (double-box layout props text) (markup?) + #:properties ((inter-box-padding 0.4) + (box-padding 0.6)) + "Trazar un rectángulo doble rodeando el texto." + (interpret-markup layout props + #@{\markup \override #`(box-padding . ,inter-box-padding) \box + \override #`(box-padding . ,box-padding) \box + @{ #text @} #@})) +@end lisp + +De nuevo, la versión equivalente que utiliza la macro de marcado sería: + @lisp #(define-markup-command (double-box layout props text) (markup?) #:properties ((inter-box-padding 0.4) @@ -598,8 +1061,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 @@ -627,7 +1091,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)) @@ -645,7 +1109,7 @@ instrucciones de marcado definidas por el usuario. (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)) @@ -662,8 +1126,8 @@ predeterminado de p.ej. 0.6: (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 @@ -700,6 +1164,9 @@ 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 @@ -711,6 +1178,15 @@ En el siguiente ejemplo se define una instrucción de lista de marcado 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)) @@ -728,17 +1204,17 @@ 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 +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. @@ -805,14 +1281,14 @@ funciona insertando un evento dentro del contexto especificado (@rinternals{ApplyOutputEvent}). Su sintaxis es @example -\applyOutput @var{contexto} @var{proc} +\applyOutput @var{Contexto} @var{proc} @end example @noindent donde @code{@var{proc}} es una función de Scheme que toma tres argumentos. Al interpretarse, la función @code{@var{proc}} se llama para cada objeto de -presentación que se encuentra en el contexto @code{@var{contexto}} +presentación que se encuentra en el contexto @code{@var{Contexto}} en el tiempo actual, con los siguientes argumentos: @itemize @@ -842,6 +1318,14 @@ cabezas de las notas que están sobre la línea central y junto a ella: } @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 #@var{función} +\applyOutput #'Staff #@var{función} +@end example + @node Funciones de callback @section Funciones de callback @@ -852,13 +1336,13 @@ Las propiedades (como @code{thickness} (grosor), @code{direction} 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) +\override Stem.thickness = #(lambda (grob) (if (= UP (ly:grob-property grob 'direction)) 2.0 7.0)) @@ -885,6 +1369,20 @@ Casi todo el motor de tipografiado está manejado por estos El procedimiento siempre toma un argumento único, que es el grob (el objeto gráfico). +Dicho procedimiento puede acceder al valor usual de la propiedad, +llamando en primer lugar a la función que es el @q{callback} usual +para esa propiedad, y que puede verse en el manual de referencia +interna o en el archivo 'define-grobs.scm': + +@example +\relative c'' @{ + \override Flag #'X-offset = #(lambda (flag) + (let ((default (ly:flag::calc-x-offset flag))) + (* default 4.0))) + c4. d8 a4. g8 +@} +@end example + 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}, @@ -934,10 +1432,11 @@ mi-callback = #(lambda (grob) @translationof Inline Scheme code 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 @@ -945,10 +1444,6 @@ F = \tweak #'font-size #-3 -\flageolet @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 @@ -1039,10 +1534,10 @@ arriba. (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) \relative c'' { - \override Tie #'after-line-breaking = + \override Tie.after-line-breaking = #my-callback c1 ~ \break - c2 ~ c + c2 ~ 2 } @end lilypond @@ -1062,9 +1557,10 @@ razones técnicas. Son ejemplos @code{NonMusicalPaperColumn} y @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