@marmooo/midy 0.2.5 → 0.2.6
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 +24 -25
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +55 -91
- package/esm/midy-GM2.d.ts +33 -29
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +146 -133
- package/esm/midy-GMLite.d.ts +18 -16
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +53 -39
- package/esm/midy.d.ts +35 -31
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +172 -161
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +24 -25
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +55 -91
- package/script/midy-GM2.d.ts +33 -29
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +146 -133
- package/script/midy-GMLite.d.ts +18 -16
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +53 -39
- package/script/midy.d.ts +35 -31
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +172 -161
package/script/midy-GM2.js
CHANGED
|
@@ -69,31 +69,37 @@ class Note {
|
|
|
69
69
|
writable: true,
|
|
70
70
|
value: void 0
|
|
71
71
|
});
|
|
72
|
+
Object.defineProperty(this, "filterDepth", {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
configurable: true,
|
|
75
|
+
writable: true,
|
|
76
|
+
value: void 0
|
|
77
|
+
});
|
|
72
78
|
Object.defineProperty(this, "volumeEnvelopeNode", {
|
|
73
79
|
enumerable: true,
|
|
74
80
|
configurable: true,
|
|
75
81
|
writable: true,
|
|
76
82
|
value: void 0
|
|
77
83
|
});
|
|
78
|
-
Object.defineProperty(this, "
|
|
84
|
+
Object.defineProperty(this, "volumeDepth", {
|
|
79
85
|
enumerable: true,
|
|
80
86
|
configurable: true,
|
|
81
87
|
writable: true,
|
|
82
88
|
value: void 0
|
|
83
89
|
});
|
|
84
|
-
Object.defineProperty(this, "
|
|
90
|
+
Object.defineProperty(this, "volumeNode", {
|
|
85
91
|
enumerable: true,
|
|
86
92
|
configurable: true,
|
|
87
93
|
writable: true,
|
|
88
94
|
value: void 0
|
|
89
95
|
});
|
|
90
|
-
Object.defineProperty(this, "
|
|
96
|
+
Object.defineProperty(this, "gainL", {
|
|
91
97
|
enumerable: true,
|
|
92
98
|
configurable: true,
|
|
93
99
|
writable: true,
|
|
94
100
|
value: void 0
|
|
95
101
|
});
|
|
96
|
-
Object.defineProperty(this, "
|
|
102
|
+
Object.defineProperty(this, "gainR", {
|
|
97
103
|
enumerable: true,
|
|
98
104
|
configurable: true,
|
|
99
105
|
writable: true,
|
|
@@ -495,6 +501,9 @@ class MidyGM2 {
|
|
|
495
501
|
...this.setChannelAudioNodes(audioContext),
|
|
496
502
|
scheduledNotes: new SparseMap(128),
|
|
497
503
|
sostenutoNotes: new SparseMap(128),
|
|
504
|
+
scaleOctaveTuningTable: new Int8Array(12), // [-64, 63] cent
|
|
505
|
+
channelPressureTable: new Uint8Array([64, 64, 64, 0, 0, 0]),
|
|
506
|
+
keyBasedInstrumentControlTable: new Int8Array(128 * 128), // [-64, 63]
|
|
498
507
|
};
|
|
499
508
|
});
|
|
500
509
|
return channels;
|
|
@@ -561,10 +570,11 @@ class MidyGM2 {
|
|
|
561
570
|
const event = this.timeline[queueIndex];
|
|
562
571
|
if (event.startTime > t + this.lookAhead)
|
|
563
572
|
break;
|
|
573
|
+
const startTime = event.startTime + this.startDelay - offset;
|
|
564
574
|
switch (event.type) {
|
|
565
575
|
case "noteOn":
|
|
566
576
|
if (event.velocity !== 0) {
|
|
567
|
-
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity,
|
|
577
|
+
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime, event.portamento);
|
|
568
578
|
break;
|
|
569
579
|
}
|
|
570
580
|
/* falls through */
|
|
@@ -572,26 +582,26 @@ class MidyGM2 {
|
|
|
572
582
|
const portamentoTarget = this.findPortamentoTarget(queueIndex);
|
|
573
583
|
if (portamentoTarget)
|
|
574
584
|
portamentoTarget.portamento = true;
|
|
575
|
-
const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity,
|
|
585
|
+
const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, startTime, portamentoTarget?.noteNumber, false);
|
|
576
586
|
if (notePromise) {
|
|
577
587
|
this.notePromises.push(notePromise);
|
|
578
588
|
}
|
|
579
589
|
break;
|
|
580
590
|
}
|
|
581
591
|
case "controller":
|
|
582
|
-
this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
|
|
592
|
+
this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value, startTime);
|
|
583
593
|
break;
|
|
584
594
|
case "programChange":
|
|
585
|
-
this.handleProgramChange(event.channel, event.programNumber);
|
|
595
|
+
this.handleProgramChange(event.channel, event.programNumber, startTime);
|
|
586
596
|
break;
|
|
587
597
|
case "channelAftertouch":
|
|
588
|
-
this.handleChannelPressure(event.channel, event.amount);
|
|
598
|
+
this.handleChannelPressure(event.channel, event.amount, startTime);
|
|
589
599
|
break;
|
|
590
600
|
case "pitchBend":
|
|
591
|
-
this.setPitchBend(event.channel, event.value + 8192);
|
|
601
|
+
this.setPitchBend(event.channel, event.value + 8192, startTime);
|
|
592
602
|
break;
|
|
593
603
|
case "sysEx":
|
|
594
|
-
this.handleSysEx(event.data);
|
|
604
|
+
this.handleSysEx(event.data, startTime);
|
|
595
605
|
}
|
|
596
606
|
queueIndex++;
|
|
597
607
|
}
|
|
@@ -838,6 +848,18 @@ class MidyGM2 {
|
|
|
838
848
|
const now = this.audioContext.currentTime;
|
|
839
849
|
return this.resumeTime + now - this.startTime - this.startDelay;
|
|
840
850
|
}
|
|
851
|
+
processScheduledNotes(channel, scheduleTime, callback) {
|
|
852
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
853
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
854
|
+
const note = noteList[i];
|
|
855
|
+
if (!note)
|
|
856
|
+
continue;
|
|
857
|
+
if (scheduleTime < note.startTime)
|
|
858
|
+
continue;
|
|
859
|
+
callback(note);
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
}
|
|
841
863
|
getActiveNotes(channel, time) {
|
|
842
864
|
const activeNotes = new SparseMap(128);
|
|
843
865
|
channel.scheduledNotes.forEach((noteList) => {
|
|
@@ -1019,14 +1041,14 @@ class MidyGM2 {
|
|
|
1019
1041
|
const note = noteList[i];
|
|
1020
1042
|
if (!note)
|
|
1021
1043
|
continue;
|
|
1022
|
-
this.updateDetune(channel, note
|
|
1044
|
+
this.updateDetune(channel, note);
|
|
1023
1045
|
}
|
|
1024
1046
|
});
|
|
1025
1047
|
}
|
|
1026
|
-
updateDetune(channel, note
|
|
1048
|
+
updateDetune(channel, note) {
|
|
1027
1049
|
const now = this.audioContext.currentTime;
|
|
1028
1050
|
const noteDetune = this.calcNoteDetune(channel, note);
|
|
1029
|
-
const detune = channel.detune + noteDetune
|
|
1051
|
+
const detune = channel.detune + noteDetune;
|
|
1030
1052
|
note.bufferSource.detune
|
|
1031
1053
|
.cancelScheduledValues(now)
|
|
1032
1054
|
.setValueAtTime(detune, now);
|
|
@@ -1048,11 +1070,11 @@ class MidyGM2 {
|
|
|
1048
1070
|
.setValueAtTime(0, volDelay)
|
|
1049
1071
|
.linearRampToValueAtTime(sustainVolume, portamentoTime);
|
|
1050
1072
|
}
|
|
1051
|
-
setVolumeEnvelope(
|
|
1073
|
+
setVolumeEnvelope(channel, note) {
|
|
1052
1074
|
const now = this.audioContext.currentTime;
|
|
1053
1075
|
const { voiceParams, startTime } = note;
|
|
1054
1076
|
const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation) *
|
|
1055
|
-
(1 +
|
|
1077
|
+
(1 + this.getAmplitudeControl(channel));
|
|
1056
1078
|
const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
|
|
1057
1079
|
const volDelay = startTime + voiceParams.volDelay;
|
|
1058
1080
|
const volAttack = volDelay + voiceParams.volAttack;
|
|
@@ -1066,20 +1088,20 @@ class MidyGM2 {
|
|
|
1066
1088
|
.setValueAtTime(attackVolume, volHold)
|
|
1067
1089
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
1068
1090
|
}
|
|
1069
|
-
setPitchEnvelope(note) {
|
|
1070
|
-
|
|
1091
|
+
setPitchEnvelope(note, scheduleTime) {
|
|
1092
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1071
1093
|
const { voiceParams } = note;
|
|
1072
1094
|
const baseRate = voiceParams.playbackRate;
|
|
1073
1095
|
note.bufferSource.playbackRate
|
|
1074
|
-
.cancelScheduledValues(
|
|
1075
|
-
.setValueAtTime(baseRate,
|
|
1096
|
+
.cancelScheduledValues(scheduleTime)
|
|
1097
|
+
.setValueAtTime(baseRate, scheduleTime);
|
|
1076
1098
|
const modEnvToPitch = voiceParams.modEnvToPitch;
|
|
1077
1099
|
if (modEnvToPitch === 0)
|
|
1078
1100
|
return;
|
|
1079
1101
|
const basePitch = this.rateToCent(baseRate);
|
|
1080
1102
|
const peekPitch = basePitch + modEnvToPitch;
|
|
1081
1103
|
const peekRate = this.centToRate(peekPitch);
|
|
1082
|
-
const modDelay = startTime + voiceParams.modDelay;
|
|
1104
|
+
const modDelay = note.startTime + voiceParams.modDelay;
|
|
1083
1105
|
const modAttack = modDelay + voiceParams.modAttack;
|
|
1084
1106
|
const modHold = modAttack + voiceParams.modHold;
|
|
1085
1107
|
const modDecay = modHold + voiceParams.modDecay;
|
|
@@ -1115,13 +1137,14 @@ class MidyGM2 {
|
|
|
1115
1137
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
1116
1138
|
.linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
|
|
1117
1139
|
}
|
|
1118
|
-
setFilterEnvelope(channel, note
|
|
1140
|
+
setFilterEnvelope(channel, note) {
|
|
1119
1141
|
const now = this.audioContext.currentTime;
|
|
1120
1142
|
const state = channel.state;
|
|
1121
1143
|
const { voiceParams, noteNumber, startTime } = note;
|
|
1122
1144
|
const softPedalFactor = 1 -
|
|
1123
1145
|
(0.1 + (noteNumber / 127) * 0.2) * state.softPedal;
|
|
1124
|
-
const baseCent = voiceParams.initialFilterFc +
|
|
1146
|
+
const baseCent = voiceParams.initialFilterFc +
|
|
1147
|
+
this.getFilterCutoffControl(channel);
|
|
1125
1148
|
const baseFreq = this.centToHz(baseCent) * softPedalFactor;
|
|
1126
1149
|
const peekFreq = this.centToHz(baseCent + voiceParams.modEnvToFilterFc) *
|
|
1127
1150
|
softPedalFactor;
|
|
@@ -1151,9 +1174,9 @@ class MidyGM2 {
|
|
|
1151
1174
|
gain: voiceParams.modLfoToFilterFc,
|
|
1152
1175
|
});
|
|
1153
1176
|
note.modulationDepth = new GainNode(this.audioContext);
|
|
1154
|
-
this.setModLfoToPitch(channel, note
|
|
1177
|
+
this.setModLfoToPitch(channel, note);
|
|
1155
1178
|
note.volumeDepth = new GainNode(this.audioContext);
|
|
1156
|
-
this.setModLfoToVolume(
|
|
1179
|
+
this.setModLfoToVolume(channel, note);
|
|
1157
1180
|
note.modulationLFO.start(startTime + voiceParams.delayModLFO);
|
|
1158
1181
|
note.modulationLFO.connect(note.filterDepth);
|
|
1159
1182
|
note.filterDepth.connect(note.filterNode.frequency);
|
|
@@ -1214,8 +1237,8 @@ class MidyGM2 {
|
|
|
1214
1237
|
}
|
|
1215
1238
|
else {
|
|
1216
1239
|
note.portamento = false;
|
|
1217
|
-
this.setVolumeEnvelope(
|
|
1218
|
-
this.setFilterEnvelope(channel, note
|
|
1240
|
+
this.setVolumeEnvelope(channel, note);
|
|
1241
|
+
this.setFilterEnvelope(channel, note);
|
|
1219
1242
|
}
|
|
1220
1243
|
if (0 < state.vibratoDepth) {
|
|
1221
1244
|
this.startVibrato(channel, note, startTime);
|
|
@@ -1429,8 +1452,9 @@ class MidyGM2 {
|
|
|
1429
1452
|
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1430
1453
|
channel.program = program;
|
|
1431
1454
|
}
|
|
1432
|
-
handleChannelPressure(channelNumber, value) {
|
|
1433
|
-
|
|
1455
|
+
handleChannelPressure(channelNumber, value, startTime) {
|
|
1456
|
+
if (!startTime)
|
|
1457
|
+
startTime = this.audioContext.currentTime;
|
|
1434
1458
|
const channel = this.channels[channelNumber];
|
|
1435
1459
|
const prev = channel.state.channelPressure;
|
|
1436
1460
|
const next = value / 127;
|
|
@@ -1440,8 +1464,8 @@ class MidyGM2 {
|
|
|
1440
1464
|
channel.detune += pressureDepth * (next - prev);
|
|
1441
1465
|
}
|
|
1442
1466
|
const table = channel.channelPressureTable;
|
|
1443
|
-
this.getActiveNotes(channel,
|
|
1444
|
-
this.
|
|
1467
|
+
this.getActiveNotes(channel, startTime).forEach((note) => {
|
|
1468
|
+
this.setControllerParameters(channel, note, table);
|
|
1445
1469
|
});
|
|
1446
1470
|
// this.applyVoiceParams(channel, 13);
|
|
1447
1471
|
}
|
|
@@ -1459,9 +1483,10 @@ class MidyGM2 {
|
|
|
1459
1483
|
this.updateChannelDetune(channel);
|
|
1460
1484
|
this.applyVoiceParams(channel, 14);
|
|
1461
1485
|
}
|
|
1462
|
-
setModLfoToPitch(channel, note
|
|
1486
|
+
setModLfoToPitch(channel, note) {
|
|
1463
1487
|
const now = this.audioContext.currentTime;
|
|
1464
|
-
const modLfoToPitch = note.voiceParams.modLfoToPitch +
|
|
1488
|
+
const modLfoToPitch = note.voiceParams.modLfoToPitch +
|
|
1489
|
+
this.getLFOPitchDepth(channel);
|
|
1465
1490
|
const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
|
|
1466
1491
|
const modulationDepth = baseDepth * Math.sign(modLfoToPitch);
|
|
1467
1492
|
note.modulationDepth.gain
|
|
@@ -1478,18 +1503,20 @@ class MidyGM2 {
|
|
|
1478
1503
|
.cancelScheduledValues(now)
|
|
1479
1504
|
.setValueAtTime(vibratoDepth * vibratoDepthSign, now);
|
|
1480
1505
|
}
|
|
1481
|
-
setModLfoToFilterFc(
|
|
1506
|
+
setModLfoToFilterFc(channel, note) {
|
|
1482
1507
|
const now = this.audioContext.currentTime;
|
|
1483
|
-
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc +
|
|
1508
|
+
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc +
|
|
1509
|
+
this.getLFOFilterDepth(channel);
|
|
1484
1510
|
note.filterDepth.gain
|
|
1485
1511
|
.cancelScheduledValues(now)
|
|
1486
1512
|
.setValueAtTime(modLfoToFilterFc, now);
|
|
1487
1513
|
}
|
|
1488
|
-
setModLfoToVolume(
|
|
1514
|
+
setModLfoToVolume(channel, note) {
|
|
1489
1515
|
const now = this.audioContext.currentTime;
|
|
1490
1516
|
const modLfoToVolume = note.voiceParams.modLfoToVolume;
|
|
1491
1517
|
const baseDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
|
|
1492
|
-
const volumeDepth = baseDepth * Math.sign(modLfoToVolume) *
|
|
1518
|
+
const volumeDepth = baseDepth * Math.sign(modLfoToVolume) *
|
|
1519
|
+
(1 + this.getLFOAmplitudeDepth(channel));
|
|
1493
1520
|
note.volumeDepth.gain
|
|
1494
1521
|
.cancelScheduledValues(now)
|
|
1495
1522
|
.setValueAtTime(volumeDepth, now);
|
|
@@ -1573,7 +1600,7 @@ class MidyGM2 {
|
|
|
1573
1600
|
return {
|
|
1574
1601
|
modLfoToPitch: (channel, note, _prevValue) => {
|
|
1575
1602
|
if (0 < channel.state.modulationDepth) {
|
|
1576
|
-
this.setModLfoToPitch(channel, note
|
|
1603
|
+
this.setModLfoToPitch(channel, note);
|
|
1577
1604
|
}
|
|
1578
1605
|
},
|
|
1579
1606
|
vibLfoToPitch: (channel, note, _prevValue) => {
|
|
@@ -1583,12 +1610,12 @@ class MidyGM2 {
|
|
|
1583
1610
|
},
|
|
1584
1611
|
modLfoToFilterFc: (channel, note, _prevValue) => {
|
|
1585
1612
|
if (0 < channel.state.modulationDepth) {
|
|
1586
|
-
this.setModLfoToFilterFc(
|
|
1613
|
+
this.setModLfoToFilterFc(channel, note);
|
|
1587
1614
|
}
|
|
1588
1615
|
},
|
|
1589
1616
|
modLfoToVolume: (channel, note, _prevValue) => {
|
|
1590
1617
|
if (0 < channel.state.modulationDepth) {
|
|
1591
|
-
this.setModLfoToVolume(
|
|
1618
|
+
this.setModLfoToVolume(channel, note);
|
|
1592
1619
|
}
|
|
1593
1620
|
},
|
|
1594
1621
|
chorusEffectsSend: (channel, note, prevValue) => {
|
|
@@ -1658,7 +1685,7 @@ class MidyGM2 {
|
|
|
1658
1685
|
this.setPortamentoStartFilterEnvelope(channel, note);
|
|
1659
1686
|
}
|
|
1660
1687
|
else {
|
|
1661
|
-
this.setFilterEnvelope(channel, note
|
|
1688
|
+
this.setFilterEnvelope(channel, note);
|
|
1662
1689
|
}
|
|
1663
1690
|
this.setPitchEnvelope(note);
|
|
1664
1691
|
}
|
|
@@ -1672,7 +1699,7 @@ class MidyGM2 {
|
|
|
1672
1699
|
if (key in voiceParams)
|
|
1673
1700
|
noteVoiceParams[key] = voiceParams[key];
|
|
1674
1701
|
}
|
|
1675
|
-
this.setVolumeEnvelope(
|
|
1702
|
+
this.setVolumeEnvelope(channel, note);
|
|
1676
1703
|
}
|
|
1677
1704
|
}
|
|
1678
1705
|
}
|
|
@@ -1706,10 +1733,10 @@ class MidyGM2 {
|
|
|
1706
1733
|
127: this.polyOn,
|
|
1707
1734
|
};
|
|
1708
1735
|
}
|
|
1709
|
-
handleControlChange(channelNumber, controllerType, value) {
|
|
1736
|
+
handleControlChange(channelNumber, controllerType, value, startTime) {
|
|
1710
1737
|
const handler = this.controlChangeHandlers[controllerType];
|
|
1711
1738
|
if (handler) {
|
|
1712
|
-
handler.call(this, channelNumber, value);
|
|
1739
|
+
handler.call(this, channelNumber, value, startTime);
|
|
1713
1740
|
const channel = this.channels[channelNumber];
|
|
1714
1741
|
this.applyVoiceParams(channel, controllerType + 128);
|
|
1715
1742
|
this.applyControlTable(channel, controllerType);
|
|
@@ -1721,55 +1748,45 @@ class MidyGM2 {
|
|
|
1721
1748
|
setBankMSB(channelNumber, msb) {
|
|
1722
1749
|
this.channels[channelNumber].bankMSB = msb;
|
|
1723
1750
|
}
|
|
1724
|
-
updateModulation(channel) {
|
|
1725
|
-
|
|
1751
|
+
updateModulation(channel, scheduleTime) {
|
|
1752
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1726
1753
|
const depth = channel.state.modulationDepth * channel.modulationDepthRange;
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
}
|
|
1735
|
-
else {
|
|
1736
|
-
this.setPitchEnvelope(note);
|
|
1737
|
-
this.startModulation(channel, note, now);
|
|
1738
|
-
}
|
|
1754
|
+
this.processScheduledNotes(channel, scheduleTime, (note) => {
|
|
1755
|
+
if (note.modulationDepth) {
|
|
1756
|
+
note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
|
|
1757
|
+
}
|
|
1758
|
+
else {
|
|
1759
|
+
this.setPitchEnvelope(note, scheduleTime);
|
|
1760
|
+
this.startModulation(channel, note, scheduleTime);
|
|
1739
1761
|
}
|
|
1740
1762
|
});
|
|
1741
1763
|
}
|
|
1742
|
-
setModulationDepth(channelNumber, modulation) {
|
|
1764
|
+
setModulationDepth(channelNumber, modulation, scheduleTime) {
|
|
1743
1765
|
const channel = this.channels[channelNumber];
|
|
1744
1766
|
channel.state.modulationDepth = modulation / 127;
|
|
1745
|
-
this.updateModulation(channel);
|
|
1767
|
+
this.updateModulation(channel, scheduleTime);
|
|
1746
1768
|
}
|
|
1747
1769
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
1748
1770
|
const channel = this.channels[channelNumber];
|
|
1749
1771
|
const factor = 5 * Math.log(10) / 127;
|
|
1750
1772
|
channel.state.portamentoTime = Math.exp(factor * portamentoTime);
|
|
1751
1773
|
}
|
|
1752
|
-
setKeyBasedVolume(channel) {
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
if (!note)
|
|
1758
|
-
continue;
|
|
1759
|
-
const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 7);
|
|
1760
|
-
if (keyBasedValue === 0)
|
|
1761
|
-
continue;
|
|
1774
|
+
setKeyBasedVolume(channel, scheduleTime) {
|
|
1775
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1776
|
+
this.processScheduledNotes(channel, scheduleTime, (note) => {
|
|
1777
|
+
const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 7);
|
|
1778
|
+
if (keyBasedValue !== 0) {
|
|
1762
1779
|
note.volumeNode.gain
|
|
1763
|
-
.cancelScheduledValues(
|
|
1764
|
-
.setValueAtTime(1 + keyBasedValue,
|
|
1780
|
+
.cancelScheduledValues(scheduleTime)
|
|
1781
|
+
.setValueAtTime(1 + keyBasedValue, scheduleTime);
|
|
1765
1782
|
}
|
|
1766
1783
|
});
|
|
1767
1784
|
}
|
|
1768
|
-
setVolume(channelNumber, volume) {
|
|
1785
|
+
setVolume(channelNumber, volume, scheduleTime) {
|
|
1769
1786
|
const channel = this.channels[channelNumber];
|
|
1770
1787
|
channel.state.volume = volume / 127;
|
|
1771
|
-
this.updateChannelVolume(channel);
|
|
1772
|
-
this.setKeyBasedVolume(channel);
|
|
1788
|
+
this.updateChannelVolume(channel, scheduleTime);
|
|
1789
|
+
this.setKeyBasedVolume(channel, scheduleTime);
|
|
1773
1790
|
}
|
|
1774
1791
|
panToGain(pan) {
|
|
1775
1792
|
const theta = Math.PI / 2 * Math.max(0, pan * 127 - 1) / 126;
|
|
@@ -1778,36 +1795,31 @@ class MidyGM2 {
|
|
|
1778
1795
|
gainRight: Math.sin(theta),
|
|
1779
1796
|
};
|
|
1780
1797
|
}
|
|
1781
|
-
setKeyBasedPan(channel) {
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
if (!note)
|
|
1787
|
-
continue;
|
|
1788
|
-
const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 10);
|
|
1789
|
-
if (keyBasedValue === 0)
|
|
1790
|
-
continue;
|
|
1798
|
+
setKeyBasedPan(channel, scheduleTime) {
|
|
1799
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1800
|
+
this.processScheduledNotes(channel, scheduleTime, (note) => {
|
|
1801
|
+
const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 10);
|
|
1802
|
+
if (keyBasedValue !== 0) {
|
|
1791
1803
|
const { gainLeft, gainRight } = this.panToGain((keyBasedValue + 1) / 2);
|
|
1792
1804
|
note.gainL.gain
|
|
1793
|
-
.cancelScheduledValues(
|
|
1794
|
-
.setValueAtTime(gainLeft,
|
|
1805
|
+
.cancelScheduledValues(scheduleTime)
|
|
1806
|
+
.setValueAtTime(gainLeft, scheduleTime);
|
|
1795
1807
|
note.gainR.gain
|
|
1796
|
-
.cancelScheduledValues(
|
|
1797
|
-
.setValueAtTime(gainRight,
|
|
1808
|
+
.cancelScheduledValues(scheduleTime)
|
|
1809
|
+
.setValueAtTime(gainRight, scheduleTime);
|
|
1798
1810
|
}
|
|
1799
1811
|
});
|
|
1800
1812
|
}
|
|
1801
|
-
setPan(channelNumber, pan) {
|
|
1813
|
+
setPan(channelNumber, pan, scheduleTime) {
|
|
1802
1814
|
const channel = this.channels[channelNumber];
|
|
1803
1815
|
channel.state.pan = pan / 127;
|
|
1804
|
-
this.updateChannelVolume(channel);
|
|
1805
|
-
this.setKeyBasedPan(channel);
|
|
1816
|
+
this.updateChannelVolume(channel, scheduleTime);
|
|
1817
|
+
this.setKeyBasedPan(channel, scheduleTime);
|
|
1806
1818
|
}
|
|
1807
|
-
setExpression(channelNumber, expression) {
|
|
1819
|
+
setExpression(channelNumber, expression, scheduleTime) {
|
|
1808
1820
|
const channel = this.channels[channelNumber];
|
|
1809
1821
|
channel.state.expression = expression / 127;
|
|
1810
|
-
this.updateChannelVolume(channel);
|
|
1822
|
+
this.updateChannelVolume(channel, scheduleTime);
|
|
1811
1823
|
}
|
|
1812
1824
|
setBankLSB(channelNumber, lsb) {
|
|
1813
1825
|
this.channels[channelNumber].bankLSB = lsb;
|
|
@@ -2435,42 +2447,46 @@ class MidyGM2 {
|
|
|
2435
2447
|
this.updateChannelDetune(channel);
|
|
2436
2448
|
}
|
|
2437
2449
|
}
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2450
|
+
getFilterCutoffControl(channel) {
|
|
2451
|
+
const channelPressure = (channel.channelPressureTable[1] - 64) *
|
|
2452
|
+
channel.state.channelPressure;
|
|
2453
|
+
return channelPressure * 15;
|
|
2454
|
+
}
|
|
2455
|
+
getAmplitudeControl(channel) {
|
|
2456
|
+
const channelPressure = channel.channelPressureTable[2] *
|
|
2457
|
+
channel.state.channelPressure;
|
|
2458
|
+
return channelPressure / 64;
|
|
2459
|
+
}
|
|
2460
|
+
getLFOPitchDepth(channel) {
|
|
2461
|
+
const channelPressure = channel.channelPressureTable[3] *
|
|
2462
|
+
channel.state.channelPressure;
|
|
2463
|
+
return channelPressure / 127 * 600;
|
|
2464
|
+
}
|
|
2465
|
+
getLFOFilterDepth(channel) {
|
|
2466
|
+
const channelPressure = channel.channelPressureTable[4] *
|
|
2467
|
+
channel.state.channelPressure;
|
|
2468
|
+
return channelPressure / 127 * 2400;
|
|
2469
|
+
}
|
|
2470
|
+
getLFOAmplitudeDepth(channel) {
|
|
2471
|
+
const channelPressure = channel.channelPressureTable[5] *
|
|
2472
|
+
channel.state.channelPressure;
|
|
2473
|
+
return channelPressure / 127;
|
|
2474
|
+
}
|
|
2475
|
+
setControllerParameters(channel, note, table) {
|
|
2476
|
+
if (table[0] !== 64)
|
|
2477
|
+
this.updateDetune(channel, note);
|
|
2442
2478
|
if (!note.portamento) {
|
|
2443
|
-
if (table[1] !== 64)
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
|
-
if (table[3] !== 0) {
|
|
2457
|
-
const channelPressure = channel.channelPressureTable[3] *
|
|
2458
|
-
channel.state.channelPressure;
|
|
2459
|
-
const pressure = channelPressure / 127 * 600;
|
|
2460
|
-
this.setModLfoToPitch(channel, note, pressure);
|
|
2461
|
-
}
|
|
2462
|
-
if (table[4] !== 0) {
|
|
2463
|
-
const channelPressure = channel.channelPressureTable[4] *
|
|
2464
|
-
channel.state.channelPressure;
|
|
2465
|
-
const pressure = channelPressure / 127 * 2400;
|
|
2466
|
-
this.setModLfoToFilterFc(note, pressure);
|
|
2467
|
-
}
|
|
2468
|
-
if (table[5] !== 0) {
|
|
2469
|
-
const channelPressure = channel.channelPressureTable[5] *
|
|
2470
|
-
channel.state.channelPressure;
|
|
2471
|
-
const pressure = channelPressure / 127;
|
|
2472
|
-
this.setModLfoToVolume(note, pressure);
|
|
2473
|
-
}
|
|
2479
|
+
if (table[1] !== 64)
|
|
2480
|
+
this.setFilterEnvelope(channel, note);
|
|
2481
|
+
if (table[2] !== 64)
|
|
2482
|
+
this.setVolumeEnvelope(channel, note);
|
|
2483
|
+
}
|
|
2484
|
+
if (table[3] !== 0)
|
|
2485
|
+
this.setModLfoToPitch(channel, note);
|
|
2486
|
+
if (table[4] !== 0)
|
|
2487
|
+
this.setModLfoToFilterFc(channel, note);
|
|
2488
|
+
if (table[5] !== 0)
|
|
2489
|
+
this.setModLfoToVolume(channel, note);
|
|
2474
2490
|
}
|
|
2475
2491
|
handleChannelPressureSysEx(data, tableName) {
|
|
2476
2492
|
const channelNumber = data[4];
|
|
@@ -2501,7 +2517,7 @@ class MidyGM2 {
|
|
|
2501
2517
|
const note = noteList[i];
|
|
2502
2518
|
if (!note)
|
|
2503
2519
|
continue;
|
|
2504
|
-
this.
|
|
2520
|
+
this.setControllerParameters(channel, note, table);
|
|
2505
2521
|
}
|
|
2506
2522
|
});
|
|
2507
2523
|
}
|
|
@@ -2565,9 +2581,6 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2565
2581
|
value: {
|
|
2566
2582
|
currentBufferSource: null,
|
|
2567
2583
|
detune: 0,
|
|
2568
|
-
scaleOctaveTuningTable: new Int8Array(12), // [-64, 63] cent
|
|
2569
|
-
channelPressureTable: new Uint8Array([64, 64, 64, 0, 0, 0]),
|
|
2570
|
-
keyBasedInstrumentControlTable: new Int8Array(128 * 128), // [-64, 63]
|
|
2571
2584
|
program: 0,
|
|
2572
2585
|
bank: 121 * 128,
|
|
2573
2586
|
bankMSB: 121,
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -45,11 +45,11 @@ export class MidyGMLite {
|
|
|
45
45
|
freqVibLFO: (_channel: any, _note: any, _prevValue: any) => void;
|
|
46
46
|
};
|
|
47
47
|
controlChangeHandlers: {
|
|
48
|
-
1: (channelNumber: any, modulation: any) => void;
|
|
48
|
+
1: (channelNumber: any, modulation: any, scheduleTime: any) => void;
|
|
49
49
|
6: (channelNumber: any, value: any) => void;
|
|
50
|
-
7: (channelNumber: any, volume: any) => void;
|
|
51
|
-
10: (channelNumber: any, pan: any) => void;
|
|
52
|
-
11: (channelNumber: any, expression: any) => void;
|
|
50
|
+
7: (channelNumber: any, volume: any, scheduleTime: any) => void;
|
|
51
|
+
10: (channelNumber: any, pan: any, scheduleTime: any) => void;
|
|
52
|
+
11: (channelNumber: any, expression: any, scheduleTime: any) => void;
|
|
53
53
|
38: (channelNumber: any, value: any) => void;
|
|
54
54
|
64: (channelNumber: any, value: any) => void;
|
|
55
55
|
100: (channelNumber: any, value: any) => void;
|
|
@@ -90,6 +90,7 @@ export class MidyGMLite {
|
|
|
90
90
|
seekTo(second: any): void;
|
|
91
91
|
calcTotalTime(): number;
|
|
92
92
|
currentTime(): number;
|
|
93
|
+
processScheduledNotes(channel: any, scheduleTime: any, callback: any): void;
|
|
93
94
|
getActiveNotes(channel: any, time: any): SparseMap;
|
|
94
95
|
getActiveNote(noteList: any, time: any): any;
|
|
95
96
|
cbToRatio(cb: any): number;
|
|
@@ -100,7 +101,7 @@ export class MidyGMLite {
|
|
|
100
101
|
updateChannelDetune(channel: any): void;
|
|
101
102
|
updateDetune(channel: any, note: any): void;
|
|
102
103
|
setVolumeEnvelope(note: any): void;
|
|
103
|
-
setPitchEnvelope(note: any): void;
|
|
104
|
+
setPitchEnvelope(note: any, scheduleTime: any): void;
|
|
104
105
|
clampCutoffFrequency(frequency: any): number;
|
|
105
106
|
setFilterEnvelope(note: any): void;
|
|
106
107
|
startModulation(channel: any, note: any, startTime: any): void;
|
|
@@ -136,11 +137,11 @@ export class MidyGMLite {
|
|
|
136
137
|
getControllerState(channel: any, noteNumber: any, velocity: any): Float32Array<any>;
|
|
137
138
|
applyVoiceParams(channel: any, controllerType: any): void;
|
|
138
139
|
createControlChangeHandlers(): {
|
|
139
|
-
1: (channelNumber: any, modulation: any) => void;
|
|
140
|
+
1: (channelNumber: any, modulation: any, scheduleTime: any) => void;
|
|
140
141
|
6: (channelNumber: any, value: any) => void;
|
|
141
|
-
7: (channelNumber: any, volume: any) => void;
|
|
142
|
-
10: (channelNumber: any, pan: any) => void;
|
|
143
|
-
11: (channelNumber: any, expression: any) => void;
|
|
142
|
+
7: (channelNumber: any, volume: any, scheduleTime: any) => void;
|
|
143
|
+
10: (channelNumber: any, pan: any, scheduleTime: any) => void;
|
|
144
|
+
11: (channelNumber: any, expression: any, scheduleTime: any) => void;
|
|
144
145
|
38: (channelNumber: any, value: any) => void;
|
|
145
146
|
64: (channelNumber: any, value: any) => void;
|
|
146
147
|
100: (channelNumber: any, value: any) => void;
|
|
@@ -149,18 +150,18 @@ export class MidyGMLite {
|
|
|
149
150
|
121: (channelNumber: any) => void;
|
|
150
151
|
123: (channelNumber: any) => Promise<void>;
|
|
151
152
|
};
|
|
152
|
-
handleControlChange(channelNumber: any, controllerType: any, value: any): void;
|
|
153
|
-
updateModulation(channel: any): void;
|
|
154
|
-
setModulationDepth(channelNumber: any, modulation: any): void;
|
|
155
|
-
setVolume(channelNumber: any, volume: any): void;
|
|
153
|
+
handleControlChange(channelNumber: any, controllerType: any, value: any, startTime: any): void;
|
|
154
|
+
updateModulation(channel: any, scheduleTime: any): void;
|
|
155
|
+
setModulationDepth(channelNumber: any, modulation: any, scheduleTime: any): void;
|
|
156
|
+
setVolume(channelNumber: any, volume: any, scheduleTime: any): void;
|
|
156
157
|
panToGain(pan: any): {
|
|
157
158
|
gainLeft: number;
|
|
158
159
|
gainRight: number;
|
|
159
160
|
};
|
|
160
|
-
setPan(channelNumber: any, pan: any): void;
|
|
161
|
-
setExpression(channelNumber: any, expression: any): void;
|
|
161
|
+
setPan(channelNumber: any, pan: any, scheduleTime: any): void;
|
|
162
|
+
setExpression(channelNumber: any, expression: any, scheduleTime: any): void;
|
|
162
163
|
dataEntryLSB(channelNumber: any, value: any): void;
|
|
163
|
-
updateChannelVolume(channel: any): void;
|
|
164
|
+
updateChannelVolume(channel: any, scheduleTime: any): void;
|
|
164
165
|
setSustainPedal(channelNumber: any, value: any): void;
|
|
165
166
|
limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
|
|
166
167
|
handleRPN(channelNumber: any): void;
|
|
@@ -198,6 +199,7 @@ declare class Note {
|
|
|
198
199
|
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
199
200
|
bufferSource: any;
|
|
200
201
|
filterNode: any;
|
|
202
|
+
filterDepth: any;
|
|
201
203
|
volumeEnvelopeNode: any;
|
|
202
204
|
volumeDepth: any;
|
|
203
205
|
modulationLFO: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAiJA;IAsBE;;;;;;;;;MASE;IAEF,+BAQC;IAxCD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,6BAAuC;IAcrC,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,8DASC;IAED,2EAqDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4EASC;IAED,mDASC;IAED,6CAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,qDAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,yGAgBC;IAED,gHAuCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+FAWC;IAED,wDAWC;IAED,iFAIC;IAED,oEAIC;IAED;;;MAMC;IAED,8DAIC;IAED,4EAIC;IAED,mDAGC;IAED,2DAWC;IAED,sDAKC;IAED,kFAeC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAt1CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|