[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2 Scheme dentro de LilyPond

@translationof Scheme in LilyPond


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.1 Sintaxis del Scheme de LilyPond

@translationof LilyPond Scheme syntax

El intérprete Guile forma parte de LilyPond, lo que significa que se puede incluir Scheme 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 # 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 ( (contributor)LilyPond grammar sección ‘LilyPond grammar’ en Guía del colaborador). 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 # 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 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 # 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 $ 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 xxx_IDENTIFIER dentro de la sintaxis) para él. Crea una 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 *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 \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 $ puede llevar a alguna que otra sorpresa, véase Importación de Scheme dentro de LilyPond. La utilización de # donde el analizador sintáctico lo contempla es normalmente preferible. Dentro de las expresiones musicales, aquellas que se crean utilizando # se interprentan como música. Sin embargo, 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 ly:music-deep-copy.

También existen los operadores de ‘división de listas’ $@ y #@ 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:

 
#(define (media a b c) (/ (+ a b c) 3))

Observe que los comentarios de LilyPond (% y %{ %}) no se pueden utilizar dentro del código de Scheme, ni siquiera dentro de 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:

 
; 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
!#

Durante el resto de esta sección, supondremos que los datos se introducen en un archivo de música, por lo que añadiremos una almohadilla # al principio de cada una de 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 expresión de Scheme mediante la utilización del operador begin:

 
#(begin
  (define fulanito 0)
  (define menganito 1))

[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.2 Variables de LilyPond

@translationof LilyPond variables

Las variables de LilyPond se almacenan internamente en la forma de variables de Scheme. Así,

 
doce = 12

equivale a

 
#(define doce 12)

Esto significa que las variables de LilyPond están disponibles para su uso dentro de expresiones de Scheme. Por ejemplo, podríamos usar

 
veintiCuatro = (* 2 doce)

lo que daría lugar a que el número 24 se almacenase dentro de la variable veintiCuatro de LilyPond (y de Scheme).

El lenguaje Scheme permite la modificación de expresiones complejas in situ y LilyPond hace uso de esta ‘modificación in situ’ al usar funciones musicales. Pero cuando las expresiones musicales se almacenan dentro de variables en lugar de ser introducidas directamente, lo que habitualmente se espera cuando se pasan a funciones musicales sería que el valor original quedase intacto. Así pues, cuando se referencia una variable musical con la barra invertida (como \veintiCuatro), LilyPond crea una copia del valor musical de tal variable para utilizarla dentro de la expresión musical circundante, en lugar de usar el valor de la variable directamente.

Por ello, las expresiones musicales de Scheme escritas con la sintasis de almohadilla # deberían utilizarse para cualquier material creado ‘partiendo de cero’ (o que se ha copiado explícitamente) en lugar de utilizarse para referenciar música directamente.

Véase también

Manual de extensión: Sintaxis del Scheme de LilyPond.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.3 Variables de entrada y Scheme

@translationof Input variables and Scheme

El formato de entrada contempla la noción de variables: en el siguiente ejemplo, se asigna una expresión musical a una variable con el nombre traLaLa.

 
traLaLa = { c'4 d'4 }

También hay una forma de ámbito: en el ejemplo siguiente, el bloque \layout también contiene una variable traLaLa, que es independiente de la \traLaLa externa.

 
traLaLa = { c'4 d'4 }
\layout { traLaLa = 1.0 }

En efecto, cada archivo de entrada constituye un ámbito, y cada bloque \header, \midi y \layout son ámbitos anidados dentro del ámbito de nivel superior.

Tanto las variables como los ámbitos están implementados en el sistema de módulos de GUILE. A cada ámbito se adjunta un módulo anónimo de Scheme. Una asignación de la forma:

 
traLaLa = { c'4 d'4 }

se convierte internamente en una definición de Scheme:

 
(define traLaLa Valor Scheme de `…')

Esto significa que las variables de LilyPond y las variables de Scheme se pueden mezclar con libertad. En el ejemplo siguiente, se almacena un fragmento de música en la variable traLaLa, y se duplica usando Scheme. El resultado se importa dentro de un bloque \score por medio de una segunda variable twice:

 
traLaLa = { c'4 d'4 }

#(define newLa (map ly:music-deep-copy
  (list traLaLa traLaLa)))
#(define twice
  (make-sequential-music newLa))

\twice

[image of music]

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 \addlyrics, de manera que necesita comprobar lo que viene a continuación. Lee el símbolo # y la expresión de Scheme siguiente sin evaluarla, de forma que puede proceder a la asignación, y posteriormente ejecutar el código de Scheme sin problema.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.4 Importación de Scheme dentro de LilyPond

@translationof Importing Scheme in LilyPond

El ejemplo anterior muestra cómo ‘exportar’ expresiones musicales desde la entrada al intérprete de Scheme. Lo contrario también es posible. Colocándolo después de $, un valor de Scheme se interpreta como si hubiera sido introducido en la sintaxis de LilyPond. En lugar de definir \twice, el ejemplo anterior podría también haberse escrito como

 
…
$(make-sequential-music newLa)

Podemos utilizar $ con una expresión de Scheme en cualquier lugar en el que usaríamos \nombre después de haber asignado la expresión de Scheme a una variable nombre. Esta sustitución se produce dentro del ‘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 $ en vez de # para definir newLa en el ejemplo anterior, la siguiente definición de Scheme habría fracasado porque traLaLa no habría sido definida aún. Para ver una explicación de este problema de momento temporal, véase Sintaxis del Scheme de LilyPond.

Un conveniente aspecto posterior pueden ser los operadores de ‘división de listas’ $@ y #@ 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

 
…
{ #@newLa }

Aquí, cada elemento de la lista que está almacenado en newLa se toma en secuencia y se inserta en la lista, como si hubiésemos escrito

 
{ #(first newLa) #(second newLa) }

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 Funciones de Scheme vacías, o almacenarlo dentro de un procedimiento:

 
#(define (nopc)
  (ly:set-option 'point-and-click #f))

…
#(nopc)
{ c'4 }

Advertencias y problemas conocidos

No es posible mezclar variables de Scheme y de LilyPond con la opción ‘--safe’.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.5 Propiedades de los objetos

@translationof Object properties

Las propiedades de los objetos se almacenan en LilyPond en forma de cadenas de listas-A, que son listas de listas-A. Las propiedades se establecen añadiendo valores al principio de la lista de propiedades. Las propiedades se leen extrayendo valores de las listas-A.

El establecimiento de un valor nuevo para una propiedad requiere la 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:

 
\override Stem.thickness = #2.6

Esta instrucción ajusta el aspecto de las plicas. Se añade una entrada de lista-A '(thickness . 2.6) a la lista de propiedades de un objeto Stem. thickness se mide a partir del grosor de las líneas del pentagrama, y así estas plicas serán 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 veintiCuatro en el ejemplo anterior) y las variables de los objetos internos, llamaremos a las últimas ‘propiedades’ y a las primeras ‘variables.’ Así, el objeto plica tiene una propiedad thickness (grosor), mientras que veintiCuatro es una variable.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.6 Variables de LilyPond compuestas

@translationof LilyPond compound variables


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

Desplazamientos

@translationof Offsets

Los desplazamientos bidimensionales (coordenadas X e Y) se almacenan como parejas. El car del desplazamiento es la coordenada X, y el cdr es la coordenada Y.

 
\override TextScript.extra-offset = #'(1 . 2)

Esto asigna la pareja (1 . 2) a la propiedad 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 procedimientos para trabajar con desplazamientos están en ‘scm/lily-library.scm’.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

Fracciones

Fractions

Las fracciones tal y como se utilizan por parte de LilyPond se almacenan, de nuevo, como parejas, esta vez de enteros sin signo. Mientras que Scheme es capaz de representar números racionaes como un tipo nativo, musicalmente ‘2/4’ y ‘1/2’ no son lo mismo, y necesitamos poder distinguir entre ellos. De igual forma, no existe el concepto de ‘fracciones’ negativas en LilyPond. Así pues, 2/4 en LilyPond significa (2 . 4) en Scheme, y #2/4 en LilyPond significa 1/2 en Scheme.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

Dimensiones

@translationof Extents

Las parejas se usan también para almacenar intervalos, que representan un rango de números desde el mínimo (el car) hasta el máximo (el cdr). Los intervalos se usan para almacenar las dimensiones en X y en Y de los objetos imprimibles. Para dimensiones en X, el car es la coordenada X de la parte izquierda, y el cdr es la coordenada X de la parte derecha. Para las dimensiones en Y, el car es la coordenada inferior, y el cdr es la coordenada superior.

Los procedimientos para trabajar con intervalos están en ‘scm/lily-library.scm’. Se deben usar estos procedimientos siempre que sea posible, para asegurar la consistencia del código.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

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 expresiones de Scheme que dan el valor deseado de la propiedad.

Las propiedades de LilyPond son símbolos de Scheme, como por ejemplo 'thickness.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

Cadenas de listas-A

@translationof Alist chains

Una cadena de listas-A es una lista que contiene listas-A de propiedades.

El conjunto de todas las propiedades que se aplican a un grob se almacena por lo general como una cadena de listas-A. Para poder encontrar el valor de una propiedad determinada que debería tener un grob, se busca por todas las listas-A de la cadena, una a una, tratando de encontrar una entrada que contenga la clave de la propiedad. Se devuelve la primera entrada de lista-A que se encuentre, y el valor es el valor de la propiedad.

El procedimiento de Scheme chain-assoc-get se usa normalmente para obtener los valores de propiedades.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]         [Arriba] [Índice general] [Índice] [ ? ]

A.2.7 Representación interna de la música

@translationof Internal music representation

Internamente, la música se representa como una lista de Scheme. La lista contiene varios elementos que afectan a la salida impresa. El análisis sintáctico es el proceso de convertir la música de la representación de entrada de LilyPond a la representación interna de Scheme.

Cuando se analiza una expresión musical, se convierte en un conjunto de objetos musicales de Scheme. La propiedad definitoria de un objeto musical es que ocupa un tiempo. El tiempo que ocupa se llama duración. Las duraciones se expresan como un número racional que mide la longitud del objeto musical en redondas.

Un objeto musical tiene tres clases de tipos:

La información real de una expresión musical se almacena en propiedades. Por ejemplo, un (internals)NoteEvent sección ‘NoteEvent’ en Referencia de Funcionamiento Interno tiene propiedades pitch y duration que almacenan la altura y la duración de esa nota. Hay una lista de todas la propiedades disponibles en el manual de Referencia de funcionamiento interno, bajo el epígrafe (internals)Music properties sección ‘Music properties’ en Referencia de Funcionamiento Interno.

Una expresión musical compuesta es un objeto musical que contiene otros objetos musicales dentro de sus propiedades. Se puede almacenar una lista de objetos dentro de la propiedad elements de un objeto musical, o un único objeto musical ‘hijo’ dentro de la propiedad element. Por ejemplo, (internals)SequentialMusic sección ‘SequentialMusic’ en Referencia de Funcionamiento Interno tiene su hijo dentro de elements, y (internals)GraceMusic sección ‘GraceMusic’ en Referencia de Funcionamiento Interno tiene su argumento único dentro de element. El cuerpo de una repetición se almacena dentro de la propiedad element de (internals)RepeatedMusic sección ‘RepeatedMusic’ en Referencia de Funcionamiento Interno, y las alternativas dentro de elements.


[ < ] [ > ]   [ << ] [ Subir ] [ >> ]

Este documento ha sido generado por gub el el 13 julio 2020 utilizando texi2html 1.82.

Otros idiomas: English, deutsch, français.
Acerca de la selección automática del idioma.