6.4.3 Definición de una instrucción de marcado nueva

Las instrucciones de marcado nuevas se pueden definir con el macro de Scheme define-markup-command.

 
(define-markup-command (nombre-de-la-instruccion layout props arg1 arg2 ...)
            (arg1-type? arg2-type? ...)
  ..command body..)

Los argumentos son

argi

i-ésimo argumento de la instrucción

argi-type?

predicado de tipo para el argumento i-ésimo

layout

la definición de ‘presentación’

props

lista de listas asociativas, que contiene todas las propiedades activas.

Como ejemplo sencillo, mostramos cómo añadir una instrucción \smallcaps, que selecciona una tipografía de versalitas. Normalmente podríamos seleccionar la tipografía de versalitas,

\markup { \override #'(font-shape . caps) Texto-en-versalitas }

Esto selecciona la tipografía de versalitas mediante el establecimiento de la propiedad font-shape a #'caps para la interpretación de Texto-en-versalitas.

Para poner lo anterior disponible como la instrucción \smallcaps, tenemos que definir una función utilizando define-markup-command. La instrucción ha de tomar un argumento del tipo markup. Por tanto, el inicio de la definición ha de ser

(define-markup-command (smallcaps layout props argument) (markup?)

Lo que aparece a continuación es el contenido de la instrucción: debemos interpretar el argument como un marcado, es decir:

(interpret-markup layout … argument)

Esta interpretación tiene que añadir '(font-shape . caps) a las propiedades activas, por lo que sustituimos lo siguiente por los … en el ejemplo anterior:

(cons (list '(font-shape . caps) ) props)

La variable 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 \character que toma en cuenta la traslación necesaria y utiliza la instrucción \smallcaps recién definida:

#(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)))

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 padding) del pentagrama y de las notas. Para asegurar que este mecanismo no anula el efecto de nuestro #:translate, añadimos una cadena vacía (#:hspace 0) antes del texto trasladado. Ahora el #:hspace 0 se pone encima de las notas, y el 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:

{
  c''^\markup \character #"Cleopatra"
  e'^\markup \character #"Giulio Cesare"
}

[image of music]

Hemos usado la forma de fuente tipográfica 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:

#(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)))))

La instrucción smallcaps primero divide su argumento de cadena en unidades o palabras separadas por espacios ((string-split str #\Space)); para cada unidad o palabra, se construye un marcado con la primera letra agrandada y en mayúscula (#:large (string-upcase (substring s 0 1))), y un segundo marcado construido con las letras siguientes reducidas de tamaño y en mayúsculas (#: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 (#:translate (cons -0.6 0) ...). Después, los marcados construidos para cada palabra se ponen en una línea mediante (make-line-markup ...). Finalmente, el marcado resultante se pasa a la función interpret-markup, con los argumentos layout y props.

Nota: ahora existe una instrucción interna \smallCaps que se puede usar para poner texto en versalitas. Consulte Text markup commands, para ver más detalles.

Advertencias y problemas conocidos

Actualmente las combinaciones de argumentos que hay disponibles (después de los argumentos estándar layout y props) para una instrucción de marcado definida con define-markup-command se limitan a la siguiente lista:

(ningún argumento)
list
markup
markup markup
scm
scm markup
scm scm
scm scm markup
scm scm markup markup
scm markup markup
scm scm scm

En la tabla de arriba, scm representa los tipos de datos nativos de Scheme como ‘number’ (número) o ‘string’ (cadena).

Como ejemplo, no es posible usar una instrucción de marcado fulanito con cuatro argumentos definida como

#(define-markup-command (fulanito layout props
                         num1    str1    num2    str2)
                        (number? string? number? string?)
  ...)

Si la aplicamos como, digamos,

\markup \fulanito #1 #"mengano" #2 #"zutano"

lilypond protesta diciendo que no puede analizar fulanito debido a su firma de Scheme desconocida.


Otros idiomas: English.

Manual de referencia de la notación