Skip to content

Commit b2e195e

Browse files
committed
glyph code support in Articulations
1 parent 91c8f4a commit b2e195e

File tree

7 files changed

+87
-137
lines changed

7 files changed

+87
-137
lines changed

src/articulation.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,17 @@ export class Articulation extends Modifier {
295295

296296
/**
297297
* Create a new articulation.
298-
* @param type entry in `Vex.Flow.articulationCodes` in `tables.ts`
298+
* @param type entry in `Vex.Flow.articulationCodes` in `tables.ts` or Glyph code.
299+
*
300+
* Notes (by default):
301+
* - Glyph codes ending with 'Above' will be positioned ABOVE
302+
* - Glyph codes ending with 'Below' will be positioned BELOW
299303
*/
300304
constructor(type: string) {
301305
super();
302306

303307
this.type = type;
304-
this.position = BELOW;
308+
this.position = ABOVE;
305309
this.render_options = {
306310
font_scale: 38,
307311
};
@@ -311,13 +315,26 @@ export class Articulation extends Modifier {
311315

312316
protected reset(): void {
313317
this.articulation = Tables.articulationCodes(this.type);
314-
const articulation = defined(this.articulation, 'ArgumentError', `Articulation not found: ${this.type}`);
315-
const code = (this.position === ABOVE ? articulation.aboveCode : articulation.belowCode) || articulation.code;
318+
// Use type as glyph code, if not defined as articulation code
319+
if (!this.articulation) {
320+
this.articulation = { code: this.type, between_lines: false };
321+
if (this.type.endsWith('Above')) this.position = ABOVE;
322+
if (this.type.endsWith('Below')) this.position = BELOW;
323+
}
324+
const code =
325+
(this.position === ABOVE ? this.articulation.aboveCode : this.articulation.belowCode) || this.articulation.code;
316326
this.glyph = new Glyph(code ?? '', this.render_options.font_scale);
327+
defined(this.glyph, 'ArgumentError', `Articulation not found: ${this.type}`);
317328

318329
this.setWidth(defined(this.glyph.getMetrics().width));
319330
}
320331

332+
/** Set if articulation should be rendered between lines. */
333+
setBetweenLines(betweenLines = true): this {
334+
this.articulation.between_lines = betweenLines;
335+
return this;
336+
}
337+
321338
/** Render articulation in position next to note. */
322339
draw(): void {
323340
const ctx = this.checkContext();

src/factory.ts

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { Formatter, FormatterOptions } from './formatter';
1717
import { FretHandFinger } from './frethandfinger';
1818
import { GhostNote } from './ghostnote';
1919
import { Glyph } from './glyph';
20-
import { GlyphArticulation } from './glypharticulation';
2120
import { GlyphNote, GlyphNoteOptions } from './glyphnote';
2221
import { GraceNote, GraceNoteStruct } from './gracenote';
2322
import { GraceNoteGroup } from './gracenotegroup';
@@ -392,28 +391,11 @@ export class Factory {
392391
return chordSymbol;
393392
}
394393

395-
GlyphArticulation(code: string, params?: { between_lines?: boolean; position?: string | number }): Articulation {
396-
const p = {
397-
position: 'above',
398-
between_lines: false,
399-
...params,
400-
};
401-
402-
const articulation = new GlyphArticulation(code, p.between_lines);
403-
articulation.setPosition(p.position);
404-
articulation.setContext(this.context);
405-
return articulation;
406-
}
407-
408-
Articulation(params?: { type?: string; position?: string | number }): Articulation {
409-
const p = {
410-
type: 'a.',
411-
position: 'above',
412-
...params,
413-
};
394+
Articulation(params?: { betweenLines?: boolean; type?: string; position?: string | number }): Articulation {
395+
const articulation = new Articulation(params?.type ?? 'a.');
414396

415-
const articulation = new Articulation(p.type);
416-
articulation.setPosition(p.position);
397+
if (params?.position != undefined) articulation.setPosition(params.position);
398+
if (params?.betweenLines != undefined) articulation.setBetweenLines(params.betweenLines);
417399
articulation.setContext(this.context);
418400
return articulation;
419401
}

src/glypharticulation.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export * from './fraction';
2727
export * from './frethandfinger';
2828
export * from './ghostnote';
2929
export * from './glyph';
30-
export * from './glypharticulation';
3130
export * from './glyphnote';
3231
export * from './gracenote';
3332
export * from './gracenotegroup';

tests/articulation_tests.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const ArticulationTests = {
2525
QUnit.module('Articulation');
2626
const run = VexFlowTests.runTests;
2727
run('Articulation - Vertical Placement', verticalPlacement);
28+
run('Articulation - Vertical Placement (Glyph codes)', verticalPlacement2);
2829
run('Articulation - Staccato/Staccatissimo', drawArticulations, { sym1: 'a.', sym2: 'av' });
2930
run('Articulation - Accent/Tenuto', drawArticulations, { sym1: 'a>', sym2: 'a-' });
3031
run('Articulation - Marcato/L.H. Pizzicato', drawArticulations, { sym1: 'a^', sym2: 'a+' });
@@ -241,6 +242,67 @@ function verticalPlacement(options: TestOptions, contextBuilder: ContextBuilder)
241242
ok(true, ' Annotation Placement');
242243
}
243244

245+
function verticalPlacement2(options: TestOptions, contextBuilder: ContextBuilder): void {
246+
const ctx = contextBuilder(options.elementId, 750, 300);
247+
248+
const staveNote = (noteStruct: StaveNoteStruct) => new StaveNote(noteStruct);
249+
const stave = new Stave(10, 50, 750).addClef('treble').setContext(ctx).draw();
250+
251+
const notes = [
252+
staveNote({ keys: ['f/4'], duration: 'q' })
253+
.addModifier(new Articulation('fermataBelow'), 0)
254+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.BELOW), 0)
255+
.addModifier(new Articulation('articTenutoBelow'), 0),
256+
staveNote({ keys: ['g/4'], duration: 'q', stem_direction: Stem.DOWN })
257+
.addModifier(new Articulation('fermataShortBelow'), 0)
258+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.BELOW), 0)
259+
.addModifier(new Articulation('articTenutoBelow'), 0),
260+
staveNote({ keys: ['c/5'], duration: 'q' })
261+
.addModifier(new Articulation('fermataLongBelow'), 0)
262+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.BELOW), 0)
263+
.addModifier(new Articulation('articTenutoBelow'), 0),
264+
staveNote({ keys: ['f/4'], duration: 'q' })
265+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.BELOW), 0)
266+
.addModifier(new Articulation('articTenutoBelow'), 0)
267+
.addModifier(new Articulation('fermataVeryShortBelow'), 0),
268+
staveNote({ keys: ['g/4'], duration: 'q', stem_direction: Stem.DOWN })
269+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.BELOW), 0)
270+
.addModifier(new Articulation('articTenutoBelow'), 0)
271+
.addModifier(new Articulation('fermataVeryLongBelow'), 0),
272+
staveNote({ keys: ['c/5'], duration: 'q' })
273+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.BELOW).setBetweenLines(), 0)
274+
.addModifier(new Articulation('articTenutoBelow').setBetweenLines(), 0)
275+
.addModifier(new Articulation('fermataBelow'), 0),
276+
staveNote({ keys: ['a/5'], duration: 'q', stem_direction: Stem.DOWN })
277+
.addModifier(new Articulation('fermataAbove'), 0)
278+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.ABOVE), 0)
279+
.addModifier(new Articulation('articTenutoAbove'), 0),
280+
staveNote({ keys: ['f/5'], duration: 'q' })
281+
.addModifier(new Articulation('fermataShortAbove'), 0)
282+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.ABOVE), 0)
283+
.addModifier(new Articulation('articTenutoAbove'), 0),
284+
staveNote({ keys: ['b/4'], duration: 'q', stem_direction: Stem.DOWN })
285+
.addModifier(new Articulation('fermataLongAbove'), 0)
286+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.ABOVE), 0)
287+
.addModifier(new Articulation('articTenutoAbove'), 0),
288+
staveNote({ keys: ['a/5'], duration: 'q', stem_direction: Stem.DOWN })
289+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.ABOVE), 0)
290+
.addModifier(new Articulation('articTenutoAbove'), 0)
291+
.addModifier(new Articulation('fermataVeryShortAbove'), 0),
292+
staveNote({ keys: ['f/5'], duration: 'q' })
293+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.ABOVE), 0)
294+
.addModifier(new Articulation('articTenutoAbove'), 0)
295+
.addModifier(new Articulation('fermataVeryLongAbove'), 0),
296+
staveNote({ keys: ['b/4'], duration: 'q', stem_direction: Stem.DOWN })
297+
.addModifier(new Articulation('augmentationDot').setPosition(ModifierPosition.ABOVE).setBetweenLines(), 0)
298+
.addModifier(new Articulation('articTenutoAbove').setBetweenLines(), 0)
299+
.addModifier(new Articulation('fermataAbove'), 0),
300+
];
301+
302+
Formatter.FormatAndDraw(ctx, stave, notes);
303+
ok(true, ' Annotation Placement (Glyph codes)');
304+
}
305+
244306
function drawArticulations2(options: TestOptions): void {
245307
expect(0);
246308
const scale = 0.8;

tests/glypharticulation_tests.ts

Lines changed: 0 additions & 86 deletions
This file was deleted.

tests/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export * from './font_tests';
3636
export * from './formatter_tests';
3737
export * from './fraction_tests';
3838
export * from './ghostnote_tests';
39-
export * from './glypharticulation_tests';
4039
export * from './glyphnote_tests';
4140
export * from './gracenote_tests';
4241
export * from './gracetabnote_tests';

0 commit comments

Comments
 (0)