@marmooo/midy 0.3.6 → 0.3.7
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 +7 -9
- package/esm/midy-GM1.d.ts +27 -24
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +121 -89
- package/esm/midy-GM2.d.ts +30 -26
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +196 -144
- package/esm/midy-GMLite.d.ts +27 -24
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +114 -84
- package/esm/midy.d.ts +32 -27
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +294 -164
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +27 -24
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +121 -89
- package/script/midy-GM2.d.ts +30 -26
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +196 -144
- package/script/midy-GMLite.d.ts +27 -24
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +114 -84
- package/script/midy.d.ts +32 -27
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +294 -164
package/script/midy-GM2.js
CHANGED
|
@@ -228,13 +228,13 @@ class MidyGM2 {
|
|
|
228
228
|
configurable: true,
|
|
229
229
|
writable: true,
|
|
230
230
|
value: 0
|
|
231
|
-
}); //
|
|
231
|
+
}); // cent
|
|
232
232
|
Object.defineProperty(this, "masterCoarseTuning", {
|
|
233
233
|
enumerable: true,
|
|
234
234
|
configurable: true,
|
|
235
235
|
writable: true,
|
|
236
236
|
value: 0
|
|
237
|
-
}); //
|
|
237
|
+
}); // cent
|
|
238
238
|
Object.defineProperty(this, "reverb", {
|
|
239
239
|
enumerable: true,
|
|
240
240
|
configurable: true,
|
|
@@ -359,6 +359,12 @@ class MidyGM2 {
|
|
|
359
359
|
writable: true,
|
|
360
360
|
value: false
|
|
361
361
|
});
|
|
362
|
+
Object.defineProperty(this, "playPromise", {
|
|
363
|
+
enumerable: true,
|
|
364
|
+
configurable: true,
|
|
365
|
+
writable: true,
|
|
366
|
+
value: void 0
|
|
367
|
+
});
|
|
362
368
|
Object.defineProperty(this, "timeline", {
|
|
363
369
|
enumerable: true,
|
|
364
370
|
configurable: true,
|
|
@@ -527,7 +533,7 @@ class MidyGM2 {
|
|
|
527
533
|
channel.controlTable.fill(-1);
|
|
528
534
|
channel.scaleOctaveTuningTable.fill(0); // [-100, 100] cent
|
|
529
535
|
channel.channelPressureTable.fill(-1);
|
|
530
|
-
channel.
|
|
536
|
+
channel.keyBasedTable.fill(-1);
|
|
531
537
|
}
|
|
532
538
|
createChannels(audioContext) {
|
|
533
539
|
const channels = Array.from({ length: this.numChannels }, () => {
|
|
@@ -543,7 +549,7 @@ class MidyGM2 {
|
|
|
543
549
|
controlTable: this.initControlTable(),
|
|
544
550
|
scaleOctaveTuningTable: new Int8Array(12), // [-64, 63] cent
|
|
545
551
|
channelPressureTable: new Int8Array(6).fill(-1),
|
|
546
|
-
|
|
552
|
+
keyBasedTable: new Int8Array(128 * 128).fill(-1),
|
|
547
553
|
keyBasedGainLs: new Array(128),
|
|
548
554
|
keyBasedGainRs: new Array(128),
|
|
549
555
|
};
|
|
@@ -618,72 +624,80 @@ class MidyGM2 {
|
|
|
618
624
|
}
|
|
619
625
|
return 0;
|
|
620
626
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
627
|
+
resetAllStates() {
|
|
628
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
629
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
630
|
+
this.voiceCache.clear();
|
|
631
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
632
|
+
this.channels[i].scheduledNotes = [];
|
|
633
|
+
this.resetChannelStates(i);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
updateStates(queueIndex, nextQueueIndex) {
|
|
637
|
+
if (nextQueueIndex < queueIndex)
|
|
638
|
+
queueIndex = 0;
|
|
639
|
+
for (let i = queueIndex; i < nextQueueIndex; i++) {
|
|
640
|
+
const event = this.timeline[i];
|
|
641
|
+
switch (event.type) {
|
|
642
|
+
case "controller":
|
|
643
|
+
this.setControlChange(event.channel, event.controllerType, event.value, 0);
|
|
644
|
+
break;
|
|
645
|
+
case "programChange":
|
|
646
|
+
this.setProgramChange(event.channel, event.programNumber, 0);
|
|
647
|
+
break;
|
|
648
|
+
case "pitchBend":
|
|
649
|
+
this.setPitchBend(event.channel, event.value + 8192, 0);
|
|
650
|
+
break;
|
|
651
|
+
case "sysEx":
|
|
652
|
+
this.handleSysEx(event.data, 0);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async playNotes() {
|
|
657
|
+
if (this.audioContext.state === "suspended") {
|
|
658
|
+
await this.audioContext.resume();
|
|
659
|
+
}
|
|
660
|
+
this.isPlaying = true;
|
|
661
|
+
this.isPaused = false;
|
|
662
|
+
this.startTime = this.audioContext.currentTime;
|
|
663
|
+
let queueIndex = this.getQueueIndex(this.resumeTime);
|
|
664
|
+
let resumeTime = this.resumeTime - this.startTime;
|
|
665
|
+
let finished = false;
|
|
666
|
+
this.notePromises = [];
|
|
667
|
+
while (queueIndex < this.timeline.length) {
|
|
668
|
+
const now = this.audioContext.currentTime;
|
|
669
|
+
const t = now + resumeTime;
|
|
670
|
+
queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
|
|
671
|
+
if (this.isPausing) {
|
|
672
|
+
await this.stopNotes(0, true, now);
|
|
673
|
+
await this.audioContext.suspend();
|
|
674
|
+
this.notePromises = [];
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
else if (this.isStopping) {
|
|
678
|
+
await this.stopNotes(0, true, now);
|
|
679
|
+
await this.audioContext.suspend();
|
|
680
|
+
finished = true;
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
else if (this.isSeeking) {
|
|
684
|
+
await this.stopNotes(0, true, now);
|
|
685
|
+
this.startTime = this.audioContext.currentTime;
|
|
686
|
+
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
687
|
+
this.updateStates(queueIndex, nextQueueIndex);
|
|
688
|
+
queueIndex = nextQueueIndex;
|
|
689
|
+
resumeTime = this.resumeTime - this.startTime;
|
|
690
|
+
this.isSeeking = false;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const waitTime = now + this.noteCheckInterval;
|
|
694
|
+
await this.scheduleTask(() => { }, waitTime);
|
|
695
|
+
}
|
|
696
|
+
if (finished) {
|
|
628
697
|
this.notePromises = [];
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
this.notePromises = [];
|
|
633
|
-
this.exclusiveClassNotes.fill(undefined);
|
|
634
|
-
this.drumExclusiveClassNotes.fill(undefined);
|
|
635
|
-
this.voiceCache.clear();
|
|
636
|
-
for (let i = 0; i < this.channels.length; i++) {
|
|
637
|
-
this.channels[i].scheduledNotes = [];
|
|
638
|
-
this.resetAllStates(i);
|
|
639
|
-
}
|
|
640
|
-
resolve();
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
const now = this.audioContext.currentTime;
|
|
644
|
-
const t = now + resumeTime;
|
|
645
|
-
queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
|
|
646
|
-
if (this.isPausing) {
|
|
647
|
-
await this.stopNotes(0, true, now);
|
|
648
|
-
this.notePromises = [];
|
|
649
|
-
this.isPausing = false;
|
|
650
|
-
this.isPaused = true;
|
|
651
|
-
resolve();
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
else if (this.isStopping) {
|
|
655
|
-
await this.stopNotes(0, true, now);
|
|
656
|
-
this.notePromises = [];
|
|
657
|
-
this.exclusiveClassNotes.fill(undefined);
|
|
658
|
-
this.drumExclusiveClassNotes.fill(undefined);
|
|
659
|
-
this.voiceCache.clear();
|
|
660
|
-
for (let i = 0; i < this.channels.length; i++) {
|
|
661
|
-
this.channels[i].scheduledNotes = [];
|
|
662
|
-
this.resetAllStates(i);
|
|
663
|
-
}
|
|
664
|
-
this.isStopping = false;
|
|
665
|
-
this.isPaused = false;
|
|
666
|
-
resolve();
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
else if (this.isSeeking) {
|
|
670
|
-
this.stopNotes(0, true, now);
|
|
671
|
-
this.exclusiveClassNotes.fill(undefined);
|
|
672
|
-
this.drumExclusiveClassNotes.fill(undefined);
|
|
673
|
-
this.startTime = this.audioContext.currentTime;
|
|
674
|
-
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
675
|
-
resumeTime = this.resumeTime - this.startTime;
|
|
676
|
-
this.isSeeking = false;
|
|
677
|
-
await schedulePlayback();
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
const waitTime = now + this.noteCheckInterval;
|
|
681
|
-
await this.scheduleTask(() => { }, waitTime);
|
|
682
|
-
await schedulePlayback();
|
|
683
|
-
}
|
|
684
|
-
};
|
|
685
|
-
schedulePlayback();
|
|
686
|
-
});
|
|
698
|
+
this.resetAllStates();
|
|
699
|
+
}
|
|
700
|
+
this.isPlaying = false;
|
|
687
701
|
}
|
|
688
702
|
ticksToSecond(ticks, secondsPerBeat) {
|
|
689
703
|
return ticks * secondsPerBeat / this.ticksPerBeat;
|
|
@@ -820,26 +834,32 @@ class MidyGM2 {
|
|
|
820
834
|
this.resumeTime = 0;
|
|
821
835
|
if (this.voiceCounter.size === 0)
|
|
822
836
|
this.cacheVoiceIds();
|
|
823
|
-
|
|
824
|
-
this.
|
|
837
|
+
this.playPromise = this.playNotes();
|
|
838
|
+
await this.playPromise;
|
|
825
839
|
}
|
|
826
|
-
stop() {
|
|
840
|
+
async stop() {
|
|
827
841
|
if (!this.isPlaying)
|
|
828
842
|
return;
|
|
829
843
|
this.isStopping = true;
|
|
844
|
+
await this.playPromise;
|
|
845
|
+
this.isStopping = false;
|
|
830
846
|
}
|
|
831
|
-
pause() {
|
|
847
|
+
async pause() {
|
|
832
848
|
if (!this.isPlaying || this.isPaused)
|
|
833
849
|
return;
|
|
834
850
|
const now = this.audioContext.currentTime;
|
|
835
851
|
this.resumeTime += now - this.startTime - this.startDelay;
|
|
836
852
|
this.isPausing = true;
|
|
853
|
+
await this.playPromise;
|
|
854
|
+
this.isPausing = false;
|
|
855
|
+
this.isPaused = true;
|
|
837
856
|
}
|
|
838
857
|
async resume() {
|
|
839
858
|
if (!this.isPaused)
|
|
840
859
|
return;
|
|
841
|
-
|
|
842
|
-
this.
|
|
860
|
+
this.playPromise = this.playNotes();
|
|
861
|
+
await this.playPromise;
|
|
862
|
+
this.isPaused = false;
|
|
843
863
|
}
|
|
844
864
|
seekTo(second) {
|
|
845
865
|
this.resumeTime = second;
|
|
@@ -1274,10 +1294,12 @@ class MidyGM2 {
|
|
|
1274
1294
|
startVibrato(channel, note, scheduleTime) {
|
|
1275
1295
|
const { voiceParams } = note;
|
|
1276
1296
|
const state = channel.state;
|
|
1297
|
+
const vibratoRate = state.vibratoRate * 2;
|
|
1298
|
+
const vibratoDelay = state.vibratoDelay * 2;
|
|
1277
1299
|
note.vibratoLFO = new OscillatorNode(this.audioContext, {
|
|
1278
|
-
frequency: this.centToHz(voiceParams.freqVibLFO) *
|
|
1300
|
+
frequency: this.centToHz(voiceParams.freqVibLFO) * vibratoRate,
|
|
1279
1301
|
});
|
|
1280
|
-
note.vibratoLFO.start(note.startTime + voiceParams.delayVibLFO *
|
|
1302
|
+
note.vibratoLFO.start(note.startTime + voiceParams.delayVibLFO * vibratoDelay);
|
|
1281
1303
|
note.vibratoDepth = new GainNode(this.audioContext);
|
|
1282
1304
|
this.setVibLfoToPitch(channel, note, scheduleTime);
|
|
1283
1305
|
note.vibratoLFO.connect(note.vibratoDepth);
|
|
@@ -1589,6 +1611,7 @@ class MidyGM2 {
|
|
|
1589
1611
|
break;
|
|
1590
1612
|
}
|
|
1591
1613
|
}
|
|
1614
|
+
channel.keyBasedTable.fill(-1);
|
|
1592
1615
|
}
|
|
1593
1616
|
setChannelPressure(channelNumber, value, scheduleTime) {
|
|
1594
1617
|
const channel = this.channels[channelNumber];
|
|
@@ -1604,7 +1627,7 @@ class MidyGM2 {
|
|
|
1604
1627
|
}
|
|
1605
1628
|
const table = channel.channelPressureTable;
|
|
1606
1629
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
1607
|
-
this.setEffects(channel, note, table);
|
|
1630
|
+
this.setEffects(channel, note, table, scheduleTime);
|
|
1608
1631
|
});
|
|
1609
1632
|
this.applyVoiceParams(channel, 13);
|
|
1610
1633
|
}
|
|
@@ -1630,23 +1653,28 @@ class MidyGM2 {
|
|
|
1630
1653
|
const modLfoToPitch = note.voiceParams.modLfoToPitch +
|
|
1631
1654
|
this.getLFOPitchDepth(channel, note);
|
|
1632
1655
|
const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
|
|
1633
|
-
const
|
|
1656
|
+
const depth = baseDepth * Math.sign(modLfoToPitch);
|
|
1634
1657
|
note.modulationDepth.gain
|
|
1635
1658
|
.cancelScheduledValues(scheduleTime)
|
|
1636
|
-
.setValueAtTime(
|
|
1659
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1637
1660
|
}
|
|
1638
1661
|
else {
|
|
1639
1662
|
this.startModulation(channel, note, scheduleTime);
|
|
1640
1663
|
}
|
|
1641
1664
|
}
|
|
1642
1665
|
setVibLfoToPitch(channel, note, scheduleTime) {
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
.
|
|
1649
|
-
|
|
1666
|
+
if (note.vibratoDepth) {
|
|
1667
|
+
const vibratoDepth = channel.state.vibratoDepth * 2;
|
|
1668
|
+
const vibLfoToPitch = note.voiceParams.vibLfoToPitch;
|
|
1669
|
+
const baseDepth = Math.abs(vibLfoToPitch) * vibratoDepth;
|
|
1670
|
+
const depth = baseDepth * Math.sign(vibLfoToPitch);
|
|
1671
|
+
note.vibratoDepth.gain
|
|
1672
|
+
.cancelScheduledValues(scheduleTime)
|
|
1673
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1674
|
+
}
|
|
1675
|
+
else {
|
|
1676
|
+
this.startVibrato(channel, note, scheduleTime);
|
|
1677
|
+
}
|
|
1650
1678
|
}
|
|
1651
1679
|
setModLfoToFilterFc(channel, note, scheduleTime) {
|
|
1652
1680
|
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc +
|
|
@@ -1724,13 +1752,12 @@ class MidyGM2 {
|
|
|
1724
1752
|
}
|
|
1725
1753
|
}
|
|
1726
1754
|
}
|
|
1727
|
-
setDelayModLFO(note
|
|
1728
|
-
const startTime = note.startTime;
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
note.modulationLFO.connect(note.filterDepth);
|
|
1755
|
+
setDelayModLFO(note) {
|
|
1756
|
+
const startTime = note.startTime + note.voiceParams.delayModLFO;
|
|
1757
|
+
try {
|
|
1758
|
+
note.modulationLFO.start(startTime);
|
|
1759
|
+
}
|
|
1760
|
+
catch { /* empty */ }
|
|
1734
1761
|
}
|
|
1735
1762
|
setFreqModLFO(note, scheduleTime) {
|
|
1736
1763
|
const freqModLFO = note.voiceParams.freqModLFO;
|
|
@@ -1739,54 +1766,65 @@ class MidyGM2 {
|
|
|
1739
1766
|
.setValueAtTime(freqModLFO, scheduleTime);
|
|
1740
1767
|
}
|
|
1741
1768
|
setFreqVibLFO(channel, note, scheduleTime) {
|
|
1769
|
+
const vibratoRate = channel.state.vibratoRate * 2;
|
|
1742
1770
|
const freqVibLFO = note.voiceParams.freqVibLFO;
|
|
1743
1771
|
note.vibratoLFO.frequency
|
|
1744
1772
|
.cancelScheduledValues(scheduleTime)
|
|
1745
|
-
.setValueAtTime(freqVibLFO *
|
|
1773
|
+
.setValueAtTime(freqVibLFO * vibratoRate, scheduleTime);
|
|
1774
|
+
}
|
|
1775
|
+
setDelayVibLFO(channel, note) {
|
|
1776
|
+
const vibratoDelay = channel.state.vibratoDelay * 2;
|
|
1777
|
+
const value = note.voiceParams.delayVibLFO;
|
|
1778
|
+
const startTime = note.startTime + value * vibratoDelay;
|
|
1779
|
+
try {
|
|
1780
|
+
note.vibratoLFO.start(startTime);
|
|
1781
|
+
}
|
|
1782
|
+
catch { /* empty */ }
|
|
1746
1783
|
}
|
|
1747
1784
|
createVoiceParamsHandlers() {
|
|
1748
1785
|
return {
|
|
1749
|
-
modLfoToPitch: (channel, note,
|
|
1786
|
+
modLfoToPitch: (channel, note, scheduleTime) => {
|
|
1750
1787
|
if (0 < channel.state.modulationDepth) {
|
|
1751
1788
|
this.setModLfoToPitch(channel, note, scheduleTime);
|
|
1752
1789
|
}
|
|
1753
1790
|
},
|
|
1754
|
-
vibLfoToPitch: (channel, note,
|
|
1791
|
+
vibLfoToPitch: (channel, note, scheduleTime) => {
|
|
1755
1792
|
if (0 < channel.state.vibratoDepth) {
|
|
1756
1793
|
this.setVibLfoToPitch(channel, note, scheduleTime);
|
|
1757
1794
|
}
|
|
1758
1795
|
},
|
|
1759
|
-
modLfoToFilterFc: (channel, note,
|
|
1796
|
+
modLfoToFilterFc: (channel, note, scheduleTime) => {
|
|
1760
1797
|
if (0 < channel.state.modulationDepth) {
|
|
1761
1798
|
this.setModLfoToFilterFc(channel, note, scheduleTime);
|
|
1762
1799
|
}
|
|
1763
1800
|
},
|
|
1764
|
-
modLfoToVolume: (channel, note,
|
|
1801
|
+
modLfoToVolume: (channel, note, scheduleTime) => {
|
|
1765
1802
|
if (0 < channel.state.modulationDepth) {
|
|
1766
1803
|
this.setModLfoToVolume(channel, note, scheduleTime);
|
|
1767
1804
|
}
|
|
1768
1805
|
},
|
|
1769
|
-
chorusEffectsSend: (channel, note,
|
|
1770
|
-
this.
|
|
1806
|
+
chorusEffectsSend: (channel, note, scheduleTime) => {
|
|
1807
|
+
this.setChorusSend(channel, note, scheduleTime);
|
|
1808
|
+
},
|
|
1809
|
+
reverbEffectsSend: (channel, note, scheduleTime) => {
|
|
1810
|
+
this.setReverbSend(channel, note, scheduleTime);
|
|
1811
|
+
},
|
|
1812
|
+
delayModLFO: (_channel, note, _scheduleTime) => {
|
|
1813
|
+
if (0 < channel.state.modulationDepth) {
|
|
1814
|
+
this.setDelayModLFO(note);
|
|
1815
|
+
}
|
|
1771
1816
|
},
|
|
1772
|
-
|
|
1773
|
-
|
|
1817
|
+
freqModLFO: (_channel, note, scheduleTime) => {
|
|
1818
|
+
if (0 < channel.state.modulationDepth) {
|
|
1819
|
+
this.setFreqModLFO(note, scheduleTime);
|
|
1820
|
+
}
|
|
1774
1821
|
},
|
|
1775
|
-
|
|
1776
|
-
freqModLFO: (_channel, note, _prevValue, scheduleTime) => this.setFreqModLFO(note, scheduleTime),
|
|
1777
|
-
delayVibLFO: (channel, note, prevValue, scheduleTime) => {
|
|
1822
|
+
delayVibLFO: (channel, note, _scheduleTime) => {
|
|
1778
1823
|
if (0 < channel.state.vibratoDepth) {
|
|
1779
|
-
|
|
1780
|
-
const prevStartTime = note.startTime + prevValue * vibratoDelay;
|
|
1781
|
-
if (scheduleTime < prevStartTime)
|
|
1782
|
-
return;
|
|
1783
|
-
const value = note.voiceParams.delayVibLFO;
|
|
1784
|
-
const startTime = note.startTime + value * vibratoDelay;
|
|
1785
|
-
note.vibratoLFO.stop(scheduleTime);
|
|
1786
|
-
note.vibratoLFO.start(startTime);
|
|
1824
|
+
setDelayVibLFO(channel, note);
|
|
1787
1825
|
}
|
|
1788
1826
|
},
|
|
1789
|
-
freqVibLFO: (channel, note,
|
|
1827
|
+
freqVibLFO: (channel, note, scheduleTime) => {
|
|
1790
1828
|
if (0 < channel.state.vibratoDepth) {
|
|
1791
1829
|
this.setFreqVibLFO(channel, note, scheduleTime);
|
|
1792
1830
|
}
|
|
@@ -1814,7 +1852,7 @@ class MidyGM2 {
|
|
|
1814
1852
|
continue;
|
|
1815
1853
|
note.voiceParams[key] = value;
|
|
1816
1854
|
if (key in this.voiceParamsHandlers) {
|
|
1817
|
-
this.voiceParamsHandlers[key](channel, note,
|
|
1855
|
+
this.voiceParamsHandlers[key](channel, note, scheduleTime);
|
|
1818
1856
|
}
|
|
1819
1857
|
else {
|
|
1820
1858
|
if (volumeEnvelopeKeySet.has(key))
|
|
@@ -1983,13 +2021,13 @@ class MidyGM2 {
|
|
|
1983
2021
|
.setValueAtTime(volume * gainRight, scheduleTime);
|
|
1984
2022
|
}
|
|
1985
2023
|
updateKeyBasedVolume(channel, keyNumber, scheduleTime) {
|
|
1986
|
-
const state = channel.state;
|
|
1987
|
-
const defaultVolume = state.volume * state.expression;
|
|
1988
|
-
const defaultPan = state.pan;
|
|
1989
2024
|
const gainL = channel.keyBasedGainLs[keyNumber];
|
|
1990
|
-
const gainR = channel.keyBasedGainRs[keyNumber];
|
|
1991
2025
|
if (!gainL)
|
|
1992
2026
|
return;
|
|
2027
|
+
const gainR = channel.keyBasedGainRs[keyNumber];
|
|
2028
|
+
const state = channel.state;
|
|
2029
|
+
const defaultVolume = state.volume * state.expression;
|
|
2030
|
+
const defaultPan = state.pan;
|
|
1993
2031
|
const keyBasedVolume = this.getKeyBasedValue(channel, keyNumber, 7);
|
|
1994
2032
|
const volume = (0 <= keyBasedVolume)
|
|
1995
2033
|
? defaultVolume * keyBasedVolume / 64
|
|
@@ -2141,8 +2179,8 @@ class MidyGM2 {
|
|
|
2141
2179
|
}
|
|
2142
2180
|
handlePitchBendRangeRPN(channelNumber, scheduleTime) {
|
|
2143
2181
|
const channel = this.channels[channelNumber];
|
|
2144
|
-
this.limitData(channel, 0, 127, 0,
|
|
2145
|
-
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
2182
|
+
this.limitData(channel, 0, 127, 0, 127);
|
|
2183
|
+
const pitchBendRange = (channel.dataMSB + channel.dataLSB / 128) * 100;
|
|
2146
2184
|
this.setPitchBendRange(channelNumber, pitchBendRange, scheduleTime);
|
|
2147
2185
|
}
|
|
2148
2186
|
setPitchBendRange(channelNumber, value, scheduleTime) {
|
|
@@ -2152,7 +2190,7 @@ class MidyGM2 {
|
|
|
2152
2190
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2153
2191
|
const state = channel.state;
|
|
2154
2192
|
const prev = state.pitchWheelSensitivity;
|
|
2155
|
-
const next = value /
|
|
2193
|
+
const next = value / 12800;
|
|
2156
2194
|
state.pitchWheelSensitivity = next;
|
|
2157
2195
|
channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
|
|
2158
2196
|
this.updateChannelDetune(channel, scheduleTime);
|
|
@@ -2161,7 +2199,8 @@ class MidyGM2 {
|
|
|
2161
2199
|
handleFineTuningRPN(channelNumber, scheduleTime) {
|
|
2162
2200
|
const channel = this.channels[channelNumber];
|
|
2163
2201
|
this.limitData(channel, 0, 127, 0, 127);
|
|
2164
|
-
const
|
|
2202
|
+
const value = channel.dataMSB * 128 + channel.dataLSB;
|
|
2203
|
+
const fineTuning = (value - 8192) / 8192 * 100;
|
|
2165
2204
|
this.setFineTuning(channelNumber, fineTuning, scheduleTime);
|
|
2166
2205
|
}
|
|
2167
2206
|
setFineTuning(channelNumber, value, scheduleTime) {
|
|
@@ -2170,7 +2209,7 @@ class MidyGM2 {
|
|
|
2170
2209
|
return;
|
|
2171
2210
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2172
2211
|
const prev = channel.fineTuning;
|
|
2173
|
-
const next =
|
|
2212
|
+
const next = value;
|
|
2174
2213
|
channel.fineTuning = next;
|
|
2175
2214
|
channel.detune += next - prev;
|
|
2176
2215
|
this.updateChannelDetune(channel, scheduleTime);
|
|
@@ -2178,7 +2217,7 @@ class MidyGM2 {
|
|
|
2178
2217
|
handleCoarseTuningRPN(channelNumber, scheduleTime) {
|
|
2179
2218
|
const channel = this.channels[channelNumber];
|
|
2180
2219
|
this.limitDataMSB(channel, 0, 127);
|
|
2181
|
-
const coarseTuning = channel.dataMSB;
|
|
2220
|
+
const coarseTuning = (channel.dataMSB - 64) * 100;
|
|
2182
2221
|
this.setCoarseTuning(channelNumber, coarseTuning, scheduleTime);
|
|
2183
2222
|
}
|
|
2184
2223
|
setCoarseTuning(channelNumber, value, scheduleTime) {
|
|
@@ -2187,7 +2226,7 @@ class MidyGM2 {
|
|
|
2187
2226
|
return;
|
|
2188
2227
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2189
2228
|
const prev = channel.coarseTuning;
|
|
2190
|
-
const next =
|
|
2229
|
+
const next = value;
|
|
2191
2230
|
channel.coarseTuning = next;
|
|
2192
2231
|
channel.detune += next - prev;
|
|
2193
2232
|
this.updateChannelDetune(channel, scheduleTime);
|
|
@@ -2195,22 +2234,22 @@ class MidyGM2 {
|
|
|
2195
2234
|
handleModulationDepthRangeRPN(channelNumber, scheduleTime) {
|
|
2196
2235
|
const channel = this.channels[channelNumber];
|
|
2197
2236
|
this.limitData(channel, 0, 127, 0, 127);
|
|
2198
|
-
const
|
|
2199
|
-
this.setModulationDepthRange(channelNumber,
|
|
2237
|
+
const value = (channel.dataMSB + channel.dataLSB / 128) * 100;
|
|
2238
|
+
this.setModulationDepthRange(channelNumber, value, scheduleTime);
|
|
2200
2239
|
}
|
|
2201
|
-
setModulationDepthRange(channelNumber,
|
|
2240
|
+
setModulationDepthRange(channelNumber, value, scheduleTime) {
|
|
2202
2241
|
const channel = this.channels[channelNumber];
|
|
2203
2242
|
if (channel.isDrum)
|
|
2204
2243
|
return;
|
|
2205
2244
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2206
|
-
channel.modulationDepthRange =
|
|
2245
|
+
channel.modulationDepthRange = value;
|
|
2207
2246
|
this.updateModulation(channel, scheduleTime);
|
|
2208
2247
|
}
|
|
2209
2248
|
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
2210
2249
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2211
2250
|
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
2212
2251
|
}
|
|
2213
|
-
|
|
2252
|
+
resetChannelStates(channelNumber) {
|
|
2214
2253
|
const scheduleTime = this.audioContext.currentTime;
|
|
2215
2254
|
const channel = this.channels[channelNumber];
|
|
2216
2255
|
const state = channel.state;
|
|
@@ -2228,8 +2267,8 @@ class MidyGM2 {
|
|
|
2228
2267
|
}
|
|
2229
2268
|
this.resetChannelTable(channel);
|
|
2230
2269
|
this.mode = "GM2";
|
|
2231
|
-
this.masterFineTuning = 0; //
|
|
2232
|
-
this.masterCoarseTuning = 0; //
|
|
2270
|
+
this.masterFineTuning = 0; // cent
|
|
2271
|
+
this.masterCoarseTuning = 0; // cent
|
|
2233
2272
|
}
|
|
2234
2273
|
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
|
|
2235
2274
|
resetAllControllers(channelNumber, _value, scheduleTime) {
|
|
@@ -2398,12 +2437,13 @@ class MidyGM2 {
|
|
|
2398
2437
|
}
|
|
2399
2438
|
}
|
|
2400
2439
|
handleMasterFineTuningSysEx(data, scheduleTime) {
|
|
2401
|
-
const
|
|
2440
|
+
const value = (data[5] * 128 + data[4]) / 16383;
|
|
2441
|
+
const fineTuning = (value - 8192) / 8192 * 100;
|
|
2402
2442
|
this.setMasterFineTuning(fineTuning, scheduleTime);
|
|
2403
2443
|
}
|
|
2404
2444
|
setMasterFineTuning(value, scheduleTime) {
|
|
2405
2445
|
const prev = this.masterFineTuning;
|
|
2406
|
-
const next =
|
|
2446
|
+
const next = value;
|
|
2407
2447
|
this.masterFineTuning = next;
|
|
2408
2448
|
const detuneChange = next - prev;
|
|
2409
2449
|
for (let i = 0; i < this.channels.length; i++) {
|
|
@@ -2415,12 +2455,12 @@ class MidyGM2 {
|
|
|
2415
2455
|
}
|
|
2416
2456
|
}
|
|
2417
2457
|
handleMasterCoarseTuningSysEx(data, scheduleTime) {
|
|
2418
|
-
const coarseTuning = data[4];
|
|
2458
|
+
const coarseTuning = (data[4] - 64) * 100;
|
|
2419
2459
|
this.setMasterCoarseTuning(coarseTuning, scheduleTime);
|
|
2420
2460
|
}
|
|
2421
2461
|
setMasterCoarseTuning(value, scheduleTime) {
|
|
2422
2462
|
const prev = this.masterCoarseTuning;
|
|
2423
|
-
const next =
|
|
2463
|
+
const next = value;
|
|
2424
2464
|
this.masterCoarseTuning = next;
|
|
2425
2465
|
const detuneChange = next - prev;
|
|
2426
2466
|
for (let i = 0; i < this.channels.length; i++) {
|
|
@@ -2754,7 +2794,7 @@ class MidyGM2 {
|
|
|
2754
2794
|
}
|
|
2755
2795
|
getKeyBasedValue(channel, keyNumber, controllerType) {
|
|
2756
2796
|
const index = keyNumber * 128 + controllerType;
|
|
2757
|
-
const controlValue = channel.
|
|
2797
|
+
const controlValue = channel.keyBasedTable[index];
|
|
2758
2798
|
return controlValue;
|
|
2759
2799
|
}
|
|
2760
2800
|
handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
|
|
@@ -2763,7 +2803,7 @@ class MidyGM2 {
|
|
|
2763
2803
|
if (!channel.isDrum)
|
|
2764
2804
|
return;
|
|
2765
2805
|
const keyNumber = data[5];
|
|
2766
|
-
const table = channel.
|
|
2806
|
+
const table = channel.keyBasedTable;
|
|
2767
2807
|
for (let i = 6; i < data.length; i += 2) {
|
|
2768
2808
|
const controllerType = data[i];
|
|
2769
2809
|
const value = data[i + 1];
|
|
@@ -2774,8 +2814,20 @@ class MidyGM2 {
|
|
|
2774
2814
|
case 10:
|
|
2775
2815
|
this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
2776
2816
|
break;
|
|
2777
|
-
|
|
2778
|
-
this.
|
|
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;
|
|
2779
2831
|
}
|
|
2780
2832
|
}
|
|
2781
2833
|
}
|
|
@@ -2827,7 +2879,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2827
2879
|
rpnLSB: 127,
|
|
2828
2880
|
mono: false, // CC#124, CC#125
|
|
2829
2881
|
modulationDepthRange: 50, // cent
|
|
2830
|
-
fineTuning: 0, //
|
|
2831
|
-
coarseTuning: 0, //
|
|
2882
|
+
fineTuning: 0, // cent
|
|
2883
|
+
coarseTuning: 0, // cent
|
|
2832
2884
|
}
|
|
2833
2885
|
});
|