| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme in LilyPond
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@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] | [ ? ] |
@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.
Manual de extensión: Sintaxis del Scheme de LilyPond.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@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
|
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] | [ ? ] |
@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 }
|
No es posible mezclar variables de Scheme y de LilyPond con la opción ‘--safe’.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@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] | [ ? ] |
@translationof LilyPond compound variables
| Desplazamientos | ||
| Fracciones | ||
| Dimensiones | ||
| Listas-A de propiedades | ||
| Cadenas de listas-A |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@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] | [ ? ] |
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] | [ ? ] |
@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] | [ ? ] |
@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] | [ ? ] |
@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] | [ ? ] |
@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:
\simultaneous lleva a una
(internals)SimultaneousMusic sección ‘SimultaneousMusic’ en Referencia de Funcionamiento Interno.
Hay una lista de todas las expresiones disponibles en el manual de
Referencia de funcionamiento interno, bajo el epígrafe
(internals)Music expressions sección ‘Music expressions’ en Referencia de Funcionamiento Interno.
event,
pero también es un note-event, un rhythmic-event, y
un melodic-event. Todas las clases de música están
listadas en el manual de Referencia de funcionamiento interno,
bajo el epígrafe
(internals)Music classes sección ‘Music classes’ en Referencia de Funcionamiento Interno.
Music de C++.
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.