abcjs 6.2.0 → 6.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**!
2
- Copyright (c) 2009-2022 Paul Rosen and Gregory Dyke
2
+ Copyright (c) 2009-2023 Paul Rosen and Gregory Dyke
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**!
2
- Copyright (c) 2009-2022 Paul Rosen and Gregory Dyke
2
+ Copyright (c) 2009-2023 Paul Rosen and Gregory Dyke
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
package/license.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**!
2
- Copyright (c) 2009-2022 Paul Rosen and Gregory Dyke
2
+ Copyright (c) 2009-2023 Paul Rosen and Gregory Dyke
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abcjs",
3
- "version": "6.2.0",
3
+ "version": "6.2.1",
4
4
  "description": "Renderer for abc music notation",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
package/plugin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**!
2
- Copyright (c) 2009-2022 Paul Rosen and Gregory Dyke
2
+ Copyright (c) 2009-2023 Paul Rosen and Gregory Dyke
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
@@ -17,7 +17,7 @@ var TimingCallbacks = function(target, params) {
17
17
  self.replaceTarget = function(newTarget) {
18
18
  self.noteTimings = newTarget.setTiming(self.qpm, self.extraMeasuresAtBeginning);
19
19
  if (newTarget.noteTimings.length === 0)
20
- newTarget.setTiming(0,0);
20
+ self.noteTimings = newTarget.setTiming(0,0);
21
21
  if (self.lineEndCallback) {
22
22
  self.lineEndTimings = getLineEndTimings(newTarget.noteTimings, self.lineEndAnticipation);
23
23
  }
@@ -572,7 +572,7 @@ var Tune = function() {
572
572
  if (!this.engraver || !this.engraver.staffgroups) {
573
573
  console.log("setTiming cannot be called before the tune is drawn.");
574
574
  this.noteTimings = [];
575
- return;
575
+ return this.noteTimings;
576
576
  }
577
577
 
578
578
  var tempo = this.metaText ? this.metaText.tempo : null;
@@ -165,6 +165,9 @@ function CreateSynth() {
165
165
  notes.push({ instrument: instrument, note: note });
166
166
  });
167
167
  });
168
+ if (self.debugCallback)
169
+ self.debugCallback("notes "+JSON.stringify(notes));
170
+
168
171
  // If there are lots of notes, load them in batches
169
172
  var batches = [];
170
173
  var CHUNK = 256;
@@ -181,8 +184,13 @@ function CreateSynth() {
181
184
 
182
185
  var index = 0;
183
186
  var next = function() {
187
+ if (self.debugCallback)
188
+ self.debugCallback("loadBatch idx="+index+ " len="+batches.length);
189
+
184
190
  if (index < batches.length) {
185
191
  self._loadBatch(batches[index], self.soundFontUrl, startTime).then(function(data) {
192
+ if (self.debugCallback)
193
+ self.debugCallback("loadBatch then");
186
194
  startTime = activeAudioContext().currentTime;
187
195
  if (data) {
188
196
  if (data.error)
@@ -194,6 +202,9 @@ function CreateSynth() {
194
202
  next();
195
203
  }, reject);
196
204
  } else {
205
+ if (self.debugCallback)
206
+ self.debugCallback("resolve init");
207
+
197
208
  resolve(results);
198
209
  }
199
210
  };
@@ -205,6 +216,8 @@ function CreateSynth() {
205
216
  // This is called recursively to see if the sounds have loaded. The "delay" parameter is how long it has been since the original call.
206
217
  var promises = [];
207
218
  batch.forEach(function(item) {
219
+ if (self.debugCallback)
220
+ self.debugCallback("getNote " + item.instrument+':'+item.note);
208
221
  promises.push(getNote(soundFontUrl, item.instrument, item.note, activeAudioContext()));
209
222
  });
210
223
  return Promise.all(promises).then(function(response) {
@@ -227,6 +240,8 @@ function CreateSynth() {
227
240
  error.push(which + ' ' + oneResponse.message);
228
241
  }
229
242
  if (pending.length > 0) {
243
+ if (self.debugCallback)
244
+ self.debugCallback("pending " + JSON.stringify(pending));
230
245
  // There was probably a second call for notes before the first one finished, so just retry a few times to see if they stop being pending.
231
246
  // Retry quickly at first so that there isn't an unnecessary delay, but increase the delay each time.
232
247
  if (!delay)
@@ -241,7 +256,9 @@ function CreateSynth() {
241
256
  which = pending[i].split(":");
242
257
  newBatch.push({instrument: which[0], note: which[1]});
243
258
  }
244
- self._loadBatch(newBatch, soundFontUrl, startTime, delay).then(function (response) {
259
+ if (self.debugCallback)
260
+ self.debugCallback("retry " + JSON.stringify(newBatch));
261
+ self._loadBatch(newBatch, soundFontUrl, startTime, delay).then(function (response) {
245
262
  resolve(response);
246
263
  }).catch(function (error) {
247
264
  reject(error);
@@ -252,11 +269,18 @@ function CreateSynth() {
252
269
  var list = [];
253
270
  for (var j = 0; j < batch.length; j++)
254
271
  list.push(batch[j].instrument+'/'+batch[j].note)
255
- return Promise.reject(new Error("timeout attempting to load: " + list.join(", ")));
272
+ if (self.debugCallback)
273
+ self.debugCallback("loadBatch timeout")
274
+ return Promise.reject(new Error("timeout attempting to load: " + list.join(", ")));
256
275
  }
257
- } else
276
+ } else {
277
+ if (self.debugCallback)
278
+ self.debugCallback("loadBatch resolve")
258
279
  return Promise.resolve({loaded: loaded, cached: cached, error: error});
280
+ }
259
281
  }).catch(function (error) {
282
+ if (self.debugCallback)
283
+ self.debugCallback("loadBatch catch "+error.message)
260
284
  });
261
285
  });
262
286
 
@@ -299,6 +323,8 @@ function CreateSynth() {
299
323
  var panDistance = panDistances && panDistances.length > trackNumber ? panDistances[trackNumber] : 0;
300
324
  noteMap.forEach(function(note) {
301
325
  var key = note.instrument + ':' + note.pitch + ':' +note.volume + ':' + Math.round((note.end-note.start)*1000)/1000 + ':' + panDistance + ':' + tempoMultiplier + ':' + (note.cents ? note.cents : 0);
326
+ if (self.debugCallback)
327
+ self.debugCallback("noteMapTrack "+key)
302
328
  if (!uniqueSounds[key])
303
329
  uniqueSounds[key] = [];
304
330
  uniqueSounds[key].push(note.start);
@@ -313,7 +339,7 @@ function CreateSynth() {
313
339
  var parts = k.split(":");
314
340
  var cents = parts[6] !== undefined ? parseFloat(parts[6]) : 0;
315
341
  parts = {instrument: parts[0], pitch: parseInt(parts[1], 10), volume: parseInt(parts[2], 10), len: parseFloat(parts[3]), pan: parseFloat(parts[4]), tempoMultiplier: parseFloat(parts[5]), cents: cents};
316
- allPromises.push(placeNote(audioBuffer, activeAudioContext().sampleRate, parts, uniqueSounds[k], self.soundFontVolumeMultiplier, self.programOffsets[parts.instrument], fadeTimeSec, self.noteEnd/1000));
342
+ allPromises.push(placeNote(audioBuffer, activeAudioContext().sampleRate, parts, uniqueSounds[k], self.soundFontVolumeMultiplier, self.programOffsets[parts.instrument], fadeTimeSec, self.noteEnd/1000, self.debugCallback));
317
343
  }
318
344
  self.audioBuffers = [audioBuffer];
319
345
 
@@ -16,7 +16,7 @@ var getNote = function (url, instrument, name, audioContext) {
16
16
  xhr.responseType = "arraybuffer";
17
17
  xhr.onload = function () {
18
18
  if (xhr.status !== 200) {
19
- reject(Error("Can't load sound at " + noteUrl));
19
+ reject(Error("Can't load sound at " + noteUrl + ' status=' + xhr.status));
20
20
  return
21
21
  }
22
22
  var noteDecoded = function(audioBuffer) {
@@ -2,7 +2,7 @@ var soundsCache = require('./sounds-cache');
2
2
  var pitchToNoteName = require('./pitch-to-note-name');
3
3
  var centsToFactor = require("./cents-to-factor");
4
4
 
5
- function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMultiplier, ofsMs, fadeTimeSec, noteEndSec) {
5
+ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMultiplier, ofsMs, fadeTimeSec, noteEndSec, debugCallback) {
6
6
  // sound contains { instrument, pitch, volume, len, pan, tempoMultiplier
7
7
  // len is in whole notes. Multiply by tempoMultiplier to get seconds.
8
8
  // ofsMs is an offset to subtract from the note to line up programs that have different length onsets.
@@ -21,6 +21,8 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
21
21
 
22
22
  if (!noteBufferPromise) {
23
23
  // if the note isn't present then just skip it - it will leave a blank spot in the audio.
24
+ if (debugCallback)
25
+ debugCallback('placeNote skipped: '+sound.instrument+':'+noteName)
24
26
  return Promise.resolve();
25
27
  }
26
28
 
@@ -81,6 +83,8 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
81
83
  copyToChannel(outputAudioBuffer, e.renderedBuffer, start);
82
84
  }
83
85
  }
86
+ if (debugCallback)
87
+ debugCallback('placeNote: '+sound.instrument+':'+noteName)
84
88
  fnResolve();
85
89
  };
86
90
  offlineCtx.startRendering();
@@ -88,7 +92,11 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
88
92
  fnResolve = resolve;
89
93
  });
90
94
  })
91
- .catch(function () {});
95
+ .catch(function (error) {
96
+ if (debugCallback)
97
+ debugCallback('placeNote catch: '+error.message)
98
+ return Promise.resolve()
99
+ });
92
100
  }
93
101
 
94
102
  var copyToChannel = function(toBuffer, fromBuffer, start) {
@@ -285,7 +285,7 @@ function StringPatterns(plugin) {
285
285
  this.measureAccidentals = {}
286
286
  this.capo = 0;
287
287
  if (capo) {
288
- this.capo = capo;
288
+ this.capo = parseInt(capo,10);
289
289
  }
290
290
  this.transpose = plugin.transpose ? plugin.transpose : 0
291
291
  this.tuning = tuning;
@@ -7,6 +7,16 @@ function printLine(renderer, x1, x2, y, klass, name, dy) {
7
7
  x2 = roundNumber(x2);
8
8
  var y1 = roundNumber(y - dy);
9
9
  var y2 = roundNumber(y + dy);
10
+ // TODO-PER: This fixes a firefox bug where a path needs to go over the 0.5 mark or it isn't displayed
11
+ if (renderer.firefox112 && dy < 1) {
12
+ var int = Math.floor(y2)
13
+ var distToHalf = 0.52 - (y2 - int)
14
+ if (distToHalf > 0) {
15
+ y1 += distToHalf
16
+ y2 += distToHalf
17
+ }
18
+ }
19
+
10
20
  var pathString = sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y1, x2, y1,
11
21
  x2, y2, x1, y2);
12
22
  var options = { path: pathString, stroke: "none", fill: fill };
@@ -12,6 +12,16 @@ function printStem(renderer, x, dx, y1, y2, klass, name) {
12
12
  }
13
13
  x = roundNumber(x);
14
14
  var x2 = roundNumber(x + dx);
15
+ // TODO-PER: This fixes a firefox bug where a path needs to go over the 0.5 mark or it isn't displayed
16
+ if (renderer.firefox112 && Math.abs(dx) < 1) {
17
+ var higher = Math.max(x,x2)
18
+ var int = Math.floor(higher)
19
+ var distToHalf = 0.52 - (higher - int)
20
+ if (distToHalf > 0) {
21
+ x += distToHalf
22
+ x2 += distToHalf
23
+ }
24
+ }
15
25
  var pathArray = [["M", x, y1], ["L", x, y2], ["L", x2, y2], ["L", x2, y1], ["z"]];
16
26
  var attr = { path: "" };
17
27
  for (var i = 0; i < pathArray.length; i++)
@@ -362,10 +362,13 @@ function notifySelect(target, dragStep, dragMax, dragIndex, ev) {
362
362
  var parent = ev.target;
363
363
  while (parent && parent.dataset && !parent.dataset.index && parent.tagName.toLowerCase() !== 'svg')
364
364
  parent = parent.parentNode;
365
- analysis.name = parent.dataset.name;
366
- analysis.clickedName = closest.dataset.name;
367
- analysis.parentClasses = parent.classList;
368
- analysis.clickedClasses = closest.classList;
365
+ if (parent && parent.dataset) {
366
+ analysis.name = parent.dataset.name;
367
+ analysis.clickedName = closest.dataset.name;
368
+ analysis.parentClasses = parent.classList;
369
+ }
370
+ if (closest && closest.classList)
371
+ analysis.clickedClasses = closest.classList;
369
372
  analysis.selectableElement = target.svgEl;
370
373
 
371
374
  for (var i = 0; i < this.listeners.length; i++) {
@@ -16,6 +16,7 @@ var Renderer = function (paper) {
16
16
  this.space = 3 * spacing.SPACE;
17
17
  this.padding = {}; // renderer's padding is managed by the controller
18
18
  this.reset();
19
+ this.firefox112 = navigator.userAgent.indexOf('Firefox/112.0') >= 0
19
20
  };
20
21
 
21
22
  Renderer.prototype.reset = function () {
package/test.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**!
2
- Copyright (c) 2009-2022 Paul Rosen and Gregory Dyke
2
+ Copyright (c) 2009-2023 Paul Rosen and Gregory Dyke
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
package/types/index.d.ts CHANGED
@@ -1142,7 +1142,7 @@ declare module 'abcjs' {
1142
1142
 
1143
1143
  export interface MidiBuffer {
1144
1144
  init(params?: MidiBufferOptions): Promise<MidiBufferPromise>
1145
- prime(): Promise<void>
1145
+ prime(): Promise<{ status: string, duration: number}>
1146
1146
  start(): void
1147
1147
  pause(): number
1148
1148
  resume(): void
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
- var version = '6.2.0';
1
+ var version = '6.2.1';
2
2
 
3
3
  module.exports = version;