abcjs 6.0.2 → 6.1.0

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.
@@ -630,7 +630,7 @@ var pitchesToPerc = require('./pitches-to-perc');
630
630
  if (name && percmap[name])
631
631
  actualPitch = percmap[name].sound;
632
632
  }
633
- var p = { cmd: 'note', pitch: actualPitch, volume: velocity, start: timeToRealTime(elem.time), duration: durationRounded(note.duration), instrument: currentInstrument };
633
+ var p = { cmd: 'note', pitch: actualPitch, volume: velocity, start: timeToRealTime(elem.time), duration: durationRounded(note.duration), instrument: currentInstrument, startChar: elem.elem.startChar, endChar: elem.elem.endChar};
634
634
  p = adjustForMicroTone(p);
635
635
  if (elem.gracenotes) {
636
636
  p.duration = p.duration / 2;
@@ -29,6 +29,10 @@ var createNoteMap = function(sequence) {
29
29
  end: Math.round((ev.start + len - gap) * 1000000)/1000000,
30
30
  volume: ev.volume
31
31
  };
32
+ if (ev.startChar)
33
+ obj.startChar = ev.startChar;
34
+ if (ev.endChar)
35
+ obj.endChar = ev.endChar;
32
36
  if (ev.style)
33
37
  obj.style = ev.style;
34
38
  if (ev.cents)
@@ -69,7 +69,7 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
69
69
  }
70
70
  var fnResolve;
71
71
  offlineCtx.oncomplete = function(e) {
72
- if (e.renderedBuffer) { // If the system gets overloaded then this can start failing. Just drop the note if so.
72
+ if (e.renderedBuffer && e.renderedBuffer.getChannelData) { // If the system gets overloaded or there are network problems then this can start failing. Just drop the note if so.
73
73
  for (var i = 0; i < startArray.length; i++) {
74
74
  //Math.floor(startArray[i] * sound.tempoMultiplier * sampleRate)
75
75
  var start = startArray[i] * sound.tempoMultiplier;
@@ -57,7 +57,7 @@ var ParserLint = function() {
57
57
  "trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent",
58
58
  "fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge",
59
59
  "open", "thumb", "snap", "turn", "roll", "irishroll", "breath", "shortphrase", "mediumphrase", "longphrase",
60
- "segno", "coda", "D.S.", "D.C.", "fine", "crescendo(", "crescendo)", "diminuendo(", "diminuendo)",
60
+ "segno", "coda", "D.S.", "D.C.", "fine", "crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)",
61
61
  "p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz", "repeatbar", "repeatbar2", "slide",
62
62
  "upbow", "downbow", "staccato", "trem1", "trem2", "trem3", "trem4",
63
63
  "/", "//", "///", "////", "turnx", "invertedturn", "invertedturnx", "arpeggio", "trill(", "trill)", "xstem",
@@ -390,6 +390,13 @@ AbstractEngraver.prototype.createABCElement = function(isFirstStaff, isSingleLin
390
390
  var beamelem = new BeamElem(this.stemHeight * this.voiceScale, this.stemdir, this.flatBeams, elems[0]);
391
391
  if (hint) beamelem.setHint();
392
392
  for (var i = 0; i < elems.length; i++) {
393
+ // Do a first pass to figure out the stem direction before creating the notes, so that staccatos and other decorations can be placed correctly.
394
+ beamelem.runningDirection(elems[i])
395
+ }
396
+ beamelem.setStemDirection()
397
+ var tempStemDir = this.stemdir
398
+ this.stemdir = beamelem.stemsUp ? 'up' : 'down'
399
+ for (i = 0; i < elems.length; i++) {
393
400
  var elem = elems[i];
394
401
  var abselem = this.createNote(elem, true, isSingleLineStaff, voice);
395
402
  abselemset.push(abselem);
@@ -402,6 +409,7 @@ AbstractEngraver.prototype.createABCElement = function(isFirstStaff, isSingleLin
402
409
  }
403
410
  beamelem.calcDir();
404
411
  voice.addBeam(beamelem);
412
+ this.stemdir = tempStemDir
405
413
  return abselemset;
406
414
  };
407
415
 
@@ -845,6 +853,7 @@ AbstractEngraver.prototype.createNote = function(elem, nostem, isSingleLineStaff
845
853
  for (var j = 0; j < this.ties.length; j++) {
846
854
  if (this.ties[j].anchor1 && this.ties[j].anchor1.pitch === notehead.pitch) {
847
855
  this.ties[j].setEndAnchor(notehead);
856
+ voice.setRange(this.ties[j])
848
857
  this.ties.splice(j, 1);
849
858
  found = true;
850
859
  break;
@@ -852,6 +861,7 @@ AbstractEngraver.prototype.createNote = function(elem, nostem, isSingleLineStaff
852
861
  }
853
862
  if (!found) {
854
863
  this.ties[0].setEndAnchor(notehead);
864
+ voice.setRange(this.ties[0])
855
865
  this.ties.splice(0, 1);
856
866
  }
857
867
  }
@@ -878,6 +888,7 @@ AbstractEngraver.prototype.createNote = function(elem, nostem, isSingleLineStaff
878
888
  if (this.slurs[slurid]) {
879
889
  slur = this.slurs[slurid];
880
890
  slur.setEndAnchor(notehead);
891
+ voice.setRange(slur)
881
892
  delete this.slurs[slurid];
882
893
  } else {
883
894
  slur = new TieElem({ anchor2: notehead, stemDir: this.stemdir, voiceNumber: voiceNumber});
@@ -1001,6 +1012,10 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
1001
1012
  // Add a little space to the left of the bar line so that nothing can crowd it.
1002
1013
  abselem.extraw -= 5;
1003
1014
 
1015
+ if (elem.chord !== undefined) {
1016
+ var ret3 = addChord(this.getTextSize, abselem, elem, 0, 0, 0, false);
1017
+ }
1018
+
1004
1019
  return abselem;
1005
1020
 
1006
1021
  };
@@ -42,6 +42,15 @@ var BeamElem = function BeamElem(stemHeight, type, flat, firstElement) {
42
42
  this.hint = true;
43
43
  };
44
44
 
45
+ BeamElem.prototype.runningDirection = function (abcelem) {
46
+ var pitch = abcelem.averagepitch;
47
+ if (pitch === undefined) return; // don't include elements like spacers in beams
48
+ this.total = Math.round(this.total+pitch);
49
+ if (!this.count)
50
+ this.count = 0;
51
+ this.count++
52
+ };
53
+
45
54
  BeamElem.prototype.add = function(abselem) {
46
55
  var pitch = abselem.abcelem.averagepitch;
47
56
  if (pitch === undefined) return; // don't include elements like spacers in beams
@@ -62,6 +71,21 @@ var BeamElem = function BeamElem(stemHeight, type, flat, firstElement) {
62
71
  this.beams.push(beam);
63
72
  };
64
73
 
74
+ BeamElem.prototype.setStemDirection = function() {
75
+ // Have to figure this out before the notes are placed because placing the notes also places the decorations.
76
+ this.average = calcAverage(this.total, this.count);
77
+ if (this.forceup) {
78
+ this.stemsUp = true;
79
+ } else if (this.forcedown) {
80
+ this.stemsUp = false;
81
+ } else {
82
+ var middleLine = 6; // hardcoded 6 is B
83
+ this.stemsUp = this.average < middleLine; // true is up, false is down;
84
+ }
85
+ delete this.count;
86
+ this.total = 0;
87
+ };
88
+
65
89
  BeamElem.prototype.calcDir = function() {
66
90
  this.average = calcAverage(this.total, this.elems.length);
67
91
  if (this.forceup) {
@@ -2,6 +2,7 @@
2
2
 
3
3
  var DynamicDecoration = require('./abc_dynamic_decoration');
4
4
  var CrescendoElem = require('./abc_crescendo_element');
5
+ var GlissandoElem = require('./abc_glissando_element');
5
6
  var glyphs = require('./abc_glyphs');
6
7
  var RelativeElement = require('./abc_relative_element');
7
8
  var TieElem = require('./abc_tie_element');
@@ -277,6 +278,7 @@ var Decoration = function Decoration() {
277
278
  Decoration.prototype.dynamicDecoration = function(voice, decoration, abselem, positioning) {
278
279
  var diminuendo;
279
280
  var crescendo;
281
+ var glissando;
280
282
  for (var i=0;i<decoration.length; i++) {
281
283
  switch(decoration[i]) {
282
284
  case "diminuendo(":
@@ -295,6 +297,14 @@ var Decoration = function Decoration() {
295
297
  crescendo = { start: this.startCrescendoX, stop: abselem};
296
298
  this.startCrescendoX = undefined;
297
299
  break;
300
+ case "glissando(":
301
+ this.startGlissandoX = abselem;
302
+ glissando = undefined;
303
+ break;
304
+ case "glissando)":
305
+ glissando = { start: this.startGlissandoX, stop: abselem};
306
+ this.startGlissandoX = undefined;
307
+ break;
298
308
  }
299
309
  }
300
310
  if (diminuendo) {
@@ -303,6 +313,9 @@ var Decoration = function Decoration() {
303
313
  if (crescendo) {
304
314
  voice.addOther(new CrescendoElem(crescendo.start, crescendo.stop, "<", positioning));
305
315
  }
316
+ if (glissando) {
317
+ voice.addOther(new GlissandoElem(glissando.start, glissando.stop));
318
+ }
306
319
  };
307
320
 
308
321
  Decoration.prototype.createDecoration = function(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) {
@@ -0,0 +1,7 @@
1
+ var GlissandoElem = function GlissandoElem(anchor1, anchor2) {
2
+ this.type = "GlissandoElem";
3
+ this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
4
+ this.anchor2 = anchor2; // must have a .x property or be null (means ends at the end of the line)
5
+ };
6
+
7
+ module.exports = GlissandoElem;
@@ -25,6 +25,17 @@ TieElem.prototype.addInternalNote = function(note) {
25
25
  TieElem.prototype.setEndAnchor = function(anchor2) {
26
26
  // console.log("end", this.anchor1 ? this.anchor1.pitch : "N/A", anchor2 ? anchor2.pitch : "N/A", this.isTie, this.isGrace);
27
27
  this.anchor2 = anchor2; // must have a .x and a .pitch property or be null (means ends at the end of the line)
28
+
29
+ // we don't really have enough info to know what the vertical extent is yet and we won't until drawing. This will just give it enough
30
+ // room on either side (we don't even know if the slur will be above yet). We need to set this so that we can make sure the voice has
31
+ // at least enough room that the line doesn't get cut off if the tie or slur is the lowest thing.
32
+ if (this.anchor1) {
33
+ this.top = Math.max(this.anchor1.pitch, this.anchor2.pitch) + 4
34
+ this.bottom = Math.min(this.anchor1.pitch, this.anchor2.pitch) - 4
35
+ } else {
36
+ this.top = this.anchor2.pitch + 4
37
+ this.bottom = this.anchor2.pitch - 4
38
+ }
28
39
  };
29
40
 
30
41
  // If we encounter a repeat sign, then we don't want to extend either a tie or a slur past it, so these are called to be a limit.
@@ -0,0 +1,75 @@
1
+ var sprintf = require('./sprintf');
2
+ var printPath = require('./print-path');
3
+ var roundNumber = require("./round-number");
4
+
5
+ function drawGlissando(renderer, params, selectables) {
6
+ if (!params.anchor1 || !params.anchor2 || !params.anchor1.heads || !params.anchor2.heads || params.anchor1.heads.length === 0 || params.anchor2.heads.length === 0)
7
+ window.console.error("Glissando Element not set.");
8
+
9
+ var margin = 4;
10
+ var leftY = renderer.calcY(params.anchor1.heads[0].pitch)
11
+ var rightY = renderer.calcY(params.anchor2.heads[0].pitch)
12
+ var leftX = params.anchor1.x + params.anchor1.w/2
13
+ var rightX = params.anchor2.x + params.anchor2.w/2
14
+ var len = lineLength(leftX, leftY, rightX, rightY)
15
+ var marginLeft = params.anchor1.w/2 + margin
16
+ var marginRight = params.anchor2.w/2 + margin
17
+ var s = slope(leftX, leftY, rightX, rightY)
18
+ var leftYAdj = getY(leftY, s, marginLeft)
19
+ var rightYAdj = getY(rightY, s, -marginRight)
20
+ var num = numSquigglies(len-marginLeft-marginRight)
21
+
22
+ var el = drawSquiggly(renderer, leftX+marginLeft, leftYAdj, num, s)
23
+ selectables.wrapSvgEl({el_type: "glissando", startChar: -1, endChar: -1}, el);
24
+ return [el];
25
+ }
26
+
27
+ function lineLength(leftX, leftY, rightX, rightY) {
28
+ // The length from notehead center to notehead center.
29
+ var w = rightX - leftX
30
+ var h = rightY - leftY
31
+ return Math.sqrt(w*w + h*h)
32
+ }
33
+
34
+ function slope(leftX, leftY, rightX, rightY) {
35
+ return (rightY-leftY) / (rightX - leftX)
36
+ }
37
+
38
+ function getY(y, slope, xOfs) {
39
+ return roundNumber(y + (xOfs)*slope);
40
+ }
41
+
42
+ function numSquigglies(length) {
43
+ var endLen = 5; // The width of the end - that is, the non repeating part
44
+ return Math.max(2, Math.floor((length - endLen*2) / 6));
45
+ }
46
+
47
+ var leftStart = [[3.5, -4.8]]
48
+ var right = [[1.5, -1], [.3, -.3], [-3.5, 3.8]]
49
+ var leftEnd = [[-1.5, 2]]
50
+ var top = [[3, 4], [3, -4]]
51
+ var bottom = [[-3, 4], [-3, -4]]
52
+
53
+ function segment(arr, slope) {
54
+ var ret = "";
55
+ for (var i = 0; i < arr.length; i++) {
56
+ ret += 'l' + arr[i][0] + ' ' + getY(arr[i][1], slope, arr[i][0])
57
+ }
58
+ return ret
59
+ }
60
+
61
+ var drawSquiggly = function(renderer, x, y, num, slope) {
62
+ var p = sprintf("M %f %f", x, y);
63
+ p += segment(leftStart, slope)
64
+ var i
65
+ for (i = 0; i < num; i++) {
66
+ p+=segment(top, slope)
67
+ }
68
+ p += segment(right, slope)
69
+ for ( i = 0; i < num; i++)
70
+ p+=segment(bottom, slope)
71
+ p+=segment(leftEnd, slope) + 'z'
72
+ return printPath(renderer, {path:p, highlight: "stroke", stroke:renderer.foregroundColor, 'class': renderer.controller.classes.generate('decoration'), "data-name": "glissando"});
73
+ }
74
+
75
+ module.exports = drawGlissando;
@@ -1,3 +1,4 @@
1
+ var drawGlissando = require('./glissando');
1
2
  var drawCrescendo = require('./crescendo');
2
3
  var drawDynamics = require('./dynamics');
3
4
  var drawTriplet = require('./triplet');
@@ -67,6 +68,9 @@ function drawVoice(renderer, params, bartop, selectables, staffPos) {
67
68
  renderer.controller.classes.incrMeasure();
68
69
  } else {
69
70
  switch (child.type) {
71
+ case "GlissandoElem":
72
+ child.elemset = drawGlissando(renderer, child, selectables);
73
+ break;
70
74
  case "CrescendoElem":
71
75
  child.elemset = drawCrescendo(renderer, child, selectables);
72
76
  break;
@@ -5,7 +5,7 @@ function formatJazzChord(chordString) {
5
5
  for (var i = 0; i < lines.length; i++) {
6
6
  var chord = lines[i];
7
7
  // If the chord isn't in a recognizable format then just skip the formatting.
8
- var reg = chord.match(/^([ABCDEFG][♯♭]?)?([^\/]+)?(\/[ABCDEFG][#b]?)?/);
8
+ var reg = chord.match(/^([ABCDEFG][♯♭]?)?([^\/]+)?(\/[ABCDEFG][#b♯♭]?)?/);
9
9
  if (reg)
10
10
  lines[i] = (reg[1]?reg[1]:'') + "\x03" + (reg[2]?reg[2]:'') + "\x03" + (reg[3]?reg[3]:'');
11
11
  }
@@ -32,7 +32,7 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
32
32
  this.rows.push({move: spacing.composer});
33
33
  if (metaText.rhythm && metaText.rhythm.length > 0) {
34
34
  var noMove = !!(metaText.composer || metaText.origin);
35
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: 'meta-top rhythm', absElemType: "rhythm", noMove: true, info: metaTextInfo.rhythm, name: "rhythm"}, getTextSize);
35
+ addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: 'meta-top rhythm', absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm"}, getTextSize);
36
36
  }
37
37
  var composerLine = "";
38
38
  if (metaText.composer) composerLine += metaText.composer;
package/types/index.d.ts CHANGED
@@ -64,7 +64,7 @@ declare module 'abcjs' {
64
64
  export type Decorations = "trill" | "lowermordent" | "uppermordent" | "mordent" | "pralltriller" | "accent" |
65
65
  "fermata" | "invertedfermata" | "tenuto" | "0" | "1" | "2" | "3" | "4" | "5" | "+" | "wedge" |
66
66
  "open" | "thumb" | "snap" | "turn" | "roll" | "irishroll" | "breath" | "shortphrase" | "mediumphrase" | "longphrase" |
67
- "segno" | "coda" | "D.S." | "D.C." | "fine" | "crescendo(" | "crescendo)" | "diminuendo(" | "diminuendo)" |
67
+ "segno" | "coda" | "D.S." | "D.C." | "fine" | "crescendo(" | "crescendo)" | "diminuendo(" | "diminuendo)" |"glissando(" | "glissando)" |
68
68
  "p" | "pp" | "f" | "ff" | "mf" | "mp" | "ppp" | "pppp" | "fff" | "ffff" | "sfz" | "repeatbar" | "repeatbar2" | "slide" |
69
69
  "upbow" | "downbow" | "staccato" | "trem1" | "trem2" | "trem3" | "trem4" |
70
70
  "/" | "//" | "///" | "////" | "turnx" | "invertedturn" | "invertedturnx" | "arpeggio" | "trill(" | "trill)" | "xstem" |
@@ -73,13 +73,13 @@ declare module 'abcjs' {
73
73
  //
74
74
  // Basic types
75
75
  //
76
- export type Selector = String | HTMLElement
76
+ export type Selector = string | HTMLElement
77
77
 
78
78
  type NumberFunction = () => number;
79
79
 
80
80
  export interface MeterFraction {
81
- num: string;
82
- den?: string;
81
+ num: number;
82
+ den?: number;
83
83
  }
84
84
 
85
85
  export interface ClefProperties {
@@ -261,6 +261,8 @@ declare module 'abcjs' {
261
261
  instrument: number;
262
262
  start: number;
263
263
  end: number;
264
+ startChar: number;
265
+ endChar: number;
264
266
  volume: number;
265
267
  style?: string;
266
268
  cents?: number;
@@ -904,7 +906,7 @@ declare module 'abcjs' {
904
906
 
905
907
  export interface AudioTrack {
906
908
  cmd: AudioTrackCommand;
907
- [param: any]; // TODO - make this a union
909
+ [param: string]: any; // TODO - make this a union
908
910
  }
909
911
 
910
912
  export interface AudioTracks {
@@ -1042,7 +1044,7 @@ declare module 'abcjs' {
1042
1044
 
1043
1045
  export interface SynthObjectController {
1044
1046
  disable(isDisabled: boolean): void
1045
- setTune(visualObj: TuneObject, userAction: Boolean, audioParams?: AbcVisualParams): Promise<SynthInitResponse>
1047
+ setTune(visualObj: TuneObject, userAction: boolean, audioParams?: any): Promise<SynthInitResponse>
1046
1048
  load(selector: string, cursorControl?: any, visualOptions?: SynthVisualOptions): void
1047
1049
  play(): void
1048
1050
  pause(): void
@@ -1054,7 +1056,9 @@ declare module 'abcjs' {
1054
1056
  }
1055
1057
 
1056
1058
  export interface SynthSequenceClass {
1057
- // TODO
1059
+ addTrack(): AudioTrack
1060
+ setInstrument(trackNumber: number, instrumentNumber: number): void
1061
+ appendNote(trackNumber: number, pitch: number, durationInMeasures: number, volume: number, cents: number): void
1058
1062
  }
1059
1063
 
1060
1064
  export namespace synth {
@@ -1068,7 +1072,7 @@ declare module 'abcjs' {
1068
1072
  export function registerAudioContext(ac?: AudioContext): boolean
1069
1073
  export function activeAudioContext(): AudioContext
1070
1074
  export function CreateSynthControl(element: Selector, options: AbcVisualParams): AudioControl
1071
- export function getMidiFile(source: String | TuneObject, options?: MidiFileOptions): MidiFile;
1075
+ export function getMidiFile(source: string | TuneObject, options?: MidiFileOptions): MidiFile;
1072
1076
  export function playEvent(pitches: MidiPitches, graceNotes: MidiGracePitches, milliSecondsPerMeasure: number): Promise<void>;
1073
1077
  export function sequence(visualObj: TuneObject, options: AbcVisualParams): AudioSequence
1074
1078
  }
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
- var version = '6.0.2';
1
+ var version = '6.1.0';
2
2
 
3
3
  module.exports = version;