Skip to content

Commit

Permalink
Add basic support for fermatas
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredjj3 committed Jan 19, 2024
1 parent 8e091cf commit e8d323c
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/musicxml/fermata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class Fermata {

/** Returns the shape of the fermata. Defaults to normal. */
getShape(): FermataShape {
return this.element.first('fermata-shape')?.content().enum(FERMATA_SHAPES) ?? 'normal';
return this.element.content().enum(FERMATA_SHAPES) ?? 'normal';
}

/** Returns the type of fermata. Defaults to upright. */
Expand Down
14 changes: 12 additions & 2 deletions src/rendering/fermata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,22 @@ export class Fermata {
}

render(): FermataRendering {
// TODO(jared): Make a real fermata.
return {
type: 'fermata',
vexflow: {
articulation: new vexflow.Articulation('a'),
articulation: this.getVfArticulation(),
},
};
}

private getVfArticulation(): vexflow.Articulation {
const type = this.musicXML.fermata.getType();

switch (type) {
case 'upright':
return new vexflow.Articulation('a@a');
case 'inverted':
return new vexflow.Articulation('a@u').setPosition(vexflow.ModifierPosition.BELOW);
}
}
}
25 changes: 23 additions & 2 deletions src/rendering/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import * as conversions from './conversions';
import { Ornament, OrnamentRendering } from './ornament';
import { Spanners } from './spanners';
import { Address } from './address';
import { Fermata, FermataRendering } from './fermata';
import { fermata } from '../util/xml';

const STEP_ORDER = [
'Cb',
Expand All @@ -37,7 +39,12 @@ const STEP_ORDER = [
'B#',
];

export type NoteModifierRendering = AccidentalRendering | LyricRendering | TokenRendering | OrnamentRendering;
export type NoteModifierRendering =
| AccidentalRendering
| LyricRendering
| TokenRendering
| OrnamentRendering
| FermataRendering;

/** The result of rendering a Note. */
export type NoteRendering = StaveNoteRendering | GraceNoteRendering;
Expand Down Expand Up @@ -182,6 +189,10 @@ export class Note {
renderings.push(ornament.render());
}

for (const fermata of note.getFermatas()) {
renderings.push(fermata.render());
}

return renderings;
});

Expand All @@ -200,6 +211,9 @@ export class Note {
case 'ornament':
vfStaveNote.addModifier(modifierRendering.vexflow.ornament, index);
break;
case 'fermata':
vfStaveNote.addModifier(modifierRendering.vexflow.articulation, index);
break;
}
}
}
Expand Down Expand Up @@ -360,7 +374,14 @@ export class Note {
return this.musicXML.note
.getNotations()
.flatMap((notations) => notations.getOrnaments())
.flatMap((ornaments) => new Ornament({ musicXML: { ornaments } }));
.map((ornaments) => new Ornament({ musicXML: { ornaments } }));
}

private getFermatas(): Fermata[] {
return this.musicXML.note
.getNotations()
.flatMap((notations) => notations.getFermatas())
.map((fermata) => new Fermata({ musicXML: { fermata } }));
}

private getDotCount(): number {
Expand Down
13 changes: 2 additions & 11 deletions src/util/xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1334,23 +1334,14 @@ export const rootfile = createNamedElementFactory<'rootfile', { fullPath: string
}
);

export const fermata = createNamedElementFactory<'fermata', { shape: NamedElement<'fermata-shape'>; type: string }>(
export const fermata = createNamedElementFactory<'fermata', { shape: string; type: string }>(
'fermata',
(e, { shape, type }) => {
if (shape) {
e.append(shape);
e.setTextContent(shape);
}
if (type) {
e.setAttribute('type', type);
}
}
);

export const fermataShape = createNamedElementFactory<'fermata-shape', { value: string }>(
'fermata-shape',
(e, { value }) => {
if (value) {
e.setTextContent(value);
}
}
);
4 changes: 2 additions & 2 deletions tests/unit/musicxml/fermata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { xml } from '@/util';
describe(Fermata, () => {
describe('getShape', () => {
it.each(FERMATA_SHAPES.values)('returns the shape of the fermata', (shape) => {
const node = xml.fermata({ shape: xml.fermataShape({ value: shape }) });
const node = xml.fermata({ shape });
const fermata = new Fermata(node);
expect(fermata.getShape()).toBe(shape);
});
Expand All @@ -16,7 +16,7 @@ describe(Fermata, () => {
});

it('defaults to normal when invalid', () => {
const node = xml.fermata({ shape: xml.fermataShape({ value: 'foo' }) });
const node = xml.fermata({ shape: 'foo' });
const fermata = new Fermata(node);
expect(fermata.getShape()).toBe('normal');
});
Expand Down

0 comments on commit e8d323c

Please sign in to comment.