@marmooo/midy 0.0.2 → 0.0.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/esm/midy-GM1.d.ts +6 -14
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +104 -155
- package/esm/midy-GM2.d.ts +17 -107
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +152 -133
- package/esm/midy-GMLite.d.ts +6 -14
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +104 -155
- package/esm/midy.d.ts +47 -10
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +173 -129
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +6 -14
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +104 -155
- package/script/midy-GM2.d.ts +17 -107
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +152 -133
- package/script/midy-GMLite.d.ts +6 -14
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +104 -155
- package/script/midy.d.ts +47 -10
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +173 -129
package/script/midy-GM1.js
CHANGED
|
@@ -11,12 +11,6 @@ class MidyGM1 {
|
|
|
11
11
|
writable: true,
|
|
12
12
|
value: 120
|
|
13
13
|
});
|
|
14
|
-
Object.defineProperty(this, "secondsPerBeat", {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true,
|
|
18
|
-
value: 0.5
|
|
19
|
-
});
|
|
20
14
|
Object.defineProperty(this, "totalTime", {
|
|
21
15
|
enumerable: true,
|
|
22
16
|
configurable: true,
|
|
@@ -147,10 +141,10 @@ class MidyGM1 {
|
|
|
147
141
|
const response = await fetch(midiUrl);
|
|
148
142
|
const arrayBuffer = await response.arrayBuffer();
|
|
149
143
|
const midi = (0, _esm_js_1.parseMidi)(new Uint8Array(arrayBuffer));
|
|
144
|
+
this.ticksPerBeat = midi.header.ticksPerBeat;
|
|
150
145
|
const midiData = this.extractMidiData(midi);
|
|
151
146
|
this.instruments = midiData.instruments;
|
|
152
147
|
this.timeline = midiData.timeline;
|
|
153
|
-
this.ticksPerBeat = midi.header.ticksPerBeat;
|
|
154
148
|
this.totalTime = this.calcTotalTime();
|
|
155
149
|
}
|
|
156
150
|
setChannelAudioNodes(audioContext) {
|
|
@@ -229,28 +223,30 @@ class MidyGM1 {
|
|
|
229
223
|
async scheduleTimelineEvents(t, offset, queueIndex) {
|
|
230
224
|
while (queueIndex < this.timeline.length) {
|
|
231
225
|
const event = this.timeline[queueIndex];
|
|
232
|
-
|
|
233
|
-
if (time > t + this.lookAhead)
|
|
226
|
+
if (event.startTime > t + this.lookAhead)
|
|
234
227
|
break;
|
|
235
228
|
switch (event.type) {
|
|
236
|
-
case "controller":
|
|
237
|
-
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
238
|
-
break;
|
|
239
229
|
case "noteOn":
|
|
240
|
-
|
|
241
|
-
|
|
230
|
+
if (event.velocity !== 0) {
|
|
231
|
+
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
/* falls through */
|
|
242
235
|
case "noteOff": {
|
|
243
|
-
const notePromise = this.scheduleNoteRelease(event.channel, event.noteNumber, event.velocity,
|
|
236
|
+
const notePromise = this.scheduleNoteRelease(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
244
237
|
if (notePromise) {
|
|
245
238
|
this.notePromises.push(notePromise);
|
|
246
239
|
}
|
|
247
240
|
break;
|
|
248
241
|
}
|
|
242
|
+
case "controller":
|
|
243
|
+
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
244
|
+
break;
|
|
249
245
|
case "programChange":
|
|
250
246
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
251
247
|
break;
|
|
252
|
-
case "
|
|
253
|
-
this.
|
|
248
|
+
case "pitchBend":
|
|
249
|
+
this.handlePitchBend(event.channel, event.value);
|
|
254
250
|
break;
|
|
255
251
|
case "sysEx":
|
|
256
252
|
this.handleSysEx(event.data);
|
|
@@ -260,9 +256,8 @@ class MidyGM1 {
|
|
|
260
256
|
return queueIndex;
|
|
261
257
|
}
|
|
262
258
|
getQueueIndex(second) {
|
|
263
|
-
const ticks = this.secondToTicks(second, this.secondsPerBeat);
|
|
264
259
|
for (let i = 0; i < this.timeline.length; i++) {
|
|
265
|
-
if (
|
|
260
|
+
if (second <= this.timeline[i].startTime) {
|
|
266
261
|
return i;
|
|
267
262
|
}
|
|
268
263
|
}
|
|
@@ -370,18 +365,28 @@ class MidyGM1 {
|
|
|
370
365
|
timeline.push(event);
|
|
371
366
|
});
|
|
372
367
|
});
|
|
368
|
+
const priority = {
|
|
369
|
+
setTempo: 0,
|
|
370
|
+
controller: 1,
|
|
371
|
+
};
|
|
373
372
|
timeline.sort((a, b) => {
|
|
374
|
-
if (a.ticks !== b.ticks)
|
|
373
|
+
if (a.ticks !== b.ticks)
|
|
375
374
|
return a.ticks - b.ticks;
|
|
376
|
-
|
|
377
|
-
if (a.type !== "controller" && b.type === "controller") {
|
|
378
|
-
return -1;
|
|
379
|
-
}
|
|
380
|
-
if (a.type === "controller" && b.type !== "controller") {
|
|
381
|
-
return 1;
|
|
382
|
-
}
|
|
383
|
-
return 0;
|
|
375
|
+
return (priority[a.type] || 2) - (priority[b.type] || 2);
|
|
384
376
|
});
|
|
377
|
+
let prevTempoTime = 0;
|
|
378
|
+
let prevTempoTicks = 0;
|
|
379
|
+
let secondsPerBeat = 0.5;
|
|
380
|
+
for (let i = 0; i < timeline.length; i++) {
|
|
381
|
+
const event = timeline[i];
|
|
382
|
+
const timeFromPrevTempo = this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
|
|
383
|
+
event.startTime = prevTempoTime + timeFromPrevTempo;
|
|
384
|
+
if (event.type === "setTempo") {
|
|
385
|
+
prevTempoTime += this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
|
|
386
|
+
secondsPerBeat = event.microsecondsPerBeat / 1000000;
|
|
387
|
+
prevTempoTicks = event.ticks;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
385
390
|
return { instruments, timeline };
|
|
386
391
|
}
|
|
387
392
|
stopNotes() {
|
|
@@ -433,32 +438,12 @@ class MidyGM1 {
|
|
|
433
438
|
}
|
|
434
439
|
}
|
|
435
440
|
calcTotalTime() {
|
|
436
|
-
const endOfTracks = [];
|
|
437
|
-
let prevTicks = 0;
|
|
438
441
|
let totalTime = 0;
|
|
439
|
-
let secondsPerBeat = 0.5;
|
|
440
442
|
for (let i = 0; i < this.timeline.length; i++) {
|
|
441
443
|
const event = this.timeline[i];
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const durationTicks = event.ticks - prevTicks;
|
|
445
|
-
totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
|
|
446
|
-
secondsPerBeat = event.microsecondsPerBeat / 1000000;
|
|
447
|
-
prevTicks = event.ticks;
|
|
448
|
-
break;
|
|
449
|
-
}
|
|
450
|
-
case "endOfTrack":
|
|
451
|
-
endOfTracks.push(event);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
let maxTicks = 0;
|
|
455
|
-
for (let i = 0; i < endOfTracks.length; i++) {
|
|
456
|
-
const event = endOfTracks[i];
|
|
457
|
-
if (maxTicks < event.ticks)
|
|
458
|
-
maxTicks = event.ticks;
|
|
444
|
+
if (totalTime < event.startTime)
|
|
445
|
+
totalTime = event.startTime;
|
|
459
446
|
}
|
|
460
|
-
const durationTicks = maxTicks - prevTicks;
|
|
461
|
-
totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
|
|
462
447
|
return totalTime;
|
|
463
448
|
}
|
|
464
449
|
currentTime() {
|
|
@@ -486,43 +471,8 @@ class MidyGM1 {
|
|
|
486
471
|
const lfo = new OscillatorNode(audioContext, {
|
|
487
472
|
frequency: 5,
|
|
488
473
|
});
|
|
489
|
-
const lfoGain = new GainNode(audioContext);
|
|
490
|
-
lfo.connect(lfoGain);
|
|
491
474
|
return {
|
|
492
475
|
lfo,
|
|
493
|
-
lfoGain,
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
createReverbEffect(audioContext, options = {}) {
|
|
497
|
-
const { decay = 0.8, preDecay = 0, } = options;
|
|
498
|
-
const sampleRate = audioContext.sampleRate;
|
|
499
|
-
const length = sampleRate * decay;
|
|
500
|
-
const impulse = new AudioBuffer({
|
|
501
|
-
numberOfChannels: 2,
|
|
502
|
-
length,
|
|
503
|
-
sampleRate,
|
|
504
|
-
});
|
|
505
|
-
const preDecayLength = Math.min(sampleRate * preDecay, length);
|
|
506
|
-
for (let channel = 0; channel < impulse.numberOfChannels; channel++) {
|
|
507
|
-
const channelData = impulse.getChannelData(channel);
|
|
508
|
-
for (let i = 0; i < preDecayLength; i++) {
|
|
509
|
-
channelData[i] = Math.random() * 2 - 1;
|
|
510
|
-
}
|
|
511
|
-
for (let i = preDecayLength; i < length; i++) {
|
|
512
|
-
const attenuation = Math.exp(-(i - preDecayLength) / sampleRate / decay);
|
|
513
|
-
channelData[i] = (Math.random() * 2 - 1) * attenuation;
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
const convolverNode = new ConvolverNode(audioContext, {
|
|
517
|
-
buffer: impulse,
|
|
518
|
-
});
|
|
519
|
-
const dryGain = new GainNode(audioContext);
|
|
520
|
-
const wetGain = new GainNode(audioContext);
|
|
521
|
-
convolverNode.connect(wetGain);
|
|
522
|
-
return {
|
|
523
|
-
convolverNode,
|
|
524
|
-
dryGain,
|
|
525
|
-
wetGain,
|
|
526
476
|
};
|
|
527
477
|
}
|
|
528
478
|
connectNoteEffects(channel, gainNode) {
|
|
@@ -534,13 +484,17 @@ class MidyGM1 {
|
|
|
534
484
|
centToHz(cent) {
|
|
535
485
|
return 8.176 * Math.pow(2, cent / 1200);
|
|
536
486
|
}
|
|
537
|
-
|
|
487
|
+
calcSemitoneOffset(channel) {
|
|
538
488
|
const tuning = channel.coarseTuning + channel.fineTuning;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
489
|
+
return channel.pitchBend * channel.pitchBendRange + tuning;
|
|
490
|
+
}
|
|
491
|
+
calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
|
|
492
|
+
return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
|
|
493
|
+
}
|
|
494
|
+
async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
|
|
542
495
|
const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
|
|
543
|
-
|
|
496
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
497
|
+
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
544
498
|
// volume envelope
|
|
545
499
|
const gainNode = new GainNode(this.audioContext, {
|
|
546
500
|
gain: 0,
|
|
@@ -559,12 +513,6 @@ class MidyGM1 {
|
|
|
559
513
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
560
514
|
.setValueAtTime(attackVolume, volHold)
|
|
561
515
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
562
|
-
if (channel.modulation > 0) {
|
|
563
|
-
const lfoGain = channel.modulationEffect.lfoGain;
|
|
564
|
-
lfoGain.connect(bufferSource.detune);
|
|
565
|
-
lfoGain.gain.cancelScheduledValues(startTime + channel.vibratoDelay);
|
|
566
|
-
lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
|
|
567
|
-
}
|
|
568
516
|
// filter envelope
|
|
569
517
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
570
518
|
const baseFreq = this.centToHz(noteInfo.initialFilterFc);
|
|
@@ -588,10 +536,23 @@ class MidyGM1 {
|
|
|
588
536
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
589
537
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
590
538
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
539
|
+
let lfoGain;
|
|
540
|
+
if (channel.modulation > 0) {
|
|
541
|
+
const vibratoDelay = startTime + channel.vibratoDelay;
|
|
542
|
+
const vibratoAttack = vibratoDelay + 0.1;
|
|
543
|
+
lfoGain = new GainNode(this.audioContext, {
|
|
544
|
+
gain: 0,
|
|
545
|
+
});
|
|
546
|
+
lfoGain.gain
|
|
547
|
+
.setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
548
|
+
.exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
|
|
549
|
+
channel.modulationEffect.lfo.connect(lfoGain);
|
|
550
|
+
lfoGain.connect(bufferSource.detune);
|
|
551
|
+
}
|
|
591
552
|
bufferSource.connect(filterNode);
|
|
592
553
|
filterNode.connect(gainNode);
|
|
593
554
|
bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
|
|
594
|
-
return { bufferSource, gainNode, filterNode };
|
|
555
|
+
return { bufferSource, gainNode, filterNode, lfoGain };
|
|
595
556
|
}
|
|
596
557
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
597
558
|
const channel = this.channels[channelNumber];
|
|
@@ -604,16 +565,17 @@ class MidyGM1 {
|
|
|
604
565
|
const noteInfo = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
|
|
605
566
|
if (!noteInfo)
|
|
606
567
|
return;
|
|
607
|
-
const { bufferSource, gainNode, filterNode } = await this
|
|
568
|
+
const { bufferSource, gainNode, filterNode, lfoGain } = await this
|
|
608
569
|
.createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3);
|
|
609
570
|
this.connectNoteEffects(channel, gainNode);
|
|
610
571
|
const scheduledNotes = channel.scheduledNotes;
|
|
611
572
|
const scheduledNote = {
|
|
612
|
-
gainNode,
|
|
613
|
-
filterNode,
|
|
614
573
|
bufferSource,
|
|
615
|
-
|
|
574
|
+
filterNode,
|
|
575
|
+
gainNode,
|
|
576
|
+
lfoGain,
|
|
616
577
|
noteInfo,
|
|
578
|
+
noteNumber,
|
|
617
579
|
startTime,
|
|
618
580
|
};
|
|
619
581
|
if (scheduledNotes.has(noteNumber)) {
|
|
@@ -640,7 +602,7 @@ class MidyGM1 {
|
|
|
640
602
|
continue;
|
|
641
603
|
if (targetNote.ending)
|
|
642
604
|
continue;
|
|
643
|
-
const { bufferSource, filterNode, gainNode, noteInfo } = targetNote;
|
|
605
|
+
const { bufferSource, filterNode, gainNode, lfoGain, noteInfo } = targetNote;
|
|
644
606
|
const velocityRate = (velocity + 127) / 127;
|
|
645
607
|
const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
|
|
646
608
|
gainNode.gain.cancelScheduledValues(stopTime);
|
|
@@ -662,6 +624,8 @@ class MidyGM1 {
|
|
|
662
624
|
bufferSource.disconnect(0);
|
|
663
625
|
filterNode.disconnect(0);
|
|
664
626
|
gainNode.disconnect(0);
|
|
627
|
+
if (lfoGain)
|
|
628
|
+
lfoGain.disconnect(0);
|
|
665
629
|
resolve();
|
|
666
630
|
};
|
|
667
631
|
bufferSource.stop(volEndTime);
|
|
@@ -672,28 +636,21 @@ class MidyGM1 {
|
|
|
672
636
|
const now = this.audioContext.currentTime;
|
|
673
637
|
return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now);
|
|
674
638
|
}
|
|
675
|
-
releaseSustainPedal(channelNumber) {
|
|
676
|
-
const
|
|
639
|
+
releaseSustainPedal(channelNumber, halfVelocity) {
|
|
640
|
+
const velocity = halfVelocity * 2;
|
|
677
641
|
const channel = this.channels[channelNumber];
|
|
642
|
+
const promises = [];
|
|
678
643
|
channel.sustainPedal = false;
|
|
679
644
|
channel.scheduledNotes.forEach((scheduledNotes) => {
|
|
680
645
|
scheduledNotes.forEach((scheduledNote) => {
|
|
681
646
|
if (scheduledNote) {
|
|
682
|
-
const {
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
gainNode.gain.linearRampToValueAtTime(0, volEndTime);
|
|
686
|
-
const maxFreq = this.audioContext.sampleRate / 2;
|
|
687
|
-
const baseFreq = this.centToHz(noteInfo.initialFilterFc);
|
|
688
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
689
|
-
const modEndTime = now + noteInfo.modRelease;
|
|
690
|
-
filterNode.frequency
|
|
691
|
-
.cancelScheduledValues(stopTime)
|
|
692
|
-
.linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
|
|
693
|
-
bufferSource.stop(volEndTime);
|
|
647
|
+
const { noteNumber } = scheduledNote;
|
|
648
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
649
|
+
promises.push(promise);
|
|
694
650
|
}
|
|
695
651
|
});
|
|
696
652
|
});
|
|
653
|
+
return promises;
|
|
697
654
|
}
|
|
698
655
|
handleMIDIMessage(statusByte, data1, data2) {
|
|
699
656
|
const channelNumber = statusByte & 0x0F;
|
|
@@ -703,46 +660,37 @@ class MidyGM1 {
|
|
|
703
660
|
return this.releaseNote(channelNumber, data1, data2);
|
|
704
661
|
case 0x90:
|
|
705
662
|
return this.noteOn(channelNumber, data1, data2);
|
|
706
|
-
case 0xA0:
|
|
707
|
-
return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
|
|
708
663
|
case 0xB0:
|
|
709
664
|
return this.handleControlChange(channelNumber, data1, data2);
|
|
710
665
|
case 0xC0:
|
|
711
666
|
return this.handleProgramChange(channelNumber, data1);
|
|
712
|
-
case 0xD0:
|
|
713
|
-
return this.handleChannelPressure(channelNumber, data1);
|
|
714
667
|
case 0xE0:
|
|
715
|
-
return this.
|
|
668
|
+
return this.handlePitchBendMessage(channelNumber, data1, data2);
|
|
716
669
|
default:
|
|
717
670
|
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
718
671
|
}
|
|
719
672
|
}
|
|
720
|
-
handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
|
|
721
|
-
const now = this.audioContext.currentTime;
|
|
722
|
-
const channel = this.channels[channelNumber];
|
|
723
|
-
const scheduledNotes = channel.scheduledNotes.get(noteNumber);
|
|
724
|
-
pressure /= 127;
|
|
725
|
-
if (scheduledNotes) {
|
|
726
|
-
scheduledNotes.forEach((scheduledNote) => {
|
|
727
|
-
if (scheduledNote) {
|
|
728
|
-
const { initialAttenuation } = scheduledNote.noteInfo;
|
|
729
|
-
const gain = this.cbToRatio(-initialAttenuation) * pressure;
|
|
730
|
-
scheduledNote.gainNode.gain.cancelScheduledValues(now);
|
|
731
|
-
scheduledNote.gainNode.gain.setValueAtTime(gain, now);
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
673
|
handleProgramChange(channelNumber, program) {
|
|
737
674
|
const channel = this.channels[channelNumber];
|
|
738
675
|
channel.program = program;
|
|
739
676
|
}
|
|
740
|
-
|
|
741
|
-
|
|
677
|
+
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
678
|
+
const pitchBend = msb * 128 + lsb;
|
|
679
|
+
this.handlePitchBend(channelNumber, pitchBend);
|
|
742
680
|
}
|
|
743
|
-
handlePitchBend(channelNumber,
|
|
744
|
-
const
|
|
745
|
-
this.channels[channelNumber]
|
|
681
|
+
handlePitchBend(channelNumber, pitchBend) {
|
|
682
|
+
const now = this.audioContext.currentTime;
|
|
683
|
+
const channel = this.channels[channelNumber];
|
|
684
|
+
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
685
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
686
|
+
const activeNotes = this.getActiveNotes(channel);
|
|
687
|
+
activeNotes.forEach((activeNote) => {
|
|
688
|
+
const { bufferSource, noteInfo, noteNumber } = activeNote;
|
|
689
|
+
const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
690
|
+
bufferSource.playbackRate
|
|
691
|
+
.cancelScheduledValues(now)
|
|
692
|
+
.setValueAtTime(playbackRate * pressure, now);
|
|
693
|
+
});
|
|
746
694
|
}
|
|
747
695
|
handleControlChange(channelNumber, controller, value) {
|
|
748
696
|
switch (controller) {
|
|
@@ -775,13 +723,9 @@ class MidyGM1 {
|
|
|
775
723
|
}
|
|
776
724
|
}
|
|
777
725
|
setModulation(channelNumber, modulation) {
|
|
778
|
-
const now = this.audioContext.currentTime;
|
|
779
726
|
const channel = this.channels[channelNumber];
|
|
780
|
-
channel.modulation = (modulation
|
|
781
|
-
channel.modulationDepthRange;
|
|
782
|
-
const lfoGain = channel.modulationEffect.lfoGain;
|
|
783
|
-
lfoGain.gain.cancelScheduledValues(now);
|
|
784
|
-
lfoGain.gain.setValueAtTime(channel.modulation, now);
|
|
727
|
+
channel.modulation = (modulation / 127) *
|
|
728
|
+
(channel.modulationDepthRange * 100);
|
|
785
729
|
}
|
|
786
730
|
setVolume(channelNumber, volume) {
|
|
787
731
|
const channel = this.channels[channelNumber];
|
|
@@ -810,7 +754,7 @@ class MidyGM1 {
|
|
|
810
754
|
const isOn = value >= 64;
|
|
811
755
|
this.channels[channelNumber].sustainPedal = isOn;
|
|
812
756
|
if (!isOn) {
|
|
813
|
-
this.releaseSustainPedal(channelNumber);
|
|
757
|
+
this.releaseSustainPedal(channelNumber, value);
|
|
814
758
|
}
|
|
815
759
|
}
|
|
816
760
|
setRPNMSB(channelNumber, value) {
|
|
@@ -912,13 +856,18 @@ class MidyGM1 {
|
|
|
912
856
|
}
|
|
913
857
|
}
|
|
914
858
|
handleMasterVolumeSysEx(data) {
|
|
915
|
-
const volume = (data[5] * 128 + data[4]
|
|
859
|
+
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
916
860
|
this.handleMasterVolume(volume);
|
|
917
861
|
}
|
|
918
862
|
handleMasterVolume(volume) {
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
863
|
+
if (volume < 0 && 1 < volume) {
|
|
864
|
+
console.error("Master Volume is out of range");
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
const now = this.audioContext.currentTime;
|
|
868
|
+
this.masterGain.gain.cancelScheduledValues(now);
|
|
869
|
+
this.masterGain.gain.setValueAtTime(volume * volume, now);
|
|
870
|
+
}
|
|
922
871
|
}
|
|
923
872
|
handleExclusiveMessage(data) {
|
|
924
873
|
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
@@ -951,7 +900,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
|
|
|
951
900
|
configurable: true,
|
|
952
901
|
writable: true,
|
|
953
902
|
value: {
|
|
954
|
-
volume:
|
|
903
|
+
volume: 100 / 127,
|
|
955
904
|
pan: 0,
|
|
956
905
|
vibratoRate: 5,
|
|
957
906
|
vibratoDepth: 0.5,
|
|
@@ -963,7 +912,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
|
|
|
963
912
|
pitchBend: 0,
|
|
964
913
|
fineTuning: 0,
|
|
965
914
|
coarseTuning: 0,
|
|
966
|
-
modulationDepthRange:
|
|
915
|
+
modulationDepthRange: 0.5,
|
|
967
916
|
}
|
|
968
917
|
});
|
|
969
918
|
Object.defineProperty(MidyGM1, "effectSettings", {
|
package/script/midy-GM2.d.ts
CHANGED
|
@@ -32,9 +32,16 @@ export class MidyGM2 {
|
|
|
32
32
|
channelPressure: number;
|
|
33
33
|
pitchBendRange: number;
|
|
34
34
|
};
|
|
35
|
+
static controllerDestinationSettings: {
|
|
36
|
+
pitchControl: number;
|
|
37
|
+
filterCutoffControl: number;
|
|
38
|
+
amplitudeControl: number;
|
|
39
|
+
lfoPitchDepth: number;
|
|
40
|
+
lfoFilterDepth: number;
|
|
41
|
+
lfoAmplitudeDepth: number;
|
|
42
|
+
};
|
|
35
43
|
constructor(audioContext: any);
|
|
36
44
|
ticksPerBeat: number;
|
|
37
|
-
secondsPerBeat: number;
|
|
38
45
|
totalTime: number;
|
|
39
46
|
reverbFactor: number;
|
|
40
47
|
masterFineTuning: number;
|
|
@@ -58,56 +65,7 @@ export class MidyGM2 {
|
|
|
58
65
|
notePromises: any[];
|
|
59
66
|
audioContext: any;
|
|
60
67
|
masterGain: any;
|
|
61
|
-
channels:
|
|
62
|
-
scheduledNotes: Map<any, any>;
|
|
63
|
-
sostenutoNotes: Map<any, any>;
|
|
64
|
-
gainNode: any;
|
|
65
|
-
pannerNode: any;
|
|
66
|
-
modulationEffect: {
|
|
67
|
-
lfo: any;
|
|
68
|
-
lfoGain: any;
|
|
69
|
-
};
|
|
70
|
-
reverbEffect: {
|
|
71
|
-
convolverNode: any;
|
|
72
|
-
dryGain: any;
|
|
73
|
-
wetGain: any;
|
|
74
|
-
};
|
|
75
|
-
chorusEffect: {
|
|
76
|
-
lfo: any;
|
|
77
|
-
lfoGain: any;
|
|
78
|
-
delayNodes: any[];
|
|
79
|
-
chorusGains: any[];
|
|
80
|
-
};
|
|
81
|
-
expression: number;
|
|
82
|
-
modulation: number;
|
|
83
|
-
sustainPedal: boolean;
|
|
84
|
-
portamento: boolean;
|
|
85
|
-
sostenutoPedal: boolean;
|
|
86
|
-
softPedal: number;
|
|
87
|
-
rpnMSB: number;
|
|
88
|
-
rpnLSB: number;
|
|
89
|
-
channelPressure: number;
|
|
90
|
-
pitchBendRange: number;
|
|
91
|
-
currentBufferSource: null;
|
|
92
|
-
volume: number;
|
|
93
|
-
pan: number;
|
|
94
|
-
portamentoTime: number;
|
|
95
|
-
reverb: number;
|
|
96
|
-
chorus: number;
|
|
97
|
-
vibratoRate: number;
|
|
98
|
-
vibratoDepth: number;
|
|
99
|
-
vibratoDelay: number;
|
|
100
|
-
bank: number;
|
|
101
|
-
bankMSB: number;
|
|
102
|
-
bankLSB: number;
|
|
103
|
-
dataMSB: number;
|
|
104
|
-
dataLSB: number;
|
|
105
|
-
program: number;
|
|
106
|
-
pitchBend: number;
|
|
107
|
-
fineTuning: number;
|
|
108
|
-
coarseTuning: number;
|
|
109
|
-
modulationDepthRange: number;
|
|
110
|
-
}[];
|
|
68
|
+
channels: any[];
|
|
111
69
|
initSoundFontTable(): any[];
|
|
112
70
|
addSoundFont(soundFont: any): void;
|
|
113
71
|
loadSoundFont(soundFontUrl: any): Promise<void>;
|
|
@@ -117,7 +75,6 @@ export class MidyGM2 {
|
|
|
117
75
|
pannerNode: any;
|
|
118
76
|
modulationEffect: {
|
|
119
77
|
lfo: any;
|
|
120
|
-
lfoGain: any;
|
|
121
78
|
};
|
|
122
79
|
reverbEffect: {
|
|
123
80
|
convolverNode: any;
|
|
@@ -131,56 +88,7 @@ export class MidyGM2 {
|
|
|
131
88
|
chorusGains: any[];
|
|
132
89
|
};
|
|
133
90
|
};
|
|
134
|
-
createChannels(audioContext: any):
|
|
135
|
-
scheduledNotes: Map<any, any>;
|
|
136
|
-
sostenutoNotes: Map<any, any>;
|
|
137
|
-
gainNode: any;
|
|
138
|
-
pannerNode: any;
|
|
139
|
-
modulationEffect: {
|
|
140
|
-
lfo: any;
|
|
141
|
-
lfoGain: any;
|
|
142
|
-
};
|
|
143
|
-
reverbEffect: {
|
|
144
|
-
convolverNode: any;
|
|
145
|
-
dryGain: any;
|
|
146
|
-
wetGain: any;
|
|
147
|
-
};
|
|
148
|
-
chorusEffect: {
|
|
149
|
-
lfo: any;
|
|
150
|
-
lfoGain: any;
|
|
151
|
-
delayNodes: any[];
|
|
152
|
-
chorusGains: any[];
|
|
153
|
-
};
|
|
154
|
-
expression: number;
|
|
155
|
-
modulation: number;
|
|
156
|
-
sustainPedal: boolean;
|
|
157
|
-
portamento: boolean;
|
|
158
|
-
sostenutoPedal: boolean;
|
|
159
|
-
softPedal: number;
|
|
160
|
-
rpnMSB: number;
|
|
161
|
-
rpnLSB: number;
|
|
162
|
-
channelPressure: number;
|
|
163
|
-
pitchBendRange: number;
|
|
164
|
-
currentBufferSource: null;
|
|
165
|
-
volume: number;
|
|
166
|
-
pan: number;
|
|
167
|
-
portamentoTime: number;
|
|
168
|
-
reverb: number;
|
|
169
|
-
chorus: number;
|
|
170
|
-
vibratoRate: number;
|
|
171
|
-
vibratoDepth: number;
|
|
172
|
-
vibratoDelay: number;
|
|
173
|
-
bank: number;
|
|
174
|
-
bankMSB: number;
|
|
175
|
-
bankLSB: number;
|
|
176
|
-
dataMSB: number;
|
|
177
|
-
dataLSB: number;
|
|
178
|
-
program: number;
|
|
179
|
-
pitchBend: number;
|
|
180
|
-
fineTuning: number;
|
|
181
|
-
coarseTuning: number;
|
|
182
|
-
modulationDepthRange: number;
|
|
183
|
-
}[];
|
|
91
|
+
createChannels(audioContext: any): any[];
|
|
184
92
|
createNoteBuffer(noteInfo: any, isSF3: any): Promise<any>;
|
|
185
93
|
createNoteBufferNode(noteInfo: any, isSF3: any): Promise<any>;
|
|
186
94
|
convertToFloat32Array(uint8Array: any): Float32Array;
|
|
@@ -205,7 +113,6 @@ export class MidyGM2 {
|
|
|
205
113
|
getActiveChannelNotes(scheduledNotes: any): any;
|
|
206
114
|
createModulationEffect(audioContext: any): {
|
|
207
115
|
lfo: any;
|
|
208
|
-
lfoGain: any;
|
|
209
116
|
};
|
|
210
117
|
createReverbEffect(audioContext: any, options?: {}): {
|
|
211
118
|
convolverNode: any;
|
|
@@ -221,23 +128,26 @@ export class MidyGM2 {
|
|
|
221
128
|
connectNoteEffects(channel: any, gainNode: any): void;
|
|
222
129
|
cbToRatio(cb: any): number;
|
|
223
130
|
centToHz(cent: any): number;
|
|
131
|
+
calcSemitoneOffset(channel: any): any;
|
|
132
|
+
calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
|
|
224
133
|
createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
|
|
225
134
|
bufferSource: any;
|
|
226
135
|
gainNode: any;
|
|
227
136
|
filterNode: any;
|
|
137
|
+
lfoGain: any;
|
|
228
138
|
}>;
|
|
229
139
|
calcBank(channel: any, channelNumber: any): any;
|
|
230
140
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
231
141
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
232
142
|
scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
233
143
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
234
|
-
releaseSustainPedal(channelNumber: any):
|
|
235
|
-
|
|
144
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
145
|
+
releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
|
|
236
146
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
|
|
237
|
-
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
238
147
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
239
148
|
handleChannelPressure(channelNumber: any, pressure: any): void;
|
|
240
|
-
|
|
149
|
+
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
150
|
+
handlePitchBend(channelNumber: any, pitchBend: any): void;
|
|
241
151
|
handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
|
|
242
152
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
243
153
|
setModulation(channelNumber: any, modulation: any): void;
|
package/script/midy-GM2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,qBAAmB;IACnB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAuBC;IAED,yCAcC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EAkDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,8EAEC;IAED;;;;;OAqFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,0DAiBC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAQC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
|