UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

218 lines (217 loc) 9.93 kB
import { BoundingBox } from './boundingbox'; import { ModifierContext } from './modifiercontext'; import { RenderContext } from './rendercontext'; import { Stave } from './stave'; import { StemmableNote } from './stemmablenote'; import { TabNote } from './tabnote'; import { TabStave } from './tabstave'; import { Tickable } from './tickable'; import { TickContext } from './tickcontext'; import { Voice } from './voice'; export interface FormatterOptions { /** Defaults to Tables.SOFTMAX_FACTOR. */ softmaxFactor?: number; /** Defaults to `false`. */ globalSoftmax?: boolean; /** Defaults to 5. */ maxIterations?: number; } export interface FormatParams { alignRests?: boolean; stave?: Stave; context?: RenderContext; autoBeam?: boolean; } export interface AlignmentContexts<T> { list: number[]; map: Record<number, T>; array: T[]; resolutionMultiplier: number; } export interface AlignmentModifierContexts { map: Map<Stave | undefined, Record<number, ModifierContext>>; array: ModifierContext[]; resolutionMultiplier: number; } /** * Format implements the formatting and layout algorithms that are used * to position notes in a voice. The algorithm can align multiple voices both * within a stave, and across multiple staves. * * To do this, the formatter breaks up voices into a grid of rational-valued * `ticks`, to which each note is assigned. Then, minimum widths are assigned * to each tick based on the widths of the notes and modifiers in that tick. This * establishes the smallest amount of space required for each tick. * * Finally, the formatter distributes the left over space proportionally to * all the ticks, setting the `x` values of the notes in each tick. * * See `tests/formatter_tests.ts` for usage examples. The helper functions included * here (`FormatAndDraw`, `FormatAndDrawTab`) also serve as useful usage examples. */ export declare class Formatter { static DEBUG: boolean; protected hasMinTotalWidth: boolean; protected minTotalWidth: number; protected contextGaps: { total: number; gaps: { x1: number; x2: number; }[]; }; protected justifyWidth: number; protected totalCost: number; protected totalShift: number; protected tickContexts: AlignmentContexts<TickContext>; protected formatterOptions: Required<FormatterOptions>; protected modifierContexts: AlignmentModifierContexts[]; protected voices: Voice[]; protected lossHistory: number[]; protected durationStats: Record<string, { mean: number; count: number; total: number; }>; /** * Helper function to layout "notes" one after the other without * regard for proportions. Useful for tests and debugging. */ static SimpleFormat(notes: Tickable[], x?: number, { paddingBetween }?: { paddingBetween?: number | undefined; }): void; /** Helper function to plot formatter debug info. */ static plotDebugging(ctx: RenderContext, formatter: Formatter, xPos: number, y1: number, y2: number, options?: { stavePadding: number; }): void; /** * Helper function to format and draw a single voice. Returns a bounding * box for the notation. * @param ctx the rendering context * @param stave the stave to which to draw (`Stave` or `TabStave`) * @param notes array of `Note` instances (`Note`, `TextNote`, `TabNote`, etc.) * @param params one of below: * * Setting `autoBeam` only `(context, stave, notes, true)` or * `(ctx, stave, notes, {autoBeam: true})` * * Setting `alignRests` a struct is needed `(context, stave, notes, {alignRests: true})` * * Setting both a struct is needed `(context, stave, notes, { * autoBeam: true, alignRests: true})` * * `autoBeam` automatically generates beams for the notes. * * `alignRests` aligns rests with nearby notes. */ static FormatAndDraw(ctx: RenderContext, stave: Stave, notes: StemmableNote[], params?: FormatParams | boolean): BoundingBox | undefined; /** * Helper function to format and draw aligned tab and stave notes in two * separate staves. * @param ctx the rendering context * @param tabstave a `TabStave` instance on which to render `TabNote`s. * @param stave a `Stave` instance on which to render `Note`s. * @param notes array of `Note` instances for the stave (`Note`, `BarNote`, etc.) * @param tabnotes array of `Note` instances for the tab stave (`TabNote`, `BarNote`, etc.) * @param autoBeam automatically generate beams. * @param params a configuration object: * * `autoBeam` automatically generates beams for the notes. * * `alignRests` aligns rests with nearby notes. */ static FormatAndDrawTab(ctx: RenderContext, tabstave: TabStave, stave: Stave, tabnotes: TabNote[], notes: Tickable[], autoBeam: boolean, params: FormatParams): void; /** * Automatically set the vertical position of rests based on previous/next note positions. * @param tickables an array of Tickables. * @param alignAllNotes If `false`, only align rests that are within a group of beamed notes. * @param alignTuplets If `false`, ignores tuplets. */ static AlignRestsToNotes(tickables: Tickable[], alignAllNotes: boolean, alignTuplets?: boolean): void; constructor(options?: FormatterOptions); /** * Find all the rests in each of the `voices` and align them vertically to neighboring notes. * * @param voices * @param alignAllNotes If `false`, only align rests within beamed groups of notes. If `true`, align all rests. */ alignRests(voices: Voice[], alignAllNotes: boolean): void; /** * Estimate the width required to render 'voices'. This is done by: * 1. Sum the widths of all the tick contexts * 2. Estimate the padding. * The latter is done by calculating the padding 3 different ways, and taking the * greatest value: * 1. the padding required for unaligned notes in different voices * 2. the padding based on the stddev of the tickable widths * 3. the padding based on the stddev of the tickable durations. * * The last 2 quantities estimate a 'width entropy', where notes might need more * room than the proportional formatting gives them. A measure of all same duration * and width will need no extra padding, and all these quantities will be * zero in that case. * * Note: joinVoices has to be called before calling preCalculateMinTotalWidth. * * @param voices the voices that contain the notes * @returns the estimated width in pixels */ preCalculateMinTotalWidth(voices: Voice[]): number; /** * Get minimum width required to render all voices. Either `format` or * `preCalculateMinTotalWidth` must be called before this method. */ getMinTotalWidth(): number; /** Calculate the resolution multiplier for `voices`. */ static getResolutionMultiplier(voices: Voice[]): number; /** Create a `ModifierContext` for each tick in `voices`. */ createModifierContexts(voices: Voice[]): void; /** * Create a `TickContext` for each tick in `voices`. Also calculate the * total number of ticks in voices. */ createTickContexts(voices: Voice[]): AlignmentContexts<TickContext>; /** * Get the AlignmentContexts of TickContexts that were created by createTickContexts. * Returns undefined if createTickContexts has not yet been run. */ getTickContexts(): AlignmentContexts<TickContext> | undefined; /** * This is the core formatter logic. Format voices and justify them * to `justifyWidth` pixels. `renderingContext` is required to justify elements * that can't retrieve widths without a canvas. This method sets the `x` positions * of all the tickables/notes in the formatter. */ preFormat(justifyWidth?: number, renderingContext?: RenderContext, voicesParam?: Voice[], stave?: Stave): number; /** Calculate the total cost of this formatting decision. */ evaluate(): number; /** * Run a single iteration of rejustification. At a high level, this method calculates * the overall "loss" (or cost) of this layout, and repositions tickcontexts in an * attempt to reduce the cost. You can call this method multiple times until it finds * and oscillates around a global minimum. * @param options parameters for tuning, currently just "alpha". * @param options[alpha] the "learning rate" for the formatter. It determines how much of a shift * the formatter should make based on its cost function. Defaults to 0.5. */ tune(options?: { alpha?: number; }): number; /** * This is the top-level call for all formatting logic completed * after `x` *and* `y` values have been computed for the notes * in the voices. */ postFormat(): this; /** * Take all `voices` and create `ModifierContext`s out of them. This tells * the formatters that the voices belong on a single stave. */ joinVoices(voices: Voice[]): this; /** * Align rests in voices, justify the contexts, and position the notes * so voices are aligned and ready to render onto the stave. This method * mutates the `x` positions of all tickables in `voices`. * * Voices are full justified to fit in `justifyWidth` pixels. * * Set `options.context` to the rendering context. Set `options.alignRests` * to true to enable rest vertical alignment. */ format(voices: Voice[], justifyWidth?: number, options?: FormatParams): this; formatToStave(voices: Voice[], stave: Stave, optionsParam?: FormatParams): this; getTickContext(tick: number): TickContext | undefined; }