Pular para o conteúdo principal
Receita número 166

Receitas · Capítulo 7 · Figuras e imagens

Corais numerados num método de harmonia em duas colunas

Corais a quatro vozes escritos em Humdrum **kern viram recursos de partitura do tipo exemplo: numerados Exemplo 4.1, citados com :ref e flutuantes como figuras.

p. 62–63 · 2–3 de 3

  • Amostra em inglês: ainda sem edição em português
  • Refile 210 × 280 mm
  • 2 colunas, medianiz de 7 mm
  • Crimson Pro 10,8/14,2
  • Fira Sans Condensed
  • Playfair Display
  • 3 páginas
  • Nível
  • Postext 1.54.0
  • Diagramado em 75 ms
  • 175 linhas de código

Em poucas palavras

Um capítulo sobre cadências de um livro de harmonia de conservatório, em duas colunas. Os cinco exemplos musicais são escritos como texto, gravados como partituras, numerados como figuras e postos perto do parágrafo que os cita.

O que você vai compor

O capítulo 4 de Four-Part Harmony, um método para os primeiros anos de conservatório, numa página de 210 × 280 mm em duas colunas de Crimson Pro. A lição trata das cadências, e os seus cinco exemplos são corais a quatro vozes em duas pautas, com os graus em algarismos romanos sob o baixo: as cinco cadências de sol maior, três versos de Nun danket alle Gott e o Salmo 134 de Genebra (o Old Hundredth) completo. Cada um leva um número, de Example 4.1 a 4.5 (Ejemplo na edição espanhola), uma legenda na fonte dos rótulos com o rótulo em vinho, e fica no topo ou no pé da coluna que segue o parágrafo que o cita; o salmo inteiro ocupa as duas colunas no topo da página 63. As harmonizações foram escritas para este método e conferidas quanto a quintas e oitavas paralelas, distância entre as vozes e resolução da sensível.

Esta receita responde a

  • Como numero os exemplos musicais e os faço flutuar como figuras num livro em duas colunas?
  • Como acrescento uma figura com legenda numerada e a cito no texto (“ver fig. 3.2”)?
  • Como decido onde vai uma figura: no alto da página, sobre as duas colunas, exatamente aqui ou na margem?

A resposta curta

script.js · linhas 26–41no 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

Tipografia
Crimson Pro, Playfair Display, Fira Sans Condensed (SIL OFL 1.1)
Materiais
Nenhum: todas as imagens são desenhadas em código

Preparo

#1 · Escrever cada coral em Humdrum **kern

script.js · linhas 263–273no 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');

O Humdrum escreve as vozes em colunas separadas por tabulações, da mais grave à mais aguda. Cada pauta é uma coluna (spine) dividida em duas com *^: tenor e baixo na clave de fá, soprano e contralto na de sol, e assim o gravador põe duas vozes por pauta com as hastes separadas (a voz da esquerda para cima, a da direita para baixo). Uma coluna **harm depois da pauta do baixo imprime os graus sob ela; Ib é a primeira inversão e Ic, a quarta e sexta. O script escreve as colunas com espaços e as converte em tabulações, para que nenhum editor estrague o arquivo, e a edição espanhola recebe os graus em maiúsculas (VI, IIb), como os livros de harmonia espanhóis os escrevem.

#2 · Fazer de cada exemplo um recurso do tipo exemplo

A resposta curta monta os cinco recursos. typeId: 'example' usa o tipo Exemplo embutido, que o motor acrescenta aos tipos de recurso do livro quando um recurso o usa, com o nome no idioma do documento (locale: 'es' dá Ejemplo) e numerado por capítulo: o primeiro exemplo do capítulo 4 é o 4.1. Um recurso de partitura fica inteiro e flutua como uma figura: position: 'top' ou 'bottom' ocupa o topo ou o pé da próxima coluna com espaço depois da citação, e span: 'page' estende o Old Hundredth pelas duas colunas. Legendas, créditos e textos alternativos vêm de um segundo arquivo Markdown por edição.

#3 · Dar aos exemplos de coluna uma pauta menor

script.js · linhas 45–53no 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 },
];

Os dois corais na largura da página seguem o scoreStyle do documento, com pautas de 5,4 mm e números de compasso no começo de cada sistema. Os exemplos de coluna escolhem o estilo nomeado column: pautas de 4,6 mm, sem números de compasso e espaçamento 0,8, que mantém os cinco compassos do exemplo 4.2 num só sistema em vez de deixar o último sozinho num segundo.

#4 · Iniciar o gravador antes da composição

script.js · linhas 398–404no 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() carrega o Verovio, o gravador, a partir do pacote; até ele rodar, cada partitura é diagramada como uma caixa cinza. A continuation faz deste o capítulo 4 de um livro mais longo, e assim os exemplos vão de 4.1 a 4.5 e os fólios começam em 61, numa página ímpar.

#5 · Abrir o capítulo sobre as duas colunas

script.js · linhas 57–77no 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) } } },
  ] },
};

A abertura ocupa as duas colunas (span: 'page' no título de nível um) e tira o antetítulo e o olho dos atributos do título. minHeight rebaixa o texto 46 mm, e as duas colunas começam na mesma linha sob o fio.

A receita 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 = 'en'; // @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),

O script.js montado funciona como está: cole-o como script de módulo em qualquer página ou abra a receita no CodePen. Pasta da receita no GitHub ↗ (abre em uma nova aba)

Variações

#Pôr um exemplo sem número no texto

Um bloco de código mantém no texto uma partitura que o texto não cita, como uma fórmula destacada: sem número nem legenda.

- ::resource{id="ex-cadences"}
+ ```humdrum {style="column" alt="As cinco cadências em sol maior"}
+ **kern	**harm	**kern
+ …
+ ```

#Chamá-los de exemplos musicais

Defina um tipo seu para outro nome e aponte typeId para ele.

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

Erros comuns

Erro comum

::resource{id="…"} só aceita aspas duplas

Uma inserção em bloco só é reconhecida como ::resource{id="…"} com aspas duplas; qualquer outra forma fica no texto como uma linha visível. Figuras exatamente aqui →

  • Um recurso de partitura nunca se divide entre colunas ou páginas. Limite os exemplos flutuantes a poucos compassos e ponha uma peça mais longa num bloco de código, que se divide entre sistemas.
  • O gravador preenche cada sistema até a largura do seu espaço, e o último mantém a largura natural. Quando um exemplo deixa um compasso sozinho num segundo sistema, reduza o spacing ou o tamanho de pauta do seu estilo.

Créditos

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