Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No output is produced by SVG renderer when used with Node.js #1854

Open
1 task done
cheap-glitch opened this issue Feb 11, 2025 · 1 comment
Open
1 task done

No output is produced by SVG renderer when used with Node.js #1854

cheap-glitch opened this issue Feb 11, 2025 · 1 comment
Assignees
Labels
area-documentation Related to documentation and sample code platform-javascript Related to the JavaScript version of alphaTab state-accepted This is a valid topic to work on. state-no-bug The reported problem is not a bug in alphaTab. type-question ❓

Comments

@cheap-glitch
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Using the low level APIs to render a Guitar Pro tab in Node doesn't produce any output. No error is being logged either.

Expected Behavior

The renderer should output some SVG markup.

Steps To Reproduce

This is the code I used, it's directly taken from the official guide on how to use alphaTab in Node.js:

Test code
import fs from "node:fs";
import process from "node:process";
import * as alphaTab from "@coderline/alphatab";

// 1. Load file
const fileData = fs.readFileSync(process.argv[2]);
const settings = new alphaTab.Settings();
const score = alphaTab.importer.ScoreLoader.loadScoreFromBytes(new Uint8Array(fileData), settings);
console.log(score);

// 2. Setup renderer
settings.core.engine = "svg";
const renderer = new alphaTab.rendering.ScoreRenderer(settings);
renderer.width = 1200;

// 3. Listen to events
let svgChunks = [];
renderer.error.on((error) => {
	console.error(error);
});
renderer.preRender.on((isResize) => {
	svgChunks = []; // Clear on new rendering
});
renderer.partialRenderFinished.on((r) => {
	svgChunks.push({
		svg: r.renderResult,
		width: r.width,
		height: r.height,
	});
});
renderer.renderFinished.on((r) => {
	console.log(svgChunks, r.totalWidth, r.totalHeight);
});

// 4. Fire off rendering
renderer.renderScore(score, [0]);

// 5. Log the SVG chunks
console.log(svgChunks.map((c) => c.svg).join("\n"));

When running this I can see some data being logged from the score object, so it's being imported correctly, but then nothing get rendered.

Output
<ref *1> Score {
  _currentRepeatGroup: <ref *2> RepeatGroup {
    masterBars: [ [MasterBar], [MasterBar] ],
    opening: MasterBar {
      alternateEndings: 0,
      nextMasterBar: [MasterBar],
      previousMasterBar: null,
      index: 0,
      keySignature: 0,
      keySignatureType: 0,
      isDoubleBar: false,
      isRepeatStart: false,
      repeatCount: 0,
      timeSignatureNumerator: 4,
      timeSignatureDenominator: 4,
      timeSignatureCommon: false,
      tripletFeel: 0,
      section: null,
      tempoAutomation: [Automation],
      fermata: null,
      start: 0,
      isAnacrusis: false,
      displayScale: 1,
      displayWidth: -1,
      score: [Circular *1],
      repeatGroup: [Circular *2]
    },
    closings: [],
    isClosed: false
  },
  _openedRepeatGroups: [
    <ref *2> RepeatGroup {
      masterBars: [Array],
      opening: [MasterBar],
      closings: [],
      isClosed: false
    }
  ],
  _properlyOpenedRepeatGroups: 0,
  album: '',
  artist: '',
  copyright: '',
  instructions: '',
  music: '',
  notices: '',
  subTitle: '',
  title: 'Lorem ipsum',
  words: '',
  tab: '',
  tempo: 120,
  tempoLabel: '',
  masterBars: [
    MasterBar {
      alternateEndings: 0,
      nextMasterBar: [MasterBar],
      previousMasterBar: null,
      index: 0,
      keySignature: 0,
      keySignatureType: 0,
      isDoubleBar: false,
      isRepeatStart: false,
      repeatCount: 0,
      timeSignatureNumerator: 4,
      timeSignatureDenominator: 4,
      timeSignatureCommon: false,
      tripletFeel: 0,
      section: null,
      tempoAutomation: [Automation],
      fermata: null,
      start: 0,
      isAnacrusis: false,
      displayScale: 1,
      displayWidth: -1,
      score: [Circular *1],
      repeatGroup: [RepeatGroup]
    },
    MasterBar {
      alternateEndings: 0,
      nextMasterBar: null,
      previousMasterBar: [MasterBar],
      index: 1,
      keySignature: 0,
      keySignatureType: 0,
      isDoubleBar: false,
      isRepeatStart: false,
      repeatCount: 0,
      timeSignatureNumerator: 4,
      timeSignatureDenominator: 4,
      timeSignatureCommon: false,
      tripletFeel: 0,
      section: null,
      tempoAutomation: null,
      fermata: null,
      start: 3840,
      isAnacrusis: false,
      displayScale: 1,
      displayWidth: -1,
      score: [Circular *1],
      repeatGroup: [RepeatGroup]
    }
  ],
  tracks: [
    Track {
      index: 0,
      staves: [Array],
      playbackInfo: [PlaybackInformation],
      color: [Color],
      name: 'Steel Guitar',
      shortName: 's.guit.',
      defaultSystemsLayout: 3,
      systemsLayout: [Array],
      percussionArticulations: [],
      score: [Circular *1]
    }
  ],
  defaultSystemsLayout: 4,
  systemsLayout: [ 4 ],
  stylesheet: RenderStylesheet { hideDynamics: true }
}
[] 1200 444

Link to jsFiddle, CodePen, Project

No response

Found in Version

1.3

Platform

Node.js

Environment

- **OS**: Windows
- **Node.js**: v23.7.0 (latest)

Anything else?

No response

@Danielku15
Copy link
Member

The guide is slightly outdated. The low-level APIs were extended lately as part of the Android implementations to further delay the rendering. I need to update the docs accordingly to this change.

You need additionally this event listener which is triggered when the layouting of one "partial result" finished, and then directly initiate the rendering of it. In UI environments this mechanism is used to first compute the layout and then do a "lazy rendering" as individual parts become visible while scrolling.

renderer.partialLayoutFinished.on((r) => {
    renderer.renderResult(r.id);
})

Working code:

import fs from "node:fs";
import process from "node:process";
import * as alphaTab from "@coderline/alphatab";

// 1. Load file
const fileData = fs.readFileSync(process.argv[2]);
const settings = new alphaTab.Settings();
const score = alphaTab.importer.ScoreLoader.loadScoreFromBytes(new Uint8Array(fileData), settings);
console.log(score);

// 2. Setup renderer
settings.core.engine = "svg";
const renderer = new alphaTab.rendering.ScoreRenderer(settings);
renderer.width = 1200;

// 3. Listen to events
let svgChunks = [];
renderer.error.on((error) => {
	console.error(error);
});
renderer.preRender.on((isResize) => {
	svgChunks = []; // Clear on new rendering
});
renderer.partialRenderFinished.on((r) => {
	svgChunks.push({
		svg: r.renderResult,
		width: r.width,
		height: r.height,
	});
});
renderer.renderFinished.on((r) => {
	console.log(svgChunks, r.totalWidth, r.totalHeight);
});
renderer.partialLayoutFinished.on((r) => {
    renderer.renderResult(r.id);
})

// 4. Fire off rendering
renderer.renderScore(score, [0]);

// 5. Log the SVG chunks
console.log(svgChunks.map((c) => c.svg).join("\n"));

@Danielku15 Danielku15 added state-accepted This is a valid topic to work on. platform-javascript Related to the JavaScript version of alphaTab type-question ❓ area-documentation Related to documentation and sample code state-no-bug The reported problem is not a bug in alphaTab. and removed state-needs-triage Bug not triaged yet. labels Feb 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-documentation Related to documentation and sample code platform-javascript Related to the JavaScript version of alphaTab state-accepted This is a valid topic to work on. state-no-bug The reported problem is not a bug in alphaTab. type-question ❓
Projects
None yet
Development

No branches or pull requests

2 participants