From: Francisco Vila Date: Tue, 26 Jan 2010 17:59:18 +0000 (+0100) Subject: Doc-es: move Extending. X-Git-Tag: release/2.13.12-1~37^2~9 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=c53f805d4ae685312674f2f04e5b6f167600c5ac;p=lilypond.git Doc-es: move Extending. --- diff --git a/Documentation/es/extending/programming-interface.itely b/Documentation/es/extending/programming-interface.itely new file mode 100644 index 0000000000..db86c8cada --- /dev/null +++ b/Documentation/es/extending/programming-interface.itely @@ -0,0 +1,1569 @@ +@c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- + +@ignore + Translation of GIT committish: d4f58bb3ad4e7fe1967a6b48f25e3addffc8aa14 + + 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.. +@end ignore + +@c \version "2.12.0" + +@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, @rlearning{Tutorial de Scheme}. + +@menu +* Funciones musicales:: +* Interfaces para el programador:: +* Construcción de funciones complejas:: +* Interfaz de marcado para el programador:: +* Contextos para programadores:: +* Procedimientos de Scheme como propiedades:: +* Usar código de Scheme en lugar de \tweak:: +* 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. + +@menu +* Panorámica de las funciones musicales:: +* Funciones de sustitución sencillas:: +* Funciones de sustitutión en parejas:: +* Matemáticas dentro de las funciones:: +* Funciones vacías:: +* Funciones sin argumentos:: +* Pranorá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 + +Es fácil hacer una función que sustituya a una variable en código de +LilyPond. La forma general de estas funciones 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...} + #@}) +@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. +@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. + +@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?} +@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. + + +@node Funciones de sustitución sencillas +@subsection Funciones de sustitución sencillas +@translationof Simple substitution functions + +He aquí un ejemplo sencillo: + +@lilypond[quote,verbatim,ragged-right] +padText = #(define-music-function (parser location padding) (number?) + #{ + \once \override TextScript #'padding = #$padding + #}) + +\relative c''' { + c4^"piu mosso" b a b + \padText #1.8 + c4^"piu mosso" d e f + \padText #2.6 + c4^"piu mosso" fis a g +} +@end lilypond + +También se pueden sustituir las expresiones musicales: + +@lilypond[quote,verbatim,ragged-right] +custosNote = #(define-music-function (parser location note) + (ly:music?) + #{ + \once \override Voice.NoteHead #'stencil = + #ly:text-interface::print + \once \override Voice.NoteHead #'text = + \markup \musicglyph #"custodes.mensural.u0" + \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 sustitutión en parejas +@subsection Funciones de sustitutión en parejas +@translationof Paired substitution functions + +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. + +@quotation +@example +manualBeam = +#(define-music-function (parser location beg-end) + (pair?) +#@{ + \once \override Beam #'positions = #$beg-end +#@}) + +\relative @{ + \manualBeam #'(3 . 6) c8 d e f +@} +@end example +@end quotation + +@noindent +o bien + +@lilypond[quote,verbatim,ragged-right] +manualBeam = +#(define-music-function (parser location beg end) + (number? number?) +#{ + \once \override Beam #'positions = #(cons $beg $end) +#}) + +\relative { + \manualBeam #3 #6 c8 d e f +} +@end lilypond + + +@node Matemáticas dentro de las funciones +@subsection Matemáticas dentro de las funciones +@translationof Mathematics in functions + +Las funciones musicales pueden contar con programación de Scheme +además de la simple sustitución: + +@lilypond[quote,verbatim,ragged-right] +AltOn = #(define-music-function (parser location mag) (number?) + #{ \override Stem #'length = #$(* 7.0 mag) + \override NoteHead #'font-size = + #$(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) #}) + +AltOff = { + \revert Stem #'length + \revert NoteHead #'font-size +} + +{ c'2 \AltOn #0.5 c'4 c' + \AltOn #1.5 c' c' \AltOff c'2 } +@end lilypond + +@noindent +Este ejemplo se puede reescribir de forma que pase expresiones +musicales: + +@lilypond[quote,verbatim,ragged-right] +withAlt = #(define-music-function (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 #}) + +{ c'2 \withAlt #0.5 {c'4 c'} + \withAlt #1.5 {c' c'} c'2 } +@end lilypond + + +@node Funciones vacías +@subsection Funciones vacías +@translationof Void 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). + +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 +noPointAndClick = +#(define-music-function (parser location) () + (ly:set-option 'point-and-click #f) + (make-music 'SequentialMusic 'void #t)) +... +\noPointAndClick % desactivar la funcionalidad Apuntar y Pulsar. +@end example + + +@node Funciones sin argumentos +@subsection Funciones sin argumentos +@translationof Functions without arguments + +En casi todos los casos, una función sin argumentos se debe escribir +con una variable: + +@example +dolce = \markup@{ \italic \bold dolce @} +@end example + +Sin embargo, en raras ocasiones puede ser de utilidad crear una +función musical sin argumentos: + +@example +displayBarNum = +#(define-music-function (parser location) () + (if (eq? #t (ly:get-option 'display-bar-numbers)) + #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} + #@{#@})) +@end example + +Para la impresión real de los números de compás donde se llama a esta +función, invoque a @command{lilypond} con + +@example +lilypond -d display-bar-numbers ARCHIVO.ly +@end example + + +@node Pranorámica de las funciones musicales disponibles +@subsection Pranorá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 + +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}. + +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 Construcción de funciones complejas +@section Construcción de funciones complejas +@translationof Building complicated functions + +Esta sección explica cómo reunir la información necesaria para crear +funciones musicales complejas. + + +@menu +* Presentación de expresiones musicales:: +* Propiedades de la música:: +* Doblar una nota con ligaduras (ejemplo):: +* Añadir articulación a las notas (ejemplo):: +@end menu + +@node Presentación de expresiones musicales +@subsection Presentación de expresiones musicales +@translationof Displaying music expressions + +@cindex interno, almacenamiento +@cindex mostrar expresiones musicales +@cindex interna, representación, mostrar + +@funindex \displayMusic + +Si se está escribiendo una función musical puede ser muy instructivo +examinar cómo se almacena internamente una expresión musical. Esto se +puede hacer con la función musical @code{\displayMusic}: + +@example +@{ + \displayMusic @{ c'4\f @} +@} +@end example + +@noindent +imprime lo siguiente: + +@example +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)) + (make-music + 'AbsoluteDynamicEvent + 'text + "f"))))) +@end example + +De forma predeterminada, LilyPond imprime estos mensajes en la consola +junto al resto de los mensajes. Para discernir entre estos mensajes y +guardar el resultado de @code{\display@{MATERIAL@}}, redirija la +salida hacia un archivo. + +@example +lilypond archivo.ly >resultado.txt +@end example + +Con la aplicación de un poco de formato, la información anterior es +fácil de leer: + +@example +(make-music 'SequentialMusic + 'elements (list (make-music 'EventChord + 'elements (list (make-music 'NoteEvent + 'duration (ly:make-duration 2 0 1 1) + 'pitch (ly:make-pitch 0 0 0)) + (make-music 'AbsoluteDynamicEvent + 'text "f"))))) +@end example + +Una secuencia musical @code{@{ ... @}} tiene el nombre +@code{SequentialMusic}, y sus expresiones internas se almacenan como +una lista en su propiedad @code{'elements}. Una nota se representa +como una expresión @code{EventChord} que contiene un objeto +@code{NoteEvent} (que almacena las propiedades de duración y altura) y +cualquier otra información adicional (en este caso, un evento +@code{AbsoluteDynamicEvent} con una propiedad de texto @code{"f"}. + + +@node Propiedades de la música +@subsection Propiedades de la música +@translationof Music properties + +El objeto @code{NoteEvent} es el primer objeto de la propiedad +@code{'elements} de @code{someNote}. + +@example +unaNota = c' +\displayMusic \unaNota +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)))) +@end example + +La función @code{display-scheme-music} es la función utilizada por +@code{\displayMusic} para imprimir la representación de Scheme de una +expresión musical. + +@example +#(display-scheme-music (first (ly:music-property unaNota 'elements))) +===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)) +@end example + +Después se accede a la altura de la nota a través de la propiedad +@code{'pitch} del objeto @code{NoteEvent}: + +@example +#(display-scheme-music + (ly:music-property (first (ly:music-property unaNota 'elements)) + 'pitch)) +===> +(ly:make-pitch 0 0 0) +@end example + +La altura de la nota se puede cambiar estableciendo el valor de esta +propiedad 'pitch: + +@funindex \displayLilyMusic + +@example +#(set! (ly:music-property (first (ly:music-property unaNota 'elements)) + 'pitch) + (ly:make-pitch 0 1 0)) ;; fijar la altura a d'. +\displayLilyMusic \unaNota +===> +d' +@end example + + +@node Doblar una nota con ligaduras (ejemplo) +@subsection Doblar una nota con ligaduras (ejemplo) +@translationof Doubling a note with slurs (example) + +Supongamos que queremos crear una función que traduce una entrada como +@code{a} a algo como @code{a( a)}. Empezamos examinando la +representación interna de la música con la que queremos terminar. + +@example +\displayMusic@{ a'( a') @} +===> +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)) + (make-music + 'SlurEvent + 'span-direction + -1))) + (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)) + (make-music + 'SlurEvent + 'span-direction + 1))))) +@end example + +Las malas noticias son que las expresiones @code{SlurEvent} se deben +añadir @q{dentro} de la nota (o más concretamente, dentro de la +expresión @code{EventChord}). + +Ahora observamos la entrada: + +@example +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)))))) +@end example + +Así pues, en nuestra función, tenemos que clonar esta expresión (de +forma que tengamos dos notas para construir la secuencia), añadir +@code{SlurEvents} a la propiedad @code{'elements} de cada una de +ellas, y por último hacer una secuencia @code{SequentialMusic} con los +dos @code{EventChords}. + +@example +doubleSlur = #(define-music-function (parser location note) (ly:music?) + "Return: @{ note ( note ) @}. + `note' is supposed to be an EventChord." + (let ((note2 (ly:music-deep-copy note))) + (set! (ly:music-property note 'elements) + (cons (make-music 'SlurEvent 'span-direction -1) + (ly:music-property note 'elements))) + (set! (ly:music-property note2 'elements) + (cons (make-music 'SlurEvent 'span-direction 1) + (ly:music-property note2 'elements))) + (make-music 'SequentialMusic 'elements (list note note2)))) +@end example + + +@node Añadir articulación a las notas (ejemplo) +@subsection Añadir articulación a las notas (ejemplo) +@translationof Adding articulation to notes (example) + +La manera fácil de añadir articulación a las notas es fundir dos +expresiones musicales en un contexto único, como está explicado en +@ref{Crear contextos}. Sin embargo, suponga que queremos escribir +una función musical que haga esto. + +Una @code{$variable} dentro de la notación @code{#@{...#@}} es como +usar una @code{\variable} normal en la notación clásica de LilyPond. +Sabemos que + +@example +@{ \musica -. -> @} +@end example + +@noindent +no funciona en LilyPond. Podemos evitar este problema adjuntando la +articulación a una nota de mentira, + +@example +@{ << \musica s1*0-.-> @} +@end example + +@noindent +pero a los efectos de este ejemplo, aprenderemos ahora cómo hacerlo en +Scheme. Comenzamos examinando nuestra entrada y la salida deseada: + +@example +% entrada +\displayMusic c4 +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch -1 0 0)))) +===== +% salida deseada +\displayMusic c4-> +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch -1 0 0)) + (make-music + 'ArticulationEvent + 'articulation-type + "marcato"))) +@end example + +Vemos que una nota (@code{c4}) se representa como una expresión +@code{EventChord}, con una expresión @code{NoteEvent} en su lista de +elementos. Para añadir una articulación marcato, se debe añadir una +expresión @code{ArticulationEvent} a la propiedad elementos de la +expresión @code{EventChord}. + +Para construir esta función, empezamos con + +@example +(define (add-marcato event-chord) + "Añadir una ArticulationEvent de marcato a los elementos de `event-chord', + que se supone que es una expresión EventChord." + (let ((result-event-chord (ly:music-deep-copy event-chord))) + (set! (ly:music-property result-event-chord 'elements) + (cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements))) + result-event-chord)) +@end example + +La primera línea es la forma de definir una función en Scheme: el +nombre de la función es @code{add-marcato}, y tiene una variable +llamada @code{event-chord}. En Scheme, el tipo de variable suele +quedar claro a partir de su nombre (¡esto también es una buena +práctica en otros lenguajes de programación!). + +@example +"Añadir una ArticulationEvent de marcato..." +@end example + +@noindent +es una descripción de lo que hace la función. No es estrictamente +necesario, pero como los nombres de variable claros, es una buena +práctica. + +@example +(let ((result-event-chord (ly:music-deep-copy event-chord))) +@end example + +@code{let} se usa para declarar variables locales. Aquí usamos una +variable local, llamada @code{result-event-chord}, a la que le damos +el valor @code{(ly:music-deep-copy event-chord)}. +@code{ly:music-deep-copy} es una función específica de LilyPond, como +todas las funciones que comienzan por @code{ly:}. Se usa para hacer +una copia de una expresión musical. Aquí, copiamos @code{event-chord} +(el parámetro de la función). Recuerde que el propósito es añadir un +marcato a una expresión @code{EventChord}. Es mejor no modificar el +@code{EventChord} que se dio como argumento, porque podría utilizarse +en algún otro lugar. + +Ahora tenemos un @code{result-event-chord}, que es una expresión +@code{NoteEventChord} y es una copia de @code{event-chord}. Añadimos +el marcato a su propiedad lista de elementos. + +@example +(set! lugar valor-nuevo) +@end example + +Aquí, lo que queremos establecer (el @q{lugar}) es la propiedad +@q{elements} de la expresión @code{result-event-chord}. + +@example +(ly:music-property result-event-chord 'elements) +@end example + +@code{ly:music-property} es la función que se usa para acceder a las +propiedades musicales (los @code{'elements}, @code{'duration}, +@code{'pitch}, etc., que vemos en la salida de @code{\displayMusic} +más arriba). El nuevo valor es la anterior propiedad elements, con un +elemento adicional: la expresión @code{ArticulationEvent}, que +copiamos a partir de la salida de @code{\displayMusic}, + +@example +(cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements)) +@end example + +@code{cons} se usa para añadir un elemento a una lista sin modificar +la lista original. Esto es lo que queremos: la misma lista que antes, +más la nueva expresión @code{ArticulationEvent}. El orden dentro de +la propiedad elements no es importante aquí. + +Finalmente, una vez añadida la articulación marcato a su propiedad +@code{elements}, podemos devolver @code{result-event-chord}, de aquí +la última línea de la función. + +Ahora transformamos la función @code{add-marcato} en una función +musical, + +@example +addMarcato = #(define-music-function (parser location event-chord) + (ly:music?) + "Añadir un ArticulationEvent de marcato a los elementos de `event-chord', + que se supone que es una expresión EventChord." + (let ((result-event-chord (ly:music-deep-copy event-chord))) + (set! (ly:music-property result-event-chord 'elements) + (cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements))) + result-event-chord)) +@end example + +Podemos verificar que esta función musical funciona correctamente, + +@example +\displayMusic \addMarcato c4 +@end example + + +@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:: +* 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 +@translationof Markup construction in Scheme + +@cindex marcado, definir instrucciones de + +El macro @code{markup} construye expresiones de marcado en Scheme, +proporcionando una sintaxis similar a la de LilyPond. Por ejemplo: + +@example +(markup #:column (#:line (#:bold #:italic "hola" #:raise 0.4 "mundo") + #:larger #:line ("fulano" "fulanito" "menganito"))) +@end example + +@noindent +equivale a: +@example +\markup \column @{ \line @{ \bold \italic "hola" \raise #0.4 "mundo" @} + \larger \line @{ fulano fulanito menganito @} @} +@end example + +@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. + +@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{\instruccion} @tab @code{#:instruccion} +@item @code{\variable} @tab @code{variable} +@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} +@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}). + +@knownissues + +El argumento markup-list de instrucciones como @code{#:line}, +@code{#:center} y @code{#:column} no pueden se una variable o el +resultado de la llamada a una función. + +@lisp +(markup #:line (funcion-que-devuelve-marcados)) +@end lisp + +@noindent +no es válido. Hay que usar las funciones @code{make-line-markup}, +@code{make-center-markup} o @code{make-column-markup} en su lugar: + +@lisp +(markup (make-line-markup (funcion-que-devuelve-marcados))) +@end lisp + + +@node Cómo funciona internamente el marcado +@subsection Cómo funciona internamente el marcado +@translationof How markups work internally + +En un elemento de marcado como + +@example +\raise #0.5 "ejemplo de texto" +@end example + +@noindent +@code{\raise} se representa en realidad por medio de la función +@code{raise-markup}. La expresión de marcado se almacena como + +@example +(list raise-markup 0.5 (list simple-markup "ejemplo de texto")) +@end example + +Cuando el marcado se convierte en objetos imprimibles (Stencils o +sellos), se llama la función @code{raise-markup} como + +@example +(apply raise-markup + @var{\objeto de marcado} + @var{lista de listas asociativas de propiedades} + 0.5 + @var{el marcado "ejemplo de texto"}) +@end example + +Primero la función @code{raise-markup} crea el sello para la cadena +@code{ejemplo de texto}, y después eleva el sello Stencil en 0.5 +espacios de pentagrama. Este es un ejemplo bastante simple; en el +resto de la sección podrán verse ejemplos más complejos, así como en +@file{scm/@/define@/-markup@/-commands@/.scm}. + + +@node Definición de una instrucción de marcado nueva +@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}. + +@lisp +(define-markup-command (@var{nombre-de-la-instruccion} @var{layout} @var{props} @var{arg1} @var{arg2} ...) + (@var{arg1-type?} @var{arg2-type?} ...) + ..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 layout +la definición de @q{presentación} +@item props +lista de listas asociativas, que contiene todas las propiedades +activas. +@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, + +@example +\markup @{ \override #'(font-shape . caps) Texto-en-versalitas @} +@end example + +@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}. + +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 + +@example +(define-markup-command (smallcaps layout props argument) (markup?) +@end example + +@noindent + +Lo que aparece a continuación es el contenido de la instrucción: +debemos interpretar el @code{argument} como un marcado, es decir: + +@example +(interpret-markup layout @dots{} argument) +@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: + +@example +(cons (list '(font-shape . caps) ) props) +@end example + +@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. + +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: + +@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))) +@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 resultado final es como sigue: + +@example +@{ + c''^\markup \character #"Cleopatra" + e'^\markup \character #"Giulio Cesare" +@} +@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\"" + (interpret-markup layout props + (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) + +{ + c''^\markup \character #"Cleopatra" c'' c'' c'' + e'^\markup \character #"Giulio Cesare" e' e' e' +} +@end lilypond + +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: + +@example +#(define-markup-command (smallcaps layout props str) (string?) + "Print the string argument in small caps." + (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 + +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. + +@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: + +@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 + +@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). + +Como ejemplo, no es posible usar una instrucción de marcado +@code{fulanito} con cuatro argumentos definida como + +@example +#(define-markup-command (fulanito layout props + num1 str1 num2 str2) + (number? string? number? string?) + ...) +@end example + +@noindent +Si la aplicamos como, digamos, + +@example +\markup \fulanito #1 #"mengano" #2 #"zutano" +@end example + +@cindex Scheme signature +@cindex signature, Scheme +@noindent +@command{lilypond} protesta diciendo que no puede analizar +@code{fulanito} debido a su firma de Scheme desconocida. + + +@node Definición de nuevas instrucciones de lista de marcado +@subsection Definición de nuevas instrucciones de lista de marcado +@translationof New markup list command definition + +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}. + +@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))))) +@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: + +@example +\markuplines @{ + \paragraph @{ + El arte de la tipografía musical se llama \italic @{grabado (en plancha).@} + El término deriva del proceso tradicional de impresión de música. + hace sólo algunas décadas, las partituras se hacían cortando y estampando + la música en una plancha de zinc o lata en una imagen invertida. + @} + \override-lines #'(par-indent . 4) \paragraph @{ + La plancha se tenía que entintar, y las depresiones causadas por los cortes + y estampados retienen la tinta. Se formaba una imagen presionando el papel + contra la plancha. El estampado y cortado se hacía completamente + a mano. + @} +@} +@end example + + +@node Contextos para programadores +@section Contextos para programadores +@translationof Contexts for programmers + +@menu +* Evaluación de contextos:: +* Ejecutar una función sobre todos los objetos de la presentación:: +@end menu + +@node Evaluación de contextos +@subsection Evaluación de contextos +@translationof Context evaluation + +@cindex código, llamadas durante la interpretación +@funindex \applyContext + +Se pueden modificar los contextos durante la interpretación con código +de Scheme. La sintaxis para esto es + +@example +\applyContext @var{función} +@end example + +@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: + +@example +\applyContext + #(lambda (x) + (format #t "\nSe nos ha llamado en el compás número ~a.\n" + (ly:context-property x 'currentBarNumber))) +@end example + + +@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 +@translationof Running a function on all layout objects + + +@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}. Su sintaxis es + +@example +\applyOutput @var{contexto} @var{proc} +@end example + +@noindent +donde @var{proc} es una función de Scheme, que toma tres argumentos. + +Al interpretarse, la función @var{proc} se llama para cada objeto de +presentación que se encuentra en el contexto @var{contexto}, con los +siguientes argumentos: + +@itemize +@item el propio objeto de presentación, +@item el contexto en que se creó el objeto de presentación, y +@item el contexto en que se procesa @code{\applyOutput}. +@end itemize + +Además, la causa del objeto de presentación, es decir el objeto o +expresión musical que es responsable de haberlo creado, está en la +propiedad @code{cause} del objeto. Por ejemplo, para la cabeza de una +nota, éste es un evento @rinternals{NoteHead}, y para un objeto +@rinternals{Stem} (plica), éste es un objeto @rinternals{Stem}. +@c Impossible - changed to Stem --FV + +He aquí una función que usar para @code{\applyOutput}; borra las +cabezas de las notas que están sobre la línea central: + +@lilypond[quote,verbatim,ragged-right] +#(define (blanker grob grob-origin context) + (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) + (eq? (ly:grob-property grob 'staff-position) 0)) + (set! (ly:grob-property grob 'transparent) #t))) + +\relative { + e4 g8 \applyOutput #'Voice #blanker b d2 +} +@end lilypond + + +@node Procedimientos de Scheme como propiedades +@section Procedimientos de Scheme como propiedades +@translationof Scheme procedures as properties + +Las propiedades (como el grosor, la dirección, etc.) se pueden +establecer a valores fijos con \override, p. ej. + +@example +\override Stem #'thickness = #2.0 +@end example + +Las propiedades pueden fijarse también a un procedimiento de scheme, + +@lilypond[fragment,verbatim,quote,relative=2] +\override Stem #'thickness = #(lambda (grob) + (if (= UP (ly:grob-property grob 'direction)) + 2.0 + 7.0)) +c b a g b a g b +@end lilypond + +@noindent +En este caso, el procedimiento se ejecuta tan pronto como el valor de +la propiedad se reclama durante el proceso de formateo. + +Casi todo el motor de tipografiado está manejado por estos +@emph{callbacks}. Entre las propiedades que usan normalmente +@emph{callbacks} están + +@table @code +@item stencil + La rutina de impresión, que construye un dibujo para el símbolo +@item X-offset + La rutina que establece la posición horizontal +@item X-extent + La rutina que calcula la anchura de un objeto +@end table + +El procedimiento siempre toma un argumento único, que es el grob (el +objeto gráfico). + +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}, + +@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}))) +@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}. + + +@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 + +La principal desventaja de @code{\tweak} es su inflexibilidad +sintáctica. Por ejemplo, lo siguiente produce un error de sintaxis. + +@example +F = \tweak #'font-size #-3 -\flageolet + +\relative c'' @{ + c4^\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 articulación a las notas (ejemplo)}, +especialmente cómo usar @code{\displayMusic} como guía de ayuda. + +@example +F = #(let ((m (make-music 'ArticulationEvent + 'articulation-type "flageolet"))) + (set! (ly:music-property m 'tweaks) + (acons 'font-size -3 + (ly:music-property m 'tweaks))) + m) + +\relative c'' @{ + c4^\F c4_\F +@} +@end example + +@noindent +Aquí, las propiedades @code{tweaks} del objeto flageolet @code{m} +(creado con @code{make-music}) se extraen con +@code{ly:music-property}, se antepone un nuevo par clave-valor para +cambiar el tamaño de la tipografía a la lista de propiedades con la +función de Scheme @code{acons}, y finalmente el resultado se escribe +de nuevo con @code{set!}. El último elemento del bloque @code{let} es +el valor de retorno, el propio @code{m}. + +@node Trucos difíciles +@section Trucos difíciles +@translationof Difficult tweaks + +Hay un cierto número de tipos de ajustes difíciles. + +@itemize + +@item +Un tipo de ajuste difícil es la apariencia de los objetos de +extensión, como las ligaduras de expresión y de unión. Inicialmente, +sólo se crea uno de estos objetos, y pueden ajustarse con el mecanismo +normal. Sin embargo, en ciertos casos los objetos extensores cruzan +los saltos de línea. Si esto ocurre, estos objetos se clonan. Se +crea un objeto distinto por cada sistema en que se encuentra. Éstos +son clones del objeto original y heredan todas sus propiedades, +incluidos los @code{\override}s. + +En otras palabras, un @code{\override} siempre afecta a todas las +piezas de un objeto de extensión fragmentado. Para cambiar sólo una +parte de un extensor en el salto de línea, es necesario inmiscuirse en +el proceso de formateado. El @emph{callback} +@code{after-line-breaking} contiene el procedimiento Scheme que se +llama después de que se han determinado los saltos de línea, y los +objetos de presentación han sido divididos sobre los distintos +sistemas. + +En el ejemplo siguiente, definimos un procedimiento +@code{my-callback}. Este procedimiento + +@itemize +@item +determina si hemos sido divididos por los saltos de línea +@item +en caso afirmativo, reúne todos los objetos divididos +@item +comprueba si somos el último de los objetos divididos +@item +en caso afirmativo, establece @code{extra-offset}. +@end itemize + +Este procedimiento se instala en @rinternals{Tie} (ligadura de unión), +de forma que la última parte de la ligadura dividida se traslada hacia +arriba. + +@lilypond[quote,verbatim,ragged-right] +#(define (my-callback grob) + (let* ( + ; have we been split? + (orig (ly:grob-original grob)) + + ; if yes, get the split pieces (our siblings) + (siblings (if (ly:grob? orig) + (ly:spanner-broken-into orig) '() ))) + + (if (and (>= (length siblings) 2) + (eq? (car (last-pair siblings)) grob)) + (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) + +\relative c'' { + \override Tie #'after-line-breaking = + #my-callback + c1 ~ \break c2 ~ c +} +@end lilypond + +@noindent +Al aplicar este truco, la nueva función de callback +@code{after-line-breaking} también debe llamar a la antigua +@code{after-line-breaking}, si existe. Por ejemplo, si se usa con +@code{Hairpin}, se debe llamar también a +@code{ly:hairpin::after-line-breaking}. + + +@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. + +@example +\overrideProperty +#"Score.NonMusicalPaperColumn" % Nombre del grob +#'line-break-system-details % Nombre de la propiedad +#'((next-padding . 20)) % Valor +@end example + +Observe, sin embargo, que @code{\override}, aplicado a +@code{NonMusicalPaperColumn} y a @code{PaperColumn}, aún funciona +como se espera dentro de los bloques @code{\context}. + +@end itemize + + +@node Interfaces de Scheme de LilyPond +@chapter Interfaces de Scheme de LilyPond +@translationof LilyPond Scheme interfaces + +@untranslated diff --git a/Documentation/es/extending/scheme-tutorial.itely b/Documentation/es/extending/scheme-tutorial.itely new file mode 100644 index 0000000000..2234abb2e9 --- /dev/null +++ b/Documentation/es/extending/scheme-tutorial.itely @@ -0,0 +1,347 @@ +@c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- + +@ignore + Translation of GIT committish: 5f51567fbc5d7a811e147ebd01f103e066f36b3a + + 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.. +@end ignore + +@c \version "2.12.0" + + +@node Tutorial de Scheme +@appendix Tutorial de Scheme +@translationof Scheme tutorial + +@funindex # +@cindex Scheme +@cindex GUILE +@cindex Scheme, código en línea +@cindex acceder a Scheme +@cindex evaluar Scheme +@cindex LISP + +LilyPond utiliza el lenguaje de programación Scheme, tanto como parte +de la sintaxis del código de entrada, como para servir de mecanismo +interno que une los módulos del programa entre sí. Esta sección es +una panorámica muy breve sobre cómo introducir datos en Scheme. Si +quiere saber más sobre Scheme, consulte +@uref{http://@/www@/.schemers@/.org}. + +LilyPond utiliza la implementación GNU Guile de Scheme, que está +basada en el estándar @qq{R5RS} del lenguaje. Si está aprendiendo +Scheme para usarlo con LilyPond, no se recomienda trabajar con una +implementación distinta (o que se refiera a un estándar diferente). +Hay información sobre Guile en +@uref{http://www.gnu.org/software/guile/}. El estándar de Scheme +@qq{R5RS} se encuentra en +@uref{http://www.schemers.org/Documents/Standards/R5RS/}. + +La instalación de LilyPond inclute también la de la implementación +Guile de Scheme. Sobre casi todos los sistemas puede experimentar en +una @qq{caja de arena} de Scheme abriendo una ventana del terminal y +tecleando @q{guile}. En algunos sistemas, sobre todo en Windows, +podría necesitar ajustar la variable de entorno @code{GUILE_LOAD_PATH} +a la carpeta @code{../usr/shr/guile/1.8} dentro de la instalación de +LilyPond (para conocer la ruta completa a esta carpeta, consulte +@ref{Otras fuentes de información}). Como alternativa, los usuarios +de Windows pueden seleccionar simplemente @q{Ejecutar} del menú Inicio +e introducir @q{guile}. + +El concepto más básico de un lenguaje son sus tipos de datos: números, +cadenas de caracteres, listas, etc. He aquí una lista de los tipos de +datos que son de relevancia respecto de la entrada de LilyPond. + +@table @asis +@item Booleanos +Los valores Booleanos son Verdadero y Falso. Verdadero en Scheme es @code{#t} +y Falso es @code{#f}. +@funindex ##t +@funindex ##f + +@item Números +Los números se escriben de la forma normal, @code{1} es el número +(entero) uno, mientras que @code{-1.5} es un número en coma flotante +(un número no entero). + +@item Cadenas +Las cadenas se encierran entre comillas: + +@example +"esto es una cadena" +@end example + +Las cadenas pueden abarcar varias líneas: + +@example +"esto +es +una cadena" +@end example + +También se pueden añadir comillas y saltos de línea con las llamadas +secuencias de escape. La cadena @code{a dijo "b"} se escribe como + +@example +"a dijo \"b\"" +@end example + +Los saltos de línea t las barras invertidas se escapan mediante +@code{\n} y @code{\\} respectivamente. +@end table + + +En un archivo de música, los fragmentos de código de Scheme se +escriben con el signo de almohadilla @code{#}. Así, los ejemplos +anteriores traducidos a LilyPond son: + +@example +##t ##f +#1 #-1.5 +#"esto es una cadena" +#"esto +es +una cadena" +@end example + +Observe que los comentarios de LilyPond (@code{%} y @code{%@{ %@}}) no +se puedden utilizar dentro del código de Scheme. Los comentarios en +el Scheme de Guile se introducen como sigue: + +@example +; esto es un comentario de una línea + +#! + Esto es un comentario de bloque (no anidable) estilo Guile + Pero se usan rara vez por parte de los Schemers y nunca dentro del + código fuente de LilyPond +!# +@end example + +Se pueden combinar en un mismo archivo de música varias expresiones de +Scheme consecutivas mediante la utilización del operador @code{begin}. +Ello permite que el número de marcas de cuadradillo se redizca a una. + +@example +#(begin + (define fulanito 0) + (define menganito 1)) +@end example + +Si el @code{#} va seguido de un paréntesis de apertura, @code{(}, como +en el ejemplo anterior, el analizador sintáctico permanece dentro del +modo de Scheme hasta que encuentra el paréntesis de cierre +correspondiente, @code{)}, por lo que no son necesarios más símbolos +de @code{#} para introducir una sección de Scheme. + +Durante el resto de esta sección, supondremos que los datos se +introducen en un archivo de música, por lo que añadiremos almohadillas +@code{#} en todas partes. + +Scheme se puede usar para hacer cálculos. Utiliza sintaxis +@emph{prefija}. Sumar 1 y@tie{}2 se escribe como @code{(+ 1 2)} y no +como el tradicional @math{1+2}. + +@lisp +#(+ 1 2) + @result{} #3 +@end lisp + +La flecha @result{} muestra que el resultado de evaluar @code{(+ 1 2)} +es@tie{}@code{3}. Los cálculos se pueden anidar; el resultado de una +función se puede usar para otro cálculo. + +@lisp +#(+ 1 (* 3 4)) + @result{} #(+ 1 12) + @result{} #13 +@end lisp + +Estos cálculos son ejemplos de evaluaciones; una expresión como +@code{(* 3 4)} se sustituye por su valor @code{12}. Algo similar +ocurre con las variables. Después de haber definido una variable + +@example +doce = #12 +@end example + +@noindent +las variables se pueden usar también dentro de las expresiones, aquí + +@example +veintiCuatro = #(* 2 doce) +@end example + +@noindent +el número 24 se almacena dentro de la variable @code{veintiCuatro}. +La misma asignación se puede hacer también completamente en Scheme, + +@example +#(define veintiCuatro (* 2 doce)) +@end example + +El @emph{nombre} de una variable también es una expresión, similar a +un número o una cadena. Se introduce como + +@example +#'veintiCuatro +@end example + +@funindex #'symbol +@cindex comillas en Scheme + +El apóstrofo @code{'} evita que el intérprete de Scheme sustituya +@code{veintiCuatro} por @code{24}. En vez de esto, obtenemos el +nombre @code{veintiCuatro}. + +Esta sintaxis se usará con mucha frecuencia, pues muchos de los trucos +de presentación consisten en asignar valores (de Scheme) a variables +internas, por ejemplo + +@example +\override Stem #'thickness = #2.6 +@end example + +Esta instrucción ajusta el aspecto de las plicas. El valor @code{2.6} +se pone dentro de la variable @code{thickness} de un objeto +@code{Stem}. @code{thickness} se mide a partir del grosor de las +líneas del pentagrama, y así estas plicas serán @code{2.6} veces el +grosor de las líneas del pentagrama. Esto hace que las plicas sean +casi el doble de gruesas de lo normal. Para distinguir entre las +variables que se definen en los archivos de entrada (como +@code{veintiCuatro} en el ejemplo anterior) y las variables de los +objetos internos, llamaremos a las últimas @q{propiedades} y a las +primeras @q{variables.} Así, el objeto plica tiene una propiedad +@code{thickness} (grosor), mientras que @code{veintiCuatro} es una +variable. + +@cindex propiedades frente a variables +@cindex variables frente a propiedades + +Los desplazamientos bidimensionales (coordenadas X e Y) así como los +tamaños de los objetos (intervalos con un punto izquierdo y otro +derecho) se introducen como @code{parejas}. Una pareja@footnote{En la +terminología de Scheme, la pareja se llama @code{cons}, y sus dos +elementos se llaman @code{car} y @code{cdr} respectivamente.} se +introduce como @code{(primero . segundo)} y, como los símbolos, se deben +preceder de un apóstrofo: + +@example +\override TextScript #'extra-offset = #'(1 . 2) +@end example + +Esto asigna la pareja (1, 2) a la propiedad @code{extra-offset} del +objeto TextScript. Estos números se miden en espacios de pentagrama, +y así esta instrucción mueve el objeto un espacio de pentagrama a la +derecha, y dos espacios hacia arriba. + +Los dos elementos de una pareja pueden ser valores arbitrarios, por +ejemplo + +@example +#'(1 . 2) +#'(#t . #f) +#'("bla-bla" . 3.14159265) +@end example + +Una lista se escribe encerrando sus elementos entre paréntesis, y +añadiendo un apóstrofo. Por ejemplo, + +@example +#'(1 2 3) +#'(1 2 "cadena" #f) +@end example + +Todo el tiempo hemos estado usando listas. Un cálculo, como @code{(+ +1 2)} también es una lista (que contiene el símbolo @code{+} y los +números 1 y@tie{}2). Normalmente, las listas se interpretan como +cálculos, y el intérprete de Scheme sustituye el resultado del +cálculo. Para escribir una lista, detenemos la evaluación. Esto se +hace precediendo la lista por un apóstrofo @code{'}. Así, para los +cálculos no usamos ningún apóstrofo. + +Dentro de una lista o pareja precedida de apóstrofo, no hay necesidad +de escribir ningún apóstrofo más. Lo siguiente es una pareja de +símbolos, una lista de símbolos y una lista de listas respectivamente: + +@example +#'(stem . head) +#'(staff clef key-signature) +#'((1) (2)) +@end example + + +@menu +* Trucos con Scheme:: +@end menu + +@node Trucos con Scheme +@appendixsec Trucos con Scheme +@translationof Tweaking with Scheme + +Hemos visto cómo la salida de LilyPond se puede modificar +profundamente usando instrucciones como @code{\override TextScript +#'extra-offset = ( 1 . -1)}. Pero tenemos incluso mucho más poder si +utilizamos Scheme. Para ver una explicación completa de esto, +consulte el @ref{Tutorial de Scheme}, y @ruser{Interfaces para programadores}. + +Podemos usar Scheme simplemente para sobreescribir instrucciones con +@code{\override}, + +@c This isn't a valid example with skylining +@c It works fine without padText -td + +@ignore +@lilypond[quote,verbatim,ragged-right] +padText = #(define-music-function (parser location padding) (number?) +#{ + \once \override TextScript #'padding = #$padding +#}) + +\relative c''' { + c4^"piu mosso" b a b + \padText #1.8 + c4^"piu mosso" d e f + \padText #2.6 + c4^"piu mosso" fis a g +} +@end lilypond +@end ignore + +Lo podemos usar para crear instrucciones nuevas: + +@c Check this is a valid example with skylining +@c It is - 'padding still works + +@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 + +Incluso se le pueden pasar expresiones musicales: + +@lilypond[quote,verbatim,ragged-right] +pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) +#{ + $x e8 a b $y b a e +#}) + +\relative c''{ + \pattern c8 c8\f + \pattern {d16 dis} { ais16-> b\p } +} +@end lilypond + diff --git a/Documentation/es/learning/scheme-tutorial.itely b/Documentation/es/learning/scheme-tutorial.itely deleted file mode 100644 index 2234abb2e9..0000000000 --- a/Documentation/es/learning/scheme-tutorial.itely +++ /dev/null @@ -1,347 +0,0 @@ -@c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- - -@ignore - Translation of GIT committish: 5f51567fbc5d7a811e147ebd01f103e066f36b3a - - 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.. -@end ignore - -@c \version "2.12.0" - - -@node Tutorial de Scheme -@appendix Tutorial de Scheme -@translationof Scheme tutorial - -@funindex # -@cindex Scheme -@cindex GUILE -@cindex Scheme, código en línea -@cindex acceder a Scheme -@cindex evaluar Scheme -@cindex LISP - -LilyPond utiliza el lenguaje de programación Scheme, tanto como parte -de la sintaxis del código de entrada, como para servir de mecanismo -interno que une los módulos del programa entre sí. Esta sección es -una panorámica muy breve sobre cómo introducir datos en Scheme. Si -quiere saber más sobre Scheme, consulte -@uref{http://@/www@/.schemers@/.org}. - -LilyPond utiliza la implementación GNU Guile de Scheme, que está -basada en el estándar @qq{R5RS} del lenguaje. Si está aprendiendo -Scheme para usarlo con LilyPond, no se recomienda trabajar con una -implementación distinta (o que se refiera a un estándar diferente). -Hay información sobre Guile en -@uref{http://www.gnu.org/software/guile/}. El estándar de Scheme -@qq{R5RS} se encuentra en -@uref{http://www.schemers.org/Documents/Standards/R5RS/}. - -La instalación de LilyPond inclute también la de la implementación -Guile de Scheme. Sobre casi todos los sistemas puede experimentar en -una @qq{caja de arena} de Scheme abriendo una ventana del terminal y -tecleando @q{guile}. En algunos sistemas, sobre todo en Windows, -podría necesitar ajustar la variable de entorno @code{GUILE_LOAD_PATH} -a la carpeta @code{../usr/shr/guile/1.8} dentro de la instalación de -LilyPond (para conocer la ruta completa a esta carpeta, consulte -@ref{Otras fuentes de información}). Como alternativa, los usuarios -de Windows pueden seleccionar simplemente @q{Ejecutar} del menú Inicio -e introducir @q{guile}. - -El concepto más básico de un lenguaje son sus tipos de datos: números, -cadenas de caracteres, listas, etc. He aquí una lista de los tipos de -datos que son de relevancia respecto de la entrada de LilyPond. - -@table @asis -@item Booleanos -Los valores Booleanos son Verdadero y Falso. Verdadero en Scheme es @code{#t} -y Falso es @code{#f}. -@funindex ##t -@funindex ##f - -@item Números -Los números se escriben de la forma normal, @code{1} es el número -(entero) uno, mientras que @code{-1.5} es un número en coma flotante -(un número no entero). - -@item Cadenas -Las cadenas se encierran entre comillas: - -@example -"esto es una cadena" -@end example - -Las cadenas pueden abarcar varias líneas: - -@example -"esto -es -una cadena" -@end example - -También se pueden añadir comillas y saltos de línea con las llamadas -secuencias de escape. La cadena @code{a dijo "b"} se escribe como - -@example -"a dijo \"b\"" -@end example - -Los saltos de línea t las barras invertidas se escapan mediante -@code{\n} y @code{\\} respectivamente. -@end table - - -En un archivo de música, los fragmentos de código de Scheme se -escriben con el signo de almohadilla @code{#}. Así, los ejemplos -anteriores traducidos a LilyPond son: - -@example -##t ##f -#1 #-1.5 -#"esto es una cadena" -#"esto -es -una cadena" -@end example - -Observe que los comentarios de LilyPond (@code{%} y @code{%@{ %@}}) no -se puedden utilizar dentro del código de Scheme. Los comentarios en -el Scheme de Guile se introducen como sigue: - -@example -; esto es un comentario de una línea - -#! - Esto es un comentario de bloque (no anidable) estilo Guile - Pero se usan rara vez por parte de los Schemers y nunca dentro del - código fuente de LilyPond -!# -@end example - -Se pueden combinar en un mismo archivo de música varias expresiones de -Scheme consecutivas mediante la utilización del operador @code{begin}. -Ello permite que el número de marcas de cuadradillo se redizca a una. - -@example -#(begin - (define fulanito 0) - (define menganito 1)) -@end example - -Si el @code{#} va seguido de un paréntesis de apertura, @code{(}, como -en el ejemplo anterior, el analizador sintáctico permanece dentro del -modo de Scheme hasta que encuentra el paréntesis de cierre -correspondiente, @code{)}, por lo que no son necesarios más símbolos -de @code{#} para introducir una sección de Scheme. - -Durante el resto de esta sección, supondremos que los datos se -introducen en un archivo de música, por lo que añadiremos almohadillas -@code{#} en todas partes. - -Scheme se puede usar para hacer cálculos. Utiliza sintaxis -@emph{prefija}. Sumar 1 y@tie{}2 se escribe como @code{(+ 1 2)} y no -como el tradicional @math{1+2}. - -@lisp -#(+ 1 2) - @result{} #3 -@end lisp - -La flecha @result{} muestra que el resultado de evaluar @code{(+ 1 2)} -es@tie{}@code{3}. Los cálculos se pueden anidar; el resultado de una -función se puede usar para otro cálculo. - -@lisp -#(+ 1 (* 3 4)) - @result{} #(+ 1 12) - @result{} #13 -@end lisp - -Estos cálculos son ejemplos de evaluaciones; una expresión como -@code{(* 3 4)} se sustituye por su valor @code{12}. Algo similar -ocurre con las variables. Después de haber definido una variable - -@example -doce = #12 -@end example - -@noindent -las variables se pueden usar también dentro de las expresiones, aquí - -@example -veintiCuatro = #(* 2 doce) -@end example - -@noindent -el número 24 se almacena dentro de la variable @code{veintiCuatro}. -La misma asignación se puede hacer también completamente en Scheme, - -@example -#(define veintiCuatro (* 2 doce)) -@end example - -El @emph{nombre} de una variable también es una expresión, similar a -un número o una cadena. Se introduce como - -@example -#'veintiCuatro -@end example - -@funindex #'symbol -@cindex comillas en Scheme - -El apóstrofo @code{'} evita que el intérprete de Scheme sustituya -@code{veintiCuatro} por @code{24}. En vez de esto, obtenemos el -nombre @code{veintiCuatro}. - -Esta sintaxis se usará con mucha frecuencia, pues muchos de los trucos -de presentación consisten en asignar valores (de Scheme) a variables -internas, por ejemplo - -@example -\override Stem #'thickness = #2.6 -@end example - -Esta instrucción ajusta el aspecto de las plicas. El valor @code{2.6} -se pone dentro de la variable @code{thickness} de un objeto -@code{Stem}. @code{thickness} se mide a partir del grosor de las -líneas del pentagrama, y así estas plicas serán @code{2.6} veces el -grosor de las líneas del pentagrama. Esto hace que las plicas sean -casi el doble de gruesas de lo normal. Para distinguir entre las -variables que se definen en los archivos de entrada (como -@code{veintiCuatro} en el ejemplo anterior) y las variables de los -objetos internos, llamaremos a las últimas @q{propiedades} y a las -primeras @q{variables.} Así, el objeto plica tiene una propiedad -@code{thickness} (grosor), mientras que @code{veintiCuatro} es una -variable. - -@cindex propiedades frente a variables -@cindex variables frente a propiedades - -Los desplazamientos bidimensionales (coordenadas X e Y) así como los -tamaños de los objetos (intervalos con un punto izquierdo y otro -derecho) se introducen como @code{parejas}. Una pareja@footnote{En la -terminología de Scheme, la pareja se llama @code{cons}, y sus dos -elementos se llaman @code{car} y @code{cdr} respectivamente.} se -introduce como @code{(primero . segundo)} y, como los símbolos, se deben -preceder de un apóstrofo: - -@example -\override TextScript #'extra-offset = #'(1 . 2) -@end example - -Esto asigna la pareja (1, 2) a la propiedad @code{extra-offset} del -objeto TextScript. Estos números se miden en espacios de pentagrama, -y así esta instrucción mueve el objeto un espacio de pentagrama a la -derecha, y dos espacios hacia arriba. - -Los dos elementos de una pareja pueden ser valores arbitrarios, por -ejemplo - -@example -#'(1 . 2) -#'(#t . #f) -#'("bla-bla" . 3.14159265) -@end example - -Una lista se escribe encerrando sus elementos entre paréntesis, y -añadiendo un apóstrofo. Por ejemplo, - -@example -#'(1 2 3) -#'(1 2 "cadena" #f) -@end example - -Todo el tiempo hemos estado usando listas. Un cálculo, como @code{(+ -1 2)} también es una lista (que contiene el símbolo @code{+} y los -números 1 y@tie{}2). Normalmente, las listas se interpretan como -cálculos, y el intérprete de Scheme sustituye el resultado del -cálculo. Para escribir una lista, detenemos la evaluación. Esto se -hace precediendo la lista por un apóstrofo @code{'}. Así, para los -cálculos no usamos ningún apóstrofo. - -Dentro de una lista o pareja precedida de apóstrofo, no hay necesidad -de escribir ningún apóstrofo más. Lo siguiente es una pareja de -símbolos, una lista de símbolos y una lista de listas respectivamente: - -@example -#'(stem . head) -#'(staff clef key-signature) -#'((1) (2)) -@end example - - -@menu -* Trucos con Scheme:: -@end menu - -@node Trucos con Scheme -@appendixsec Trucos con Scheme -@translationof Tweaking with Scheme - -Hemos visto cómo la salida de LilyPond se puede modificar -profundamente usando instrucciones como @code{\override TextScript -#'extra-offset = ( 1 . -1)}. Pero tenemos incluso mucho más poder si -utilizamos Scheme. Para ver una explicación completa de esto, -consulte el @ref{Tutorial de Scheme}, y @ruser{Interfaces para programadores}. - -Podemos usar Scheme simplemente para sobreescribir instrucciones con -@code{\override}, - -@c This isn't a valid example with skylining -@c It works fine without padText -td - -@ignore -@lilypond[quote,verbatim,ragged-right] -padText = #(define-music-function (parser location padding) (number?) -#{ - \once \override TextScript #'padding = #$padding -#}) - -\relative c''' { - c4^"piu mosso" b a b - \padText #1.8 - c4^"piu mosso" d e f - \padText #2.6 - c4^"piu mosso" fis a g -} -@end lilypond -@end ignore - -Lo podemos usar para crear instrucciones nuevas: - -@c Check this is a valid example with skylining -@c It is - 'padding still works - -@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 - -Incluso se le pueden pasar expresiones musicales: - -@lilypond[quote,verbatim,ragged-right] -pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) -#{ - $x e8 a b $y b a e -#}) - -\relative c''{ - \pattern c8 c8\f - \pattern {d16 dis} { ais16-> b\p } -} -@end lilypond - diff --git a/Documentation/es/notation/programming-interface.itely b/Documentation/es/notation/programming-interface.itely deleted file mode 100644 index 23912d55ee..0000000000 --- a/Documentation/es/notation/programming-interface.itely +++ /dev/null @@ -1,1562 +0,0 @@ -@c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- - -@ignore - Translation of GIT committish: d4f58bb3ad4e7fe1967a6b48f25e3addffc8aa14 - - 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.. -@end ignore - -@c \version "2.12.0" - -@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, @rlearning{Tutorial de Scheme}. - -@menu -* Funciones musicales:: -* Interfaces para el programador:: -* Construcción de funciones complejas:: -* Interfaz de marcado para el programador:: -* Contextos para programadores:: -* Procedimientos de Scheme como propiedades:: -* Usar código de Scheme en lugar de \tweak:: -* 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. - -@menu -* Panorámica de las funciones musicales:: -* Funciones de sustitución sencillas:: -* Funciones de sustitutión en parejas:: -* Matemáticas dentro de las funciones:: -* Funciones vacías:: -* Funciones sin argumentos:: -* Pranorá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 - -Es fácil hacer una función que sustituya a una variable en código de -LilyPond. La forma general de estas funciones 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...} - #@}) -@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. -@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. - -@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?} -@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. - - -@node Funciones de sustitución sencillas -@subsection Funciones de sustitución sencillas -@translationof Simple substitution functions - -He aquí un ejemplo sencillo: - -@lilypond[quote,verbatim,ragged-right] -padText = #(define-music-function (parser location padding) (number?) - #{ - \once \override TextScript #'padding = #$padding - #}) - -\relative c''' { - c4^"piu mosso" b a b - \padText #1.8 - c4^"piu mosso" d e f - \padText #2.6 - c4^"piu mosso" fis a g -} -@end lilypond - -También se pueden sustituir las expresiones musicales: - -@lilypond[quote,verbatim,ragged-right] -custosNote = #(define-music-function (parser location note) - (ly:music?) - #{ - \once \override Voice.NoteHead #'stencil = - #ly:text-interface::print - \once \override Voice.NoteHead #'text = - \markup \musicglyph #"custodes.mensural.u0" - \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 sustitutión en parejas -@subsection Funciones de sustitutión en parejas -@translationof Paired substitution functions - -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. - -@quotation -@example -manualBeam = -#(define-music-function (parser location beg-end) - (pair?) -#@{ - \once \override Beam #'positions = #$beg-end -#@}) - -\relative @{ - \manualBeam #'(3 . 6) c8 d e f -@} -@end example -@end quotation - -@noindent -o bien - -@lilypond[quote,verbatim,ragged-right] -manualBeam = -#(define-music-function (parser location beg end) - (number? number?) -#{ - \once \override Beam #'positions = #(cons $beg $end) -#}) - -\relative { - \manualBeam #3 #6 c8 d e f -} -@end lilypond - - -@node Matemáticas dentro de las funciones -@subsection Matemáticas dentro de las funciones -@translationof Mathematics in functions - -Las funciones musicales pueden contar con programación de Scheme -además de la simple sustitución: - -@lilypond[quote,verbatim,ragged-right] -AltOn = #(define-music-function (parser location mag) (number?) - #{ \override Stem #'length = #$(* 7.0 mag) - \override NoteHead #'font-size = - #$(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) #}) - -AltOff = { - \revert Stem #'length - \revert NoteHead #'font-size -} - -{ c'2 \AltOn #0.5 c'4 c' - \AltOn #1.5 c' c' \AltOff c'2 } -@end lilypond - -@noindent -Este ejemplo se puede reescribir de forma que pase expresiones -musicales: - -@lilypond[quote,verbatim,ragged-right] -withAlt = #(define-music-function (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 #}) - -{ c'2 \withAlt #0.5 {c'4 c'} - \withAlt #1.5 {c' c'} c'2 } -@end lilypond - - -@node Funciones vacías -@subsection Funciones vacías -@translationof Void 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). - -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 -noPointAndClick = -#(define-music-function (parser location) () - (ly:set-option 'point-and-click #f) - (make-music 'SequentialMusic 'void #t)) -... -\noPointAndClick % desactivar la funcionalidad Apuntar y Pulsar. -@end example - - -@node Funciones sin argumentos -@subsection Funciones sin argumentos -@translationof Functions without arguments - -En casi todos los casos, una función sin argumentos se debe escribir -con una variable: - -@example -dolce = \markup@{ \italic \bold dolce @} -@end example - -Sin embargo, en raras ocasiones puede ser de utilidad crear una -función musical sin argumentos: - -@example -displayBarNum = -#(define-music-function (parser location) () - (if (eq? #t (ly:get-option 'display-bar-numbers)) - #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} - #@{#@})) -@end example - -Para la impresión real de los números de compás donde se llama a esta -función, invoque a @command{lilypond} con - -@example -lilypond -d display-bar-numbers ARCHIVO.ly -@end example - - -@node Pranorámica de las funciones musicales disponibles -@subsection Pranorá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 - -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}. - -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 Construcción de funciones complejas -@section Construcción de funciones complejas -@translationof Building complicated functions - -Esta sección explica cómo reunir la información necesaria para crear -funciones musicales complejas. - - -@menu -* Presentación de expresiones musicales:: -* Propiedades de la música:: -* Doblar una nota con ligaduras (ejemplo):: -* Añadir articulación a las notas (ejemplo):: -@end menu - -@node Presentación de expresiones musicales -@subsection Presentación de expresiones musicales -@translationof Displaying music expressions - -@cindex interno, almacenamiento -@cindex mostrar expresiones musicales -@cindex interna, representación, mostrar - -@funindex \displayMusic - -Si se está escribiendo una función musical puede ser muy instructivo -examinar cómo se almacena internamente una expresión musical. Esto se -puede hacer con la función musical @code{\displayMusic}: - -@example -@{ - \displayMusic @{ c'4\f @} -@} -@end example - -@noindent -imprime lo siguiente: - -@example -(make-music - 'SequentialMusic - 'elements - (list (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)) - (make-music - 'AbsoluteDynamicEvent - 'text - "f"))))) -@end example - -De forma predeterminada, LilyPond imprime estos mensajes en la consola -junto al resto de los mensajes. Para discernir entre estos mensajes y -guardar el resultado de @code{\display@{MATERIAL@}}, redirija la -salida hacia un archivo. - -@example -lilypond archivo.ly >resultado.txt -@end example - -Con la aplicación de un poco de formato, la información anterior es -fácil de leer: - -@example -(make-music 'SequentialMusic - 'elements (list (make-music 'EventChord - 'elements (list (make-music 'NoteEvent - 'duration (ly:make-duration 2 0 1 1) - 'pitch (ly:make-pitch 0 0 0)) - (make-music 'AbsoluteDynamicEvent - 'text "f"))))) -@end example - -Una secuencia musical @code{@{ ... @}} tiene el nombre -@code{SequentialMusic}, y sus expresiones internas se almacenan como -una lista en su propiedad @code{'elements}. Una nota se representa -como una expresión @code{EventChord} que contiene un objeto -@code{NoteEvent} (que almacena las propiedades de duración y altura) y -cualquier otra información adicional (en este caso, un evento -@code{AbsoluteDynamicEvent} con una propiedad de texto @code{"f"}. - - -@node Propiedades de la música -@subsection Propiedades de la música -@translationof Music properties - -El objeto @code{NoteEvent} es el primer objeto de la propiedad -@code{'elements} de @code{someNote}. - -@example -unaNota = c' -\displayMusic \unaNota -===> -(make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)))) -@end example - -La función @code{display-scheme-music} es la función utilizada por -@code{\displayMusic} para imprimir la representación de Scheme de una -expresión musical. - -@example -#(display-scheme-music (first (ly:music-property unaNota 'elements))) -===> -(make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)) -@end example - -Después se accede a la altura de la nota a través de la propiedad -@code{'pitch} del objeto @code{NoteEvent}: - -@example -#(display-scheme-music - (ly:music-property (first (ly:music-property unaNota 'elements)) - 'pitch)) -===> -(ly:make-pitch 0 0 0) -@end example - -La altura de la nota se puede cambiar estableciendo el valor de esta -propiedad 'pitch: - -@funindex \displayLilyMusic - -@example -#(set! (ly:music-property (first (ly:music-property unaNota 'elements)) - 'pitch) - (ly:make-pitch 0 1 0)) ;; fijar la altura a d'. -\displayLilyMusic \unaNota -===> -d' -@end example - - -@node Doblar una nota con ligaduras (ejemplo) -@subsection Doblar una nota con ligaduras (ejemplo) -@translationof Doubling a note with slurs (example) - -Supongamos que queremos crear una función que traduce una entrada como -@code{a} a algo como @code{a( a)}. Empezamos examinando la -representación interna de la música con la que queremos terminar. - -@example -\displayMusic@{ a'( a') @} -===> -(make-music - 'SequentialMusic - 'elements - (list (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 5 0)) - (make-music - 'SlurEvent - 'span-direction - -1))) - (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 5 0)) - (make-music - 'SlurEvent - 'span-direction - 1))))) -@end example - -Las malas noticias son que las expresiones @code{SlurEvent} se deben -añadir @q{dentro} de la nota (o más concretamente, dentro de la -expresión @code{EventChord}). - -Ahora observamos la entrada: - -@example -(make-music - 'SequentialMusic - 'elements - (list (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 5 0)))))) -@end example - -Así pues, en nuestra función, tenemos que clonar esta expresión (de -forma que tengamos dos notas para construir la secuencia), añadir -@code{SlurEvents} a la propiedad @code{'elements} de cada una de -ellas, y por último hacer una secuencia @code{SequentialMusic} con los -dos @code{EventChords}. - -@example -doubleSlur = #(define-music-function (parser location note) (ly:music?) - "Return: @{ note ( note ) @}. - `note' is supposed to be an EventChord." - (let ((note2 (ly:music-deep-copy note))) - (set! (ly:music-property note 'elements) - (cons (make-music 'SlurEvent 'span-direction -1) - (ly:music-property note 'elements))) - (set! (ly:music-property note2 'elements) - (cons (make-music 'SlurEvent 'span-direction 1) - (ly:music-property note2 'elements))) - (make-music 'SequentialMusic 'elements (list note note2)))) -@end example - - -@node Añadir articulación a las notas (ejemplo) -@subsection Añadir articulación a las notas (ejemplo) -@translationof Adding articulation to notes (example) - -La manera fácil de añadir articulación a las notas es fundir dos -expresiones musicales en un contexto único, como está explicado en -@ref{Crear contextos}. Sin embargo, suponga que queremos escribir -una función musical que haga esto. - -Una @code{$variable} dentro de la notación @code{#@{...#@}} es como -usar una @code{\variable} normal en la notación clásica de LilyPond. -Sabemos que - -@example -@{ \musica -. -> @} -@end example - -@noindent -no funciona en LilyPond. Podemos evitar este problema adjuntando la -articulación a una nota de mentira, - -@example -@{ << \musica s1*0-.-> @} -@end example - -@noindent -pero a los efectos de este ejemplo, aprenderemos ahora cómo hacerlo en -Scheme. Comenzamos examinando nuestra entrada y la salida deseada: - -@example -% entrada -\displayMusic c4 -===> -(make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch -1 0 0)))) -===== -% salida deseada -\displayMusic c4-> -===> -(make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch -1 0 0)) - (make-music - 'ArticulationEvent - 'articulation-type - "marcato"))) -@end example - -Vemos que una nota (@code{c4}) se representa como una expresión -@code{EventChord}, con una expresión @code{NoteEvent} en su lista de -elementos. Para añadir una articulación marcato, se debe añadir una -expresión @code{ArticulationEvent} a la propiedad elementos de la -expresión @code{EventChord}. - -Para construir esta función, empezamos con - -@example -(define (add-marcato event-chord) - "Añadir una ArticulationEvent de marcato a los elementos de `event-chord', - que se supone que es una expresión EventChord." - (let ((result-event-chord (ly:music-deep-copy event-chord))) - (set! (ly:music-property result-event-chord 'elements) - (cons (make-music 'ArticulationEvent - 'articulation-type "marcato") - (ly:music-property result-event-chord 'elements))) - result-event-chord)) -@end example - -La primera línea es la forma de definir una función en Scheme: el -nombre de la función es @code{add-marcato}, y tiene una variable -llamada @code{event-chord}. En Scheme, el tipo de variable suele -quedar claro a partir de su nombre (¡esto también es una buena -práctica en otros lenguajes de programación!). - -@example -"Añadir una ArticulationEvent de marcato..." -@end example - -@noindent -es una descripción de lo que hace la función. No es estrictamente -necesario, pero como los nombres de variable claros, es una buena -práctica. - -@example -(let ((result-event-chord (ly:music-deep-copy event-chord))) -@end example - -@code{let} se usa para declarar variables locales. Aquí usamos una -variable local, llamada @code{result-event-chord}, a la que le damos -el valor @code{(ly:music-deep-copy event-chord)}. -@code{ly:music-deep-copy} es una función específica de LilyPond, como -todas las funciones que comienzan por @code{ly:}. Se usa para hacer -una copia de una expresión musical. Aquí, copiamos @code{event-chord} -(el parámetro de la función). Recuerde que el propósito es añadir un -marcato a una expresión @code{EventChord}. Es mejor no modificar el -@code{EventChord} que se dio como argumento, porque podría utilizarse -en algún otro lugar. - -Ahora tenemos un @code{result-event-chord}, que es una expresión -@code{NoteEventChord} y es una copia de @code{event-chord}. Añadimos -el marcato a su propiedad lista de elementos. - -@example -(set! lugar valor-nuevo) -@end example - -Aquí, lo que queremos establecer (el @q{lugar}) es la propiedad -@q{elements} de la expresión @code{result-event-chord}. - -@example -(ly:music-property result-event-chord 'elements) -@end example - -@code{ly:music-property} es la función que se usa para acceder a las -propiedades musicales (los @code{'elements}, @code{'duration}, -@code{'pitch}, etc., que vemos en la salida de @code{\displayMusic} -más arriba). El nuevo valor es la anterior propiedad elements, con un -elemento adicional: la expresión @code{ArticulationEvent}, que -copiamos a partir de la salida de @code{\displayMusic}, - -@example -(cons (make-music 'ArticulationEvent - 'articulation-type "marcato") - (ly:music-property result-event-chord 'elements)) -@end example - -@code{cons} se usa para añadir un elemento a una lista sin modificar -la lista original. Esto es lo que queremos: la misma lista que antes, -más la nueva expresión @code{ArticulationEvent}. El orden dentro de -la propiedad elements no es importante aquí. - -Finalmente, una vez añadida la articulación marcato a su propiedad -@code{elements}, podemos devolver @code{result-event-chord}, de aquí -la última línea de la función. - -Ahora transformamos la función @code{add-marcato} en una función -musical, - -@example -addMarcato = #(define-music-function (parser location event-chord) - (ly:music?) - "Añadir un ArticulationEvent de marcato a los elementos de `event-chord', - que se supone que es una expresión EventChord." - (let ((result-event-chord (ly:music-deep-copy event-chord))) - (set! (ly:music-property result-event-chord 'elements) - (cons (make-music 'ArticulationEvent - 'articulation-type "marcato") - (ly:music-property result-event-chord 'elements))) - result-event-chord)) -@end example - -Podemos verificar que esta función musical funciona correctamente, - -@example -\displayMusic \addMarcato c4 -@end example - - -@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:: -* 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 -@translationof Markup construction in Scheme - -@cindex marcado, definir instrucciones de - -El macro @code{markup} construye expresiones de marcado en Scheme, -proporcionando una sintaxis similar a la de LilyPond. Por ejemplo: - -@example -(markup #:column (#:line (#:bold #:italic "hola" #:raise 0.4 "mundo") - #:larger #:line ("fulano" "fulanito" "menganito"))) -@end example - -@noindent -equivale a: -@example -\markup \column @{ \line @{ \bold \italic "hola" \raise #0.4 "mundo" @} - \larger \line @{ fulano fulanito menganito @} @} -@end example - -@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. - -@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{\instruccion} @tab @code{#:instruccion} -@item @code{\variable} @tab @code{variable} -@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} -@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}). - -@knownissues - -El argumento markup-list de instrucciones como @code{#:line}, -@code{#:center} y @code{#:column} no pueden se una variable o el -resultado de la llamada a una función. - -@lisp -(markup #:line (funcion-que-devuelve-marcados)) -@end lisp - -@noindent -no es válido. Hay que usar las funciones @code{make-line-markup}, -@code{make-center-markup} o @code{make-column-markup} en su lugar: - -@lisp -(markup (make-line-markup (funcion-que-devuelve-marcados))) -@end lisp - - -@node Cómo funciona internamente el marcado -@subsection Cómo funciona internamente el marcado -@translationof How markups work internally - -En un elemento de marcado como - -@example -\raise #0.5 "ejemplo de texto" -@end example - -@noindent -@code{\raise} se representa en realidad por medio de la función -@code{raise-markup}. La expresión de marcado se almacena como - -@example -(list raise-markup 0.5 (list simple-markup "ejemplo de texto")) -@end example - -Cuando el marcado se convierte en objetos imprimibles (Stencils o -sellos), se llama la función @code{raise-markup} como - -@example -(apply raise-markup - @var{\objeto de marcado} - @var{lista de listas asociativas de propiedades} - 0.5 - @var{el marcado "ejemplo de texto"}) -@end example - -Primero la función @code{raise-markup} crea el sello para la cadena -@code{ejemplo de texto}, y después eleva el sello Stencil en 0.5 -espacios de pentagrama. Este es un ejemplo bastante simple; en el -resto de la sección podrán verse ejemplos más complejos, así como en -@file{scm/@/define@/-markup@/-commands@/.scm}. - - -@node Definición de una instrucción de marcado nueva -@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}. - -@lisp -(define-markup-command (@var{nombre-de-la-instruccion} @var{layout} @var{props} @var{arg1} @var{arg2} ...) - (@var{arg1-type?} @var{arg2-type?} ...) - ..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 layout -la definición de @q{presentación} -@item props -lista de listas asociativas, que contiene todas las propiedades -activas. -@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, - -@example -\markup @{ \override #'(font-shape . caps) Texto-en-versalitas @} -@end example - -@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}. - -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 - -@example -(define-markup-command (smallcaps layout props argument) (markup?) -@end example - -@noindent - -Lo que aparece a continuación es el contenido de la instrucción: -debemos interpretar el @code{argument} como un marcado, es decir: - -@example -(interpret-markup layout @dots{} argument) -@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: - -@example -(cons (list '(font-shape . caps) ) props) -@end example - -@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. - -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: - -@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))) -@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 resultado final es como sigue: - -@example -@{ - c''^\markup \character #"Cleopatra" - e'^\markup \character #"Giulio Cesare" -@} -@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\"" - (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) - -{ - c''^\markup \character #"Cleopatra" c'' c'' c'' - e'^\markup \character #"Giulio Cesare" e' e' e' -} -@end lilypond - -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: - -@example -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps." - (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 - -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. - -@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: - -@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 - -@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). - -Como ejemplo, no es posible usar una instrucción de marcado -@code{fulanito} con cuatro argumentos definida como - -@example -#(define-markup-command (fulanito layout props - num1 str1 num2 str2) - (number? string? number? string?) - ...) -@end example - -@noindent -Si la aplicamos como, digamos, - -@example -\markup \fulanito #1 #"mengano" #2 #"zutano" -@end example - -@cindex Scheme signature -@cindex signature, Scheme -@noindent -@command{lilypond} protesta diciendo que no puede analizar -@code{fulanito} debido a su firma de Scheme desconocida. - - -@node Definición de nuevas instrucciones de lista de marcado -@subsection Definición de nuevas instrucciones de lista de marcado -@translationof New markup list command definition - -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}. - -@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))))) -@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: - -@example -\markuplines @{ - \paragraph @{ - El arte de la tipografía musical se llama \italic @{grabado (en plancha).@} - El término deriva del proceso tradicional de impresión de música. - hace sólo algunas décadas, las partituras se hacían cortando y estampando - la música en una plancha de zinc o lata en una imagen invertida. - @} - \override-lines #'(par-indent . 4) \paragraph @{ - La plancha se tenía que entintar, y las depresiones causadas por los cortes - y estampados retienen la tinta. Se formaba una imagen presionando el papel - contra la plancha. El estampado y cortado se hacía completamente - a mano. - @} -@} -@end example - - -@node Contextos para programadores -@section Contextos para programadores -@translationof Contexts for programmers - -@menu -* Evaluación de contextos:: -* Ejecutar una función sobre todos los objetos de la presentación:: -@end menu - -@node Evaluación de contextos -@subsection Evaluación de contextos -@translationof Context evaluation - -@cindex código, llamadas durante la interpretación -@funindex \applyContext - -Se pueden modificar los contextos durante la interpretación con código -de Scheme. La sintaxis para esto es - -@example -\applyContext @var{función} -@end example - -@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: - -@example -\applyContext - #(lambda (x) - (format #t "\nSe nos ha llamado en el compás número ~a.\n" - (ly:context-property x 'currentBarNumber))) -@end example - - -@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 -@translationof Running a function on all layout objects - - -@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}. Su sintaxis es - -@example -\applyOutput @var{contexto} @var{proc} -@end example - -@noindent -donde @var{proc} es una función de Scheme, que toma tres argumentos. - -Al interpretarse, la función @var{proc} se llama para cada objeto de -presentación que se encuentra en el contexto @var{contexto}, con los -siguientes argumentos: - -@itemize -@item el propio objeto de presentación, -@item el contexto en que se creó el objeto de presentación, y -@item el contexto en que se procesa @code{\applyOutput}. -@end itemize - -Además, la causa del objeto de presentación, es decir el objeto o -expresión musical que es responsable de haberlo creado, está en la -propiedad @code{cause} del objeto. Por ejemplo, para la cabeza de una -nota, éste es un evento @rinternals{NoteHead}, y para un objeto -@rinternals{Stem} (plica), éste es un objeto @rinternals{Stem}. -@c Impossible - changed to Stem --FV - -He aquí una función que usar para @code{\applyOutput}; borra las -cabezas de las notas que están sobre la línea central: - -@lilypond[quote,verbatim,ragged-right] -#(define (blanker grob grob-origin context) - (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) - (eq? (ly:grob-property grob 'staff-position) 0)) - (set! (ly:grob-property grob 'transparent) #t))) - -\relative { - e4 g8 \applyOutput #'Voice #blanker b d2 -} -@end lilypond - - -@node Procedimientos de Scheme como propiedades -@section Procedimientos de Scheme como propiedades -@translationof Scheme procedures as properties - -Las propiedades (como el grosor, la dirección, etc.) se pueden -establecer a valores fijos con \override, p. ej. - -@example -\override Stem #'thickness = #2.0 -@end example - -Las propiedades pueden fijarse también a un procedimiento de scheme, - -@lilypond[fragment,verbatim,quote,relative=2] -\override Stem #'thickness = #(lambda (grob) - (if (= UP (ly:grob-property grob 'direction)) - 2.0 - 7.0)) -c b a g b a g b -@end lilypond - -@noindent -En este caso, el procedimiento se ejecuta tan pronto como el valor de -la propiedad se reclama durante el proceso de formateo. - -Casi todo el motor de tipografiado está manejado por estos -@emph{callbacks}. Entre las propiedades que usan normalmente -@emph{callbacks} están - -@table @code -@item stencil - La rutina de impresión, que construye un dibujo para el símbolo -@item X-offset - La rutina que establece la posición horizontal -@item X-extent - La rutina que calcula la anchura de un objeto -@end table - -El procedimiento siempre toma un argumento único, que es el grob (el -objeto gráfico). - -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}, - -@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}))) -@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}. - - -@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 - -La principal desventaja de @code{\tweak} es su inflexibilidad -sintáctica. Por ejemplo, lo siguiente produce un error de sintaxis. - -@example -F = \tweak #'font-size #-3 -\flageolet - -\relative c'' @{ - c4^\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 articulación a las notas (ejemplo)}, -especialmente cómo usar @code{\displayMusic} como guía de ayuda. - -@example -F = #(let ((m (make-music 'ArticulationEvent - 'articulation-type "flageolet"))) - (set! (ly:music-property m 'tweaks) - (acons 'font-size -3 - (ly:music-property m 'tweaks))) - m) - -\relative c'' @{ - c4^\F c4_\F -@} -@end example - -@noindent -Aquí, las propiedades @code{tweaks} del objeto flageolet @code{m} -(creado con @code{make-music}) se extraen con -@code{ly:music-property}, se antepone un nuevo par clave-valor para -cambiar el tamaño de la tipografía a la lista de propiedades con la -función de Scheme @code{acons}, y finalmente el resultado se escribe -de nuevo con @code{set!}. El último elemento del bloque @code{let} es -el valor de retorno, el propio @code{m}. - -@node Trucos difíciles -@section Trucos difíciles -@translationof Difficult tweaks - -Hay un cierto número de tipos de ajustes difíciles. - -@itemize - -@item -Un tipo de ajuste difícil es la apariencia de los objetos de -extensión, como las ligaduras de expresión y de unión. Inicialmente, -sólo se crea uno de estos objetos, y pueden ajustarse con el mecanismo -normal. Sin embargo, en ciertos casos los objetos extensores cruzan -los saltos de línea. Si esto ocurre, estos objetos se clonan. Se -crea un objeto distinto por cada sistema en que se encuentra. Éstos -son clones del objeto original y heredan todas sus propiedades, -incluidos los @code{\override}s. - -En otras palabras, un @code{\override} siempre afecta a todas las -piezas de un objeto de extensión fragmentado. Para cambiar sólo una -parte de un extensor en el salto de línea, es necesario inmiscuirse en -el proceso de formateado. El @emph{callback} -@code{after-line-breaking} contiene el procedimiento Scheme que se -llama después de que se han determinado los saltos de línea, y los -objetos de presentación han sido divididos sobre los distintos -sistemas. - -En el ejemplo siguiente, definimos un procedimiento -@code{my-callback}. Este procedimiento - -@itemize -@item -determina si hemos sido divididos por los saltos de línea -@item -en caso afirmativo, reúne todos los objetos divididos -@item -comprueba si somos el último de los objetos divididos -@item -en caso afirmativo, establece @code{extra-offset}. -@end itemize - -Este procedimiento se instala en @rinternals{Tie} (ligadura de unión), -de forma que la última parte de la ligadura dividida se traslada hacia -arriba. - -@lilypond[quote,verbatim,ragged-right] -#(define (my-callback grob) - (let* ( - ; have we been split? - (orig (ly:grob-original grob)) - - ; if yes, get the split pieces (our siblings) - (siblings (if (ly:grob? orig) - (ly:spanner-broken-into orig) '() ))) - - (if (and (>= (length siblings) 2) - (eq? (car (last-pair siblings)) grob)) - (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) - -\relative c'' { - \override Tie #'after-line-breaking = - #my-callback - c1 ~ \break c2 ~ c -} -@end lilypond - -@noindent -Al aplicar este truco, la nueva función de callback -@code{after-line-breaking} también debe llamar a la antigua -@code{after-line-breaking}, si existe. Por ejemplo, si se usa con -@code{Hairpin}, se debe llamar también a -@code{ly:hairpin::after-line-breaking}. - - -@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. - -@example -\overrideProperty -#"Score.NonMusicalPaperColumn" % Nombre del grob -#'line-break-system-details % Nombre de la propiedad -#'((next-padding . 20)) % Valor -@end example - -Observe, sin embargo, que @code{\override}, aplicado a -@code{NonMusicalPaperColumn} y a @code{PaperColumn}, aún funciona -como se espera dentro de los bloques @code{\context}. - -@end itemize