Convertir elementos de marcado en cadenas (Extender LilyPond)

#### Convertir elementos de marcado en cadenas

Los elementos de marcado se convierten a veces en cadenas normales por ejemplo cuando se producen metadatos de PDF basados en el campo `title` del encabezamiento o para convertir la letra de las canciones a MIDI. Esta conversión conlleva inherentemente pérdidas, pero intenta hacerlo de la forma más fiel que sea posible. La función que se usa para ello es `markup->string`.

>     composerName = \markup \box "Arnold Schönberg"

>     \markup \composerName

>     \markup \typewriter #(markup->string composerName)

Cuando se trata de instrucciones de marcado personalizadas, el comportamiento por omisión es convertir en primer lugar todos los argumentos de marcados, o de listas de marcados, y concatenar los resultados con espacios.

>     #(define-markup-command (authors-and layout props authorA authorB)
>                             (markup? markup?)
>        (interpret-markup layout props
>         #{
>           \markup \fill-line { \box #authorA and \box #authorB }
>         #}))

>     defaultBehavior = \markup \authors-and "Bertolt Brecht" "Kurt Weill"

>     \markup \defaultBehavior

>     \markup \typewriter #(markup->string defaultBehavior)

`markup->string` también puede recibir los argumentos con nombre `#:layout layout` y `#:props props`, con el mismo significado que en la definición de una instrucción de marcado. Sin embargo, son opcionales porque no siempre pueden aportarse (como el argumento `layout` durante la conversión a MIDI).

Para contemplar las conversiones especiales dentro de instrucciones de marcado personalizadas, se puede dar el parámetro `#:as-string` a `define-markup-command`. Espera como argumento una expresión, que se evalúa por parte de `markup->string` para dar el resultado en forma de cadena.

>     #(define-markup-command (authors-and layout props authorA authorB)
>                             (markup? markup?)
>        #:as-string (format #f "~a and ~a"
>                            (markup->string authorA #:layout layout #:props props)
>                            (markup->string authorB #:layout layout #:props props))
>        (interpret-markup layout props
>         #{
>           \markup \fill-line { \box #authorA and \box #authorB }
>         #}))

>     customized = \markup \authors-and "Bertolt Brecht" "Kurt Weill"

>     \markup \customized

>     \markup \typewriter #(markup->string customized)

Dentro de la expresión, están disponibles las mismas relaciones de enlace que en el cuerpo de la instrucción de marcado principal, concretamente `layout` y `props`, el argumento de la instrucción, y opcionalmente las propiedades.

>     #(define-markup-command (authors-and layout props authorA authorB)
>                             (markup? markup?)
>        #:properties ((author-separator " and "))
>        #:as-string (format #f "~a~a~a"
>                            (markup->string authorA #:layout layout #:props props)
>                            (markup->string author-separator #:layout layout #:props props)
>                            (markup->string authorB #:layout layout #:props props))
>        (interpret-markup layout props
>         #{
>           \markup { \box #authorA #author-separator \box #authorB }
>         #}))

>     customized = \markup \override #'(author-separator . ", ")
>                          \authors-and "Bertolt Brecht" "Kurt Weill"

>     \markup \customized

>     \markup \typewriter #(markup->string customized)

Lo más frecuente es que una rutina procesadora solamente necesite llamar recursivamente a `markup->string` sobre ciertos argumentos, como se ha mostrado arriba. Sin embargo, también puede hacer uso directamente de `layout` y de `props`, de la misma manera que en el cuerpo principal. Hay que tener cuidado de que el argumento `layout` sea `#f` si no se le ha dado ningún `#:layout` a la función `markup->string`. El argumento `props` es, por omisión, una lista vacía.

#### Extender LilyPond v2.26.0 (stable-branch).

- Appendix A Tutorial de Scheme
  - A.1 Introducción a Scheme
    - A.1.1 Cajón de arena de Scheme
    - A.1.2 Variables de Scheme
    - A.1.3 Tipos de datos simples de Scheme
    - A.1.4 Tipos de datos compuestos de Scheme
      - Parejas
      - Listas
      - Listas asociativas (listas-A)
      - Tablas de hash
    - A.1.5 Cálculos en Scheme
    - A.1.6 Procedimientos de Scheme
      - Definir procedimientos
      - Predicados
      - Valores de retorno
    - A.1.7 Condicionales de Scheme
      - if
      - cond
  - A.2 Scheme dentro de LilyPond
    - A.2.1 Sintaxis del Scheme de LilyPond
    - A.2.2 Variables de LilyPond
    - A.2.3 Depuración del código de Scheme
    - A.2.4 Variables de entrada y Scheme
    - A.2.5 Importación de Scheme dentro de LilyPond
    - A.2.6 Propiedades de los objetos
    - A.2.7 Variables de LilyPond compuestas
      - Desplazamientos
      - Fracciones
      - Dimensiones
      - Listas-A de propiedades
      - Cadenas de listas-A
    - A.2.8 El modelo de caja de LilyPond
    - A.2.9 Representación interna de la música
  - A.3 Construir funciones complicadas
    - A.3.1 Una primera aproximación (ejemplo)
    - A.3.2 Presentación de las expresiones musicales
    - A.3.3 Propiedades musicales
    - A.3.4 Duplicar una nota con ligaduras (ejemplo)
    - A.3.5 Añadir articulaciones a las notas (ejemplo)
- B Interfaces para programadores
  - B.1 Bloques de código de LilyPond
  - B.2 Funciones de Scheme
    - B.2.1 Definición de funciones de Scheme
    - B.2.2 Uso de las funciones de Scheme
    - B.2.3 Funciones de Scheme vacías
  - B.3 Funciones musicales
    - B.3.1 Definiciones de funciones musicales
    - B.3.2 Uso de las funciones musicales
    - B.3.3 Funciones de sustitución sencillas
    - B.3.4 Funciones de sustitución intermedias
    - B.3.5 Matemáticas dentro de las funciones
    - B.3.6 Funciones sin argumentos
    - B.3.7 Funciones musicales vacías
  - B.4 Funciones de eventos
  - B.5 Funciones de marcado
    - B.5.1 Construcción de elementos de marcado en Scheme
    - B.5.2 Cómo funcionan internamente los elementos de marcado
    - B.5.3 Definición de una instrucción de marcado nueva
      - Sintaxis de la definición de instrucciones de marcado
      - Acerca de las propiedades
      - Un ejemplo completo
      - Adaptación de instrucciones incorporadas
      - Convertir elementos de marcado en cadenas
    - B.5.4 Definición de nuevas instrucciones de lista de marcado
  - B.6 Contextos para programadores
    - B.6.1 Evaluación de contextos
    - B.6.2 Ejecutar una función sobre todos los objetos de la presentación
  - B.7 Funciones de callback
  - B.8 Contenedores Unpure-pure
  - B.9 Trucos difíciles
- C Interfaces de Scheme de LilyPond
- Appendix D GNU Free Documentation License
- Appendix E Índice