Skip to content

Commit

Permalink
Merge pull request #251 from cuthbertLab/older-lyrics
Browse files Browse the repository at this point in the history
Restore v0.14 lyrics
  • Loading branch information
mscuthbert authored Jun 11, 2024
2 parents 1fa6524 + 4265d5f commit 56ccf5b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 131 deletions.
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Music21j

**Music21j: An Interactive Framework for Musical Analysis**

Copyright ©2013-21, Michael Scott Asato Cuthbert, some rights reserved (BSD).
Copyright (c) 2013-24, Michael Scott Asato Cuthbert, some rights reserved (BSD).

**Music21j** is a Javascript reinterpretation of the [Music21 Python] package,
a toolkit for computer-aided musicology, now with intuitive HTML/Javascript
Expand All @@ -22,11 +22,9 @@ point we're focusing on documenting usage; developer docs will come
later.

Music21j requires your users to have a relatively recent web browser -- the project
targets browsers no more than two years old.
Safari 9+, Chrome since 2015 (v.32+), Edge 14+, or Firefox since 2014 (v. 26+).
Internet Explorer 11+ is currently supported, though timing of playback can be a bit off, but
support for it will be removed soon. Microsoft Edge is the only major desktop browser for which
there is no support for MIDI devices.
targets browsers no more than 30 months old.
Safari is the only major desktop browser for which there is no out of the box
support for MIDI devices.

Documentation
-------------
Expand Down Expand Up @@ -102,7 +100,7 @@ const n = new music21.note.Note('F#');

Version
--------
0.15 beta
0.16 beta


License
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "music21j",
"version": "0.15.8",
"version": "0.16.0",
"description": "A toolkit for computer-aided musicology, Javascript version",
"main": "releases/music21.debug.js",
"typings": "releases/src/main.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,6 @@ export {
webmidi,
};

export const VERSION = '0.15.8';
export const VERSION = '0.16.0';

parseLoader.runConfiguration();
13 changes: 10 additions & 3 deletions src/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ export class Lyric extends prebase.ProtoM21Object {
}

vexflowLyric({lyric_line=-3}: VexflowLyricOptions = {}): VFLyricAnnotation|null {
// This was used in music21 0.15 and will be again in the future once
// VexFlow no longer spills into next measure. For now, it is UNUSED.
if (!this.text) {
return null;
}
Expand Down Expand Up @@ -413,14 +415,17 @@ export class GeneralNote extends base.Music21Object {
keys: [],
duration: this.duration.vexflowDuration + 'r',
});
this.vexflowAddLyrics(vfn);
// not until later version
// this.vexflowAddLyrics(vfn);
return vfn;
}

/**
* Add lyrics to the VFStaveNote as Annotation objects.
*/
vexflowAddLyrics(vfn: VFStaveNote): void {
// This was used in music21 0.15 and will be again in the future once
// VexFlow no longer spills into next measure. For now it is UNUSED.
const lyric_line = this.activeSite?.renderOptions.lyricsLine ?? -3;
for (const l of this.lyrics) {
const vf_lyric = l.vexflowLyric({lyric_line});
Expand Down Expand Up @@ -595,7 +600,8 @@ export class NotRest extends GeneralNote {
strokeStyle: this.noteheadColor,
});
}
this.vexflowAddLyrics(vfn);
// not until next version...
// this.vexflowAddLyrics(vfn);
this.activeVexflowNote = vfn;
return vfn;
}
Expand Down Expand Up @@ -879,7 +885,8 @@ export class Rest extends GeneralNote {
strokeStyle: this.color,
});
}
this.vexflowAddLyrics(vfn);
// not until next version of vexflow.
// this.vexflowAddLyrics(vfn);
this.activeVexflowNote = vfn;
return vfn;
}
Expand Down
2 changes: 1 addition & 1 deletion src/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1967,7 +1967,7 @@ export class Stream<ElementType extends base.Music21Object = base.Music21Object>
*
* Will be moved to vfShow eventually when converter objects are enabled...maybe.
*
* Takes in a canvas or the div surrounding an SVG object
* Takes in the div surrounding an SVG object (or a canvas)
*/
renderVexflow(where?: HTMLDivElement|HTMLCanvasElement): vfShow.Renderer {
const canvasOrSVG = <HTMLDivElement|HTMLCanvasElement> common.coerceHTMLElement(where);
Expand Down
3 changes: 3 additions & 0 deletions src/vfShims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
* Based on music21 (music21p), Copyright (c) 2006-24, Michael Scott Asato Cuthbert
*
* The infamous vfShims returns! To fix things that Vexflow makes hard to fix!
*
* These were used in 0.15.x on the new lyrics, but are currently unused, since
* the new lyrics in Vexflow would cause staves to overflow.
*/

import {
Expand Down
199 changes: 98 additions & 101 deletions src/vfShow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ import {
Stave as VFStave, StaveConnector as VFStaveConnector,
type StaveConnectorType as VFStaveConnectorType,
StaveNote as VFStaveNote,
StaveTie as VFStaveTie, SVGContext as VFSVGContext, // TextNote as VFTextNote,
StaveTie as VFStaveTie, SVGContext as VFSVGContext,
TextNote as VFTextNote,
Tuplet as VFTuplet, Voice as VFVoice,
} from 'vexflow';
// import type {FontInfo as VFFontInfo} from 'vexflow/src/font';
import type {FontInfo as VFFontInfo} from 'vexflow/src/font';

import { debug } from './debug';
import * as clef from './clef';
// import * as duration from './duration';
import * as duration from './duration';
import * as note from './note'; // for default_vf_lyric_style -- can move later if import prob.
import * as stream from './stream'; // this is able to be imported fine.

import {coerceHTMLElement} from './common';

// imports for typechecking only
import type * as note from './note';
import type * as renderOptions from './renderOptions';
import type {Tuplet} from './duration';
import {StaveConnector} from './types';
Expand Down Expand Up @@ -58,16 +59,16 @@ const _clefSingleton = new clef.TrebleClef();
export class RenderStack {
streams: stream.Stream[] = [];
voices: VFVoice[] = []; // for the music
// textVoices: VFVoice[] = []; // for lyrics
textVoices: VFVoice[] = []; // for lyrics
voiceToStreamMapping: Map<VFVoice, stream.Stream> = new Map();

/**
* returns this.voices as a new array
* returns this.voices and this.textVoices as one, new array.
*/
allTickables(): VFVoice[] {
const t: VFVoice[] = [];
t.push(...this.voices);
// t.push(...this.textVoices);
t.push(...this.textVoices);
return t;
}

Expand Down Expand Up @@ -352,9 +353,9 @@ export class Renderer {
stack.streams.push(s);
stack.voiceToStreamMapping.set(vf_voice, s);

// if (s.hasLyrics()) {
// stack.textVoices.push(...this.getLyricVoices(s, stave));
// }
if (s.hasLyrics()) {
stack.textVoices.push(...this.getLyricVoices(s, stave));
}
return stave;
}

Expand Down Expand Up @@ -382,7 +383,7 @@ export class Renderer {
}

/**
* Draws the Voices (just music no longer text) from `this.stacks`
* Draws the Voices (music and text) from `this.stacks`
*
*/
drawMeasureStacks(): void {
Expand Down Expand Up @@ -538,20 +539,20 @@ export class Renderer {
*
* s -- usually a Measure or Voice
*/
// getLyricVoices(s: stream.Stream, stave: VFStave): VFVoice[] {
// const textVoices = [];
// const max_lyric_depth = Math.max(...s.notesAndRests.map(
// (gn => gn.lyrics.length)
// ));
// for (let depth = 0; depth < max_lyric_depth + 1; depth++) {
// const textVoice = this.vexflowVoice(s);
// const lyrics: VFTextNote[] = this.vexflowLyrics(s, stave, depth);
// textVoice.setStave(stave);
// textVoice.addTickables(lyrics);
// textVoices.push(textVoice);
// }
// return textVoices;
// }
getLyricVoices(s: stream.Stream, stave: VFStave): VFVoice[] {
const textVoices = [];
const max_lyric_depth = Math.max(...s.notesAndRests.map(
(gn => gn.lyrics.length)
));
for (let depth = 0; depth < max_lyric_depth + 1; depth++) {
const textVoice = this.vexflowVoice(s);
const lyrics: VFTextNote[] = this.vexflowLyrics(s, stave, depth);
textVoice.setStave(stave);
textVoice.addTickables(lyrics);
textVoices.push(textVoice);
}
return textVoices;
}

/**
* Aligns all of `this.stacks` (after they've been prepared) so they align properly.
Expand Down Expand Up @@ -953,56 +954,52 @@ export class Renderer {
return notes;
}

// /**
// * Gets an Array of `Vex.Flow.TextNote` objects from any lyrics found in s at a given lyric depth.
// */
// vexflowLyrics(s: stream.Stream, stave?: VFStave, depth: number=0): VFTextNote[] {
// // runs on a flat, gapless, no-overlap stream, returns a list of TextNote objects...
// const lyricTextNotes: VFTextNote[] = [];
// for (const el of s.notesAndRests) {
// const lyricsArray = el.lyrics;
// if (lyricsArray === undefined) {
// continue;
// }
// let text: string = '';
// let d = el.duration;
//
// // connectors deal with hyphens.
// let addConnector: boolean|string = false;
// const font = {
// family: 'Serif',
// size: 12,
// weight: '',
// };
//
// const lyricAtDepth = lyricsArray[depth]; // rename lyricAtDepth
// if (lyricAtDepth) {
// text = lyricAtDepth.text ?? '';
// if (['middle', 'begin'].includes(lyricAtDepth.syllabic)) {
// addConnector = ' ' + lyricAtDepth.lyricConnector;
// const tempQl = el.duration.quarterLength / 2.0;
// d = new duration.Duration(tempQl);
// }
// if (lyricAtDepth.style.fontFamily) {
// font.family = lyricAtDepth.style.fontFamily;
// }
// if (lyricAtDepth.style.fontSize) {
// font.size = lyricAtDepth.style.fontSize;
// }
// if (lyricAtDepth.style.fontWeight) {
// font.weight = lyricAtDepth.style.fontWeight;
// }
// }
// const line = 11 + (depth * 2);
// const t1 = getTextNote(text, font, d, stave, lyricAtDepth, line);
// lyricTextNotes.push(t1);
// if (addConnector !== false) {
// const connector = getTextNote(addConnector, font, d, stave, undefined, line);
// lyricTextNotes.push(connector);
// }
// }
// return lyricTextNotes;
// }
/**
* Gets an Array of `Vex.Flow.TextNote` objects from any lyrics found in s at a given lyric depth.
*/
vexflowLyrics(s: stream.Stream, stave?: VFStave, depth: number=0): VFTextNote[] {
// runs on a flat, gapless, no-overlap stream, returns a list of TextNote objects...
const lyricTextNotes: VFTextNote[] = [];
for (const el of s.notesAndRests) {
const lyricsArray = el.lyrics;
if (lyricsArray === undefined) {
continue;
}
let text: string = '';
let d = el.duration;

// connectors deal with hyphens.
let addConnector: boolean|string = false;
const font = {...note.default_vf_lyric_style} as VFFontInfo;

const lyricAtDepth = lyricsArray[depth]; // rename lyricAtDepth
if (lyricAtDepth) {
text = lyricAtDepth.text ?? '';
if (['middle', 'begin'].includes(lyricAtDepth.syllabic)) {
addConnector = ' ' + lyricAtDepth.lyricConnector;
const tempQl = el.duration.quarterLength / 2.0;
d = new duration.Duration(tempQl);
}
if (lyricAtDepth.style.fontFamily) {
font.family = lyricAtDepth.style.fontFamily;
}
if (lyricAtDepth.style.fontSize) {
font.size = lyricAtDepth.style.fontSize;
}
if (lyricAtDepth.style.fontWeight) {
font.weight = lyricAtDepth.style.fontWeight;
}
}
const line = 11 + (depth * 2);
const t1 = getTextNote(text, font, d, stave, lyricAtDepth, line);
lyricTextNotes.push(t1);
if (addConnector !== false) {
const connector = getTextNote(addConnector, font, d, stave, undefined, line);
lyricTextNotes.push(connector);
}
}
return lyricTextNotes;
}

/**
* Creates a Vex.Flow.Voice of the appropriate length given a Stream.
Expand Down Expand Up @@ -1248,32 +1245,32 @@ export class Renderer {
}
}

// export function getTextNote(
// text: string,
// font: VFFontInfo,
// d: duration.Duration,
// stave: VFStave,
// lyricObj: note.Lyric = undefined,
// line: number = 11,
// ): VFTextNote {
// // console.log(text, font, d);
// // noinspection TypeScriptValidateJSTypes
// const t1 = new VFTextNote({
// text,
// font,
// duration: d.vexflowDuration,
// })
// .setLine(line)
// .setStave(stave)
// .setJustification(VFTextNote.Justification.LEFT);
// if (lyricObj) {
// t1.setStyle(lyricObj.style);
// }
// if (d.tuplets.length > 0) {
// t1.applyTickMultiplier(d.tuplets[0].numberNotesNormal, d.tuplets[0].numberNotesActual);
// }
// return t1;
// }
export function getTextNote(
text: string,
font: VFFontInfo,
d: duration.Duration,
stave: VFStave,
lyricObj: note.Lyric = undefined,
line: number = 11,
): VFTextNote {
// console.log(text, font, d);
// noinspection TypeScriptValidateJSTypes
const t1 = new VFTextNote({
text,
font,
duration: d.vexflowDuration,
})
.setLine(line)
.setStave(stave)
.setJustification(VFTextNote.Justification.LEFT);
if (lyricObj) {
t1.setStyle({fillStyle: lyricObj.style.color});
}
if (d.tuplets.length > 0) {
t1.applyTickMultiplier(d.tuplets[0].numberNotesNormal, d.tuplets[0].numberNotesActual);
}
return t1;
}



Loading

0 comments on commit 56ccf5b

Please sign in to comment.