abcjs-rails 2.1 → 2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- })();