A.3.5 Añadir articulaciones a las notas (ejemplo) (Extender LilyPond)

#### A.3.5 Añadir articulaciones a las notas (ejemplo)

La manera fácil de añadir articulación a las notas es juxtaponer dos expresiones musicales. Sin embargo, supongamos que queremos escribir una función musical que lo haga.

Una `$variable` dentro de la notación `#{…#}` es como una `\variable` normal en la notación clásica de LilyPond. Podríamos escribir

    { \music -. -> }

pero a los efectos de este ejemplo, aprenderemos ahora cómo hacerlo en Scheme. Empezamos examinando nuestra entrada y la salida deseada.

    %  input
    \displayMusic c4
    ===>
    (make-music
      'NoteEvent
      'duration
      (ly:make-duration 2 0 1/1)
      'pitch
      (ly:make-pitch -1 0 0))))
    =====
    %  desired output
    \displayMusic c4->
    ===>
    (make-music
      'NoteEvent
      'articulations
      (list (make-music
              'ArticulationEvent
              'articulation-type 'accent))
      'duration
      (ly:make-duration 2 0 1/1)
      'pitch
      (ly:make-pitch -1 0 0))

Vemos que una nota (`c4`) se representa como una expresión `NoteEvent`. Para añadir una articulación de acento, se debe añadir una expresión `ArticulationEvent` a la propiedad `articulations` de la expresión `NoteEvent`.

Para construir esta función, empezamos con

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

La primera línea es la forma de definir una función en Scheme: el nombre de la función es `add-accent`, y tiene una variable llamada `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!)

    "Add an accent…"

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.

Se preguntará por qué modificamos el evento de nota directamente en lugar de trabajar sobre una copia (se puede usar `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 ‘`\name`’ o la música procedente de expresiones de Scheme inmediatas ‘`$(…)`’ proporcionan una copia). Dado que sería ineficiente crear copias innecesarias, el valor devuelto de una función musical 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 `\relative` o `\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 ‘`\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 `music-map`, veremos que se atienen a los mismos principios.

¿En qué punto nos encontramos? Ahora tenemos un `note-event` que podemos modificar, no a causa de la utilización de `ly:music-deep-copy` sino por una explicación muy desarrollada. Añadimos el acento a su propiedad de lista `'articulations`.

    (set! place new-value)

Aquí, lo que queremos establecer (el ‘place’) es la propiedad `'articulations` de la expresión `note-event`.

    (ly:music-property note-event 'articulations)

`ly:music-property` es la función ustilizada para acceder a las propiedades musicales (las `'articulations`, `'duration`, `'pitch`, etc, que vemos arriba en la salida de `\displayMusic`). El nuevo valor es la antigua propiedad `'articulations`, con un elemento adicional: la expresión `ArticulationEvent`, que copiamos a partir de la salida de `\displayMusic`,

    (cons (make-music 'ArticulationEvent
            'articulation-type 'accent)
          (ly:music-property result-event-chord 'articulations))

Se usa `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 `ArticulationEvent`. El orden dentro de la propiedad `'articulations` no tiene importancia aquí.

Finalmente, una vez hemos añadido la articulación de acento a su propiedad `articulations`, podemos devolver `note-event`, de aquí la última línea de la función.

Ahora transformamos la función `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 argumento).

    addAccent = #(define-music-function (note-event) (ly:music?)
      "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)

A continuación verificamos que esta función musical funciona correctamente:

    \displayMusic \addAccent c4

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