abcjs-rails 2.1 → 2.3

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.
@@ -1336,11 +1336,13 @@ window.ABCJS.parse.Parse = function() {
1336
1336
  if (core.graceNotes !== undefined) el.graceNotes = core.graceNotes;
1337
1337
  delete el.startSlur;
1338
1338
  if (multilineVars.inTie) {
1339
- if (el.pitches !== undefined)
1339
+ if (el.pitches !== undefined) {
1340
1340
  el.pitches[0].endTie = true;
1341
- else
1341
+ multilineVars.inTie = false;
1342
+ } else if (el.rest.type !== 'spacer') {
1342
1343
  el.rest.endTie = true;
1343
- multilineVars.inTie = false;
1344
+ multilineVars.inTie = false;
1345
+ }
1344
1346
  }
1345
1347
  if (core.startTie || el.startTie)
1346
1348
  multilineVars.inTie = true;
@@ -330,7 +330,10 @@ window.ABCJS.parse.ParseHeader = function(tokenizer, warn, multilineVars, tune)
330
330
  tune.appendStartingElement('key', -1, -1, window.ABCJS.parse.parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
331
331
  return [ e-i+1+ws ];
332
332
  case "[P:":
333
- tune.appendElement('part', -1, -1, {title: line.substring(i+3, e)});
333
+ if (tune.lines.length <= tune.lineNum)
334
+ multilineVars.partForNextLine = line.substring(i+3, e);
335
+ else
336
+ tune.appendElement('part', -1, -1, {title: line.substring(i+3, e)});
334
337
  return [ e-i+1+ws ];
335
338
  case "[L:":
336
339
  this.setDefaultLength(line, i+3, e);
@@ -267,7 +267,9 @@ if (!window.ABCJS.write)
267
267
 
268
268
  var sy = (asc) ? -1.5 : 1.5;
269
269
  if (isGrace) sy = sy * 2 / 3; // This makes the second beam on grace notes closer to the first one.
270
- for (var durlog = ABCJS.write.getDurlog(elem.abcelem.duration); durlog < -3; durlog++) { // get the duration via abcelem because of triplets
270
+ var duration = elem.abcelem.duration; // get the duration via abcelem because of triplets
271
+ if (duration === 0) duration = 0.25; // if this is stemless, then we use quarter note as the duration.
272
+ for (var durlog = ABCJS.write.getDurlog(duration); durlog < -3; durlog++) {
271
273
  if (auxBeams[-4 - durlog]) {
272
274
  auxBeams[-4 - durlog].single = false;
273
275
  } else {
@@ -253,6 +253,7 @@ ABCJS.write.EngraverController.prototype.setXSpacing = function (staffGroup, for
253
253
  ABCJS.write.EngraverController.prototype.engraveStaffLine = function (staffGroup) {
254
254
  if (this.lastStaffGroupIndex > -1)
255
255
  this.renderer.addStaffPadding(this.staffgroups[this.lastStaffGroupIndex], staffGroup);
256
+ this.renderer.voiceNumber = null;
256
257
  staffGroup.draw(this.renderer);
257
258
  var height = staffGroup.height * ABCJS.write.spacing.STEP;
258
259
  //this.renderer.printVerticalLine(this.width+this.renderer.padding.left, this.renderer.y, this.renderer.y+height);
@@ -92,8 +92,8 @@ ABCJS.write.Renderer.prototype.setPaperSize = function (maxwidth, scale) {
92
92
  this.paper.canvas.parentNode.setAttribute("style","width:"+w+"px");
93
93
  if (scale !== 1) {
94
94
  this.paper.canvas.style.transform = "scale("+scale+","+scale+")";
95
- this.paper.canvas.style['-ms-tranform'] = "scale("+scale+","+scale+")";
96
- this.paper.canvas.style['-webkit-tranform'] = "scale("+scale+","+scale+")";
95
+ this.paper.canvas.style['-ms-transform'] = "scale("+scale+","+scale+")";
96
+ this.paper.canvas.style['-webkit-transform'] = "scale("+scale+","+scale+")";
97
97
  this.paper.canvas.style['transform-origin'] = "0 0";
98
98
  this.paper.canvas.style['-ms-transform-origin-x'] = "0";
99
99
  this.paper.canvas.style['-ms-transform-origin-y'] = "0";
@@ -101,8 +101,8 @@ ABCJS.write.Renderer.prototype.setPaperSize = function (maxwidth, scale) {
101
101
  this.paper.canvas.style['-webkit-transform-origin-y'] = "0";
102
102
  } else {
103
103
  this.paper.canvas.style.transform = "";
104
- this.paper.canvas.style['-ms-tranform'] = "";
105
- this.paper.canvas.style['-webkit-tranform'] = "";
104
+ this.paper.canvas.style['-ms-transform'] = "";
105
+ this.paper.canvas.style['-webkit-transform'] = "";
106
106
  }
107
107
  this.paper.canvas.parentNode.style.overflow="hidden";
108
108
  this.paper.canvas.parentNode.style.height=""+h+"px";
@@ -324,6 +324,7 @@ ABCJS.write.Renderer.prototype.engraveTopText = function(width, abctune) {
324
324
  ABCJS.write.Renderer.prototype.engraveExtraText = function(width, abctune) {
325
325
  this.lineNumber = null;
326
326
  this.measureNumber = null;
327
+ this.voiceNumber = null;
327
328
 
328
329
  var extraText;
329
330
  if (abctune.metaText.unalignedWords) {
@@ -613,6 +614,7 @@ ABCJS.write.Renderer.prototype.addClasses = function (c) {
613
614
  if (c.length > 0) ret.push(c);
614
615
  if (this.lineNumber !== null) ret.push("l"+this.lineNumber);
615
616
  if (this.measureNumber !== null) ret.push("m"+this.measureNumber);
617
+ if (this.voiceNumber !== null) ret.push("v"+this.voiceNumber);
616
618
  return ret.join(' ');
617
619
  };
618
620
 
@@ -375,6 +375,7 @@ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer) {
375
375
  for (var i=0;i<this.voices.length;i++) {
376
376
  var staff = this.voices[i].staff;
377
377
  renderer.y = staff.absoluteY;
378
+ renderer.voiceNumber = i;
378
379
  //renderer.y = staff.y;
379
380
  // offset for starting the counting at middle C
380
381
  if (!this.voices[i].duplicate) {
@@ -85,11 +85,11 @@ if (!window.ABCJS.write)
85
85
  stem.setX(x);
86
86
  abselem.addExtra(stem);
87
87
  }
88
- abselem.x = x;
89
- temponote.setX(x);
90
- temponote.draw(renderer, x);
91
- if (stem)
92
- stem.draw(renderer, x);
88
+ abselem.setX(x);
89
+ for (var i = 0; i < abselem.children.length; i++)
90
+ abselem.children[i].draw(renderer, x);
91
+ //if (stem)
92
+ // stem.draw(renderer, x);
93
93
  x += (abselem.w + 5);
94
94
  var str = "= " + this.tempo.bpm;
95
95
  text = renderer.renderText(x, y, str, 'tempofont', 'tempo', "start");
@@ -1,5 +1,5 @@
1
1
  module Abcjs
2
2
  module Rails
3
- VERSION = "2.1"
3
+ VERSION = "2.3"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abcjs-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: '2.1'
4
+ version: '2.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Rosen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-09 00:00:00.000000000 Z
11
+ date: 2015-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -38,7 +38,10 @@ files:
38
38
  - app/assets/javascripts/abcjs/api/abc_tunebook.js
39
39
  - app/assets/javascripts/abcjs/data/abc_tune.js
40
40
  - app/assets/javascripts/abcjs/edit/abc_editor.js
41
- - app/assets/javascripts/abcjs/midi/abc_midiwriter.js
41
+ - app/assets/javascripts/abcjs/midi/abc_midi_create.js
42
+ - app/assets/javascripts/abcjs/midi/abc_midi_flattener.js
43
+ - app/assets/javascripts/abcjs/midi/abc_midi_renderer.js
44
+ - app/assets/javascripts/abcjs/midi/abc_midi_sequencer.js
42
45
  - app/assets/javascripts/abcjs/parse/abc_common.js
43
46
  - app/assets/javascripts/abcjs/parse/abc_parse.js
44
47
  - app/assets/javascripts/abcjs/parse/abc_parse_directive.js
@@ -87,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
90
  version: '0'
88
91
  requirements: []
89
92
  rubyforge_project:
90
- rubygems_version: 2.4.5
93
+ rubygems_version: 2.4.5.1
91
94
  signing_key:
92
95
  specification_version: 4
93
96
  summary: This packages the abcjs javascript files in a gem for easy reuse in Rails
@@ -1,701 +0,0 @@
1
- /*global window, document, setTimeout */
2
-
3
- if (!window.ABCJS)
4
- window.ABCJS = {};
5
-
6
- if (!window.ABCJS.midi)
7
- window.ABCJS.midi = {};
8
-
9
- (function() {
10
- function setAttributes(elm, attrs){
11
- for(var attr in attrs)
12
- if (attrs.hasOwnProperty(attr))
13
- elm.setAttribute(attr, attrs[attr]);
14
- return elm;
15
- }
16
-
17
- //TODO-PER: put this back in when the MIDIPlugin works again.
18
- //window.oldunload = window.onbeforeunload;
19
- //window.onbeforeunload = function() {
20
- // if (window.oldunload)
21
- // window.oldunload();
22
- // if (typeof(MIDIPlugin) !== "undefined" && MIDIPlugin) { // PER: take care of crash in IE 8
23
- // MIDIPlugin.closePlugin();
24
- // }
25
- //};
26
-
27
-
28
- function MidiProxy(javamidi,qtmidi) {
29
- this.javamidi = javamidi;
30
- this.qtmidi = qtmidi;
31
- }
32
-
33
- MidiProxy.prototype.setTempo = function (qpm) {
34
- this.javamidi.setTempo(qpm);
35
- this.qtmidi.setTempo(qpm);
36
- };
37
-
38
- MidiProxy.prototype.startTrack = function () {
39
- this.javamidi.startTrack();
40
- this.qtmidi.startTrack();
41
- };
42
-
43
- MidiProxy.prototype.endTrack = function () {
44
- this.javamidi.endTrack();
45
- this.qtmidi.endTrack();
46
- };
47
-
48
- MidiProxy.prototype.setInstrument = function (number) {
49
- this.javamidi.setInstrument(number);
50
- this.qtmidi.setInstrument(number);
51
- };
52
-
53
- MidiProxy.prototype.startNote = function (pitch, loudness, abcelem) {
54
- this.javamidi.startNote(pitch, loudness, abcelem);
55
- this.qtmidi.startNote(pitch, loudness, abcelem);
56
- };
57
-
58
- MidiProxy.prototype.endNote = function (pitch, length) {
59
- this.javamidi.endNote(pitch, length);
60
- this.qtmidi.endNote(pitch, length);
61
- };
62
-
63
- MidiProxy.prototype.addRest = function (length) {
64
- this.javamidi.addRest(length);
65
- this.qtmidi.addRest(length);
66
- };
67
-
68
- MidiProxy.prototype.embed = function(parent) {
69
- this.javamidi.embed(parent);
70
- this.qtmidi.embed(parent,true);
71
- };
72
-
73
- function JavaMidi(midiwriter) {
74
- this.playlist = []; // contains {time:t,funct:f} pairs
75
- this.trackcount = 0;
76
- this.timecount = 0;
77
- this.tempo = 60;
78
- this.midiapi = MIDIPlugin;
79
- this.midiwriter = midiwriter;
80
- this.noteOnAndChannel = "%90";
81
- }
82
-
83
- JavaMidi.prototype.setTempo = function (qpm) {
84
- this.tempo = qpm;
85
- };
86
-
87
- JavaMidi.prototype.startTrack = function () {
88
- this.silencelength = 0;
89
- this.trackcount++;
90
- this.timecount=0;
91
- this.playlistpos=0;
92
- this.first=true;
93
- if (this.instrument) {
94
- this.setInstrument(this.instrument);
95
- }
96
- if (this.channel) {
97
- this.setChannel(this.channel);
98
- }
99
- };
100
-
101
- JavaMidi.prototype.endTrack = function () {
102
- // need to do anything?
103
- };
104
-
105
- JavaMidi.prototype.setInstrument = function (number) {
106
- this.instrument=number;
107
- this.midiapi.setInstrument(number);
108
- //TODO push this into the playlist?
109
- };
110
-
111
- JavaMidi.prototype.setChannel = function (number) {
112
- this.channel=number;
113
- this.midiapi.setChannel(number);
114
- };
115
-
116
- JavaMidi.prototype.updatePos = function() {
117
- while(this.playlist[this.playlistpos] &&
118
- this.playlist[this.playlistpos].time<this.timecount) {
119
- this.playlistpos++;
120
- }
121
- };
122
-
123
- JavaMidi.prototype.startNote = function (pitch, loudness, abcelem) {
124
- this.timecount+=this.silencelength;
125
- this.silencelength = 0;
126
- if (this.first) {
127
- //nothing special if first?
128
- }
129
- this.updatePos();
130
- var self=this;
131
- this.playlist.splice(this.playlistpos,0, {
132
- time:this.timecount,
133
- funct:function() {
134
- self.midiapi.playNote(pitch);
135
- self.midiwriter.notifySelect(abcelem);
136
- }
137
- });
138
- };
139
-
140
- JavaMidi.prototype.endNote = function (pitch, length) {
141
- this.timecount+=length;
142
- this.updatePos();
143
- var self=this;
144
- this.playlist.splice(this.playlistpos, 0, {
145
- time:this.timecount,
146
- funct: function() {
147
- self.midiapi.stopNote(pitch);
148
- }
149
- });
150
- };
151
-
152
- JavaMidi.prototype.addRest = function (length) {
153
- this.silencelength += length;
154
- };
155
-
156
- JavaMidi.prototype.embed = function(parent) {
157
-
158
-
159
- this.playlink = setAttributes(document.createElement('a'), {
160
- style: "border:1px solid black; margin:3px;"
161
- });
162
- this.playlink.innerHTML = "play";
163
- var self = this;
164
- this.playlink.onmousedown = function() {
165
- if (self.playing) {
166
- this.innerHTML = "play";
167
- self.pausePlay();
168
- } else {
169
- this.innerHTML = "pause";
170
- self.startPlay();
171
- }
172
- };
173
- parent.appendChild(this.playlink);
174
-
175
- var stoplink = setAttributes(document.createElement('a'), {
176
- style: "border:1px solid black; margin:3px;"
177
- });
178
- stoplink.innerHTML = "stop";
179
- //var self = this;
180
- stoplink.onmousedown = function() {
181
- self.stopPlay();
182
- };
183
- parent.appendChild(stoplink);
184
- this.i=0;
185
- this.currenttime=0;
186
- this.playing = false;
187
- };
188
-
189
- JavaMidi.prototype.stopPlay = function() {
190
- this.i=0;
191
- this.currenttime=0;
192
- this.pausePlay();
193
- this.playlink.innerHTML = "play";
194
- };
195
-
196
- JavaMidi.prototype.startPlay = function() {
197
- this.playing = true;
198
- var self = this;
199
- // repeat every 16th note TODO see the min in the piece
200
- this.ticksperinterval = 480/4;
201
- this.doPlay();
202
- this.playinterval = window.setInterval(function() {self.doPlay(); },
203
- (60000/(this.tempo*4)));
204
- };
205
-
206
- JavaMidi.prototype.pausePlay = function() {
207
- this.playing = false;
208
- window.clearInterval(this.playinterval);
209
- this.midiapi.stopAllNotes();
210
- };
211
-
212
- JavaMidi.prototype.doPlay = function() {
213
- while(this.playlist[this.i] &&
214
- this.playlist[this.i].time <= this.currenttime) {
215
- this.playlist[this.i].funct();
216
- this.i++;
217
- }
218
- if (this.playlist[this.i]) {
219
- this.currenttime+=this.ticksperinterval;
220
- } else {
221
- this.stopPlay();
222
- }
223
- };
224
-
225
- function Midi() {
226
- this.trackstrings="";
227
- this.trackcount = 0;
228
- this.noteOnAndChannel = "%90";
229
- }
230
-
231
- Midi.prototype.setTempo = function (qpm) {
232
- if (this.trackcount===0) {
233
- this.startTrack();
234
- this.track+="%00%FF%51%03"+toHex(Math.round(60000000/qpm),6);
235
- this.endTrack();
236
- }
237
- };
238
-
239
- Midi.prototype.startTrack = function () {
240
- this.track = "";
241
- this.silencelength = 0;
242
- this.trackcount++;
243
- this.first=true;
244
- if (this.instrument) {
245
- this.setInstrument(this.instrument);
246
- }
247
- };
248
-
249
- Midi.prototype.endTrack = function () {
250
- var tracklength = toHex(this.track.length/3+4,8);
251
- this.track = "MTrk"+tracklength+ // track header
252
- this.track +
253
- '%00%FF%2F%00'; // track end
254
- this.trackstrings += this.track;
255
- };
256
-
257
- Midi.prototype.setInstrument = function (number) {
258
- if (this.track)
259
- this.track = "%00%C0"+toHex(number,2)+this.track;
260
- else
261
- this.track = "%00%C0"+toHex(number,2);
262
- this.instrument=number;
263
- };
264
-
265
- Midi.prototype.setChannel = function (number) {
266
- this.channel=number - 1;
267
- this.noteOnAndChannel = "%9" + this.channel.toString(16);
268
- };
269
-
270
- Midi.prototype.startNote = function (pitch, loudness) {
271
- this.track+=toDurationHex(this.silencelength); // only need to shift by amount of silence (if there is any)
272
- this.silencelength = 0;
273
- if (this.first) {
274
- this.first = false;
275
- this.track+=this.noteOnAndChannel;
276
- }
277
- this.track += "%"+pitch.toString(16)+"%"+loudness; //note
278
- };
279
-
280
- Midi.prototype.endNote = function (pitch, length) {
281
- this.track += toDurationHex(length); //duration
282
- this.track += "%"+pitch.toString(16)+"%00";//end note
283
- };
284
-
285
- Midi.prototype.addRest = function (length) {
286
- this.silencelength += length;
287
- };
288
-
289
- Midi.prototype.embed = function(parent, noplayer) {
290
-
291
- var data="data:audio/midi," +
292
- "MThd%00%00%00%06%00%01"+toHex(this.trackcount,4)+"%01%e0"+ // header
293
- this.trackstrings;
294
-
295
- // var embedContainer = document.createElement("div");
296
- // embedContainer.className = "embedContainer";
297
- // document.body.appendChild(embedContainer);
298
- // embedContainer.innerHTML = '<object id="embed1" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab"><param name="src" value="' + data + '"></param><param name="Autoplay" value="false"></param><embed name="embed1" src="' + data + '" autostart="false" enablejavascript="true" /></object>';
299
- // embed = document["embed1"];
300
-
301
-
302
- var link = setAttributes(document.createElement('a'), {
303
- href: data
304
- });
305
- link.innerHTML = "download midi";
306
- parent.insertBefore(link,parent.firstChild);
307
-
308
- if (noplayer) return;
309
-
310
- var embed = setAttributes(document.createElement('embed'), {
311
- src : data,
312
- type : 'video/quicktime',
313
- controller : 'true',
314
- autoplay : 'false',
315
- loop : 'false',
316
- enablejavascript: 'true',
317
- style:'display:block; height: 20px;'
318
- });
319
- parent.insertBefore(embed,parent.firstChild);
320
- };
321
-
322
- // s is assumed to be of even length
323
- function encodeHex(s) {
324
- var ret = "";
325
- for (var i=0; i<s.length; i+=2) {
326
- ret += "%";
327
- ret += s.substr(i,2);
328
- }
329
- return ret;
330
- }
331
-
332
- function toHex(n, padding) {
333
- var s = n.toString(16);
334
- while (s.length<padding) {
335
- s="0"+s;
336
- }
337
- return encodeHex(s);
338
- }
339
-
340
- function toDurationHex(n) {
341
- var res = 0;
342
- var a = [];
343
-
344
- // cut up into 7 bit chunks;
345
- while (n!==0) {
346
- a.push(n & 0x7F);
347
- n = n>>7;
348
- }
349
-
350
- // join the 7 bit chunks together, all but last chunk get leading 1
351
- for (var i=a.length-1;i>=0;i--) {
352
- res = res << 8;
353
- var bits = a[i];
354
- if (i!==0) {
355
- bits = bits | 0x80;
356
- }
357
- res = res | bits;
358
- }
359
-
360
- var padding = res.toString(16).length;
361
- padding += padding%2;
362
-
363
- return toHex(res, padding);
364
- }
365
-
366
- ABCJS.midi.MidiWriter = function(parent, options) {
367
- options = options || {};
368
- this.parent = parent;
369
- this.scale = [0,2,4,5,7,9,11];
370
- this.restart = {line:0, staff:0, voice:0, pos:0};
371
- this.visited = {};
372
- this.multiplier =1;
373
- this.next = null;
374
- this.qpm = options.qpm || 180;
375
- this.program = options.program || 2;
376
- this.noteOnAndChannel = "%90";
377
- this.javamidi = options.type ==="java" || false;
378
- this.listeners = [];
379
- this.transpose = 0; // PER
380
- if (this.javamidi) {
381
- MIDIPlugin = document.MIDIPlugin;
382
- setTimeout(function() { // run on next event loop (once MIDIPlugin is loaded)
383
- try { // activate MIDIPlugin
384
- MIDIPlugin.openPlugin();
385
-
386
- } catch(e) { // plugin not supported (download externals)
387
- var a = document.createElement("a");
388
- a.href = "http://java.sun.com/products/java-media/sound/soundbanks.html";
389
- a.target = "_blank";
390
- a.appendChild(document.createTextNode("Download Soundbank"));
391
- parent.appendChild(a);
392
- }
393
- }, 0);
394
- }
395
-
396
- };
397
-
398
- ABCJS.midi.MidiWriter.prototype.addListener = function(listener) {
399
- this.listeners.push(listener);
400
- };
401
-
402
- ABCJS.midi.MidiWriter.prototype.notifySelect = function (abcelem) {
403
- for (var i=0; i<this.listeners.length;i++) {
404
- this.listeners[i].notifySelect(abcelem.abselem);
405
- }
406
- };
407
-
408
- ABCJS.midi.MidiWriter.prototype.getMark = function() {
409
- return {line:this.line, staff:this.staff,
410
- voice:this.voice, pos:this.pos};
411
- };
412
-
413
- ABCJS.midi.MidiWriter.prototype.getMarkString = function(mark) {
414
- mark = mark || this;
415
- return "line"+mark.line+"staff"+mark.staff+
416
- "voice"+mark.voice+"pos"+mark.pos;
417
- };
418
-
419
- ABCJS.midi.MidiWriter.prototype.goToMark = function(mark) {
420
- this.line=mark.line;
421
- this.staff=mark.staff;
422
- this.voice=mark.voice;
423
- this.pos=mark.pos;
424
- };
425
-
426
- ABCJS.midi.MidiWriter.prototype.markVisited = function() {
427
- this.lastmark = this.getMarkString();
428
- this.visited[this.lastmark] = true;
429
- };
430
-
431
- ABCJS.midi.MidiWriter.prototype.isVisited = function() {
432
- if (this.visited[this.getMarkString()]) return true;
433
- return false;
434
- };
435
-
436
- ABCJS.midi.MidiWriter.prototype.setJumpMark = function(mark) {
437
- this.visited[this.lastmark] = mark;
438
- };
439
-
440
- ABCJS.midi.MidiWriter.prototype.getJumpMark = function() {
441
- return this.visited[this.getMarkString()];
442
- };
443
-
444
- ABCJS.midi.MidiWriter.prototype.getLine = function() {
445
- return this.abctune.lines[this.line];
446
- };
447
-
448
- ABCJS.midi.MidiWriter.prototype.getStaff = function() {
449
- try {
450
- return this.getLine().staff[this.staff];
451
- } catch (e) {
452
-
453
- }
454
- };
455
-
456
- ABCJS.midi.MidiWriter.prototype.getVoice = function() {
457
- return this.getStaff().voices[this.voice];
458
- };
459
-
460
- ABCJS.midi.MidiWriter.prototype.getElem = function() {
461
- return this.getVoice()[this.pos];
462
- };
463
-
464
- ABCJS.midi.MidiWriter.prototype.writeABC = function(abctune) {
465
- try {
466
- this.midi = (this.javamidi) ? new MidiProxy(new JavaMidi(this), new Midi()) : new Midi();
467
- this.baraccidentals = [];
468
- this.abctune = abctune;
469
- this.baseduration = 480*4; // nice and divisible, equals 1 whole note
470
-
471
- // PER: add global transposition.
472
- if (abctune.formatting.midi && abctune.formatting.midi.transpose)
473
- this.transpose = abctune.formatting.midi.transpose;
474
-
475
- // PER: changed format of the global midi commands from the parser. Using the new definition here.
476
- if (abctune.formatting.midi && abctune.formatting.midi.program && abctune.formatting.midi.program.program) {
477
- this.midi.setInstrument(abctune.formatting.midi.program.program);
478
- } else {
479
- this.midi.setInstrument(this.program);
480
- }
481
- if (abctune.formatting.midi && abctune.formatting.midi.channel) {
482
- this.midi.setChannel(abctune.formatting.midi.channel);
483
- }
484
-
485
- if (abctune.metaText.tempo) {
486
- var duration = 1/4;
487
- if (abctune.metaText.tempo.duration) {
488
- duration = abctune.metaText.tempo.duration[0];
489
- }
490
- var bpm = 60;
491
- if (abctune.metaText.tempo.bpm) {
492
- bpm = abctune.metaText.tempo.bpm;
493
- }
494
- this.qpm = bpm*duration*4;
495
- }
496
- this.midi.setTempo(this.qpm);
497
-
498
- // visit each voice completely in turn
499
- // "problematic" because it means visiting only one staff+voice for each line each time
500
- this.staffcount=1; // we'll know the actual number once we enter the code
501
- for(this.staff=0;this.staff<this.staffcount;this.staff++) {
502
- this.voicecount=1;
503
- for(this.voice=0;this.voice<this.voicecount;this.voice++) {
504
- this.midi.startTrack();
505
- this.restart = {line:0, staff:this.staff, voice:this.voice, pos:0};
506
- this.next= null;
507
- for(this.line=0; this.line<abctune.lines.length; this.line++) {
508
- var abcline = abctune.lines[this.line];
509
- if (this.getLine().staff) {
510
- this.writeABCLine();
511
- }
512
- }
513
- this.midi.endTrack();
514
- }
515
- }
516
-
517
- this.midi.embed(this.parent);
518
- } catch (e) {
519
- this.parent.innerHTML="Couldn't write midi: "+e;
520
- }
521
- };
522
-
523
- ABCJS.midi.MidiWriter.prototype.writeABCLine = function() {
524
- this.staffcount = this.getLine().staff.length;
525
- this.voicecount = this.getStaff().voices.length;
526
- this.setKeySignature(this.getStaff().key);
527
- this.writeABCVoiceLine();
528
- };
529
-
530
- ABCJS.midi.MidiWriter.prototype.writeABCVoiceLine = function () {
531
- this.pos=0;
532
- while (this.pos<this.getVoice().length) {
533
- this.writeABCElement(this.getElem());
534
- if (this.next) {
535
- this.goToMark(this.next);
536
- this.next = null;
537
- if (!this.getLine().staff) return;
538
- } else {
539
- this.pos++;
540
- }
541
- }
542
- };
543
-
544
- ABCJS.midi.MidiWriter.prototype.writeABCElement = function(elem) {
545
- var foo;
546
- switch (elem.el_type) {
547
- case "note":
548
- this.writeNote(elem);
549
- break;
550
-
551
- case "key":
552
- this.setKeySignature(elem);
553
- break;
554
- case "bar":
555
- this.handleBar(elem);
556
- break;
557
- case "meter":
558
- case "clef":
559
- break;
560
- default:
561
-
562
- }
563
-
564
- };
565
-
566
-
567
- ABCJS.midi.MidiWriter.prototype.writeNote = function(elem) {
568
-
569
- if (elem.startTriplet) {
570
- if (elem.startTriplet === 2)
571
- this.multiplier = 3/2;
572
- else
573
- this.multiplier=(elem.startTriplet-1)/elem.startTriplet;
574
- }
575
-
576
- var mididuration = elem.duration*this.baseduration*this.multiplier;
577
- if (elem.pitches) {
578
- var midipitches = [];
579
- for (var i=0; i<elem.pitches.length; i++) {
580
- var note = elem.pitches[i];
581
- var pitch= note.pitch;
582
- if (note.accidental) {
583
- switch(note.accidental) { // change that pitch (not other octaves) for the rest of the bar
584
- case "sharp":
585
- this.baraccidentals[pitch]=1; break;
586
- case "flat":
587
- this.baraccidentals[pitch]=-1; break;
588
- case "natural":
589
- this.baraccidentals[pitch]=0; break;
590
- case "dblsharp":
591
- this.baraccidentals[pitch]=2; break;
592
- case "dblflat":
593
- this.baraccidentals[pitch]=-2; break;
594
- }
595
- }
596
-
597
- midipitches[i] = 60 + 12*this.extractOctave(pitch)+this.scale[this.extractNote(pitch)];
598
-
599
- if (this.baraccidentals[pitch]!==undefined) {
600
- midipitches[i] += this.baraccidentals[pitch];
601
- } else { // use normal accidentals
602
- midipitches[i] += this.accidentals[this.extractNote(pitch)];
603
- }
604
- midipitches[i] += this.transpose; // PER
605
-
606
- this.midi.startNote(midipitches[i], 64, elem);
607
-
608
- if (note.startTie) {
609
- this.tieduration=mididuration;
610
- }
611
- }
612
-
613
- for (i=0; i<elem.pitches.length; i++) {
614
- var note = elem.pitches[i];
615
- var pitch= note.pitch+this.transpose; // PER
616
- if (note.startTie) continue; // don't terminate it
617
- if (note.endTie) {
618
- this.midi.endNote(midipitches[i],mididuration+this.tieduration);
619
- } else {
620
- this.midi.endNote(midipitches[i],mididuration);
621
- }
622
- mididuration = 0; // put these to zero as we've moved forward in the midi
623
- this.tieduration=0;
624
- }
625
- } else if (elem.rest && elem.rest.type !== 'spacer') {
626
- this.midi.addRest(mididuration);
627
- }
628
-
629
- if (elem.endTriplet) {
630
- this.multiplier=1;
631
- }
632
-
633
- };
634
-
635
- ABCJS.midi.MidiWriter.prototype.handleBar = function (elem) {
636
- this.baraccidentals = [];
637
-
638
-
639
- var repeat = (elem.type==="bar_right_repeat" || elem.type==="bar_dbl_repeat");
640
- var skip = (elem.startEnding)?true:false;
641
- var setvisited = (repeat || skip);
642
- var setrestart = (elem.type==="bar_left_repeat" || elem.type==="bar_dbl_repeat" || elem.type==="bar_thick_thin" || elem.type==="bar_thin_thick" || elem.type==="bar_thin_thin" || elem.type==="bar_right_repeat");
643
-
644
- var next = null;
645
-
646
- if (this.isVisited()) {
647
- next = this.getJumpMark();
648
- } else {
649
-
650
- if (skip || repeat) {
651
- if (this.visited[this.lastmark] === true) {
652
- this.setJumpMark(this.getMark());
653
- }
654
- }
655
-
656
- if (setvisited) {
657
- this.markVisited();
658
- }
659
-
660
- if (repeat) {
661
- next = this.restart;
662
- this.setJumpMark(this.getMark());
663
- }
664
- }
665
-
666
- if (setrestart) {
667
- this.restart = this.getMark();
668
- }
669
-
670
- if (next && this.getMarkString(next)!==this.getMarkString()) {
671
- this.next = next;
672
- }
673
-
674
- };
675
-
676
- ABCJS.midi.MidiWriter.prototype.setKeySignature = function(elem) {
677
- this.accidentals = [0,0,0,0,0,0,0];
678
- if (this.abctune.formatting.bagpipes) {
679
- elem.accidentals=[{acc: 'natural', note: 'g'}, {acc: 'sharp', note: 'f'}, {acc: 'sharp', note: 'c'}];
680
- }
681
- if (!elem.accidentals) return;
682
- window.ABCJS.parse.each(elem.accidentals, function(acc) {
683
- var d = (acc.acc === "sharp") ? 1 : (acc.acc === "natural") ?0 : -1;
684
-
685
- var lowercase = acc.note.toLowerCase();
686
- var note = this.extractNote(lowercase.charCodeAt(0)-'c'.charCodeAt(0));
687
- this.accidentals[note]+=d;
688
- }, this);
689
-
690
- };
691
-
692
- ABCJS.midi.MidiWriter.prototype.extractNote = function(pitch) {
693
- pitch = pitch%7;
694
- if (pitch<0) pitch+=7;
695
- return pitch;
696
- };
697
-
698
- ABCJS.midi.MidiWriter.prototype.extractOctave = function(pitch) {
699
- return Math.floor(pitch/7);
700
- };
701
- })();