Skip to content

Commit

Permalink
Starting to work on MuseScore cursor
Browse files Browse the repository at this point in the history
  • Loading branch information
infojunkie committed Oct 7, 2024
1 parent 4775254 commit bf22af1
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 42 deletions.
1 change: 1 addition & 0 deletions dist/musicxml-player.esm.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.player-sheet {
overflow: auto;
position: relative;
}
.player-cursor {
z-index: 2;
Expand Down
76 changes: 58 additions & 18 deletions dist/musicxml-player.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4121,6 +4121,12 @@ function atoab(base64) {
return Uint8Array.from(atob(base64), c => c.charCodeAt(0)).buffer;
}

function assertIsDefined(value) {
if (value === undefined || value === null) {
throw new Error(`Unexpected ${value} value found.`);
}
}

const createExtendedExponentialRampToValueAutomationEvent = (value, endTime, insertTime) => {
return { endTime, insertTime, type: 'exponentialRampToValue', value };
};
Expand Down Expand Up @@ -15310,8 +15316,12 @@ URL.revokeObjectURL(url);
class MuseScoreRendererConverter {
constructor(_downloader) {
this._downloader = _downloader;
this._cursor = document.createElement('div');
this._cursor.className = 'player-cursor';
}
destroy() {
this._cursor.remove();
}
destroy() { }
initialize(container, musicXml) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
Expand Down Expand Up @@ -15358,18 +15368,49 @@ class MuseScoreRendererConverter {
if (this._timemap.length > 1) {
this._timemap.last().duration = this._timemap[this._timemap.length - 2].duration;
}
// Store info we'll need later.
this._positions = SaxonJS.XPath.evaluate('//elements/element', mpos).map(element => {
return {
x: parseInt(element.getAttribute('x')),
y: parseInt(element.getAttribute('y')),
sx: parseInt(element.getAttribute('sx')),
sy: parseInt(element.getAttribute('sy')),
page: parseInt(element.getAttribute('page')),
};
});
}
// Render the SVGs.
(_a = this._media) === null || _a === void 0 ? void 0 : _a.svgs.forEach(svg => {
(_a = this._media) === null || _a === void 0 ? void 0 : _a.svgs.forEach((svg, i) => {
var _a;
const page = document.createElement('div');
page.setAttribute('id', `page-${i}`);
page.innerHTML = window.atob(svg);
(_a = page.getElementsByTagName('path')[0]) === null || _a === void 0 ? void 0 : _a.setAttribute('fill', 'transparent');
container.appendChild(page);
});
// Initialize the cursor.
container.parentElement.appendChild(this._cursor);
});
}
moveTo(_index, _start, _offset, _duration) { }
moveTo(_index, _start, _offset, _duration) {
assertIsDefined(this._timemap);
assertIsDefined(this._positions);
const index = binarySearch(this._timemap, {
measure: 0,
timestamp: _start,
duration: 0,
}, (a, b) => {
const d = a.timestamp - b.timestamp;
if (Math.abs(d) < Number.EPSILON)
return 0;
return d;
});
this._positions[index].x;
this._positions[index].y;
this._positions[index].sy;
this._cursor.style.transform = `translate()`;
this._cursor.style.height = ``;
}
resize() { }
get midi() {
if (!this._midi)
Expand Down Expand Up @@ -15811,9 +15852,9 @@ class VerovioRenderer {
this._cursor.className = 'player-cursor';
}
destroy() {
var _a, _b;
(_a = this._cursor) === null || _a === void 0 ? void 0 : _a.remove();
(_b = this._vrv) === null || _b === void 0 ? void 0 : _b.destroy();
var _a;
this._cursor.remove();
(_a = this._vrv) === null || _a === void 0 ? void 0 : _a.destroy();
}
initialize(container, musicXml) {
return __awaiter(this, void 0, void 0, function* () {
Expand Down Expand Up @@ -15900,17 +15941,16 @@ class VerovioRenderer {
this._move();
}
resize() {
if (this._container && this._vrv) {
this._redraw();
// Force the notes highlighting and cursor position to be recalculated.
this._notes = [];
this.moveTo(this._measure.index, this._measure.start, this._measure.offset, this._measure.duration);
}
assertIsDefined(this._container);
assertIsDefined(this._vrv);
this._redraw();
// Force the notes highlighting and cursor position to be recalculated.
this._notes = [];
this.moveTo(this._measure.index, this._measure.start, this._measure.offset, this._measure.duration);
}
get version() {
if (!this._vrv)
throw 'TODO';
return `verovio v${this._vrv.getVersion()}`;
var _a, _b;
return `verovio v${(_b = (_a = this._vrv) === null || _a === void 0 ? void 0 : _a.getVersion()) !== null && _b !== void 0 ? _b : `Unknown`}`;
}
_isHorizontalLayout() {
return this._vrvOptions.breaks === 'none';
Expand Down Expand Up @@ -15943,8 +15983,8 @@ class VerovioRenderer {
}
_redraw() {
var _a, _b, _c;
if (!this._container || !this._vrv)
throw 'TODO';
assertIsDefined(this._container);
assertIsDefined(this._vrv);
this._vrv.setOptions(Object.assign(Object.assign({}, this._vrvOptions), {
pageHeight: (this._container.parentElement.clientHeight * 100) /
((_a = this._vrvOptions.scale) !== null && _a !== void 0 ? _a : 100),
Expand Down Expand Up @@ -16235,5 +16275,5 @@ var _polyfillNode_module = /*#__PURE__*/Object.freeze({
__proto__: null
});

export { FetchConverter, MidiControllerMessage, MidiRegisteredParameterNumber, MmaConverter, MuseScoreRendererConverter, OpenSheetMusicDisplayRenderer, Player, VerovioConverter, VerovioRenderer, WebAudioFontOutput, atoab, binarySearch, fetish, parseMidiEvent, parseMidiFile, parseMusicXML };
export { FetchConverter, MidiControllerMessage, MidiRegisteredParameterNumber, MmaConverter, MuseScoreRendererConverter, OpenSheetMusicDisplayRenderer, Player, VerovioConverter, VerovioRenderer, WebAudioFontOutput, assertIsDefined, atoab, binarySearch, fetish, parseMidiEvent, parseMidiFile, parseMusicXML };
//# sourceMappingURL=musicxml-player.esm.js.map
2 changes: 1 addition & 1 deletion dist/musicxml-player.esm.js.map

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions dist/types/MuseScoreRendererConverter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export declare class MuseScoreRendererConverter implements ISheetRenderer, IMidi
private _media?;
private _midi?;
private _timemap?;
private _cursor;
private _positions?;
constructor(_downloader: string | MuseScoreDownloader | ReturnType<MuseScoreDownloader>);
destroy(): void;
initialize(container: HTMLElement, musicXml: string): Promise<void>;
Expand Down
2 changes: 1 addition & 1 deletion dist/types/MuseScoreRendererConverter.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/types/VerovioRenderer.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions dist/types/helpers/assertions.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export declare function assertIsDefined<T>(value: T): asserts value is NonNullable<T>;
//# sourceMappingURL=assertions.d.ts.map
1 change: 1 addition & 0 deletions dist/types/helpers/assertions.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/types/helpers/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './parse-musicxml';
export * from './midi-controller-message';
export * from './midi-registered-parameter-number';
export * from './arraybuffer-base64';
export * from './assertions';
//# sourceMappingURL=index.d.ts.map
2 changes: 1 addition & 1 deletion dist/types/helpers/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 54 additions & 5 deletions src/MuseScoreRendererConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { IMidiFile } from 'midi-json-parser-worker';
import type { IMidiConverter, MeasureTimemap } from './IMidiConverter';
import type { ISheetRenderer } from './ISheetRenderer';
import type { MeasureIndex, MillisecsTimestamp } from './Player';
import { atoab, fetish } from './helpers';
import { atoab, fetish, binarySearch, assertIsDefined } from './helpers';
import SaxonJS from './saxon-js/SaxonJS2.rt';

export type MuseScoreDownloader = (musicXml: string) => {
Expand Down Expand Up @@ -69,10 +69,23 @@ export class MuseScoreRendererConverter implements ISheetRenderer, IMidiConverte
private _media?: ReturnType<MuseScoreDownloader>;
private _midi?: IMidiFile;
private _timemap?: MeasureTimemap;
private _cursor: HTMLDivElement;
private _positions?: {
x: number,
y: number,
sx: number,
sy: number,
page: number
}[];

constructor(private _downloader: string | MuseScoreDownloader | ReturnType<MuseScoreDownloader>) {}
constructor(private _downloader: string | MuseScoreDownloader | ReturnType<MuseScoreDownloader>) {
this._cursor = document.createElement('div');
this._cursor.className = 'player-cursor';
}

destroy(): void {}
destroy(): void {
this._cursor.remove();
}

async initialize(
container: HTMLElement,
Expand Down Expand Up @@ -124,23 +137,59 @@ export class MuseScoreRendererConverter implements ISheetRenderer, IMidiConverte
if (this._timemap.length > 1) {
this._timemap.last().duration = this._timemap[this._timemap.length - 2].duration;
}

// Store info we'll need later.
this._positions = (<any[]>SaxonJS.XPath.evaluate('//elements/element', mpos)).map(element => { return {
x: parseInt(element.getAttribute('x')),
y: parseInt(element.getAttribute('y')),
sx: parseInt(element.getAttribute('sx')),
sy: parseInt(element.getAttribute('sy')),
page: parseInt(element.getAttribute('page')),
}});
}

// Render the SVGs.
this._media?.svgs.forEach(svg => {
this._media?.svgs.forEach((svg, i) => {
const page = document.createElement('div');
page.setAttribute('id', `page-${i}`);
page.innerHTML = window.atob(svg);
page.getElementsByTagName('path')[0]?.setAttribute('fill', 'transparent');
container.appendChild(page);
});

// Initialize the cursor.
container.parentElement!.appendChild(this._cursor);
}

moveTo(
_index: MeasureIndex,
_start: MillisecsTimestamp,
_offset: MillisecsTimestamp,
_duration?: MillisecsTimestamp,
): void {}
): void {
assertIsDefined(this._timemap);
assertIsDefined(this._positions);

const index = binarySearch(
this._timemap,
{
measure: 0,
timestamp: _start,
duration: 0,
},
(a, b) => {
const d = a.timestamp - b.timestamp;
if (Math.abs(d) < Number.EPSILON) return 0;
return d;
},
);

const x = this._positions[index].x;
const y = this._positions[index].y;
const height = this._positions[index].sy;
this._cursor.style.transform = `translate()`;
this._cursor.style.height = ``;
}

resize(): void {}

Expand Down
32 changes: 17 additions & 15 deletions src/VerovioRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import createVerovioModule from 'verovio/wasm';
import { VerovioToolkit } from 'verovio/esm';
import { VerovioOptions } from 'verovio';
import { MeasureTimemap } from './IMidiConverter';
import { assertIsDefined } from './helpers';

export interface TimemapEntryFixed {
tstamp: number;
Expand Down Expand Up @@ -106,7 +107,7 @@ export class VerovioRenderer implements ISheetRenderer {
}

destroy() {
this._cursor?.remove();
this._cursor.remove();
this._vrv?.destroy();
}

Expand Down Expand Up @@ -212,23 +213,23 @@ export class VerovioRenderer implements ISheetRenderer {
}

resize(): void {
if (this._container && this._vrv) {
this._redraw();
assertIsDefined(this._container);
assertIsDefined(this._vrv);

// Force the notes highlighting and cursor position to be recalculated.
this._notes = [];
this.moveTo(
this._measure.index,
this._measure.start,
this._measure.offset,
this._measure.duration,
);
}
this._redraw();

// Force the notes highlighting and cursor position to be recalculated.
this._notes = [];
this.moveTo(
this._measure.index,
this._measure.start,
this._measure.offset,
this._measure.duration,
);
}

get version(): string {
if (!this._vrv) throw 'TODO';
return `verovio v${this._vrv.getVersion()}`;
return `verovio v${this._vrv?.getVersion() ?? `Unknown`}`;
}

private _isHorizontalLayout(): boolean {
Expand Down Expand Up @@ -265,7 +266,8 @@ export class VerovioRenderer implements ISheetRenderer {
}

private _redraw() {
if (!this._container || !this._vrv) throw 'TODO';
assertIsDefined(this._container);
assertIsDefined(this._vrv);

this._vrv.setOptions({
...this._vrvOptions,
Expand Down
Loading

0 comments on commit bf22af1

Please sign in to comment.