@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/esm/midy-GM2.js
CHANGED
|
@@ -272,6 +272,18 @@ export class MidyGM2 {
|
|
|
272
272
|
writable: true,
|
|
273
273
|
value: 0
|
|
274
274
|
});
|
|
275
|
+
Object.defineProperty(this, "lastActiveSensing", {
|
|
276
|
+
enumerable: true,
|
|
277
|
+
configurable: true,
|
|
278
|
+
writable: true,
|
|
279
|
+
value: 0
|
|
280
|
+
});
|
|
281
|
+
Object.defineProperty(this, "activeSensingThreshold", {
|
|
282
|
+
enumerable: true,
|
|
283
|
+
configurable: true,
|
|
284
|
+
writable: true,
|
|
285
|
+
value: 0.3
|
|
286
|
+
});
|
|
275
287
|
Object.defineProperty(this, "noteCheckInterval", {
|
|
276
288
|
enumerable: true,
|
|
277
289
|
configurable: true,
|
|
@@ -312,7 +324,7 @@ export class MidyGM2 {
|
|
|
312
324
|
enumerable: true,
|
|
313
325
|
configurable: true,
|
|
314
326
|
writable: true,
|
|
315
|
-
value:
|
|
327
|
+
value: Array.from({ length: 128 }, () => [])
|
|
316
328
|
});
|
|
317
329
|
Object.defineProperty(this, "voiceCounter", {
|
|
318
330
|
enumerable: true,
|
|
@@ -399,8 +411,10 @@ export class MidyGM2 {
|
|
|
399
411
|
length: 1,
|
|
400
412
|
sampleRate: audioContext.sampleRate,
|
|
401
413
|
});
|
|
414
|
+
this.messageHandlers = this.createMessageHandlers();
|
|
402
415
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
403
416
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
417
|
+
this.keyBasedControllerHandlers = this.createKeyBasedControllerHandlers();
|
|
404
418
|
this.channels = this.createChannels(audioContext);
|
|
405
419
|
this.reverbEffect = this.createReverbEffect(audioContext);
|
|
406
420
|
this.chorusEffect = this.createChorusEffect(audioContext);
|
|
@@ -410,21 +424,14 @@ export class MidyGM2 {
|
|
|
410
424
|
this.scheduler.connect(audioContext.destination);
|
|
411
425
|
this.GM2SystemOn();
|
|
412
426
|
}
|
|
413
|
-
initSoundFontTable() {
|
|
414
|
-
const table = new Array(128);
|
|
415
|
-
for (let i = 0; i < 128; i++) {
|
|
416
|
-
table[i] = new Map();
|
|
417
|
-
}
|
|
418
|
-
return table;
|
|
419
|
-
}
|
|
420
427
|
addSoundFont(soundFont) {
|
|
421
428
|
const index = this.soundFonts.length;
|
|
422
429
|
this.soundFonts.push(soundFont);
|
|
423
430
|
const presetHeaders = soundFont.parsed.presetHeaders;
|
|
431
|
+
const soundFontTable = this.soundFontTable;
|
|
424
432
|
for (let i = 0; i < presetHeaders.length; i++) {
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
banks.set(presetHeader.bank, index);
|
|
433
|
+
const { preset, bank } = presetHeaders[i];
|
|
434
|
+
soundFontTable[preset][bank] = index;
|
|
428
435
|
}
|
|
429
436
|
}
|
|
430
437
|
async toUint8Array(input) {
|
|
@@ -502,13 +509,17 @@ export class MidyGM2 {
|
|
|
502
509
|
this.GM2SystemOn();
|
|
503
510
|
}
|
|
504
511
|
getVoiceId(channel, noteNumber, velocity) {
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
|
|
512
|
+
const programNumber = channel.programNumber;
|
|
513
|
+
const bankTable = this.soundFontTable[programNumber];
|
|
514
|
+
if (!bankTable)
|
|
515
|
+
return;
|
|
516
|
+
const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
|
|
517
|
+
const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
|
|
518
|
+
const soundFontIndex = bankTable[bank];
|
|
508
519
|
if (soundFontIndex === undefined)
|
|
509
520
|
return;
|
|
510
521
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
511
|
-
const voice = soundFont.getVoice(
|
|
522
|
+
const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
512
523
|
const { instrument, sampleID } = voice.generators;
|
|
513
524
|
return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
|
|
514
525
|
}
|
|
@@ -577,13 +588,16 @@ export class MidyGM2 {
|
|
|
577
588
|
}
|
|
578
589
|
return bufferSource;
|
|
579
590
|
}
|
|
580
|
-
async scheduleTimelineEvents(
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
591
|
+
async scheduleTimelineEvents(scheduleTime, queueIndex) {
|
|
592
|
+
const timeOffset = this.resumeTime - this.startTime;
|
|
593
|
+
const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
|
|
594
|
+
const schedulingOffset = this.startDelay - timeOffset;
|
|
595
|
+
const timeline = this.timeline;
|
|
596
|
+
while (queueIndex < timeline.length) {
|
|
597
|
+
const event = timeline[queueIndex];
|
|
598
|
+
if (lookAheadCheckTime < event.startTime)
|
|
584
599
|
break;
|
|
585
|
-
const
|
|
586
|
-
const startTime = event.startTime + delay;
|
|
600
|
+
const startTime = event.startTime + schedulingOffset;
|
|
587
601
|
switch (event.type) {
|
|
588
602
|
case "noteOn":
|
|
589
603
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
@@ -658,13 +672,18 @@ export class MidyGM2 {
|
|
|
658
672
|
this.isPaused = false;
|
|
659
673
|
this.startTime = this.audioContext.currentTime;
|
|
660
674
|
let queueIndex = this.getQueueIndex(this.resumeTime);
|
|
661
|
-
let resumeTime = this.resumeTime - this.startTime;
|
|
662
675
|
let finished = false;
|
|
663
676
|
this.notePromises = [];
|
|
664
677
|
while (queueIndex < this.timeline.length) {
|
|
665
678
|
const now = this.audioContext.currentTime;
|
|
666
|
-
|
|
667
|
-
|
|
679
|
+
if (0 < this.lastActiveSensing &&
|
|
680
|
+
this.activeSensingThreshold < performance.now() - this.lastActiveSensing) {
|
|
681
|
+
await this.stopNotes(0, true, now);
|
|
682
|
+
await this.audioContext.suspend();
|
|
683
|
+
finished = true;
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
668
687
|
if (this.isPausing) {
|
|
669
688
|
await this.stopNotes(0, true, now);
|
|
670
689
|
await this.audioContext.suspend();
|
|
@@ -683,7 +702,6 @@ export class MidyGM2 {
|
|
|
683
702
|
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
684
703
|
this.updateStates(queueIndex, nextQueueIndex);
|
|
685
704
|
queueIndex = nextQueueIndex;
|
|
686
|
-
resumeTime = this.resumeTime - this.startTime;
|
|
687
705
|
this.isSeeking = false;
|
|
688
706
|
continue;
|
|
689
707
|
}
|
|
@@ -693,6 +711,7 @@ export class MidyGM2 {
|
|
|
693
711
|
if (finished) {
|
|
694
712
|
this.notePromises = [];
|
|
695
713
|
this.resetAllStates();
|
|
714
|
+
this.lastActiveSensing = 0;
|
|
696
715
|
}
|
|
697
716
|
this.isPlaying = false;
|
|
698
717
|
}
|
|
@@ -702,17 +721,17 @@ export class MidyGM2 {
|
|
|
702
721
|
secondToTicks(second, secondsPerBeat) {
|
|
703
722
|
return second * this.ticksPerBeat / secondsPerBeat;
|
|
704
723
|
}
|
|
724
|
+
getSoundFontId(channel) {
|
|
725
|
+
const programNumber = channel.programNumber;
|
|
726
|
+
const bankNumber = channel.isDrum ? 128 : channel.bankLSB;
|
|
727
|
+
const bank = bankNumber.toString().padStart(3, "0");
|
|
728
|
+
const program = programNumber.toString().padStart(3, "0");
|
|
729
|
+
return `${bank}:${program}`;
|
|
730
|
+
}
|
|
705
731
|
extractMidiData(midi) {
|
|
706
732
|
const instruments = new Set();
|
|
707
733
|
const timeline = [];
|
|
708
|
-
const
|
|
709
|
-
for (let i = 0; i < tmpChannels.length; i++) {
|
|
710
|
-
tmpChannels[i] = {
|
|
711
|
-
programNumber: -1,
|
|
712
|
-
bankMSB: this.channels[i].bankMSB,
|
|
713
|
-
bankLSB: this.channels[i].bankLSB,
|
|
714
|
-
};
|
|
715
|
-
}
|
|
734
|
+
const channels = this.channels;
|
|
716
735
|
for (let i = 0; i < midi.tracks.length; i++) {
|
|
717
736
|
const track = midi.tracks[i];
|
|
718
737
|
let currentTicks = 0;
|
|
@@ -722,48 +741,40 @@ export class MidyGM2 {
|
|
|
722
741
|
event.ticks = currentTicks;
|
|
723
742
|
switch (event.type) {
|
|
724
743
|
case "noteOn": {
|
|
725
|
-
const channel =
|
|
726
|
-
|
|
727
|
-
channel.programNumber = event.programNumber;
|
|
728
|
-
switch (channel.bankMSB) {
|
|
729
|
-
case 120:
|
|
730
|
-
instruments.add(`128:0`);
|
|
731
|
-
break;
|
|
732
|
-
case 121:
|
|
733
|
-
instruments.add(`${channel.bankLSB}:0`);
|
|
734
|
-
break;
|
|
735
|
-
default: {
|
|
736
|
-
const bankNumber = channel.bankMSB * 128 + channel.bankLSB;
|
|
737
|
-
instruments.add(`${bankNumber}:0`);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
channel.programNumber = 0;
|
|
741
|
-
}
|
|
744
|
+
const channel = channels[event.channel];
|
|
745
|
+
instruments.add(this.getSoundFontId(channel));
|
|
742
746
|
break;
|
|
743
747
|
}
|
|
744
748
|
case "controller":
|
|
745
749
|
switch (event.controllerType) {
|
|
746
750
|
case 0:
|
|
747
|
-
|
|
751
|
+
this.setBankMSB(event.channel, event.value);
|
|
748
752
|
break;
|
|
749
753
|
case 32:
|
|
750
|
-
|
|
754
|
+
this.setBankLSB(event.channel, event.value);
|
|
751
755
|
break;
|
|
752
756
|
}
|
|
753
757
|
break;
|
|
754
758
|
case "programChange": {
|
|
755
|
-
const channel =
|
|
756
|
-
channel
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
759
|
+
const channel = channels[event.channel];
|
|
760
|
+
this.setProgramChange(event.channel, event.programNumber);
|
|
761
|
+
instruments.add(this.getSoundFontId(channel));
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
case "sysEx": {
|
|
765
|
+
const data = event.data;
|
|
766
|
+
if (data[0] === 126 && data[1] === 9 && data[2] === 3) {
|
|
767
|
+
switch (data[3]) {
|
|
768
|
+
case 1:
|
|
769
|
+
this.GM1SystemOn(scheduleTime);
|
|
770
|
+
break;
|
|
771
|
+
case 2: // GM System Off
|
|
772
|
+
break;
|
|
773
|
+
case 3:
|
|
774
|
+
this.GM2SystemOn(scheduleTime);
|
|
775
|
+
break;
|
|
776
|
+
default:
|
|
777
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
767
778
|
}
|
|
768
779
|
}
|
|
769
780
|
}
|
|
@@ -1086,7 +1097,7 @@ export class MidyGM2 {
|
|
|
1086
1097
|
updateDetune(channel, note, scheduleTime) {
|
|
1087
1098
|
const noteDetune = this.calcNoteDetune(channel, note);
|
|
1088
1099
|
const detune = channel.detune + noteDetune;
|
|
1089
|
-
if (
|
|
1100
|
+
if (this.isPortamento(channel, note)) {
|
|
1090
1101
|
const startTime = note.startTime;
|
|
1091
1102
|
const deltaCent = (note.noteNumber - note.portamentoNoteNumber) * 100;
|
|
1092
1103
|
const portamentoTime = startTime + this.getPortamentoTime(channel, note);
|
|
@@ -1337,7 +1348,7 @@ export class MidyGM2 {
|
|
|
1337
1348
|
if (prevNote && prevNote.noteNumber !== noteNumber) {
|
|
1338
1349
|
note.portamentoNoteNumber = prevNote.noteNumber;
|
|
1339
1350
|
}
|
|
1340
|
-
if (
|
|
1351
|
+
if (!channel.isDrum && this.isPortamento(channel, note)) {
|
|
1341
1352
|
this.setPortamentoVolumeEnvelope(channel, note, now);
|
|
1342
1353
|
this.setPortamentoFilterEnvelope(channel, note, now);
|
|
1343
1354
|
this.setPortamentoPitchEnvelope(note, now);
|
|
@@ -1365,22 +1376,6 @@ export class MidyGM2 {
|
|
|
1365
1376
|
note.bufferSource.start(startTime);
|
|
1366
1377
|
return note;
|
|
1367
1378
|
}
|
|
1368
|
-
calcBank(channel) {
|
|
1369
|
-
switch (this.mode) {
|
|
1370
|
-
case "GM1":
|
|
1371
|
-
if (channel.isDrum)
|
|
1372
|
-
return 128;
|
|
1373
|
-
return 0;
|
|
1374
|
-
case "GM2":
|
|
1375
|
-
if (channel.bankMSB === 121)
|
|
1376
|
-
return 0;
|
|
1377
|
-
if (channel.isDrum)
|
|
1378
|
-
return 128;
|
|
1379
|
-
return channel.bank;
|
|
1380
|
-
default:
|
|
1381
|
-
return channel.bank;
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
1379
|
handleExclusiveClass(note, channelNumber, startTime) {
|
|
1385
1380
|
const exclusiveClass = note.voiceParams.exclusiveClass;
|
|
1386
1381
|
if (exclusiveClass === 0)
|
|
@@ -1416,13 +1411,17 @@ export class MidyGM2 {
|
|
|
1416
1411
|
}
|
|
1417
1412
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
1418
1413
|
const channel = this.channels[channelNumber];
|
|
1419
|
-
const
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1414
|
+
const programNumber = channel.programNumber;
|
|
1415
|
+
const bankTable = this.soundFontTable[programNumber];
|
|
1416
|
+
if (!bankTable)
|
|
1417
|
+
return;
|
|
1418
|
+
const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
|
|
1419
|
+
const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
|
|
1420
|
+
const soundFontIndex = bankTable[bank];
|
|
1422
1421
|
if (soundFontIndex === undefined)
|
|
1423
1422
|
return;
|
|
1424
1423
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
1425
|
-
const voice = soundFont.getVoice(
|
|
1424
|
+
const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
1426
1425
|
if (!voice)
|
|
1427
1426
|
return;
|
|
1428
1427
|
const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
|
|
@@ -1574,41 +1573,45 @@ export class MidyGM2 {
|
|
|
1574
1573
|
channel.sostenutoNotes = [];
|
|
1575
1574
|
return promises;
|
|
1576
1575
|
}
|
|
1577
|
-
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
1576
|
+
createMessageHandlers() {
|
|
1577
|
+
const handlers = new Array(256);
|
|
1578
|
+
// Channel Message
|
|
1579
|
+
handlers[0x80] = (data, scheduleTime) => this.noteOff(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1580
|
+
handlers[0x90] = (data, scheduleTime) => this.noteOn(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1581
|
+
handlers[0xB0] = (data, scheduleTime) => this.setControlChange(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1582
|
+
handlers[0xC0] = (data, scheduleTime) => this.setProgramChange(data[0] & 0x0F, data[1], scheduleTime);
|
|
1583
|
+
handlers[0xD0] = (data, scheduleTime) => this.setChannelPressure(data[0] & 0x0F, data[1], scheduleTime);
|
|
1584
|
+
handlers[0xE0] = (data, scheduleTime) => this.handlePitchBendMessage(data[0] & 0x0F, data[1], data[2], scheduleTime);
|
|
1585
|
+
// System Real Time Message
|
|
1586
|
+
handlers[0xFE] = (_data, _scheduleTime) => this.activeSensing();
|
|
1587
|
+
return handlers;
|
|
1588
|
+
}
|
|
1589
|
+
handleMessage(data, scheduleTime) {
|
|
1590
|
+
const status = data[0];
|
|
1591
|
+
if (status === 0xF0) {
|
|
1592
|
+
return this.handleSysEx(data.subarray(1), scheduleTime);
|
|
1595
1593
|
}
|
|
1594
|
+
const handler = this.messageHandlers[status];
|
|
1595
|
+
if (handler)
|
|
1596
|
+
handler(data, scheduleTime);
|
|
1597
|
+
}
|
|
1598
|
+
activeSensing() {
|
|
1599
|
+
this.lastActiveSensing = performance.now();
|
|
1596
1600
|
}
|
|
1597
1601
|
setProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
1598
1602
|
const channel = this.channels[channelNumber];
|
|
1599
|
-
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1600
1603
|
channel.programNumber = programNumber;
|
|
1601
1604
|
if (this.mode === "GM2") {
|
|
1602
1605
|
switch (channel.bankMSB) {
|
|
1603
1606
|
case 120:
|
|
1604
1607
|
channel.isDrum = true;
|
|
1608
|
+
channel.keyBasedTable.fill(-1);
|
|
1605
1609
|
break;
|
|
1606
1610
|
case 121:
|
|
1607
1611
|
channel.isDrum = false;
|
|
1608
1612
|
break;
|
|
1609
1613
|
}
|
|
1610
1614
|
}
|
|
1611
|
-
channel.keyBasedTable.fill(-1);
|
|
1612
1615
|
}
|
|
1613
1616
|
setChannelPressure(channelNumber, value, scheduleTime) {
|
|
1614
1617
|
const channel = this.channels[channelNumber];
|
|
@@ -1933,22 +1936,20 @@ export class MidyGM2 {
|
|
|
1933
1936
|
this.updateModulation(channel, scheduleTime);
|
|
1934
1937
|
}
|
|
1935
1938
|
updatePortamento(channel, scheduleTime) {
|
|
1939
|
+
if (channel.isDrum)
|
|
1940
|
+
return;
|
|
1936
1941
|
this.processScheduledNotes(channel, (note) => {
|
|
1937
|
-
if (
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
this.updateDetune(channel, note, scheduleTime);
|
|
1943
|
-
}
|
|
1942
|
+
if (this.isPortamento(channel, note)) {
|
|
1943
|
+
this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
|
|
1944
|
+
this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
|
|
1945
|
+
this.setPortamentoPitchEnvelope(note, scheduleTime);
|
|
1946
|
+
this.updateDetune(channel, note, scheduleTime);
|
|
1944
1947
|
}
|
|
1945
1948
|
else {
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
this.updateDetune(channel, note, scheduleTime);
|
|
1951
|
-
}
|
|
1949
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
1950
|
+
this.setFilterEnvelope(channel, note, scheduleTime);
|
|
1951
|
+
this.setPitchEnvelope(note, scheduleTime);
|
|
1952
|
+
this.updateDetune(channel, note, scheduleTime);
|
|
1952
1953
|
}
|
|
1953
1954
|
});
|
|
1954
1955
|
}
|
|
@@ -2054,6 +2055,9 @@ export class MidyGM2 {
|
|
|
2054
2055
|
this.releaseSustainPedal(channelNumber, value, scheduleTime);
|
|
2055
2056
|
}
|
|
2056
2057
|
}
|
|
2058
|
+
isPortamento(channel, note) {
|
|
2059
|
+
return 0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber;
|
|
2060
|
+
}
|
|
2057
2061
|
setPortamento(channelNumber, value, scheduleTime) {
|
|
2058
2062
|
const channel = this.channels[channelNumber];
|
|
2059
2063
|
if (channel.isDrum)
|
|
@@ -2090,7 +2094,7 @@ export class MidyGM2 {
|
|
|
2090
2094
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2091
2095
|
state.softPedal = softPedal / 127;
|
|
2092
2096
|
this.processScheduledNotes(channel, (note) => {
|
|
2093
|
-
if (
|
|
2097
|
+
if (this.isPortamento(channel, note)) {
|
|
2094
2098
|
this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
|
|
2095
2099
|
this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
|
|
2096
2100
|
}
|
|
@@ -2358,11 +2362,9 @@ export class MidyGM2 {
|
|
|
2358
2362
|
const channel = this.channels[i];
|
|
2359
2363
|
channel.bankMSB = 0;
|
|
2360
2364
|
channel.bankLSB = 0;
|
|
2361
|
-
channel.bank = 0;
|
|
2362
2365
|
channel.isDrum = false;
|
|
2363
2366
|
}
|
|
2364
2367
|
this.channels[9].bankMSB = 1;
|
|
2365
|
-
this.channels[9].bank = 128;
|
|
2366
2368
|
this.channels[9].isDrum = true;
|
|
2367
2369
|
}
|
|
2368
2370
|
GM2SystemOn(scheduleTime) {
|
|
@@ -2373,11 +2375,9 @@ export class MidyGM2 {
|
|
|
2373
2375
|
const channel = this.channels[i];
|
|
2374
2376
|
channel.bankMSB = 121;
|
|
2375
2377
|
channel.bankLSB = 0;
|
|
2376
|
-
channel.bank = 121 * 128;
|
|
2377
2378
|
channel.isDrum = false;
|
|
2378
2379
|
}
|
|
2379
2380
|
this.channels[9].bankMSB = 120;
|
|
2380
|
-
this.channels[9].bank = 120 * 128;
|
|
2381
2381
|
this.channels[9].isDrum = true;
|
|
2382
2382
|
}
|
|
2383
2383
|
handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
|
|
@@ -2422,16 +2422,11 @@ export class MidyGM2 {
|
|
|
2422
2422
|
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
2423
2423
|
this.setMasterVolume(volume, scheduleTime);
|
|
2424
2424
|
}
|
|
2425
|
-
setMasterVolume(
|
|
2425
|
+
setMasterVolume(value, scheduleTime) {
|
|
2426
2426
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
else {
|
|
2431
|
-
this.masterVolume.gain
|
|
2432
|
-
.cancelScheduledValues(scheduleTime)
|
|
2433
|
-
.setValueAtTime(volume * volume, scheduleTime);
|
|
2434
|
-
}
|
|
2427
|
+
this.masterVolume.gain
|
|
2428
|
+
.cancelScheduledValues(scheduleTime)
|
|
2429
|
+
.setValueAtTime(value * value, scheduleTime);
|
|
2435
2430
|
}
|
|
2436
2431
|
handleMasterFineTuningSysEx(data, scheduleTime) {
|
|
2437
2432
|
const value = (data[5] * 128 + data[4]) / 16383;
|
|
@@ -2794,6 +2789,22 @@ export class MidyGM2 {
|
|
|
2794
2789
|
const controlValue = channel.keyBasedTable[index];
|
|
2795
2790
|
return controlValue;
|
|
2796
2791
|
}
|
|
2792
|
+
createKeyBasedControllerHandlers() {
|
|
2793
|
+
const handlers = new Array(128);
|
|
2794
|
+
handlers[7] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2795
|
+
handlers[10] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2796
|
+
handlers[91] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
|
|
2797
|
+
if (note.noteNumber === keyNumber) {
|
|
2798
|
+
this.setReverbSend(channel, note, scheduleTime);
|
|
2799
|
+
}
|
|
2800
|
+
});
|
|
2801
|
+
handlers[93] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
|
|
2802
|
+
if (note.noteNumber === keyNumber) {
|
|
2803
|
+
this.setChorusSend(channel, note, scheduleTime);
|
|
2804
|
+
}
|
|
2805
|
+
});
|
|
2806
|
+
return handlers;
|
|
2807
|
+
}
|
|
2797
2808
|
handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
|
|
2798
2809
|
const channelNumber = data[4];
|
|
2799
2810
|
const channel = this.channels[channelNumber];
|
|
@@ -2806,26 +2817,9 @@ export class MidyGM2 {
|
|
|
2806
2817
|
const value = data[i + 1];
|
|
2807
2818
|
const index = keyNumber * 128 + controllerType;
|
|
2808
2819
|
table[index] = value;
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2813
|
-
break;
|
|
2814
|
-
case 91:
|
|
2815
|
-
this.processScheduledNotes(channel, (note) => {
|
|
2816
|
-
if (note.noteNumber === keyNumber) {
|
|
2817
|
-
this.setReverbSend(channel, note, scheduleTime);
|
|
2818
|
-
}
|
|
2819
|
-
});
|
|
2820
|
-
break;
|
|
2821
|
-
case 93:
|
|
2822
|
-
this.processScheduledNotes(channel, (note) => {
|
|
2823
|
-
if (note.noteNumber === keyNumber) {
|
|
2824
|
-
this.setChorusSend(channel, note, scheduleTime);
|
|
2825
|
-
}
|
|
2826
|
-
});
|
|
2827
|
-
break;
|
|
2828
|
-
}
|
|
2820
|
+
const handler = this.keyBasedControllerHandlers[controllerType];
|
|
2821
|
+
if (handler)
|
|
2822
|
+
handler(channel, keyNumber, scheduleTime);
|
|
2829
2823
|
}
|
|
2830
2824
|
}
|
|
2831
2825
|
handleSysEx(data, scheduleTime) {
|
|
@@ -2866,7 +2860,6 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2866
2860
|
scheduleIndex: 0,
|
|
2867
2861
|
detune: 0,
|
|
2868
2862
|
programNumber: 0,
|
|
2869
|
-
bank: 121 * 128,
|
|
2870
2863
|
bankMSB: 121,
|
|
2871
2864
|
bankLSB: 0,
|
|
2872
2865
|
dataMSB: 0,
|
package/esm/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
|
}
|
package/esm/midy-GMLite.d.ts.map
CHANGED
|
@@ -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"}
|