X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fes%2Fextending%2Fscheme-tutorial.itely;h=6483a5b75e1fe865f87f7fd7c6de05a2f7a6ae3c;hb=91532052a38c0643e1b3cfca216d70052febb89a;hp=a19fdc77a46a9d58324f245580a81104cb14ee59;hpb=a8d54f44df1fe4f89823f6b78364870ce51174dc;p=lilypond.git diff --git a/Documentation/es/extending/scheme-tutorial.itely b/Documentation/es/extending/scheme-tutorial.itely index a19fdc77a4..6483a5b75e 100644 --- a/Documentation/es/extending/scheme-tutorial.itely +++ b/Documentation/es/extending/scheme-tutorial.itely @@ -1,20 +1,19 @@ @c -*- coding: utf-8; mode: texinfo; documentlanguage: es -*- @ignore - Translation of GIT committish: fe2cae0fa47ec4ec0184e6b3d15572fbcba881cf + Translation of GIT committish: 743dc7b27888c776186336cf4b330d3ebfc821de 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" +@c \version "2.19.22" @node Tutorial de Scheme @appendix Tutorial de Scheme @translationof Scheme tutorial -@funindex # @cindex Scheme @cindex GUILE @cindex Scheme, código en línea @@ -74,13 +73,21 @@ 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 +a la carpeta @code{../usr/share/guile/1.8} dentro de la instalación de LilyPond (para conocer la ruta completa a esta carpeta, consulte @rlearning{Otras fuentes de información}). Como alternativa, los usuarios de Windows pueden seleccionar simplemente @q{Ejecutar} del menú Inicio e introducir @q{guile}. -Una vez está funcionando el cajón de arena de Guile, verá un indicador +Sin embargo, está disponible un cajón de arena de Scheme listo para +funcionar con todo LilyPond cargado, con esta instrucción de la línea +de órdenes: +@example +lilypond scheme-sandbox +@end example + +@noindent +Una vez está funcionando el cajón de arena, verá un indicador del sistema de Guile: @lisp @@ -88,7 +95,12 @@ guile> @end lisp Podemos introducir expresiones de Scheme en este indicador para -experimentar con Scheme. +experimentar con Scheme. Si quiere usar la biblioteca readline de GNU +para una más cómoda edición de la línea de órdenes de Scheme, consulte +el archivo @file{ly/scheme-sandbox.ly} para más información. Si ya ha +activado la biblioteca readline para las sesiones de Guile +interactivas fuera de LilyPond, debería funcionar también en el cajón +de arena. @node Variables de Scheme @subsection Variables de Scheme @@ -161,7 +173,7 @@ Los valores Booleanos son Verdadero y Falso. Verdadero en Scheme es @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 +(entero) uno, mientras que @w{@code{-1.5}} es un número en coma flotante (un número no entero). @item Cadenas @@ -213,7 +225,16 @@ También existen tipos de datos compuestos en Scheme. Entre los tipos más usados en la programación de LilyPond se encuentran las parejas, las listas, las listas-A y las tablas de hash. -@subheading Parejas +@menu +* Parejas:: +* Listas:: +* Listas asociativas (listas-A):: +* Tablas de hash:: +@end menu + +@node Parejas +@unnumberedsubsubsec Parejas +@translationof Pairs El tipo fundacional de datos compuestos de Scheme es la @code{pareja}. Como se espera por su nombre, una pareja son dos valores unidos en uno @@ -256,7 +277,7 @@ los procedimientos de Scheme @code{car} y @code{cdr}, respectivamente. @lisp guile> (define mipareja (cons 123 "Hola") -... ) +@dots{} ) guile> (car mipareja) 123 guile> (cdr mipareja) @@ -270,8 +291,9 @@ Nota: @code{cdr} se pronuncia "could-er", según Sussman y Abelson, véase @uref{http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133} - -@subheading Listas +@node Listas +@unnumberedsubsubsec Listas +@translationof Lists Una estructura de datos muy común en Scheme es la @emph{lista}. Formalmente, una lista se define como la lista vacía (representada @@ -302,7 +324,10 @@ considera un dialecto de Lisp, donde @q{lisp} es una abreviatura de @q{List Processing} (proceso de listas). Todas las expresiones de Scheme son listas. -@subheading Listas asociativas (listas-A) + +@node Listas asociativas (listas-A) +@unnumberedsubsubsec Listas asociativas (listas-A) +@translationof Association lists (alists) Un tipo especial de listas son las @emph{listas asociativas} o @emph{listas-A}. Se puede usar una lista-A para almacenar datos para @@ -328,7 +353,10 @@ guile> Las listas-A se usan mucho en LilyPond para almacenar propiedades y otros datos. -@subheading Tablas de hash + +@node Tablas de hash +@unnumberedsubsubsec Tablas de hash +@translationof Hash tables Estructuras de datos que se utilizan en LilyPond de forma ocasional. Una tabla de hash es similar a una matriz, pero los índices de la @@ -505,7 +533,15 @@ Los procedimientos de Scheme son expresiones de Scheme ejecutables que devuelven un valor resultante de su ejecución. También pueden manipular variables definidas fuera del procedimiento. -@subheading Definir procedimientos +@menu +* Definir procedimientos:: +* Predicados:: +* Valores de retorno:: +@end menu + +@node Definir procedimientos +@unnumberedsubsubsec Definir procedimientos +@translationof Defining procedures Los procedimientos se definen en Scheme con @code{define}: @@ -531,7 +567,10 @@ guile> (media 3 12) 15/2 @end lisp -@subheading Predicados + +@node Predicados +@unnumberedsubsubsec Predicados +@translationof Predicates Los procedimientos de Scheme que devuelven valores booleanos se suelen llamar @emph{predicados}. Por convenio (pero no por necesidad), @@ -545,7 +584,10 @@ guile> (menor-que-diez? 15) #f @end lisp -@subheading Valores de retorno + +@node Valores de retorno +@unnumberedsubsubsec Valores de retorno +@translationof Return values Los procedimientos de Scheme siempre devuelven un valor de retorno, que es el valor de la última expresión ejecutada en el procedimiento. @@ -572,15 +614,23 @@ let: @lisp guile> (let ((x 2) (y 3) (z 4)) (display (+ x y)) (display (- z 4)) -... (+ (* x y) (/ z x))) +@dots{} (+ (* x y) (/ z x))) 508 @end lisp + @node Condicionales de Scheme @subsection Condicionales de Scheme @translationof Scheme conditionals -@subheading if +@menu +* if:: +* cond:: +@end menu + +@node if +@unnumberedsubsubsec if +@translationof if Scheme tiene un procedimiento @code{if}: @@ -601,14 +651,17 @@ guile> (if (> a b) "a es mayor que b" "a no es mayor que b") "a no es mayor que b" @end lisp -@subheading cond -Otro procedimiento condicional en scheme es @code{cond}: +@node cond +@unnumberedsubsubsec cond +@translationof cond + +Otro procedimiento condicional en Scheme es @code{cond}: @example (cond (expresión-de-prueba-1 secuencia-de-expresiones-resultante-1) (expresión-de-prueba-2 secuencia-de-expresiones-resultante-2) - ... + @dots{} (expresión-de-prueba-n secuencia-de-expresiones-resultante-n)) @end example @@ -631,6 +684,7 @@ guile> (cond ((< a b) "a es menor que b") * Sintaxis del Scheme de LilyPond:: * Variables de LilyPond:: * Variables de entrada y Scheme:: +* Importación de Scheme dentro de LilyPond:: * Propiedades de los objetos:: * Variables de LilyPond compuestas:: * Representación interna de la música:: @@ -639,30 +693,90 @@ guile> (cond ((< a b) "a es menor que b") @node Sintaxis del Scheme de LilyPond @subsection Sintaxis del Scheme de LilyPond @translationof LilyPond Scheme syntax +@funindex $ +@funindex # El intérprete Guile forma parte de LilyPond, lo que significa que se puede incluir Scheme dentro de los archivos de entrada de LilyPond. -La marca de almohadilla @code{#} se utiliza para indicar al analizador -sintáctico de LilyPond que lo siguiente es un valor de Scheme. - -Una vez el analizador sintáctico se encuentra con un símbolo de -almohadilla, la entrada se le pasa al intérprete Guile para evaluar la -expresión de Scheme. El intérprete continúa procesando la entrada -hasta que se encuentra con el final de una expresión de Scheme. - -Los procedimientos de Scheme se pueden definir dentro de los archivos -de entrada de LilyPond: +Existen varios métodos para incluir Scheme dentro de LilyPond. + +La manera más sencilla es utilizar el símbolo de +almohadilla@tie{}@code{#} antes de una expresión de Scheme. + +Ahora bien, el código de entrada de LilyPond se estructura en +elementos y expresiones, de forma parecida a cómo el lenguaje humano +se estructura en palabras y frases. LilyPond tiene un analizador +léxico que reconoce elementos indivisibles (números literales, cadenas +de texto, elementos de Scheme, nombres de nota, etc.), y un analizador +que entiende la sintaxis, la Gramática de LilyPond (@rcontrib{LilyPond grammar}). +Una vez que sabe que se aplica una regla sintáctica concreta, ejecuta +las acciones asociadas con ella. + +El método del símbolo de almohadilla@tie{}@code{#} para incrustar +Scheme se adapta de forma natural a este sistema. Una vez que el +analizador léxico ve un símbolo de almohadilla, llama al lector de +Scheme para que lea una expresión de Scheme completa (que puede ser un +identificador, una expresión encerrada entre paréntesis, o algunas +otras cosas). Después de que se ha leído la expresión de Scheme, se +almacena como el valor de un elemento @code{SCM_TOKEN} de la +gramática. Después de que el analizador sintáctico ya sabe cómo hacer +uso de este elemento, llama a Guila para que evalúe la expresión de +Scheme. Dado que el analizador sintáctico suele requerir un poco de +lectura por delante por parte del analizador léxico para tomar sus +decisiones de análisis sintáctico, esta separación de lectura y +evaluación entre los analizadores léxico y sintáctico es justamente lo +que se necesita para mantener sincronizadas las ejecuciones de +expresiones de LilyPond y de Scheme. Por este motivo se debe usar el +símbolo de almohadilla@tie{}@code{#} para llamar a Scheme siempre que +sea posible. + +Otra forma de llamar al intérprete de Scheme desde lilyPond es el uso +del símbolo de dólar@tie{}@code{$} en lugar de la almohadilla para +introducir las expresiondes de Scheme. En este caso, LilyPond evalúa +el código justo después de que el analizador léxico lo ha leído. +Comprueba el tipo resultante de la expresión de Scheme y después +selecciona un tipo de elemento (uno de los varios elementos +@code{xxx_IDENTIFIER} dentro de la sintaxis) para él. Crea una +@emph{copia} del valor y la usa como valor del elemento. Si el valor +de la expresión es vacío (El valor de Guile de @code{*unspecified*}), +no se pasa nada en absoluto al analizador sintáctico. + +Éste es, de hecho, el mismo mecanismo exactamente que LilyPond emplea +cuando llamamos a cualquier variable o función musical por su nombre, +como @code{\nombre}, con la única diferencia de que el nombre viene +determinado por el analizador léxico de LilyPond sin consultar al +lector de Scheme, y así solamente se aceptan los nombres de variable +consistentes con el modo actual de LilyPond. + +La acción inmediata de @code{$} puede llevar a alguna que otra +sorpresa, véase @ref{Variables de entrada y Scheme}. La utilización +de @code{#} donde el analizador sintáctico lo contempla es normalmente +preferible. Dentro de las expresiones musicales, aquellas que se +crean utilizando @code{#} @emph{se interprentan} como música. Sin +embargo, @emph{no se copian} antes de ser utilizadas. Si forman parte +de alguna estructura que aún podría tener algún uso, quizá tenga que +utilizar explícitamente @code{ly:music-deep-copy}. + +@funindex $@@ +@funindex #@@ +También existen los operadores de @q{división de listas} @code{$@@} y +@code{#@@} que insertan todos los elementos de una lista dentro del +contexto circundante. + +Ahora echemos un vistazo a algo de código de Scheme real. Los +procedimientos de Scheme se pueden definir dentro de los archivos de +entrada de LilyPond: @example -#(define (average a b c) (/ (+ a b c) 3)) +#(define (media a b c) (/ (+ a b c) 3)) @end example Observe que los comentarios de LilyPond (@code{%} y @code{%@{ %@}}) no se pueden utilizar dentro del código de Scheme, ni siquiera dentro de -un archivo de entrada de LilyPond input file, porque es el intérprete -Guile, y no el analizador sintáctico de LilyPond, el que está -interpretando la expresión de Scheme. Los comentarios en el Scheme de -Guile se introducen como sigue: +un archivo de entrada de LilyPond, porque es el intérprete Guile, y no +el analizador léxico de LilyPond, el que está leyendo la expresión de +Scheme. Los comentarios en el Scheme de Guile se introducen como +sigue: @example ; esto es un comentario de una línea @@ -675,8 +789,8 @@ Guile se introducen como sigue: @end example 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{#} al principio de todas las expresiones de Scheme. +introducen en un archivo de música, por lo que añadiremos +almohadillas@tie{}@code{#} al principio de todas las expresiones de Scheme. Todas las expresiones de Scheme del nivel jerárquico superior dentro de un archivo de entrada de LilyPond se pueden combinar en una sola @@ -718,6 +832,18 @@ veintiCuatro = (* 2 doce) lo que daría lugar a que el número 24 se almacenase dentro de la variable @code{veintiCuatro} de LilyPond (y de Scheme). +La forma usual de referirse a las variables de LilyPond, +@ref{Sintaxis del Scheme de LilyPond}, + +es llamarlas usando una barra invertida, es decir +@code{\veintiCuatro}. Dado que esto crea una copia para la mayor +parte de los tipos internos de LilyPond, concretamente las expresiones +musicales, las funciones musicales no sueln crear copias del material +que ellas mismas modifican. Por este motivo, las expresiones +musicales dadas con @code{#} no deberían, por lo general, contener +material que no se haya creado partiendo de cero o copiado +explícitamente en lugar de estar referenciado directamente. + @node Variables de entrada y Scheme @subsection Variables de entrada y Scheme @translationof Input variables and Scheme @@ -758,7 +884,7 @@ traLaLa = @{ c'4 d'4 @} se convierte internamente en una definición de Scheme: @example -(define traLaLa @var{Valor Scheme de `@code{... }'}) +(define traLaLa @var{Valor Scheme de `@code{@dots{}}'}) @end example Esto significa que las variables de LilyPond y las variables de Scheme @@ -770,46 +896,87 @@ usando Scheme. El resultado se importa dentro de un bloque @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 } +\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 la sentencia muda del ejemplo -anterior, la definición de @code{newLa} se ejecuta antes de que se -defina @code{traLaLa}, produciendo un error de sintaxis. +En realidad, éste es un ejemplo bastante interesante. La asignación +solo tiene lugar después de que el analizador sintáctico se ha +asegurado de que no sigue nada parecido a @code{\addlyrics}, de manera +que necesita comprobar lo que viene a continuación. Lee el símbolo +@code{#} y la expresión de Scheme siguiente @emph{sin} evaluarla, de +forma que puede proceder a la asignación, y @emph{posteriormente} +ejecutar el código de Scheme sin problema. + +@node Importación de Scheme dentro de LilyPond +@subsection Importación de Scheme dentro de LilyPond +@translationof Importing Scheme in LilyPond +@funindex $ +@funindex # El ejemplo anterior muestra cómo @q{exportar} expresiones musicales desde la entrada al intérprete de Scheme. Lo contrario también es -posible. Envolviendo un valor de Scheme en la función -@code{ly:export}, se interpreta un valor de Scheme como si hubiera -sido introducido en la sintaxis de LilyPond. En lugar de definir -@code{\twice}, el ejemplo anterior podría también haberse escrito como +posible. Colocándolo después de @code{$}, un valor de Scheme se +interpreta como si hubiera sido introducido en la sintaxis de +LilyPond. En lugar de definir @code{\twice}, el ejemplo anterior +podría también haberse escrito como @example -... -@{ #(ly:export (make-sequential-music (list newLa))) @} +@dots{} +$(make-sequential-music 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 dentro de un macro (para -llamarse más tarde), utilice @ref{Funciones vacías}, o bien +Podemos utilizar @code{$} con una expresión de Scheme en cualquier +lugar en el que usaríamos @code{\@var{nombre}} después de haber +asignado la expresión de Scheme a una variable @var{nombre}. Esta +sustitución se produce dentro del @q{analizador léxico}, de manera que +LilyPond no llega a darse cuenta de la diferencia. + +Sin embargo, existe un inconveniente, el de la medida del tiempo. Si +hubiésemos estado usando @code{$} en vez de @code{#} para definir +@code{newLa} en el ejemplo anterior, la siguiente definición de Scheme +habría fracasado porque @code{traLaLa} no habría sido definida aún. +Para ver una explicación de este problema de momento temporal, véase +@ref{Sintaxis del Scheme de LilyPond}. + +@funindex $@@ +@funindex #@@ +Un conveniente aspecto posterior pueden ser los operadores de +@q{división de listas} @code{$@@} y @code{#@@} para la inserción de +los elementos de una lista dentro del contexto circundante. +Utilizándolos, la última parte del ejemplo se podría haber escrito +como + +@example +@dots{} +@{ #@@newLa @} +@end example + +Aquí, cada elemento de la lista que está almacenado en @code{newLa} se +toma en secuencia y se inserta en la lista, como si hubiésemos escrito + +@example +@{ #(first newLa) #(second newLa) @} +@end example + +Ahora bien, en todas esas formas, el código de Scheme se evalúa en el +momento en que el código de entrada aún se está procesando, ya sea en +el analizador léxico o en el analizador sintáctico. Si necesitamos +que se ejecute en un momento posterior, debemos consultar +@ref{Funciones de Scheme vacías}, o almacenarlo dentro de un +procedimiento: @example #(define (nopc) (ly:set-option 'point-and-click #f)) -... +@dots{} #(nopc) @{ c'4 @} @end example @@ -817,7 +984,7 @@ llamarse más tarde), utilice @ref{Funciones vacías}, o bien @knownissues No es posible mezclar variables de Scheme y de LilyPond con la opción -@code{--safe}. +@option{--safe}. @node Propiedades de los objetos @@ -834,7 +1001,7 @@ asignación de un valor a la lista-A con una clave y un valor. La sintaxis de LilyPond para hacer esto es la siguiente: @example -\override Stem #'thickness = #2.6 +\override Stem.thickness = #2.6 @end example Esta instrucción ajusta el aspecto de las plicas. Se añade una @@ -861,14 +1028,25 @@ tiene una propiedad @code{thickness} (grosor), mientras que @subsection Variables de LilyPond compuestas @translationof LilyPond compound variables -@subheading Desplazamientos +@menu +* Desplazamientos:: +* Fracciones:: +* Dimensiones:: +* Listas-A de propiedades:: +* Cadenas de listas-A:: +@end menu + + +@node Desplazamientos +@unnumberedsubsubsec Desplazamientos +@translationof Offsets Los desplazamientos bidimensionales (coordenadas X e Y) se almacenan -como @code{parejas}. El @code{car} del desplazamiento es la +como @emph{parejas}. El @code{car} del desplazamiento es la coordenada X, y el @code{cdr} es la coordenada Y. @example -\override TextScript #'extra-offset = #'(1 . 2) +\override TextScript.extra-offset = #'(1 . 2) @end example Esto asigna la pareja @code{(1 . 2)} a la propiedad @@ -879,7 +1057,23 @@ espacio de pentagrama a la derecha, y dos espacios hacia arriba. Los procedimientos para trabajar con desplazamientos están en @file{scm/lily-library.scm}. -@subheading Dimensiones +@node Fracciones +@unnumberedsubsubsec Fracciones +@subheading Fractions + +Las fracciones tal y como se utilizan por parte de LilyPond +se almacenan, de nuevo, como @emph{parejas}, esta +vez de enteros sin signo. Mientras que Scheme es capaz de representar números racionaes +como un tipo nativo, musicalmente @samp{2/4} y @samp{1/2} no son lo mismo, +y necesitamos poder distinguir entre ellos. De igual forma, no existe el concepto +de @q{fracciones} negativas en LilyPond. Así pues, @code{2/4} en LilyPond +significa @code{(2 . 4)} en Scheme, y @code{#2/4} en LilyPond significa +@code{1/2} en Scheme. + + +@node Dimensiones +@unnumberedsubsubsec Dimensiones +@translationof Extents Las parejas se usan también para almacenar intervalos, que representan un rango de números desde el mínimo (el @code{car}) hasta el máximo @@ -894,7 +1088,10 @@ Los procedimientos para trabajar con intervalos están en @file{scm/lily-library.scm}. Se deben usar estos procedimientos siempre que sea posible, para asegurar la consistencia del código. -@subheading Listas-A de propiedades + +@node Listas-A de propiedades +@unnumberedsubsubsec Listas-A de propiedades +@translationof Property alists Una lista-A de propiedades es una estructura de datos de LilyPond que es una lista-A cuyas claves son propiedades y cuyos valores son @@ -903,7 +1100,10 @@ expresiones de Scheme que dan el valor deseado de la propiedad. Las propiedades de LilyPond son símbolos de Scheme, como por ejemplo @code{'thickness}. -@subheading Cadenas de listas-A + +@node Cadenas de listas-A +@unnumberedsubsubsec Cadenas de listas-A +@translationof Alist chains Una cadena de listas-A es una lista que contiene listas-A de propiedades. @@ -1019,18 +1219,16 @@ imprime lo siguiente: 'SequentialMusic 'elements (list (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)) - (make-music 'AbsoluteDynamicEvent 'text - "f"))))) + "f")) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 0 0)))) @end example De forma predeterminada, LilyPond imprime estos mensajes sobre la @@ -1042,27 +1240,45 @@ salida a un archivo. lilypond archivo.ly >salida.txt @end example -Con la aplicación de un poco de formateo, la información anterior es -fácil de leer, +Con un poco de magia combinada de LilyPond y Scheme, podemos realmente +hacer que LilyPond dirija solamente esta salida a su propio archivo: + +@example +@{ + #(with-output-to-file "display.txt" + (lambda () #@{ \displayMusic @{ c'4\f @} #@})) +@} +@end example + + +Un poco de reformateo hace a la información anterior más 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"))))) + 'elements (list + (make-music 'NoteEvent + 'articulations (list + (make-music 'AbsoluteDynamicEvent + 'text + "f")) + 'duration (ly:make-duration 2 0 1/1) + 'pitch (ly:make-pitch 0 0 0)))) @end example -Una secuencia musical @code{@{ ... @}} tiene el nombre +Una secuencia musical @code{@{ @dots{} @}} tiene el nombre @code{SequentialMusic}, y sus expresiones internas se almacenan coma una lista dentro de 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 información adicional (en este caso, un evento -@code{AbsoluteDynamicEvent} con una propiedad @code{"f"} de texto. +representa como un objeto @code{NoteEvent} (que almacena las +propiedades de duración y altura) con información adjunta (en este +caso, un evento @code{AbsoluteDynamicEvent} con una propiedad +@code{"f"} de texto) almacenada en su propiedad @code{articulations}. +@funindex{\void} +@code{\displayMusic} devuelve la música que imprime en la consola, y +por ello se interpretará al tiempo que se imprime en la consola. Para +evitar la interpretación, escriba @code{\void} antes de +@code{\displayMusic}. @node Propiedades musicales @subsection Propiedades musicales @@ -1072,24 +1288,41 @@ cualquier información adicional (en este caso, un evento @c @emph{context} properties, and @emph{layout} properties. These @c are potentially confusing. -El objeto @code{NoteEvent} es el primer objeto de la propiedad -@code{'elements} de @code{someNote}. +Veamos un ejemplo: @example someNote = c' \displayMusic \someNote ===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 0 0)) +@end example + +The @code{NoteEvent} object is the representation of @code{someNote}. +Straightforward. How about putting c' in a chord? + +@example +someNote = +\displayMusic \someNote +===> (make-music 'EventChord 'elements (list (make-music 'NoteEvent 'duration - (ly:make-duration 2 0 1 1) + (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 0 0)))) @end example +Ahora el objeto @code{NoteEvent} es el primer objeto +de la propiedad @code{'elements} de @code{someNote}. + La función @code{display-scheme-music} es la función que se usa por parte de @code{\displayMusic} para imprimir la representación de Scheme de una expresión musical. @@ -1100,7 +1333,7 @@ Scheme de una expresión musical. (make-music 'NoteEvent 'duration - (ly:make-duration 2 0 1 1) + (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 0 0)) @end example @@ -1136,7 +1369,7 @@ d' @translationof Doubling a note with slurs (example) Supongamos que queremos crear una función que convierte una entrada -como @code{a} en @code{a( a)}. Comenzamos examinando la +como @code{a} en @code{@{ a( a) @}}. Comenzamos examinando la representación interna de la música con la que queremos terminar. @example @@ -1146,71 +1379,68 @@ representación interna de la música con la que queremos terminar. 'SequentialMusic 'elements (list (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (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))) + -1)) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 5 0)) (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (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))))) + 1)) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 5 0)))) @end example -Las malas noticias son que las expresiones @code{SlurEvent} se deben -añadir @q{dentro} de la nota (o para ser más exactos, dentro de la -expresión @code{EventChord}). +La mala noticia es que las expresiones @code{SlurEvent} se deben +añadir @q{dentro} de la nota (dentro de la +propiedad @code{articulations}). Ahora examinamos la entrada, @example +\displayMusic 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)))))) + '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{SlurEvent} a la propiedad @code{'elements} de cada una de +@code{SlurEvent} a la propiedad @code{'articulations} de cada una de ellas, y por último hacer una secuencia @code{SequentialMusic} con los -dos @code{EventChords}. +dos elementos @code{NoteEvent}. Para añadir a una propiedad, es útil saber +que una propiedad no establecida se lee como @code{'()}, la lista +vacía, así que no se requiere ninguna comprobación especial antes de +que pongamos otro elemento delante de la propiedad +@code{articulations}. + @example -doubleSlur = #(define-music-function (parser location note) (ly:music?) +doubleSlur = #(define-music-function (note) (ly:music?) "Return: @{ note ( note ) @}. - `note' is supposed to be an EventChord." + `note' is supposed to be a single note." (let ((note2 (ly:music-deep-copy note))) - (set! (ly:music-property note 'elements) + (set! (ly:music-property note 'articulations) (cons (make-music 'SlurEvent 'span-direction -1) - (ly:music-property note 'elements))) - (set! (ly:music-property note2 'elements) + (ly:music-property note 'articulations))) + (set! (ly:music-property note2 'articulations) (cons (make-music 'SlurEvent 'span-direction 1) - (ly:music-property note2 'elements))) + (ly:music-property note2 'articulations))) (make-music 'SequentialMusic 'elements (list note note2)))) @end example @@ -1220,11 +1450,15 @@ doubleSlur = #(define-music-function (parser location note) (ly:music?) @translationof Adding articulation to notes (example) La manera fácil de añadir articulación a las notas es mezclar dos -expresiones musicales en un solo contexto, como se explica en -@ruser{Crear contextos}. Sin embargo, supongamos que queremos -escribir una función musical que lo haga. - -Una @code{$variable} dentro de la notación @code{#@{...#@}} es como +expresiones musicales en un solo contexto. +Sin embargo, supongamos que queremos +escribir una función musical que lo haga. Esto tiene la ventaja +adicional de que podemos usar esa función musical para añadir una +articulación (como una instrucción de digitación) a una nota única +dentro de un acorde, lo cual no es posible si nos limitamos a mezclar +fragmentos de música independientes. + +Una @code{$variable} dentro de la notación @code{#@{@dots{}#@}} es como una @code{\variable} normal en la notación clásica de LilyPond. Sabemos que @@ -1234,10 +1468,10 @@ Sabemos que @noindent no funciona en LilyPond. Podríamos evitar este problema adjuntando la -articulación a una nota falsa, +articulación a un acorde vacío, @example -@{ << \music s1*0-.-> @} +@{ << \music <> -. -> >> @} @end example @noindent @@ -1249,61 +1483,54 @@ Scheme. Empezamos examinando nuestra entrada y la 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)))) + 'NoteEvent + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch -1 0 0)))) ===== % desired output \displayMusic c4-> ===> (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (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"))) + "accent")) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch -1 0 0)) @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 de marcato, se debe añadir -una expresión @code{ArticulationEvent} a la propiedad elements de la -expresión @code{EventChord}. +@code{NoteEvent}. Para añadir una articulación de acento, se debe +añadir una expresión @code{ArticulationEvent} a la propiedad +@code{articulations} de la expresión @code{NoteEvent}. Para construir esta función, empezamos con @example -(define (add-marcato event-chord) - "Add a marcato ArticulationEvent to the elements of `event-chord', - which is supposed to be an EventChord expression." - (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)) +(define (add-accent note-event) + "Add an accent ArticulationEvent to the articulations of `note-event', + which is supposed to be a NoteEvent expression." + (set! (ly:music-property note-event 'articulations) + (cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property note-event 'articulations))) + note-event) @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 +nombre de la función es @code{add-accent}, y tiene una variable +llamada @code{note-event}. 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 -"Add a marcato..." +"Add an accent@dots{}" @end example @noindent @@ -1311,85 +1538,102 @@ es una descripción de lo que hace la función. No es estrictamente necesaria, pero de igual forma que los nombres claros de variable, es una buena práctica. -@example -(let ((result-event-chord (ly:music-deep-copy event-chord))) -@end example - -Se usa @code{let} para declarar las 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 nuestro propósito es -añadir un marcato a una expresión @code{EventChord}. Es mejor no -modificar el @code{EventChord} que se ha dado 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 de la lista de @code{'elements}. +Se preguntará porqué modificamos el evento de nota directamente en +lugar de trabajar sobre una copia (se puede usar +@code{ly:music-deep-copy} para ello). La razón es un contrato +silencioso: se permite que las funciones musicales modifiquen sus +argumentos; o bien se generan partiendo de cero (como la entrada del +usuario) o están ya copiadas (referenciar una variable de música con +@samp{\name} o la música procedente de expresiones de Scheme +inmediatas @samp{$(@dots{})} proporcionan una copia). Dado que sería +ineficiente crear copias innecesarias, el valor devuelto de una +función musical @emph{no} se copia. Así pues, para cumplir dicho +contrato, no debemos usar ningún argumento más de una vez, y +devolverlo cuenta como una vez. + +En un ejemplo anterior, hemos construido música mediante la repetición +de un argumento musical dado. En tal caso, al menos una repetidión +tuvo que ser una copia de sí misma. Si no lo fuese, podrían ocurrir +cosas muy extrañas. Por ejemplo, si usamos @code{\relative} o +@code{\transpose} sobre la música resultante que contiene los mismos +elementos varias veces, estarían sujetos varias veces a la +relativización o al transporte. Si los asignamos a una variable de +música, se rompe el curso porque hacer referencia a @samp{\name} +creará de nuevo una copia que no retiene la identidad de los elementos +repetidos. + +Ahora bien, aun cuando la función anterior no es una función musical, +se usará normalmente dentro de funciones musicales. Así pues, tiene +sentido obedecer el mismo convenio que usamos para las funciones +musicales: la entrada puede modificarse para producir la salida, y el +código que llama es responsable de crear las copias si aún necesita el +propio argumento sin modificar. Si observamos las propias funciones +de LilyPond como @code{music-map}, veremos que se atienen a los mismos +principios. + +¿En qué punto nos encontramos? Ahora tenemos un @code{note-event} que +podemos modificar, no a causa de la utilización de +@code{ly:music-deep-copy} sino por una explicación muy desarrollada. +Añadimos el acento a su propiedad de lista @code{'articulations}. @example -(set! lugar valor-nuevo) +(set! place new-value) @end example -Aquí, lo que queremos establecer (el @q{lugar}) es la propiedad -@code{'elements} de la expresión @code{result-event-chord}. +Aquí, lo que queremos establecer (el @q{place}) es la propiedad +@code{'articulations} de la expresión @code{note-event}. @example -(ly:music-property result-event-chord 'elements) +(ly:music-property note-event 'articulations) @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 vimos en la salida de @code{\displayMusic} -anterior). El nuevo valor es la antigua propiedad @code{'elements}, -con un elemento adicional: la expresión @code{ArticulationEvent}, que -copiamos a partir de la salida de @code{\displayMusic}, +@code{ly:music-property} es la función ustilizada para acceder a las +propiedades musicales (las @code{'articulations}, @code{'duration}, +@code{'pitch}, etc, que vemos arriba en la salida de +@code{\displayMusic}). El nuevo valor es la antigua propiedad +@code{'articulations}, 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)) + 'articulation-type "accent") + (ly:music-property result-event-chord 'articulations)) @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 expresión @code{ArticulationEvent} nueva. El orden dentro de -la propiedad @code{'elements} no es importante aquí. +Se usa @code{cons} para añadir un elemento a la parte delantera de una +lista sin modificar la lista original. Esto es lo que queremos: la +misma lista de antes, más la nueva expresión @code{ArticulationEvent}. +El orden dentro de la propiedad @code{'articulations} no tiene +importancia aquí. -Finalmente, una vez hemos añadido la articulación marcato a su -propiedad @code{elements}, podemos devolver @code{result-event-chord}, -de ahí la última línea de la función. +Finalmente, una vez hemos añadido la articulación de acento a su +propiedad @code{articulations}, podemos devolver @code{note-event}, de +aquí la última línea de la función. -Ahora transformamos la función @code{add-marcato} en una función -musical: +Ahora transformamos la función @code{add-accent} en una función +musical (es cuestión de un poco de aderezo sintáctico y una +declaración del tipo de su único argumento @q{real}). @example -addMarcato = #(define-music-function (parser location event-chord) +addAccent = #(define-music-function (note-event) (ly:music?) - "Add a marcato ArticulationEvent to the elements of `event-chord', - which is supposed to be an EventChord expression." - (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)) + "Add an accent ArticulationEvent to the articulations of `note-event', + which is supposed to be a NoteEvent expression." + (set! (ly:music-property note-event 'articulations) + (cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property note-event 'articulations))) + note-event) @end example Podemos verificar que esta función musical funciona correctamente: @example -\displayMusic \addMarcato c4 +\displayMusic \addAccent c4 @end example - - - - @ignore @menu * Trucos con Scheme:: @@ -1397,11 +1641,12 @@ Podemos verificar que esta función musical funciona correctamente: @c @nod e Trucos con Scheme @c @sectio n Trucos con Scheme -@translationof Tweaking with Scheme +@c @transl ationof 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 +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}. @@ -1415,13 +1660,13 @@ TODO Find a simple example @ignore @lilypond[quote,verbatim,ragged-right] -padText = #(define-music-function (parser location padding) (number?) +padText = #(define-music-function (padding) (number?) #{ - \once \override TextScript #'padding = #$padding + \once \override TextScript.padding = #padding #}) -\relative c''' { - c4^"piu mosso" b a b +\relative { + c'''4^"piu mosso" b a b \padText #1.8 c4^"piu mosso" d e f \padText #2.6 @@ -1438,17 +1683,17 @@ Lo podemos usar para crear instrucciones nuevas: @lilypond[quote,verbatim,ragged-right] -tempoPadded = #(define-music-function (parser location padding tempotext) - (number? string?) +tempoPadded = #(define-music-function (padding tempotext) + (number? markup?) #{ - \once \override Score.MetronomeMark #'padding = $padding - \tempo \markup { \bold $tempotext } + \once \override Score.MetronomeMark.padding = #padding + \tempo \markup { \bold #tempotext } #}) -\relative c'' { +\relative { \tempo \markup { "Low tempo" } - c4 d e f g1 - \tempoPadded #4.0 #"High tempo" + c''4 d e f g1 + \tempoPadded #4.0 "High tempo" g4 f e d c1 } @end lilypond @@ -1457,9 +1702,9 @@ tempoPadded = #(define-music-function (parser location padding tempotext) Incluso se le pueden pasar expresiones musicales: @lilypond[quote,verbatim,ragged-right] -pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) +pattern = #(define-music-function (x y) (ly:music? ly:music?) #{ - $x e8 a b $y b a e + #x e8 a b #y b a e #}) \relative c''{