UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

218 lines (193 loc) 5.72 kB
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna Cheppudira 2013. // Co-author: Benjamin W. Bohl // MIT License import { Glyph } from './glyph'; import { Stave } from './stave'; import { StaveModifier, StaveModifierPosition } from './stavemodifier'; import { Tables } from './tables'; import { Category } from './typeguard'; import { defined, log } from './util'; export interface ClefType { point: number; code: string; line?: number; } // eslint-disable-next-line function L(...args: any[]) { if (Clef.DEBUG) log('Vex.Flow.Clef', args); } /** * Clef implements various types of clefs that can be rendered on a stave. * * See `tests/clef_tests.ts` for usage examples. */ export class Clef extends StaveModifier { /** To enable logging for this class, set `Vex.Flow.Clef.DEBUG` to `true`. */ static DEBUG: boolean = false; static get CATEGORY(): string { return Category.Clef; } annotation?: { code: string; line: number; x_shift: number; point: number; }; /** * The attribute `clef` must be a key from * `Clef.types` */ clef: ClefType = Clef.types['treble']; protected glyph?: Glyph; protected attachment?: Glyph; protected size?: string; protected type?: string; /** * Every clef name is associated with a glyph code from the font file * and a default stave line number. */ static get types(): Record<string, ClefType> { return { treble: { code: 'gClef', line: 3, point: 0, }, bass: { code: 'fClef', line: 1, point: 0, }, alto: { code: 'cClef', line: 2, point: 0, }, tenor: { code: 'cClef', line: 1, point: 0, }, percussion: { code: 'restMaxima', line: 2, point: 0, }, soprano: { code: 'cClef', line: 4, point: 0, }, 'mezzo-soprano': { code: 'cClef', line: 3, point: 0, }, 'baritone-c': { code: 'cClef', line: 0, point: 0, }, 'baritone-f': { code: 'fClef', line: 2, point: 0, }, subbass: { code: 'fClef', line: 0, point: 0, }, french: { code: 'gClef', line: 4, point: 0, }, tab: { code: '6stringTabClef', point: 0, }, }; } /** Create a new clef. */ constructor(type: string, size?: string, annotation?: string) { super(); this.setPosition(StaveModifierPosition.BEGIN); this.setType(type, size, annotation); this.setWidth(Tables.currentMusicFont().lookupMetric(`clef.${this.size}.width`)); L('Creating clef:', type); } /** Set clef type, size and annotation. */ setType(type: string, size?: string, annotation?: string): this { this.type = type; this.clef = Clef.types[type]; if (size === undefined) { this.size = 'default'; } else { this.size = size; } const musicFont = Tables.currentMusicFont(); this.clef.point = musicFont.lookupMetric(`clef.${this.size}.point`, 0); this.glyph = new Glyph(this.clef.code, this.clef.point, { category: `clef.${this.clef.code}.${this.size}`, }); // If an annotation, such as 8va, is specified, add it to the Clef object. if (annotation !== undefined) { const code = musicFont.lookupMetric(`clef.annotations.${annotation}.smuflCode`); const point = musicFont.lookupMetric(`clef.annotations.${annotation}.${this.size}.point`); const line = musicFont.lookupMetric(`clef.annotations.${annotation}.${this.size}.${this.type}.line`); const x_shift = musicFont.lookupMetric(`clef.annotations.${annotation}.${this.size}.${this.type}.shiftX`); this.annotation = { code, point, line, x_shift }; this.attachment = new Glyph(this.annotation.code, this.annotation.point); this.attachment.metrics.x_max = 0; this.attachment.setXShift(this.annotation.x_shift); } else { this.annotation = undefined; } return this; } /** Get clef width. */ getWidth(): number { if (this.type === 'tab') { defined(this.stave, 'ClefError', "Can't get width without stave."); } return this.width; } /** Set associated stave. */ setStave(stave: Stave): this { this.stave = stave; if (this.type === 'tab') { const glyph = defined(this.glyph, 'ClefError', "Can't set stave without glyph."); const numLines = this.stave.getNumLines(); const musicFont = Tables.currentMusicFont(); const point = musicFont.lookupMetric(`clef.lineCount.${numLines}.point`); const shiftY = musicFont.lookupMetric(`clef.lineCount.${numLines}.shiftY`); glyph.setPoint(point); glyph.setYShift(shiftY); } return this; } /** Render clef. */ draw(): void { const glyph = defined(this.glyph, 'ClefError', "Can't draw clef without glyph."); const stave = this.checkStave(); const ctx = stave.checkContext(); this.setRendered(); this.applyStyle(ctx); ctx.openGroup('clef', this.getAttribute('id')); glyph.setStave(stave); glyph.setContext(ctx); if (this.clef.line !== undefined) { this.placeGlyphOnLine(glyph, stave, this.clef.line); } glyph.renderToStave(this.x); if (this.annotation !== undefined && this.attachment !== undefined) { this.placeGlyphOnLine(this.attachment, stave, this.annotation.line); this.attachment.setStave(stave); this.attachment.setContext(ctx); this.attachment.renderToStave(this.x); } ctx.closeGroup(); this.restoreStyle(ctx); } }