@marmooo/midy 0.3.7 → 0.3.8
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/README.md +31 -11
- package/esm/midy-GM1.d.ts +9 -6
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +67 -57
- package/esm/midy-GM2.d.ts +13 -7
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +147 -154
- package/esm/midy-GMLite.d.ts +8 -6
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +68 -59
- package/esm/midy.d.ts +13 -7
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +208 -226
- package/package.json +2 -2
- package/script/midy-GM1.d.ts +9 -6
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +67 -57
- package/script/midy-GM2.d.ts +13 -7
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +147 -154
- package/script/midy-GMLite.d.ts +8 -6
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +68 -59
- package/script/midy.d.ts +13 -7
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +208 -226
package/script/midy-GM2.js
CHANGED
|
@@ -275,6 +275,18 @@ class MidyGM2 {
|
|
|
275
275
|
writable: true,
|
|
276
276
|
value: 0
|
|
277
277
|
});
|
|
278
|
+
Object.defineProperty(this, "lastActiveSensing", {
|
|
279
|
+
enumerable: true,
|
|
280
|
+
configurable: true,
|
|
281
|
+
writable: true,
|
|
282
|
+
value: 0
|
|
283
|
+
});
|
|
284
|
+
Object.defineProperty(this, "activeSensingThreshold", {
|
|
285
|
+
enumerable: true,
|
|
286
|
+
configurable: true,
|
|
287
|
+
writable: true,
|
|
288
|
+
value: 0.3
|
|
289
|
+
});
|
|
278
290
|
Object.defineProperty(this, "noteCheckInterval", {
|
|
279
291
|
enumerable: true,
|
|
280
292
|
configurable: true,
|
|
@@ -315,7 +327,7 @@ class MidyGM2 {
|
|
|
315
327
|
enumerable: true,
|
|
316
328
|
configurable: true,
|
|
317
329
|
writable: true,
|
|
318
|
-
value:
|
|
330
|
+
value: Array.from({ length: 128 }, () => [])
|
|
319
331
|
});
|
|
320
332
|
Object.defineProperty(this, "voiceCounter", {
|
|
321
333
|
enumerable: true,
|
|
@@ -402,8 +414,10 @@ class MidyGM2 {
|
|
|
402
414
|
length: 1,
|
|
403
415
|
sampleRate: audioContext.sampleRate,
|
|
404
416
|
});
|
|
417
|
+
this.messageHandlers = this.createMessageHandlers();
|
|
405
418
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
406
419
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
420
|
+
this.keyBasedControllerHandlers = this.createKeyBasedControllerHandlers();
|
|
407
421
|
this.channels = this.createChannels(audioContext);
|
|
408
422
|
this.reverbEffect = this.createReverbEffect(audioContext);
|
|
409
423
|
this.chorusEffect = this.createChorusEffect(audioContext);
|
|
@@ -413,21 +427,14 @@ class MidyGM2 {
|
|
|
413
427
|
this.scheduler.connect(audioContext.destination);
|
|
414
428
|
this.GM2SystemOn();
|
|
415
429
|
}
|
|
416
|
-
initSoundFontTable() {
|
|
417
|
-
const table = new Array(128);
|
|
418
|
-
for (let i = 0; i < 128; i++) {
|
|
419
|
-
table[i] = new Map();
|
|
420
|
-
}
|
|
421
|
-
return table;
|
|
422
|
-
}
|
|
423
430
|
addSoundFont(soundFont) {
|
|
424
431
|
const index = this.soundFonts.length;
|
|
425
432
|
this.soundFonts.push(soundFont);
|
|
426
433
|
const presetHeaders = soundFont.parsed.presetHeaders;
|
|
434
|
+
const soundFontTable = this.soundFontTable;
|
|
427
435
|
for (let i = 0; i < presetHeaders.length; i++) {
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
banks.set(presetHeader.bank, index);
|
|
436
|
+
const { preset, bank } = presetHeaders[i];
|
|
437
|
+
soundFontTable[preset][bank] = index;
|
|
431
438
|
}
|
|
432
439
|
}
|
|
433
440
|
async toUint8Array(input) {
|
|
@@ -505,13 +512,17 @@ class MidyGM2 {
|
|
|
505
512
|
this.GM2SystemOn();
|
|
506
513
|
}
|
|
507
514
|
getVoiceId(channel, noteNumber, velocity) {
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
|
|
515
|
+
const programNumber = channel.programNumber;
|
|
516
|
+
const bankTable = this.soundFontTable[programNumber];
|
|
517
|
+
if (!bankTable)
|
|
518
|
+
return;
|
|
519
|
+
const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
|
|
520
|
+
const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
|
|
521
|
+
const soundFontIndex = bankTable[bank];
|
|
511
522
|
if (soundFontIndex === undefined)
|
|
512
523
|
return;
|
|
513
524
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
514
|
-
const voice = soundFont.getVoice(
|
|
525
|
+
const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
515
526
|
const { instrument, sampleID } = voice.generators;
|
|
516
527
|
return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
|
|
517
528
|
}
|
|
@@ -580,13 +591,16 @@ class MidyGM2 {
|
|
|
580
591
|
}
|
|
581
592
|
return bufferSource;
|
|
582
593
|
}
|
|
583
|
-
async scheduleTimelineEvents(
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
594
|
+
async scheduleTimelineEvents(scheduleTime, queueIndex) {
|
|
595
|
+
const timeOffset = this.resumeTime - this.startTime;
|
|
596
|
+
const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
|
|
597
|
+
const schedulingOffset = this.startDelay - timeOffset;
|
|
598
|
+
const timeline = this.timeline;
|
|
599
|
+
while (queueIndex < timeline.length) {
|
|
600
|
+
const event = timeline[queueIndex];
|
|
601
|
+
if (lookAheadCheckTime < event.startTime)
|
|
587
602
|
break;
|
|
588
|
-
const
|
|
589
|
-
const startTime = event.startTime + delay;
|
|
603
|
+
const startTime = event.startTime + schedulingOffset;
|
|
590
604
|
switch (event.type) {
|
|
591
605
|
case "noteOn":
|
|
592
606
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
@@ -661,13 +675,18 @@ class MidyGM2 {
|
|
|
661
675
|
this.isPaused = false;
|
|
662
676
|
this.startTime = this.audioContext.currentTime;
|
|
663
677
|
let queueIndex = this.getQueueIndex(this.resumeTime);
|
|
664
|
-
let resumeTime = this.resumeTime - this.startTime;
|
|
665
678
|
let finished = false;
|
|
666
679
|
this.notePromises = [];
|
|
667
680
|
while (queueIndex < this.timeline.length) {
|
|
668
681
|
const now = this.audioContext.currentTime;
|
|
669
|
-
|
|
670
|
-
|
|
682
|
+
if (0 < this.lastActiveSensing &&
|
|
683
|
+
this.activeSensingThreshold < performance.now() - this.lastActiveSensing) {
|
|
684
|
+
await this.stopNotes(0, true, now);
|
|
685
|
+
await this.audioContext.suspend();
|
|
686
|
+
finished = true;
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
671
690
|
if (this.isPausing) {
|
|
672
691
|
await this.stopNotes(0, true, now);
|
|
673
692
|
await this.audioContext.suspend();
|
|
@@ -686,7 +705,6 @@ class MidyGM2 {
|
|
|
686
705
|
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
687
706
|
this.updateStates(queueIndex, nextQueueIndex);
|
|
688
707
|
queueIndex = nextQueueIndex;
|
|
689
|
-
resumeTime = this.resumeTime - this.startTime;
|
|
690
708
|
this.isSeeking = false;
|
|
691
709
|
continue;
|
|
692
710
|
}
|
|
@@ -696,6 +714,7 @@ class MidyGM2 {
|
|
|
696
714
|
if (finished) {
|
|
697
715
|
this.notePromises = [];
|
|
698
716
|
this.resetAllStates();
|
|
717
|
+
this.lastActiveSensing = 0;
|
|
699
718
|
}
|
|
700
719
|
this.isPlaying = false;
|
|
701
720
|
}
|
|
@@ -705,17 +724,17 @@ class MidyGM2 {
|
|
|
705
724
|
secondToTicks(second, secondsPerBeat) {
|
|
706
725
|
return second * this.ticksPerBeat / secondsPerBeat;
|
|
707
726
|
}
|
|
727
|
+
getSoundFontId(channel) {
|
|
728
|
+
const programNumber = channel.programNumber;
|
|
729
|
+
const bankNumber = channel.isDrum ? 128 : channel.bankLSB;
|
|
730
|
+
const bank = bankNumber.toString().padStart(3, "0");
|
|
731
|
+
const program = programNumber.toString().padStart(3, "0");
|
|
732
|
+
return `${bank}:${program}`;
|
|
733
|
+
}
|
|
708
734
|
extractMidiData(midi) {
|
|
709
735
|
const instruments = new Set();
|
|
710
736
|
const timeline = [];
|
|
711
|
-
const
|
|
712
|
-
for (let i = 0; i < tmpChannels.length; i++) {
|
|
713
|
-
tmpChannels[i] = {
|
|
714
|
-
programNumber: -1,
|
|
715
|
-
bankMSB: this.channels[i].bankMSB,
|
|
716
|
-
bankLSB: this.channels[i].bankLSB,
|
|
717
|
-
};
|
|
718
|
-
}
|
|
737
|
+
const channels = this.channels;
|
|
719
738
|
for (let i = 0; i < midi.tracks.length; i++) {
|
|
720
739
|
const track = midi.tracks[i];
|
|
721
740
|
let currentTicks = 0;
|
|
@@ -725,48 +744,40 @@ class MidyGM2 {
|
|
|
725
744
|
event.ticks = currentTicks;
|
|
726
745
|
switch (event.type) {
|
|
727
746
|
case "noteOn": {
|
|
728
|
-
const channel =
|
|
729
|
-
|
|
730
|
-
channel.programNumber = event.programNumber;
|
|
731
|
-
switch (channel.bankMSB) {
|
|
732
|
-
case 120:
|
|
733
|
-
instruments.add(`128:0`);
|
|
734
|
-
break;
|
|
735
|
-
case 121:
|
|
736
|
-
instruments.add(`${channel.bankLSB}:0`);
|
|
737
|
-
break;
|
|
738
|
-
default: {
|
|
739
|
-
const bankNumber = channel.bankMSB * 128 + channel.bankLSB;
|
|
740
|
-
instruments.add(`${bankNumber}:0`);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
channel.programNumber = 0;
|
|
744
|
-
}
|
|
747
|
+
const channel = channels[event.channel];
|
|
748
|
+
instruments.add(this.getSoundFontId(channel));
|
|
745
749
|
break;
|
|
746
750
|
}
|
|
747
751
|
case "controller":
|
|
748
752
|
switch (event.controllerType) {
|
|
749
753
|
case 0:
|
|
750
|
-
|
|
754
|
+
this.setBankMSB(event.channel, event.value);
|
|
751
755
|
break;
|
|
752
756
|
case 32:
|
|
753
|
-
|
|
757
|
+
this.setBankLSB(event.channel, event.value);
|
|
754
758
|
break;
|
|
755
759
|
}
|
|
756
760
|
break;
|
|
757
761
|
case "programChange": {
|
|
758
|
-
const channel =
|
|
759
|
-
channel
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
762
|
+
const channel = channels[event.channel];
|
|
763
|
+
this.setProgramChange(event.channel, event.programNumber);
|
|
764
|
+
instruments.add(this.getSoundFontId(channel));
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
case "sysEx": {
|
|
768
|
+
const data = event.data;
|
|
769
|
+
if (data[0] === 126 && data[1] === 9 && data[2] === 3) {
|
|
770
|
+
switch (data[3]) {
|
|
771
|
+
case 1:
|
|
772
|
+
this.GM1SystemOn(scheduleTime);
|
|
773
|
+
break;
|
|
774
|
+
case 2: // GM System Off
|
|
775
|
+
break;
|
|
776
|
+
case 3:
|
|
777
|
+
this.GM2SystemOn(scheduleTime);
|
|
778
|
+
break;
|
|
779
|
+
default:
|
|
780
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
770
781
|
}
|
|
771
782
|
}
|
|
772
783
|
}
|
|
@@ -1089,7 +1100,7 @@ class MidyGM2 {
|
|
|
1089
1100
|
updateDetune(channel, note, scheduleTime) {
|
|
1090
1101
|
const noteDetune = this.calcNoteDetune(channel, note);
|
|
1091
1102
|
const detune = channel.detune + noteDetune;
|
|
1092
|
-
if (
|
|
1103
|
+
if (this.isPortamento(channel, note)) {
|
|
1093
1104
|
const startTime = note.startTime;
|
|
1094
1105
|
const deltaCent = (note.noteNumber - note.portamentoNoteNumber) * 100;
|
|
1095
1106
|
const portamentoTime = startTime + this.getPortamentoTime(channel, note);
|
|
@@ -1340,7 +1351,7 @@ class MidyGM2 {
|
|
|
1340
1351
|
if (prevNote && prevNote.noteNumber !== noteNumber) {
|
|
1341
1352
|
note.portamentoNoteNumber = prevNote.noteNumber;
|
|
1342
1353
|
}
|
|
1343
|
-
if (
|
|
1354
|
+
if (!channel.isDrum && this.isPortamento(channel, note)) {
|
|
1344
1355
|
this.setPortamentoVolumeEnvelope(channel, note, now);
|
|
1345
1356
|
this.setPortamentoFilterEnvelope(channel, note, now);
|
|
1346
1357
|
this.setPortamentoPitchEnvelope(note, now);
|
|
@@ -1368,22 +1379,6 @@ class MidyGM2 {
|
|
|
1368
1379
|
note.bufferSource.start(startTime);
|
|
1369
1380
|
return note;
|
|
1370
1381
|
}
|
|
1371
|
-
calcBank(channel) {
|
|
1372
|
-
switch (this.mode) {
|
|
1373
|
-
case "GM1":
|
|
1374
|
-
if (channel.isDrum)
|
|
1375
|
-
return 128;
|
|
1376
|
-
return 0;
|
|
1377
|
-
case "GM2":
|
|
1378
|
-
if (channel.bankMSB === 121)
|
|
1379
|
-
return 0;
|
|
1380
|
-
if (channel.isDrum)
|
|
1381
|
-
return 128;
|
|
1382
|
-
return channel.bank;
|
|
1383
|
-
default:
|
|
1384
|
-
return channel.bank;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
1382
|
handleExclusiveClass(note, channelNumber, startTime) {
|
|
1388
1383
|
const exclusiveClass = note.voiceParams.exclusiveClass;
|
|
1389
1384
|
if (exclusiveClass === 0)
|
|
@@ -1419,13 +1414,17 @@ class MidyGM2 {
|
|
|
1419
1414
|
}
|
|
1420
1415
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
1421
1416
|
const channel = this.channels[channelNumber];
|
|
1422
|
-
const
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1417
|
+
const programNumber = channel.programNumber;
|
|
1418
|
+
const bankTable = this.soundFontTable[programNumber];
|
|
1419
|
+
if (!bankTable)
|
|
1420
|
+
return;
|
|
1421
|
+
const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
|
|
1422
|
+
const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
|
|
1423
|
+
const soundFontIndex = bankTable[bank];
|
|
1425
1424
|
if (soundFontIndex === undefined)
|
|
1426
1425
|
return;
|
|
1427
1426
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
1428
|
-
const voice = soundFont.getVoice(
|
|
1427
|
+
const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
1429
1428
|
if (!voice)
|
|
1430
1429
|
return;
|
|
1431
1430
|
const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
|
|
@@ -1577,41 +1576,45 @@ class MidyGM2 {
|
|
|
1577
1576
|
channel.sostenutoNotes = [];
|
|
1578
1577
|
return promises;
|
|
1579
1578
|
}
|
|
1580
|
-
|
|
1581
|
-
const
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
1579
|
+
createMessageHandlers() {
|
|
1580
|
+
const handlers = new Array(256);
|
|
1581
|
+
// Channel Message
|
|
1582
|
+
handlers[0x80] = (data, scheduleTime) => this.noteOff(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1583
|
+
handlers[0x90] = (data, scheduleTime) => this.noteOn(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1584
|
+
handlers[0xB0] = (data, scheduleTime) => this.setControlChange(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1585
|
+
handlers[0xC0] = (data, scheduleTime) => this.setProgramChange(data[0] & 0x0F, data[1], scheduleTime);
|
|
1586
|
+
handlers[0xD0] = (data, scheduleTime) => this.setChannelPressure(data[0] & 0x0F, data[1], scheduleTime);
|
|
1587
|
+
handlers[0xE0] = (data, scheduleTime) => this.handlePitchBendMessage(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1588
|
+
// System Real Time Message
|
|
1589
|
+
handlers[0xFE] = (_data, _scheduleTime) => this.activeSensing();
|
|
1590
|
+
return handlers;
|
|
1591
|
+
}
|
|
1592
|
+
handleMessage(data, scheduleTime) {
|
|
1593
|
+
const status = data[0];
|
|
1594
|
+
if (status === 0xF0) {
|
|
1595
|
+
return this.handleSysEx(data.subarray(1), scheduleTime);
|
|
1598
1596
|
}
|
|
1597
|
+
const handler = this.messageHandlers[status];
|
|
1598
|
+
if (handler)
|
|
1599
|
+
handler(data, scheduleTime);
|
|
1600
|
+
}
|
|
1601
|
+
activeSensing() {
|
|
1602
|
+
this.lastActiveSensing = performance.now();
|
|
1599
1603
|
}
|
|
1600
1604
|
setProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
1601
1605
|
const channel = this.channels[channelNumber];
|
|
1602
|
-
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1603
1606
|
channel.programNumber = programNumber;
|
|
1604
1607
|
if (this.mode === "GM2") {
|
|
1605
1608
|
switch (channel.bankMSB) {
|
|
1606
1609
|
case 120:
|
|
1607
1610
|
channel.isDrum = true;
|
|
1611
|
+
channel.keyBasedTable.fill(-1);
|
|
1608
1612
|
break;
|
|
1609
1613
|
case 121:
|
|
1610
1614
|
channel.isDrum = false;
|
|
1611
1615
|
break;
|
|
1612
1616
|
}
|
|
1613
1617
|
}
|
|
1614
|
-
channel.keyBasedTable.fill(-1);
|
|
1615
1618
|
}
|
|
1616
1619
|
setChannelPressure(channelNumber, value, scheduleTime) {
|
|
1617
1620
|
const channel = this.channels[channelNumber];
|
|
@@ -1936,22 +1939,20 @@ class MidyGM2 {
|
|
|
1936
1939
|
this.updateModulation(channel, scheduleTime);
|
|
1937
1940
|
}
|
|
1938
1941
|
updatePortamento(channel, scheduleTime) {
|
|
1942
|
+
if (channel.isDrum)
|
|
1943
|
+
return;
|
|
1939
1944
|
this.processScheduledNotes(channel, (note) => {
|
|
1940
|
-
if (
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
this.updateDetune(channel, note, scheduleTime);
|
|
1946
|
-
}
|
|
1945
|
+
if (this.isPortamento(channel, note)) {
|
|
1946
|
+
this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
|
|
1947
|
+
this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
|
|
1948
|
+
this.setPortamentoPitchEnvelope(note, scheduleTime);
|
|
1949
|
+
this.updateDetune(channel, note, scheduleTime);
|
|
1947
1950
|
}
|
|
1948
1951
|
else {
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
this.updateDetune(channel, note, scheduleTime);
|
|
1954
|
-
}
|
|
1952
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
1953
|
+
this.setFilterEnvelope(channel, note, scheduleTime);
|
|
1954
|
+
this.setPitchEnvelope(note, scheduleTime);
|
|
1955
|
+
this.updateDetune(channel, note, scheduleTime);
|
|
1955
1956
|
}
|
|
1956
1957
|
});
|
|
1957
1958
|
}
|
|
@@ -2057,6 +2058,9 @@ class MidyGM2 {
|
|
|
2057
2058
|
this.releaseSustainPedal(channelNumber, value, scheduleTime);
|
|
2058
2059
|
}
|
|
2059
2060
|
}
|
|
2061
|
+
isPortamento(channel, note) {
|
|
2062
|
+
return 0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber;
|
|
2063
|
+
}
|
|
2060
2064
|
setPortamento(channelNumber, value, scheduleTime) {
|
|
2061
2065
|
const channel = this.channels[channelNumber];
|
|
2062
2066
|
if (channel.isDrum)
|
|
@@ -2093,7 +2097,7 @@ class MidyGM2 {
|
|
|
2093
2097
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2094
2098
|
state.softPedal = softPedal / 127;
|
|
2095
2099
|
this.processScheduledNotes(channel, (note) => {
|
|
2096
|
-
if (
|
|
2100
|
+
if (this.isPortamento(channel, note)) {
|
|
2097
2101
|
this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
|
|
2098
2102
|
this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
|
|
2099
2103
|
}
|
|
@@ -2361,11 +2365,9 @@ class MidyGM2 {
|
|
|
2361
2365
|
const channel = this.channels[i];
|
|
2362
2366
|
channel.bankMSB = 0;
|
|
2363
2367
|
channel.bankLSB = 0;
|
|
2364
|
-
channel.bank = 0;
|
|
2365
2368
|
channel.isDrum = false;
|
|
2366
2369
|
}
|
|
2367
2370
|
this.channels[9].bankMSB = 1;
|
|
2368
|
-
this.channels[9].bank = 128;
|
|
2369
2371
|
this.channels[9].isDrum = true;
|
|
2370
2372
|
}
|
|
2371
2373
|
GM2SystemOn(scheduleTime) {
|
|
@@ -2376,11 +2378,9 @@ class MidyGM2 {
|
|
|
2376
2378
|
const channel = this.channels[i];
|
|
2377
2379
|
channel.bankMSB = 121;
|
|
2378
2380
|
channel.bankLSB = 0;
|
|
2379
|
-
channel.bank = 121 * 128;
|
|
2380
2381
|
channel.isDrum = false;
|
|
2381
2382
|
}
|
|
2382
2383
|
this.channels[9].bankMSB = 120;
|
|
2383
|
-
this.channels[9].bank = 120 * 128;
|
|
2384
2384
|
this.channels[9].isDrum = true;
|
|
2385
2385
|
}
|
|
2386
2386
|
handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
|
|
@@ -2425,16 +2425,11 @@ class MidyGM2 {
|
|
|
2425
2425
|
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
2426
2426
|
this.setMasterVolume(volume, scheduleTime);
|
|
2427
2427
|
}
|
|
2428
|
-
setMasterVolume(
|
|
2428
|
+
setMasterVolume(value, scheduleTime) {
|
|
2429
2429
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
else {
|
|
2434
|
-
this.masterVolume.gain
|
|
2435
|
-
.cancelScheduledValues(scheduleTime)
|
|
2436
|
-
.setValueAtTime(volume * volume, scheduleTime);
|
|
2437
|
-
}
|
|
2430
|
+
this.masterVolume.gain
|
|
2431
|
+
.cancelScheduledValues(scheduleTime)
|
|
2432
|
+
.setValueAtTime(value * value, scheduleTime);
|
|
2438
2433
|
}
|
|
2439
2434
|
handleMasterFineTuningSysEx(data, scheduleTime) {
|
|
2440
2435
|
const value = (data[5] * 128 + data[4]) / 16383;
|
|
@@ -2797,6 +2792,22 @@ class MidyGM2 {
|
|
|
2797
2792
|
const controlValue = channel.keyBasedTable[index];
|
|
2798
2793
|
return controlValue;
|
|
2799
2794
|
}
|
|
2795
|
+
createKeyBasedControllerHandlers() {
|
|
2796
|
+
const handlers = new Array(128);
|
|
2797
|
+
handlers[7] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2798
|
+
handlers[10] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2799
|
+
handlers[91] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
|
|
2800
|
+
if (note.noteNumber === keyNumber) {
|
|
2801
|
+
this.setReverbSend(channel, note, scheduleTime);
|
|
2802
|
+
}
|
|
2803
|
+
});
|
|
2804
|
+
handlers[93] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
|
|
2805
|
+
if (note.noteNumber === keyNumber) {
|
|
2806
|
+
this.setChorusSend(channel, note, scheduleTime);
|
|
2807
|
+
}
|
|
2808
|
+
});
|
|
2809
|
+
return handlers;
|
|
2810
|
+
}
|
|
2800
2811
|
handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
|
|
2801
2812
|
const channelNumber = data[4];
|
|
2802
2813
|
const channel = this.channels[channelNumber];
|
|
@@ -2809,26 +2820,9 @@ class MidyGM2 {
|
|
|
2809
2820
|
const value = data[i + 1];
|
|
2810
2821
|
const index = keyNumber * 128 + controllerType;
|
|
2811
2822
|
table[index] = value;
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2816
|
-
break;
|
|
2817
|
-
case 91:
|
|
2818
|
-
this.processScheduledNotes(channel, (note) => {
|
|
2819
|
-
if (note.noteNumber === keyNumber) {
|
|
2820
|
-
this.setReverbSend(channel, note, scheduleTime);
|
|
2821
|
-
}
|
|
2822
|
-
});
|
|
2823
|
-
break;
|
|
2824
|
-
case 93:
|
|
2825
|
-
this.processScheduledNotes(channel, (note) => {
|
|
2826
|
-
if (note.noteNumber === keyNumber) {
|
|
2827
|
-
this.setChorusSend(channel, note, scheduleTime);
|
|
2828
|
-
}
|
|
2829
|
-
});
|
|
2830
|
-
break;
|
|
2831
|
-
}
|
|
2823
|
+
const handler = this.keyBasedControllerHandlers[controllerType];
|
|
2824
|
+
if (handler)
|
|
2825
|
+
handler(channel, keyNumber, scheduleTime);
|
|
2832
2826
|
}
|
|
2833
2827
|
}
|
|
2834
2828
|
handleSysEx(data, scheduleTime) {
|
|
@@ -2870,7 +2864,6 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2870
2864
|
scheduleIndex: 0,
|
|
2871
2865
|
detune: 0,
|
|
2872
2866
|
programNumber: 0,
|
|
2873
|
-
bank: 121 * 128,
|
|
2874
2867
|
bankMSB: 121,
|
|
2875
2868
|
bankLSB: 0,
|
|
2876
2869
|
dataMSB: 0,
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export class MidyGMLite {
|
|
|
3
3
|
scheduleIndex: number;
|
|
4
4
|
detune: number;
|
|
5
5
|
programNumber: number;
|
|
6
|
-
bank: number;
|
|
7
6
|
dataMSB: number;
|
|
8
7
|
dataLSB: number;
|
|
9
8
|
rpnMSB: number;
|
|
@@ -21,7 +20,7 @@ export class MidyGMLite {
|
|
|
21
20
|
startTime: number;
|
|
22
21
|
resumeTime: number;
|
|
23
22
|
soundFonts: any[];
|
|
24
|
-
soundFontTable:
|
|
23
|
+
soundFontTable: never[][];
|
|
25
24
|
voiceCounter: Map<any, any>;
|
|
26
25
|
voiceCache: Map<any, any>;
|
|
27
26
|
isPlaying: boolean;
|
|
@@ -39,6 +38,7 @@ export class MidyGMLite {
|
|
|
39
38
|
masterVolume: any;
|
|
40
39
|
scheduler: any;
|
|
41
40
|
schedulerBuffer: any;
|
|
41
|
+
messageHandlers: any[];
|
|
42
42
|
voiceParamsHandlers: {
|
|
43
43
|
modLfoToPitch: (channel: any, note: any, scheduleTime: any) => void;
|
|
44
44
|
vibLfoToPitch: (_channel: any, _note: any, _scheduleTime: any) => void;
|
|
@@ -53,7 +53,6 @@ export class MidyGMLite {
|
|
|
53
53
|
};
|
|
54
54
|
controlChangeHandlers: any[];
|
|
55
55
|
channels: any[];
|
|
56
|
-
initSoundFontTable(): any[];
|
|
57
56
|
addSoundFont(soundFont: any): void;
|
|
58
57
|
toUint8Array(input: any): Promise<Uint8Array<ArrayBuffer>>;
|
|
59
58
|
loadSoundFont(input: any): Promise<void>;
|
|
@@ -68,13 +67,14 @@ export class MidyGMLite {
|
|
|
68
67
|
createChannels(audioContext: any): any[];
|
|
69
68
|
createAudioBuffer(voiceParams: any): Promise<any>;
|
|
70
69
|
createBufferSource(channel: any, voiceParams: any, audioBuffer: any): any;
|
|
71
|
-
scheduleTimelineEvents(
|
|
70
|
+
scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
|
|
72
71
|
getQueueIndex(second: any): number;
|
|
73
72
|
resetAllStates(): void;
|
|
74
73
|
updateStates(queueIndex: any, nextQueueIndex: any): void;
|
|
75
74
|
playNotes(): Promise<void>;
|
|
76
75
|
ticksToSecond(ticks: any, secondsPerBeat: any): number;
|
|
77
76
|
secondToTicks(second: any, secondsPerBeat: any): number;
|
|
77
|
+
getSoundFontId(channel: any): string;
|
|
78
78
|
extractMidiData(midi: any): {
|
|
79
79
|
instruments: Set<any>;
|
|
80
80
|
timeline: any[];
|
|
@@ -116,7 +116,9 @@ export class MidyGMLite {
|
|
|
116
116
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
117
117
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
|
|
118
118
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
119
|
-
|
|
119
|
+
createMessageHandlers(): any[];
|
|
120
|
+
handleMessage(data: any, scheduleTime: any): void;
|
|
121
|
+
handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
|
|
120
122
|
setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
|
|
121
123
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
|
|
122
124
|
setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
|
|
@@ -168,7 +170,7 @@ export class MidyGMLite {
|
|
|
168
170
|
GM1SystemOn(scheduleTime: any): void;
|
|
169
171
|
handleUniversalRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
|
170
172
|
handleMasterVolumeSysEx(data: any, scheduleTime: any): void;
|
|
171
|
-
setMasterVolume(
|
|
173
|
+
setMasterVolume(value: any, scheduleTime: any): void;
|
|
172
174
|
handleSysEx(data: any, scheduleTime: any): void;
|
|
173
175
|
scheduleTask(callback: any, scheduleTime: any): Promise<any>;
|
|
174
176
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA0GA;IA4BE
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA0GA;IA4BE;;;;;;;;;MASE;IAEF,+BAeC;IArDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IACrC,+BAEE;IAcA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAWC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDAUC;IAED,0EAUC;IAED,yEAqDC;IAED,mCAOC;IAED,uBAQC;IAED,yDA2BC;IAED,2BAwCC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,yEASC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,6FAyBC;IAED,oGA2CC;IAED,0EAiBC;IAED,8EAiBC;IAED,kGAiCC;IAED,6FASC;IAED,gCASC;IAED,iEAoBC;IAED,qGAkBC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;IAED,sFAeC;IAED,+BAmBC;IAED,kDAOC;IAED,uGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAWC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA9hDD;IAWE,0FAMC;IAhBD,cAAW;IACX,gBAAe;IACf,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|