Skip to content

Commit

Permalink
Merge pull request #898 from rvilarl/migration/stemmablenote
Browse files Browse the repository at this point in the history
Migration/stemmablenote
  • Loading branch information
0xfe authored Apr 15, 2021
2 parents 4361321 + 5adca1b commit 4add403
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 49 deletions.
3 changes: 2 additions & 1 deletion src/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface NoteRenderOptions {
y_shift?: number;
extend_left?: number;
extend_right?: number;
glyph_font_scale?: number;
glyph_font_scale: number;
annotation_spacing: number;
glyph_font_size?: number;
scale?: number;
Expand Down Expand Up @@ -302,6 +302,7 @@ export abstract class Note extends Tickable {
// The render surface.
this.render_options = {
annotation_spacing: 5,
glyph_font_scale: 1,
};
}

Expand Down
111 changes: 64 additions & 47 deletions src/stemmablenote.js → src/stemmablenote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,67 @@ import { Vex } from './vex';
import { Flow } from './tables';
import { Stem } from './stem';
import { Glyph } from './glyph';
import { Note } from './note';
import { Note, NoteStruct } from './note';
import { GlyphProps } from './glyph';

//** TODO: Move to Stem.ts */
export interface StemStruct {
stem_down_y_base_offset: number;
stem_up_y_base_offset: number;
stem_down_y_offset: number;
stem_up_y_offset: number;
stemletHeight: number;
isStemlet: boolean;
hide: boolean;
stem_direction: number;
stem_extension: number;
y_bottom: number;
y_top: number;
x_end: number;
x_begin: number;
}

export abstract class StemmableNote extends Note {
stem_direction?: number;
stem?: Stem;

protected flag?: Glyph;
protected stem_extension_override?: number;

export class StemmableNote extends Note {
constructor(note_struct) {
constructor(note_struct: NoteStruct) {
super(note_struct);
this.setAttribute('type', 'StemmableNote');

this.stem = null;
this.stem_extension_override = null;
this.beam = null;
}

// Get and set the note's `Stem`
getStem() {
getStem(): Stem | undefined {
return this.stem;
}
setStem(stem) {

setStem(stem: Stem): this {
this.stem = stem;
return this;
}

// Builds and sets a new stem
buildStem() {
buildStem(): this {
const stem = new Stem();
this.setStem(stem);
return this;
}

buildFlag(category = 'flag') {
const { glyph, beam } = this;
const shouldRenderFlag = beam === null;
buildFlag(category = 'flag'): void {
const { glyph } = this;

if (glyph && glyph.flag && shouldRenderFlag) {
if (this.hasFlag()) {
const flagCode = this.getStemDirection() === Stem.DOWN ? glyph.code_flag_downstem : glyph.code_flag_upstem;

this.flag = new Glyph(flagCode, this.render_options.glyph_font_scale, { category });
}
}

// Get the custom glyph associated with the outer note head on the base of the stem.
getBaseCustomNoteHeadGlyph() {
getBaseCustomNoteHeadGlyph(): GlyphProps {
if (this.getStemDirection() === Stem.DOWN) {
return this.customGlyphs[this.customGlyphs.length - 1];
} else {
Expand All @@ -57,12 +77,12 @@ export class StemmableNote extends Note {
}

// Get the full length of stem
getStemLength() {
getStemLength(): number {
return Stem.HEIGHT + this.getStemExtension();
}

// Get the number of beams for this duration
getBeamCount() {
getBeamCount(): number {
const glyph = this.getGlyph();

if (glyph) {
Expand All @@ -73,7 +93,7 @@ export class StemmableNote extends Note {
}

// Get the minimum length of stem
getStemMinimumLength() {
getStemMinimumLength(): number {
const frac = Flow.durationToFraction(this.duration);
let length = frac.value() <= 1 ? 0 : 20;
// if note is flagged, cannot shorten beam
Expand All @@ -100,10 +120,11 @@ export class StemmableNote extends Note {
}

// Get/set the direction of the stem
getStemDirection() {
getStemDirection(): number | undefined {
return this.stem_direction;
}
setStemDirection(direction) {

setStemDirection(direction: number): this {
if (!direction) direction = Stem.UP;
if (direction !== Stem.UP && direction !== Stem.DOWN) {
throw new Vex.RERR('BadArgument', `Invalid stem direction: ${direction}`);
Expand Down Expand Up @@ -138,18 +159,18 @@ export class StemmableNote extends Note {

// Reset and reformat everything.
this.reset();
if (this.flag) {
if (this.hasFlag()) {
this.buildFlag();
}
this.beam = null;
this.beam = undefined;
if (this.preFormatted) {
this.preFormat();
}
return this;
}

// Get the `x` coordinate of the stem
getStemX() {
getStemX(): number {
const x_begin = this.getAbsoluteX() + this.x_shift;
const x_end = this.getAbsoluteX() + this.x_shift + this.getGlyphWidth();
const stem_x = this.stem_direction === Stem.DOWN ? x_begin : x_end;
Expand All @@ -158,12 +179,12 @@ export class StemmableNote extends Note {

// Get the `x` coordinate for the center of the glyph.
// Used for `TabNote` stems and stemlets over rests
getCenterGlyphX() {
getCenterGlyphX(): number {
return this.getAbsoluteX() + this.x_shift + this.getGlyphWidth() / 2;
}

// Get the stem extension for the current duration
getStemExtension() {
getStemExtension(): number {
const glyph = this.getGlyph();

if (this.stem_extension_override != null) {
Expand All @@ -178,26 +199,21 @@ export class StemmableNote extends Note {
}

// Set the stem length to a specific. Will override the default length.
setStemLength(height) {
setStemLength(height: number): this {
this.stem_extension_override = height - Stem.HEIGHT;
return this;
}

// Get the top and bottom `y` values of the stem.
getStemExtents() {
return this.stem.getExtents();
getStemExtents(): Record<string, number> | undefined {
return this.stem?.getExtents();
}

// Sets the current note's beam
setBeam(beam) {
this.beam = beam;
return this;
}

// Get the `y` value for the top/bottom modifiers at a specific `textLine`
getYForTopText(textLine) {
/** Gets the `y` value for the top modifiers at a specific `textLine`. */
getYForTopText(textLine: number): number {
if (!this.stave) throw new Vex.RERR('NoStave', 'No stave attached to this note.');
const extents = this.getStemExtents();
if (this.hasStem()) {
if (extents) {
return Math.min(
this.stave.getYForTopText(textLine),
extents.topY - this.render_options.annotation_spacing * (textLine + 1)
Expand All @@ -207,9 +223,11 @@ export class StemmableNote extends Note {
}
}

getYForBottomText(textLine) {
/** Gets the `y` value for the bottom modifiers at a specific `textLine`. */
getYForBottomText(textLine: number): number {
if (!this.stave) throw new Vex.RERR('NoStave', 'No stave attached to this note.');
const extents = this.getStemExtents();
if (this.hasStem()) {
if (extents) {
return Math.max(
this.stave.getYForTopText(textLine),
extents.baseY + this.render_options.annotation_spacing * textLine
Expand All @@ -219,25 +237,24 @@ export class StemmableNote extends Note {
}
}

hasFlag() {
hasFlag(): boolean {
return Flow.getGlyphProps(this.duration).flag && !this.beam;
}

// Post format the note
postFormat() {
if (this.beam) this.beam.postFormat();

/** Post formats the note. */
postFormat(): this {
this.beam?.postFormat();
this.postFormatted = true;

return this;
}

// Render the stem onto the canvas
drawStem(stem_struct) {
/** Renders the stem onto the canvas. */
drawStem(stem_struct: StemStruct): void {
this.checkContext();
this.setRendered();

this.setStem(new Stem(stem_struct));
this.stem.setContext(this.context).draw();
this.stem?.setContext(this.getContext()).draw();
}
}
5 changes: 4 additions & 1 deletion src/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const Flow = {
keyProperties: keyProperties,
integerToNote: integerToNote,
durationToTicks: durationToTicks,
durationToFraction: durationToFraction,
getGlyphProps: getGlyphProps,
};

Expand Down Expand Up @@ -697,7 +698,9 @@ Flow.sanitizeDuration = (duration) => {
};

// Convert the `duration` to an fraction
Flow.durationToFraction = (duration) => new Fraction().parse(Flow.sanitizeDuration(duration));
function durationToFraction(duration) {
return new Fraction().parse(Flow.sanitizeDuration(duration));
}

// Convert the `duration` to an number
Flow.durationToNumber = (duration) => Flow.durationToFraction(duration).value();
Expand Down
3 changes: 3 additions & 0 deletions typedoc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
export * from './src/element';
export * from './src/font';
export * from './src/fraction';
export * from './src/glyph';
export * from './src/gracenotegroup';
export * from './src/music';
export * from './src/note';
export * from './src/stemmablenote';
export * from './src/tickable';
export * from './src/tickcontext';
export * from './src/tuning';
Expand Down

0 comments on commit 4add403

Please sign in to comment.