abcjs 6.6.3 → 6.6.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abcjs",
3
- "version": "6.6.3",
3
+ "version": "6.6.4",
4
4
  "description": "Renderer for abc music notation",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -2,10 +2,6 @@ var TimingCallbacks = function(target, params) {
2
2
  var self = this;
3
3
  if (!params) params = {};
4
4
  self.qpm = params.qpm ? parseInt(params.qpm, 10) : null;
5
- if (!self.qpm) {
6
- var tempo = target.metaText ? target.metaText.tempo : null;
7
- self.qpm = target.getBpm(tempo);
8
- }
9
5
  self.extraMeasuresAtBeginning = params.extraMeasuresAtBeginning ? parseInt(params.extraMeasuresAtBeginning, 10) : 0;
10
6
  self.beatCallback = params.beatCallback; // This is called for each beat.
11
7
  self.eventCallback = params.eventCallback; // This is called for each note or rest encountered.
@@ -16,6 +12,10 @@ var TimingCallbacks = function(target, params) {
16
12
  self.joggerTimer = null;
17
13
 
18
14
  self.replaceTarget = function(newTarget) {
15
+ if (!params.qpm) {
16
+ var tempo = newTarget.metaText ? newTarget.metaText.tempo : null;
17
+ self.qpm = newTarget.getBpm(tempo);
18
+ }
19
19
  self.noteTimings = newTarget.setTiming(self.qpm, self.extraMeasuresAtBeginning);
20
20
  if (newTarget.noteTimings.length === 0)
21
21
  self.noteTimings = newTarget.setTiming(0,0);
@@ -245,17 +245,47 @@ var TimingCallbacks = function(target, params) {
245
245
  };
246
246
  }
247
247
 
248
- var thisStartTime = self.startTime; // the beat callback can call seek and change the position from beneath us.
249
- self.beatCallback(
250
- self.beatStarts[self.currentBeat].b,
251
- self.totalBeats / self.beatSubdivisions,
252
- self.lastMoment,
253
- position,
254
- debugInfo);
255
- if (thisStartTime !== self.startTime) {
256
- return timestamp - self.startTime;
257
- } // else
258
- // self.currentBeat++;
248
+ // there is a case where self.beatStarts[self.currentBeat] doesn't exist, but I don't know how. Give more info in that case for better debugging.
249
+ if (self.currentBeat < 0 || self.currentBeat >= self.beatStarts.length || !self.beatStarts[self.currentBeat]) {
250
+ var obj = {
251
+ currentBeat: self.currentBeat,
252
+ beatStartLength: self.beatStarts.length,
253
+ totalBeats: self.totalBeats,
254
+
255
+ startTime: self.startTime,
256
+ currentTime: self.currentTime,
257
+ lastMoment: self.lastMoment,
258
+ lastTimestamp: self.lastTimestamp,
259
+
260
+ qpm: self.qpm,
261
+ millisecondsPerBeat: self.millisecondsPerBeat,
262
+ beatSubdivisions: self.beatSubdivisions,
263
+
264
+ currentEvent: self.currentEvent,
265
+ currentLine: self.currentLine,
266
+
267
+ isPaused: self.isPaused,
268
+ isRunning: self.isRunning,
269
+ pausedPercent: self.pausedPercent,
270
+ justUnpaused: self.justUnpaused,
271
+ newSeekPercent: self.newSeekPercent,
272
+ }
273
+ setTimeout(function() {
274
+ // throw the error outside of the normal processing so that everything else continues working.
275
+ throw new Error("abcjs-timing-callback error: " + JSON.stringify(obj))
276
+ }, 1)
277
+ } else {
278
+ var thisStartTime = self.startTime; // the beat callback can call seek and change the position from beneath us.
279
+ self.beatCallback(
280
+ self.beatStarts[self.currentBeat].b,
281
+ self.totalBeats / self.beatSubdivisions,
282
+ self.lastMoment,
283
+ position,
284
+ debugInfo);
285
+ if (thisStartTime !== self.startTime) {
286
+ return timestamp - self.startTime;
287
+ }
288
+ }
259
289
  }
260
290
  return null;
261
291
  };
@@ -508,6 +508,8 @@ var Parse = function() {
508
508
  }
509
509
  strTune = arr.join(" "); //. the split removed two characters, so this puts them back
510
510
  }
511
+ // If there is an escaped percent, then temporarily change it so it doesn't affect the processing.
512
+ strTune = strTune.replace(/\\%/g,"\u200B\uFF05")
511
513
  // take care of line continuations right away, but keep the same number of characters
512
514
  strTune = strTune.replace(/\\([ \t]*)(%.*)*\n/g, function(all, backslash, comment){
513
515
  var padding = comment ? Array(comment.length +1).join(' ') : "";
@@ -356,7 +356,9 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
356
356
  return [ e-i+1+ws ];
357
357
  case "[M:":
358
358
  var meter = this.setMeter(line.substring(i+3, e));
359
- if (tuneBuilder.hasBeginMusic() && meter)
359
+ if (startLine && multilineVars.currentVoice && meter)
360
+ multilineVars.staves[multilineVars.currentVoice.staffNum].meter = meter;
361
+ else if (tuneBuilder.hasBeginMusic() && meter)
360
362
  tuneBuilder.appendStartingElement('meter', startChar, endChar, meter);
361
363
  else
362
364
  multilineVars.meter = meter;
@@ -85,9 +85,20 @@ var parseKeyVoice = {};
85
85
  key.accidentals.forEach(function(k) {
86
86
  ret.accidentals.push(Object.assign({},k));
87
87
  });
88
+ if (key.explicitAccidentals) {
89
+ ret.explicitAccidentals = [];
90
+ key.explicitAccidentals.forEach(function(k) {
91
+ ret.explicitAccidentals.push(Object.assign({},k));
92
+ });
93
+ }
88
94
  return ret;
89
95
  };
90
96
 
97
+ var setVoiceKey = function() {
98
+ if (multilineVars.currentVoice)
99
+ multilineVars.currentVoice.key = parseKeyVoice.deepCopyKey(multilineVars.key);
100
+ };
101
+
91
102
  var pitches = {A: 5, B: 6, C: 0, D: 1, E: 2, F: 3, G: 4, a: 12, b: 13, c: 7, d: 8, e: 9, f: 10, g: 11};
92
103
 
93
104
  parseKeyVoice.addPosToKey = function(clef, key) {
@@ -230,18 +241,30 @@ var parseKeyVoice = {};
230
241
  multilineVars.key = { root: "HP", accidentals: [], acc: "", mode: "" };
231
242
  ret.foundKey = true;
232
243
  tokens.shift();
244
+ if (!isInline) {
245
+ multilineVars.globalKey = parseKeyVoice.deepCopyKey(multilineVars.key);
246
+ }
247
+ setVoiceKey();
233
248
  break;
234
249
  case 'Hp':
235
250
  parseDirective.addDirective("bagpipes");
236
251
  multilineVars.key = { root: "Hp", accidentals: [{acc: 'natural', note: 'g'}, {acc: 'sharp', note: 'f'}, {acc: 'sharp', note: 'c'}], acc: "", mode: "" };
237
252
  ret.foundKey = true;
238
253
  tokens.shift();
254
+ if (!isInline) {
255
+ multilineVars.globalKey = parseKeyVoice.deepCopyKey(multilineVars.key);
256
+ }
257
+ setVoiceKey();
239
258
  break;
240
259
  case 'none':
241
260
  // we got the none key - that's the same as C to us
242
261
  multilineVars.key = { root: "none", accidentals: [], acc: "", mode: "" };
243
262
  ret.foundKey = true;
244
263
  tokens.shift();
264
+ if (!isInline) {
265
+ multilineVars.globalKey = parseKeyVoice.deepCopyKey(multilineVars.key);
266
+ }
267
+ setVoiceKey();
245
268
  break;
246
269
  default:
247
270
  var retPitch = tokenizer.getKeyPitch(tokens[0].token);
@@ -309,6 +332,10 @@ var parseKeyVoice = {};
309
332
  }
310
333
  }
311
334
  }
335
+ if (!isInline) {
336
+ multilineVars.globalKey = parseKeyVoice.deepCopyKey(multilineVars.key);
337
+ }
338
+ setVoiceKey();
312
339
  }
313
340
  break;
314
341
  }
@@ -358,6 +385,10 @@ var parseKeyVoice = {};
358
385
  }
359
386
  }
360
387
  }
388
+ if (!isInline) {
389
+ multilineVars.globalKey = parseKeyVoice.deepCopyKey(multilineVars.key);
390
+ }
391
+ setVoiceKey();
361
392
  }
362
393
 
363
394
  // Now see if any optional parameters are present. They have the form "key=value", except that "clef=" is optional
@@ -499,6 +530,10 @@ var parseKeyVoice = {};
499
530
  return // there was no change so don't reset it.
500
531
  }
501
532
  multilineVars.currentVoice = currentVoice;
533
+ if (currentVoice.key)
534
+ multilineVars.key = parseKeyVoice.deepCopyKey(currentVoice.key);
535
+ else if (multilineVars.globalKey)
536
+ multilineVars.key = parseKeyVoice.deepCopyKey(multilineVars.globalKey);
502
537
  return tuneBuilder.setCurrentVoice(currentVoice.staffNum, currentVoice.index, id);
503
538
  };
504
539