Kurz gesagt
Ein Kapitel über Kadenzen aus einer Harmonielehre fürs Konservatorium, in zwei Spalten. Die fünf Notenbeispiele werden als Text geschrieben, als echte Noten gestochen, wie Abbildungen nummeriert und nahe dem Absatz gesetzt, der sie nennt.
Was Sie setzen
Kapitel 4 von Four-Part Harmony, einer Harmonielehre für die ersten Jahre am Konservatorium, auf einer Seite von 210 × 280 mm in zwei Spalten aus der Crimson Pro. Die Lektion behandelt Kadenzen, und ihre fünf Beispiele sind vierstimmige Choräle auf zwei Systemen mit römischen Stufenziffern unter dem Bass: die fünf Kadenzen in G-Dur, drei Zeilen von Nun danket alle Gott und der Genfer Psalm 134 (Old Hundredth) vollständig. Jedes trägt eine Nummer von Example 4.1 bis 4.5 (Ejemplo in der spanischen Ausgabe), eine Legende in der Auszeichnungsschrift mit weinrotem Etikett und steht am Kopf oder Fuß der Spalte nach dem Absatz, der es zitiert; der ganze Psalm läuft am Kopf von Seite 63 über beide Spalten. Die Sätze wurden für diese Harmonielehre geschrieben und auf Quint- und Oktavparallelen, Stimmabstände und die Auflösung des Leittons geprüft.
Dieses Rezept beantwortet
- Wie nummeriere ich Notenbeispiele und lasse sie in einem zweispaltigen Buch wie Abbildungen fließen?
- Wie füge ich eine Abbildung mit nummerierter Bildunterschrift ein und verweise im Text darauf („siehe Abb. 3.2“)?
- Wie bestimme ich, wo eine Abbildung steht: oben auf der Seite, über beide Spalten, genau hier oder am Rand?
Die kurze Antwort
// 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' }),
];
Zutaten
- Funktionen
- Nummerierte NotenbeispielePlatzierung von AbbildungenVerweise, die Abbildungen platzierenNotensatzNotenstilNummerierte BildunterschriftenAbbildung und Tabelle in Ihrer SpracheEigene RessourcentypenFormat der BildunterschriftQuellen- und BildnachweiseEine oder zwei SpaltenGestaltete AuftakteÜberschriftenattributeKolumnentitel und SeitenzahlenGespiegelte RänderKopfzeilen nach SeitenrolleKästenAbsatzformateSemantische Farbpalette
- Schrift
- Crimson Pro, Playfair Display, Fira Sans Condensed (SIL OFL 1.1)
- Dateien
- Keine: Jedes Bild wird im Code gezeichnet
Zubereitung
#1 · Jeden Choral in Humdrum **kern schreiben
// 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 schreibt die Stimmen in Spalten, durch Tabulatoren getrennt, von der tiefsten zur höchsten. Jedes Notensystem ist eine Spalte (spine), die *^ in zwei teilt: Tenor und Bass im Bassschlüssel, Sopran und Alt im Violinschlüssel. So setzt der Notenstecher zwei Stimmen pro System mit getrennten Hälsen (die linke Stimme nach oben, die rechte nach unten). Eine **harm-Spalte nach dem Basssystem druckt die Stufen darunter; Ib ist die erste Umkehrung, Ic der Quartsextakkord. Das Skript schreibt die Spalten mit Leerzeichen und macht Tabulatoren daraus, damit kein Editor die Datei verdirbt, und die spanische Ausgabe erhält ihre Stufen in Großbuchstaben (VI, IIb), wie spanische Harmonielehren sie schreiben.
#2 · Jedes Beispiel zur Ressource vom Typ example machen
Die kurze Antwort baut die fünf Ressourcen. typeId: 'example' nimmt den eingebauten Typ Notenbeispiel, den die Engine den Ressourcentypen des Buchs hinzufügt, sobald eine Ressource ihn verwendet, benannt in der Sprache des Dokuments (locale: 'es' ergibt Ejemplo) und pro Kapitel nummeriert: Das erste Beispiel von Kapitel 4 ist 4.1. Eine Notenressource bleibt ganz und fließt wie eine Abbildung: position: 'top' oder 'bottom' nimmt Kopf oder Fuß der nächsten Spalte mit Platz nach dem Zitat, und span: 'page' setzt den Old Hundredth über beide Spalten. Legenden, Nachweise und Alternativtexte kommen aus einer zweiten Markdown-Datei pro Ausgabe.
#3 · Den Spaltenbeispielen ein kleineres System geben
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 },
];
Die beiden seitenbreiten Choräle folgen dem scoreStyle des Dokuments, mit 5,4 mm hohen Systemen und Taktzahlen am Anfang jeder Zeile. Die Beispiele in einer Spalte wählen den benannten Stil column: 4,6 mm, keine Taktzahlen und eine Spationierung von 0,8, die die fünf Takte von Beispiel 4.2 in einer Zeile hält, statt den letzten allein in eine zweite zu schicken.
#4 · Den Notenstecher vor dem Satz starten
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() lädt Verovio, den Notenstecher, aus dem Paket; bis er läuft, wird jede Partitur als graue Box gesetzt. Die continuation macht dies zu Kapitel 4 eines längeren Buchs, sodass die Beispiele 4.1 bis 4.5 heißen und die Seitenzahlen bei 61 auf einer rechten Seite beginnen.
#5 · Das Kapitel über beide Spalten öffnen
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) } } },
] },
};
Der Auftakt nimmt beide Spalten ein (span: 'page' an der Überschrift der ersten Ebene) und holt Dachzeile und Vorspann aus den Attributen der Überschrift. minHeight senkt den Text um 46 mm, sodass beide Spalten auf derselben Zeile unter der Linie beginnen.
Das ganze Rezept
// ═══ 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),
Das zusammengesetzte script.js läuft unverändert: Fügen Sie es in das Modulskript einer beliebigen Seite ein, oder öffnen Sie das Rezept auf CodePen. Ordner des Rezepts auf GitHub ↗ (öffnet sich in einem neuen Tab)
Varianten
#Ein Beispiel ohne Nummer in den Text setzen
Ein Codeblock hält eine Partitur im Text, die der Text nicht zitiert, wie eine abgesetzte Formel: ohne Nummer und ohne Legende.
- ::resource{id="ex-cadences"}
+ ```humdrum {style="column" alt="Die fünf Kadenzen in G-Dur"}
+ **kern **harm **kern
+ …
+ ```#Sie Musikbeispiele nennen
Legen Sie einen eigenen Typ für einen anderen Namen an und lassen Sie typeId darauf zeigen.
- resourceTypes: defaultResourceTypes(LANG),
+ resourceTypes: [...defaultResourceTypes(LANG), { id: 'musex', name: 'Musikbeispiel',
+ shortLabel: 'Mb.', captionPrefix: 'Musikbeispiel', numberingTemplate: '{h1}.{n}',
+ resetOn: 'h1', counterFormat: 'decimal' }],Häufige Fehler
Häufiger Fehler
::resource{id="…"} nimmt nur doppelte Anführungszeichen
Eine Block-Einbettung wird nur als ::resource{id="…"} mit doppelten Anführungszeichen erkannt; jede andere Form bleibt als sichtbare Zeile im Text. Abbildungen genau hier →
- Eine Notenressource wird nie zwischen Spalten oder Seiten geteilt. Halten Sie fließende Beispiele auf wenige Takte und setzen Sie ein längeres Stück in einen Codeblock, der zwischen den Zeilen umbricht.
- Der Notenstecher füllt jede Zeile auf die Breite ihres Platzes, die letzte behält ihre natürliche Breite. Lässt ein Beispiel einen Takt allein in einer zweiten Zeile, senken Sie
spacingoder die Systemgröße seines Stils.
Nachweise
- Rezept
- Ignacio Ferro
- Text
- Chapter text and the four-part settings of every example · Ignacio Ferro · CC BY 4.0
- Melody of Nun danket alle Gott (Praxis pietatis melica, 1647), read from the soprano of Bach's setting BWV 386 · Johann Crüger · gemeinfrei
- Melody of the Old Hundredth (Psalm 134 in the Genevan Psalter, 1551) · Louis Bourgeois (attributed) · gemeinfrei
- Schriften
- Crimson Pro (SIL OFL 1.1) · Playfair Display (SIL OFL 1.1) · Fira Sans Condensed (SIL OFL 1.1)
- Code
- MIT, wie Postext
Diesen Text bearbeiten ↗ (öffnet sich in einem neuen Tab)Ordner des Rezepts auf GitHub ↗ (öffnet sich in einem neuen Tab)


