Saltar al contenido principal
Receta número 166

Recetario · Capítulo 7 · Figuras e imágenes

Corales numerados en un método de armonía a dos columnas

Corales a cuatro voces escritos en Humdrum **kern pasan a recursos de partitura de tipo ejemplo: numerados, citados con :ref y flotantes como figuras.

pp. 62–63 · 2–3 de 3

  • Formato 210 × 280 mm
  • 2 columnas, medianil de 7 mm
  • Crimson Pro 10,8/14,2
  • Fira Sans Condensed
  • Playfair Display
  • 3 páginas
  • Nivel
  • Postext 1.54.0
  • Compuesto en 89 ms
  • 175 líneas de código

En pocas palabras

Un capítulo sobre las cadencias de un libro de armonía de conservatorio, a dos columnas. Sus cinco ejemplos musicales se escriben como texto, se graban como partituras, se numeran como figuras y van junto al párrafo que los cita.

Lo que vas a componer

El capítulo 4 de Armonía a cuatro voces, un método para los primeros cursos del conservatorio, en una página de 210 × 280 mm a dos columnas de Crimson Pro. La lección trata de las cadencias, y sus cinco ejemplos son corales a cuatro voces en dos pentagramas, con los grados en cifras romanas bajo el bajo: las cinco cadencias de sol mayor, tres versos de Nun danket alle Gott y el Salmo 134 de Ginebra completo. Cada uno lleva su número, de Ejemplo 4.1 a 4.5 (Example en la edición inglesa), un pie en la letra de rótulos con la etiqueta en granate, y se coloca en la cabeza o el pie de la columna que sigue al párrafo que lo cita; el salmo entero ocupa las dos columnas en la cabeza de la página 63. Las armonizaciones se escribieron para este método y se revisaron en busca de quintas y octavas paralelas, distancias entre voces y resolución de la sensible.

Esta receta responde a

  • ¿Cómo numero los ejemplos musicales y los hago flotar como figuras en un libro a dos columnas?
  • ¿Cómo añado una figura con pie numerado y la cito en el texto («véase la fig. 3.2»)?
  • ¿Cómo decido dónde va una figura: en la cabeza de la página, a lo ancho de las dos columnas, justo aquí o al margen?

La respuesta corta

script.js · líneas 26–41en el código completo
// In the Markdown, :ref{id="ex-old-hundredth" style="full"} prints 'Example 4.4' ('Ejemplo
// 4.4' in Spanish) and ::resource{id="…"} anchors the float after the paragraph that cites it.
const example = (id, source, placement, styleId) => {
  const [caption, note, altText] = CAPTIONS[id];
  return { id, typeId: 'example', kind: 'score', caption, note, altText, placement,
    score: { format: 'humdrum', source, styleId }, createdAt: 0, updatedAt: 0 };
};
// The **kern sources are in #region art-scores; captions in content.captions.<lang>.md.
const resources = () => [
  example('ex-cadences', CADENCES, { position: 'bottom' }, 'column'),
  example('ex-nun-danket', NUN_DANKET, { position: 'top' }, 'column'),
  example('ex-nun-danket-3', NUN_DANKET_3, { position: 'auto' }, 'column'),
  // Across both columns in the document's own score style: the whole tune in two systems.
  example('ex-old-hundredth', OLD_HUNDREDTH, { position: 'top', span: 'page' }),
  example('ex-deceptive', DECEPTIVE, { position: 'auto', span: 'page' }),
];

Ingredientes

Tipografía
Crimson Pro, Playfair Display, Fira Sans Condensed (SIL OFL 1.1)
Recursos
Ninguno: todas las imágenes se dibujan en código

Elaboración

#1 · Escribe cada coral en Humdrum **kern

script.js · líneas 263–273en el código completo
// Each example lists its spines as Humdrum wants them, lowest first: the bass staff split into
// tenor and bass, the **harm spine (printed under that staff), the treble staff split into
// soprano and alto. Writing them with spaces keeps the pen free of tab characters.
const kern = (meter, body) => [
  '**kern **harm **kern', '*clefF4 * *clefG2', '*k[f#] * *k[f#]', `*M${meter} * *M${meter}`,
  '*^ * *^', ...body.trim().split('\n'), '== == == == ==', '*- *- *- *- *-',
].map((row) => row.trim().split(/ +/)
  // Spanish harmony books write every degree in capitals: vi is VI, iib is IIb.
  .map((cell) => (LANG === 'es' && /^(?:i{1,3}|iv|vi{0,2})[bc7]?$/.test(cell)
    ? cell.replace(/^[iv]+/, (degree) => degree.toUpperCase()) : cell))
  .join('\t')).join('\n');

Humdrum escribe las voces en columnas separadas por tabuladores, de la más grave a la más aguda. Cada pentagrama es una columna (spine) dividida en dos con *^: tenor y bajo en el pentagrama de fa, soprano y contralto en el de sol, de modo que el grabador pone dos voces por pentagrama con las plicas separadas (la voz de la izquierda hacia arriba, la de la derecha hacia abajo). Una columna **harm tras el pentagrama del bajo imprime los grados bajo él; Ib es la primera inversión y Ic, la cuarta y sexta. El guion escribe las columnas con espacios y las convierte en tabuladores, así ningún editor puede estropear el archivo, y la edición española recibe los grados en mayúsculas (VI, IIb), como los escriben los libros de armonía en español.

#2 · Haz de cada ejemplo un recurso de tipo ejemplo

La respuesta corta construye los cinco recursos. typeId: 'example' toma el tipo Ejemplo integrado, que el motor añade a los tipos de recurso del libro cuando un recurso lo usa, con el nombre en el idioma del documento (locale: 'es' da Ejemplo) y numerado por capítulo, de modo que el primer ejemplo del capítulo 4 es el 4.1. Un recurso de partitura se mantiene entero y flota como una figura: position: 'top' o 'bottom' toma la cabeza o el pie de la siguiente columna con sitio tras la cita, y span: 'page' extiende el Salmo 134 por las dos columnas. Los pies, los créditos y los textos alternativos salen de un segundo archivo Markdown por edición.

#3 · Da a los ejemplos de columna un pentagrama menor

script.js · líneas 45–53en el código completo
const scoreStyle = {
  staffSize: mm(5.4), musicFont: 'Bravura', barNumbers: 'system', color: col('ink'),
  textFont: TEXT, // the Roman numerals under the bass, in the text face
  marginTop: pt(4), marginBottom: pt(2),
};
const scoreStyles = [ // rastral 4.6 mm: four staves of a chorale fit a column in two systems
  { id: 'column', name: t({ en: 'Column examples', es: 'Ejemplos de columna' }),
    staffSize: mm(4.6), barNumbers: 'none', spacing: 0.8 },
];

Los dos corales a lo ancho de la página usan el scoreStyle del documento, con pentagramas de 5,4 mm y números de compás al principio de cada sistema. Los ejemplos de columna eligen el estilo con nombre column: pentagramas de 4,6 mm, sin números de compás y espaciado 0,8, que mantiene los cinco compases del ejemplo 4.2 en un solo sistema en lugar de dejar el último solo en un segundo.

#4 · Arranca el grabador antes de componer

script.js · líneas 398–404en el código completo
await initMusicEngine(); // until it runs, every score is laid out as a grey box
const continuation = { pageNumbering: { startAt: 61 }, // odd: the opener is a recto
  headings: { h1: 3, h2: 0, h3: 0, h4: 0, h5: 0, h6: 0 } }; // the next # is chapter 4
const doc = await buildDocumentWithFonts({ markdown, resources: resources(), continuation },
  config, kitFonts(FONTS));
showPages(doc, { title: t({ en: 'Numbered chorale examples in a harmony method',
  es: 'Corales numerados en un método de armonía' }) });

initMusicEngine() carga Verovio, el grabador, desde el paquete; hasta que arranca, cada partitura se compone como una caja gris. La continuation hace de este el capítulo 4 de un libro más largo, así que los ejemplos se numeran del 4.1 al 4.5 y los folios empiezan en el 61, en página impar.

#5 · Abre el capítulo sobre las dos columnas

script.js · líneas 57–77en el código completo
const label = { fontFamily: LABEL, fontWeight: 600, textTransform: 'uppercase' };
const opener = {
  enabled: true, minHeight: mm(46),
  slot: { elements: [
      { kind: 'text', id: 'kicker', content: '{attr.kicker}', ...label, fontSize: pt(9),
        letterSpacing: pt(1.8), color: col('accent'), align: 'left',
        placement: { anchor: { to: 'container', edge: 'top-left' },
          offset: { x: mm(0), y: mm(6) } } },
      { kind: 'text', id: 'title', content: '{titleText}', fontFamily: DISPLAY, fontSize: pt(36),
        lineHeight: 1.05, fontWeight: 400, color: col('ink'), align: 'left',
        placement: { anchor: { to: '#kicker', edge: 'below' }, offset: { x: mm(0), y: mm(3) },
          size: { width: mm(150), height: 'auto' } } },
      { kind: 'text', id: 'deck', content: '{attr.deck}', fontFamily: TEXT, fontSize: pt(13),
        lineHeight: 1.25, italic: true, color: col('muted'), align: 'left',
        placement: { anchor: { to: '#title', edge: 'below' }, offset: { x: mm(0), y: mm(3) },
          size: { width: mm(120), height: 'auto' } } },
      { kind: 'rule', id: 'rule', direction: 'horizontal', thickness: pt(1.5), color: col('accent'),
        placement: { anchor: { to: '#deck', edge: 'below' }, offset: { x: mm(0), y: mm(5) },
          size: { width: mm(18) } } },
  ] },
};

La apertura ocupa las dos columnas (span: 'page' en el título de nivel uno) y toma el antetítulo y la entradilla de los atributos del título. minHeight hunde el texto 46 mm, de modo que las dos columnas empiezan en la misma línea bajo el filete.

La receta completa

Sandbox
// ═══ Postext Cookbook · Nº 166 · Numbered chorale examples in a harmony method ══
// https://postext.dev/en/cookbook/conservatory-method-chorales
// Code: MIT · Text and four-part settings: original (CC BY 4.0) · Melodies: public domain
// Fonts: Crimson Pro, Playfair Display, Fira Sans Condensed (OFL 1.1) · Needs postext ≥ 1.54.0
import {
  buildDocumentWithFonts, renderPageToCanvas, defaultResourceTypes, initMusicEngine,
} from 'https://esm.sh/postext';

const LANG = 'es'; // @lang: the language of the sample document ('en' | 'es')
const RECIPE = 'conservatory-method-chorales';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// A claret accent on warm paper tones, every colour linked by id.
const palette = { ink: '#1f1a17', accent: '#7a2531', tint: '#f5eee6', rule: '#cdbfb2',
  muted: '#6a5f57', paper: '#ffffff' };
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = [
  ...Object.entries(palette).map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } })),
  { id: 'main-color', name: 'accent (defaults)', value: { hex: palette.accent, model: 'hex' } },
];
const [TEXT, DISPLAY, LABEL] = ['Crimson Pro', 'Playfair Display', 'Fira Sans Condensed'];
const OUTER = 16; // outer margin in mm: running heads and folios align to it
const LEAD = 14.2; // body leading in pt

// #region answer: score resources typed 'example', floated and numbered like figures
// In the Markdown, :ref{id="ex-old-hundredth" style="full"} prints 'Example 4.4' ('Ejemplo
// 4.4' in Spanish) and ::resource{id="…"} anchors the float after the paragraph that cites it.
const example = (id, source, placement, styleId) => {
  const [caption, note, altText] = CAPTIONS[id];
  return { id, typeId: 'example', kind: 'score', caption, note, altText, placement,
    score: { format: 'humdrum', source, styleId }, createdAt: 0, updatedAt: 0 };
};
// The **kern sources are in #region art-scores; captions in content.captions.<lang>.md.
const resources = () => [
  example('ex-cadences', CADENCES, { position: 'bottom' }, 'column'),
  example('ex-nun-danket', NUN_DANKET, { position: 'top' }, 'column'),
  example('ex-nun-danket-3', NUN_DANKET_3, { position: 'auto' }, 'column'),
  // Across both columns in the document's own score style: the whole tune in two systems.
  example('ex-old-hundredth', OLD_HUNDREDTH, { position: 'top', span: 'page' }),
  example('ex-deceptive', DECEPTIVE, { position: 'auto', span: 'page' }),
];
// #endregion

// #region scores: one score style for the page-wide chorale, a smaller one for the columns
const scoreStyle = {
  staffSize: mm(5.4), musicFont: 'Bravura', barNumbers: 'system', color: col('ink'),
  textFont: TEXT, // the Roman numerals under the bass, in the text face
  marginTop: pt(4), marginBottom: pt(2),

El script.js compuesto funciona tal cual: pégalo como script de módulo en cualquier página o abre la receta en CodePen. Carpeta de la receta en GitHub ↗ (se abre en una nueva pestaña)

Variantes

#Pon un ejemplo sin número en el texto

Un bloque de código con la partitura la deja en el texto sin que el texto la cite, como una fórmula destacada: sin número ni pie.

- ::resource{id="ex-cadences"}
+ ```humdrum {style="column" alt="Las cinco cadencias en sol mayor"}
+ **kern	**harm	**kern
+ …
+ ```

#Llámalos ejemplos musicales

Define un tipo propio para otro nombre y apunta typeId a él.

- resourceTypes: defaultResourceTypes(LANG),
+ resourceTypes: [...defaultResourceTypes(LANG), { id: 'musex', name: 'Ejemplo musical',
+   shortLabel: 'Ej. mus.', captionPrefix: 'Ejemplo musical', numberingTemplate: '{h1}.{n}',
+   resetOn: 'h1', counterFormat: 'decimal' }],

Errores frecuentes

Error frecuente

::resource{id="…"} solo admite comillas dobles

Una inserción de bloque solo se reconoce como ::resource{id="…"} con comillas dobles; cualquier otra forma se queda en el texto como una línea visible. Figuras justo aquí →

  • Un recurso de partitura nunca se parte entre columnas ni entre páginas. Limita los ejemplos flotantes a unos pocos compases y pon las piezas más largas en un bloque de código, que se parte entre sistemas.
  • El grabador llena cada sistema hasta el ancho de su hueco, y el último sistema conserva su ancho natural. Si un ejemplo deja un compás solo en un segundo sistema, baja el spacing o el tamaño de pentagrama de su estilo.

Créditos

Texto
Fuentes
Crimson Pro (SIL OFL 1.1) · Playfair Display (SIL OFL 1.1) · Fira Sans Condensed (SIL OFL 1.1)
Sandbox