@marmooo/midy 0.4.1 → 0.4.2
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 +12 -0
- package/esm/midy-GM1.d.ts +8 -7
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +102 -58
- package/esm/midy-GM2.d.ts +8 -7
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +120 -68
- package/esm/midy-GMLite.d.ts +7 -6
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +98 -56
- package/esm/midy.d.ts +10 -7
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +162 -80
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +8 -7
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +102 -58
- package/script/midy-GM2.d.ts +8 -7
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +120 -68
- package/script/midy-GMLite.d.ts +7 -6
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +98 -56
- package/script/midy.d.ts +10 -7
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +162 -80
package/script/midy.js
CHANGED
|
@@ -29,12 +29,6 @@ class Note {
|
|
|
29
29
|
writable: true,
|
|
30
30
|
value: false
|
|
31
31
|
});
|
|
32
|
-
Object.defineProperty(this, "pending", {
|
|
33
|
-
enumerable: true,
|
|
34
|
-
configurable: true,
|
|
35
|
-
writable: true,
|
|
36
|
-
value: true
|
|
37
|
-
});
|
|
38
32
|
Object.defineProperty(this, "bufferSource", {
|
|
39
33
|
enumerable: true,
|
|
40
34
|
configurable: true,
|
|
@@ -116,6 +110,9 @@ class Note {
|
|
|
116
110
|
this.noteNumber = noteNumber;
|
|
117
111
|
this.velocity = velocity;
|
|
118
112
|
this.startTime = startTime;
|
|
113
|
+
this.ready = new Promise((resolve) => {
|
|
114
|
+
this.resolveReady = resolve;
|
|
115
|
+
});
|
|
119
116
|
}
|
|
120
117
|
}
|
|
121
118
|
const drumExclusiveClassesByKit = new Array(57);
|
|
@@ -193,6 +190,7 @@ const defaultControllerState = {
|
|
|
193
190
|
// dataDecrement: { type: 128 + 97, defaultValue: 0 },
|
|
194
191
|
// rpnLSB: { type: 128 + 100, defaultValue: 127 },
|
|
195
192
|
// rpnMSB: { type: 128 + 101, defaultValue: 127 },
|
|
193
|
+
// rpgMakerLoop: { type: 128 + 111, defaultValue: 0 },
|
|
196
194
|
// allSoundOff: { type: 128 + 120, defaultValue: 0 },
|
|
197
195
|
// resetAllControllers: { type: 128 + 121, defaultValue: 0 },
|
|
198
196
|
// allNotesOff: { type: 128 + 123, defaultValue: 0 },
|
|
@@ -252,8 +250,9 @@ const pitchEnvelopeKeys = [
|
|
|
252
250
|
"playbackRate",
|
|
253
251
|
];
|
|
254
252
|
const pitchEnvelopeKeySet = new Set(pitchEnvelopeKeys);
|
|
255
|
-
class Midy {
|
|
253
|
+
class Midy extends EventTarget {
|
|
256
254
|
constructor(audioContext) {
|
|
255
|
+
super();
|
|
257
256
|
Object.defineProperty(this, "mode", {
|
|
258
257
|
enumerable: true,
|
|
259
258
|
configurable: true,
|
|
@@ -414,6 +413,18 @@ class Midy {
|
|
|
414
413
|
writable: true,
|
|
415
414
|
value: false
|
|
416
415
|
});
|
|
416
|
+
Object.defineProperty(this, "loop", {
|
|
417
|
+
enumerable: true,
|
|
418
|
+
configurable: true,
|
|
419
|
+
writable: true,
|
|
420
|
+
value: true
|
|
421
|
+
});
|
|
422
|
+
Object.defineProperty(this, "loopStart", {
|
|
423
|
+
enumerable: true,
|
|
424
|
+
configurable: true,
|
|
425
|
+
writable: true,
|
|
426
|
+
value: 0
|
|
427
|
+
});
|
|
417
428
|
Object.defineProperty(this, "playPromise", {
|
|
418
429
|
enumerable: true,
|
|
419
430
|
configurable: true,
|
|
@@ -635,7 +646,7 @@ class Midy {
|
|
|
635
646
|
}
|
|
636
647
|
return bufferSource;
|
|
637
648
|
}
|
|
638
|
-
|
|
649
|
+
scheduleTimelineEvents(scheduleTime, queueIndex) {
|
|
639
650
|
const timeOffset = this.resumeTime - this.startTime;
|
|
640
651
|
const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
|
|
641
652
|
const schedulingOffset = this.startDelay - timeOffset;
|
|
@@ -647,7 +658,7 @@ class Midy {
|
|
|
647
658
|
const startTime = event.startTime + schedulingOffset;
|
|
648
659
|
switch (event.type) {
|
|
649
660
|
case "noteOn":
|
|
650
|
-
|
|
661
|
+
this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
651
662
|
break;
|
|
652
663
|
case "noteOff": {
|
|
653
664
|
this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
@@ -694,22 +705,23 @@ class Midy {
|
|
|
694
705
|
}
|
|
695
706
|
}
|
|
696
707
|
updateStates(queueIndex, nextQueueIndex) {
|
|
708
|
+
const now = this.audioContext.currentTime;
|
|
697
709
|
if (nextQueueIndex < queueIndex)
|
|
698
710
|
queueIndex = 0;
|
|
699
711
|
for (let i = queueIndex; i < nextQueueIndex; i++) {
|
|
700
712
|
const event = this.timeline[i];
|
|
701
713
|
switch (event.type) {
|
|
702
714
|
case "controller":
|
|
703
|
-
this.setControlChange(event.channel, event.controllerType, event.value,
|
|
715
|
+
this.setControlChange(event.channel, event.controllerType, event.value, now - this.resumeTime + event.startTime);
|
|
704
716
|
break;
|
|
705
717
|
case "programChange":
|
|
706
|
-
this.setProgramChange(event.channel, event.programNumber,
|
|
718
|
+
this.setProgramChange(event.channel, event.programNumber, now - this.resumeTime + event.startTime);
|
|
707
719
|
break;
|
|
708
720
|
case "pitchBend":
|
|
709
|
-
this.setPitchBend(event.channel, event.value + 8192,
|
|
721
|
+
this.setPitchBend(event.channel, event.value + 8192, now - this.resumeTime + event.startTime);
|
|
710
722
|
break;
|
|
711
723
|
case "sysEx":
|
|
712
|
-
this.handleSysEx(event.data,
|
|
724
|
+
this.handleSysEx(event.data, now - this.resumeTime + event.startTime);
|
|
713
725
|
}
|
|
714
726
|
}
|
|
715
727
|
}
|
|
@@ -717,58 +729,95 @@ class Midy {
|
|
|
717
729
|
if (this.audioContext.state === "suspended") {
|
|
718
730
|
await this.audioContext.resume();
|
|
719
731
|
}
|
|
732
|
+
const paused = this.isPaused;
|
|
720
733
|
this.isPlaying = true;
|
|
721
734
|
this.isPaused = false;
|
|
722
735
|
this.startTime = this.audioContext.currentTime;
|
|
736
|
+
if (paused) {
|
|
737
|
+
this.dispatchEvent(new Event("resumed"));
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
this.dispatchEvent(new Event("started"));
|
|
741
|
+
}
|
|
723
742
|
let queueIndex = this.getQueueIndex(this.resumeTime);
|
|
724
|
-
let
|
|
743
|
+
let exitReason;
|
|
725
744
|
this.notePromises = [];
|
|
726
|
-
while (
|
|
745
|
+
while (true) {
|
|
727
746
|
const now = this.audioContext.currentTime;
|
|
728
747
|
if (0 < this.lastActiveSensing &&
|
|
729
748
|
this.activeSensingThreshold < performance.now() - this.lastActiveSensing) {
|
|
730
749
|
await this.stopNotes(0, true, now);
|
|
731
750
|
await this.audioContext.suspend();
|
|
732
|
-
|
|
751
|
+
exitReason = "aborted";
|
|
733
752
|
break;
|
|
734
753
|
}
|
|
754
|
+
if (this.timeline.length <= queueIndex) {
|
|
755
|
+
await this.stopNotes(0, true, now);
|
|
756
|
+
if (this.loop) {
|
|
757
|
+
this.notePromises = [];
|
|
758
|
+
this.resetAllStates();
|
|
759
|
+
this.startTime = this.audioContext.currentTime;
|
|
760
|
+
this.resumeTime = this.loopStart;
|
|
761
|
+
if (0 < this.loopStart) {
|
|
762
|
+
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
763
|
+
this.updateStates(queueIndex, nextQueueIndex);
|
|
764
|
+
queueIndex = nextQueueIndex;
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
queueIndex = 0;
|
|
768
|
+
}
|
|
769
|
+
this.dispatchEvent(new Event("looped"));
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
await this.audioContext.suspend();
|
|
774
|
+
exitReason = "ended";
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
735
778
|
if (this.isPausing) {
|
|
736
779
|
await this.stopNotes(0, true, now);
|
|
737
780
|
await this.audioContext.suspend();
|
|
738
781
|
this.notePromises = [];
|
|
782
|
+
this.isPausing = false;
|
|
783
|
+
exitReason = "paused";
|
|
739
784
|
break;
|
|
740
785
|
}
|
|
741
786
|
else if (this.isStopping) {
|
|
742
787
|
await this.stopNotes(0, true, now);
|
|
743
788
|
await this.audioContext.suspend();
|
|
744
|
-
|
|
789
|
+
this.isStopping = false;
|
|
790
|
+
exitReason = "stopped";
|
|
745
791
|
break;
|
|
746
792
|
}
|
|
747
793
|
else if (this.isSeeking) {
|
|
748
|
-
|
|
794
|
+
this.stopNotes(0, true, now);
|
|
749
795
|
this.startTime = this.audioContext.currentTime;
|
|
750
796
|
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
751
797
|
this.updateStates(queueIndex, nextQueueIndex);
|
|
752
798
|
queueIndex = nextQueueIndex;
|
|
753
799
|
this.isSeeking = false;
|
|
800
|
+
this.dispatchEvent(new Event("seeked"));
|
|
754
801
|
continue;
|
|
755
802
|
}
|
|
756
|
-
queueIndex =
|
|
803
|
+
queueIndex = this.scheduleTimelineEvents(now, queueIndex);
|
|
757
804
|
const waitTime = now + this.noteCheckInterval;
|
|
758
805
|
await this.scheduleTask(() => { }, waitTime);
|
|
759
806
|
}
|
|
760
|
-
if (
|
|
761
|
-
const now = this.audioContext.currentTime;
|
|
762
|
-
await this.stopNotes(0, true, now);
|
|
763
|
-
await this.audioContext.suspend();
|
|
764
|
-
finished = true;
|
|
765
|
-
}
|
|
766
|
-
if (finished) {
|
|
807
|
+
if (exitReason !== "paused") {
|
|
767
808
|
this.notePromises = [];
|
|
768
809
|
this.resetAllStates();
|
|
769
810
|
this.lastActiveSensing = 0;
|
|
770
811
|
}
|
|
771
812
|
this.isPlaying = false;
|
|
813
|
+
if (exitReason === "paused") {
|
|
814
|
+
this.isPaused = true;
|
|
815
|
+
this.dispatchEvent(new Event("paused"));
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
this.isPaused = false;
|
|
819
|
+
this.dispatchEvent(new Event(exitReason));
|
|
820
|
+
}
|
|
772
821
|
}
|
|
773
822
|
ticksToSecond(ticks, secondsPerBeat) {
|
|
774
823
|
return ticks * secondsPerBeat / this.ticksPerBeat;
|
|
@@ -905,24 +954,20 @@ class Midy {
|
|
|
905
954
|
return;
|
|
906
955
|
this.isStopping = true;
|
|
907
956
|
await this.playPromise;
|
|
908
|
-
this.isStopping = false;
|
|
909
957
|
}
|
|
910
958
|
async pause() {
|
|
911
959
|
if (!this.isPlaying || this.isPaused)
|
|
912
960
|
return;
|
|
913
961
|
const now = this.audioContext.currentTime;
|
|
914
|
-
this.resumeTime = now
|
|
962
|
+
this.resumeTime = now + this.resumeTime - this.startTime;
|
|
915
963
|
this.isPausing = true;
|
|
916
964
|
await this.playPromise;
|
|
917
|
-
this.isPausing = false;
|
|
918
|
-
this.isPaused = true;
|
|
919
965
|
}
|
|
920
966
|
async resume() {
|
|
921
967
|
if (!this.isPaused)
|
|
922
968
|
return;
|
|
923
969
|
this.playPromise = this.playNotes();
|
|
924
970
|
await this.playPromise;
|
|
925
|
-
this.isPaused = false;
|
|
926
971
|
}
|
|
927
972
|
seekTo(second) {
|
|
928
973
|
this.resumeTime = second;
|
|
@@ -945,19 +990,23 @@ class Midy {
|
|
|
945
990
|
const now = this.audioContext.currentTime;
|
|
946
991
|
return now + this.resumeTime - this.startTime;
|
|
947
992
|
}
|
|
948
|
-
processScheduledNotes(channel, callback) {
|
|
993
|
+
async processScheduledNotes(channel, callback) {
|
|
949
994
|
const scheduledNotes = channel.scheduledNotes;
|
|
995
|
+
const tasks = [];
|
|
950
996
|
for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
|
|
951
997
|
const note = scheduledNotes[i];
|
|
952
998
|
if (!note)
|
|
953
999
|
continue;
|
|
954
1000
|
if (note.ending)
|
|
955
1001
|
continue;
|
|
956
|
-
callback(note);
|
|
1002
|
+
const task = note.ready.then(() => callback(note));
|
|
1003
|
+
tasks.push(task);
|
|
957
1004
|
}
|
|
1005
|
+
await Promise.all(tasks);
|
|
958
1006
|
}
|
|
959
|
-
processActiveNotes(channel, scheduleTime, callback) {
|
|
1007
|
+
async processActiveNotes(channel, scheduleTime, callback) {
|
|
960
1008
|
const scheduledNotes = channel.scheduledNotes;
|
|
1009
|
+
const tasks = [];
|
|
961
1010
|
for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
|
|
962
1011
|
const note = scheduledNotes[i];
|
|
963
1012
|
if (!note)
|
|
@@ -966,8 +1015,10 @@ class Midy {
|
|
|
966
1015
|
continue;
|
|
967
1016
|
if (scheduleTime < note.startTime)
|
|
968
1017
|
break;
|
|
969
|
-
callback(note);
|
|
1018
|
+
const task = note.ready.then(() => callback(note));
|
|
1019
|
+
tasks.push(task);
|
|
970
1020
|
}
|
|
1021
|
+
await Promise.all(tasks);
|
|
971
1022
|
}
|
|
972
1023
|
createConvolutionReverbImpulse(audioContext, decay, preDecay) {
|
|
973
1024
|
const sampleRate = audioContext.sampleRate;
|
|
@@ -1547,11 +1598,7 @@ class Midy {
|
|
|
1547
1598
|
return;
|
|
1548
1599
|
await this.setNoteAudioNode(channel, note, realtime);
|
|
1549
1600
|
this.setNoteRouting(channelNumber, note, startTime);
|
|
1550
|
-
note.
|
|
1551
|
-
const off = note.offEvent;
|
|
1552
|
-
if (off) {
|
|
1553
|
-
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
1554
|
-
}
|
|
1601
|
+
note.resolveReady();
|
|
1555
1602
|
}
|
|
1556
1603
|
disconnectNote(note) {
|
|
1557
1604
|
note.bufferSource.disconnect();
|
|
@@ -1596,7 +1643,7 @@ class Midy {
|
|
|
1596
1643
|
}, stopTime);
|
|
1597
1644
|
});
|
|
1598
1645
|
}
|
|
1599
|
-
noteOff(channelNumber, noteNumber,
|
|
1646
|
+
noteOff(channelNumber, noteNumber, _velocity, endTime, force) {
|
|
1600
1647
|
const channel = this.channels[channelNumber];
|
|
1601
1648
|
const state = channel.state;
|
|
1602
1649
|
if (!force) {
|
|
@@ -1615,13 +1662,11 @@ class Midy {
|
|
|
1615
1662
|
if (index < 0)
|
|
1616
1663
|
return;
|
|
1617
1664
|
const note = channel.scheduledNotes[index];
|
|
1618
|
-
if (note.pending) {
|
|
1619
|
-
note.offEvent = { velocity, startTime: endTime };
|
|
1620
|
-
return;
|
|
1621
|
-
}
|
|
1622
1665
|
note.ending = true;
|
|
1623
1666
|
this.setNoteIndex(channel, index);
|
|
1624
|
-
const promise =
|
|
1667
|
+
const promise = note.ready.then(() => {
|
|
1668
|
+
return this.releaseNote(channel, note, endTime);
|
|
1669
|
+
});
|
|
1625
1670
|
this.notePromises.push(promise);
|
|
1626
1671
|
return promise;
|
|
1627
1672
|
}
|
|
@@ -1722,7 +1767,7 @@ class Midy {
|
|
|
1722
1767
|
this.setEffects(channel, note, table, scheduleTime);
|
|
1723
1768
|
}
|
|
1724
1769
|
});
|
|
1725
|
-
this.applyVoiceParams(channel, 10);
|
|
1770
|
+
this.applyVoiceParams(channel, 10, scheduleTime);
|
|
1726
1771
|
}
|
|
1727
1772
|
setProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
1728
1773
|
const channel = this.channels[channelNumber];
|
|
@@ -1755,7 +1800,7 @@ class Midy {
|
|
|
1755
1800
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
1756
1801
|
this.setEffects(channel, note, table, scheduleTime);
|
|
1757
1802
|
});
|
|
1758
|
-
this.applyVoiceParams(channel, 13);
|
|
1803
|
+
this.applyVoiceParams(channel, 13, scheduleTime);
|
|
1759
1804
|
}
|
|
1760
1805
|
handlePitchBendMessage(channelNumber, lsb, msb, scheduleTime) {
|
|
1761
1806
|
const pitchBend = msb * 128 + lsb;
|
|
@@ -1765,7 +1810,8 @@ class Midy {
|
|
|
1765
1810
|
const channel = this.channels[channelNumber];
|
|
1766
1811
|
if (channel.isDrum)
|
|
1767
1812
|
return;
|
|
1768
|
-
|
|
1813
|
+
if (!(0 <= scheduleTime))
|
|
1814
|
+
scheduleTime = this.audioContext.currentTime;
|
|
1769
1815
|
const state = channel.state;
|
|
1770
1816
|
const prev = state.pitchWheel * 2 - 1;
|
|
1771
1817
|
const next = (value - 8192) / 8192;
|
|
@@ -2043,6 +2089,7 @@ class Midy {
|
|
|
2043
2089
|
handlers[97] = this.dataDecrement;
|
|
2044
2090
|
handlers[100] = this.setRPNLSB;
|
|
2045
2091
|
handlers[101] = this.setRPNMSB;
|
|
2092
|
+
handlers[111] = this.setRPGMakerLoop;
|
|
2046
2093
|
handlers[120] = this.allSoundOff;
|
|
2047
2094
|
handlers[121] = this.resetAllControllers;
|
|
2048
2095
|
handlers[123] = this.allNotesOff;
|
|
@@ -2084,7 +2131,8 @@ class Midy {
|
|
|
2084
2131
|
const channel = this.channels[channelNumber];
|
|
2085
2132
|
if (channel.isDrum)
|
|
2086
2133
|
return;
|
|
2087
|
-
|
|
2134
|
+
if (!(0 <= scheduleTime))
|
|
2135
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2088
2136
|
const state = channel.state;
|
|
2089
2137
|
const intPart = Math.trunc(value);
|
|
2090
2138
|
state.modulationDepthMSB = intPart / 127;
|
|
@@ -2110,7 +2158,8 @@ class Midy {
|
|
|
2110
2158
|
});
|
|
2111
2159
|
}
|
|
2112
2160
|
setPortamentoTime(channelNumber, value, scheduleTime) {
|
|
2113
|
-
|
|
2161
|
+
if (!(0 <= scheduleTime))
|
|
2162
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2114
2163
|
const channel = this.channels[channelNumber];
|
|
2115
2164
|
const state = channel.state;
|
|
2116
2165
|
const intPart = Math.trunc(value);
|
|
@@ -2121,7 +2170,8 @@ class Midy {
|
|
|
2121
2170
|
this.updatePortamento(channel, scheduleTime);
|
|
2122
2171
|
}
|
|
2123
2172
|
setVolume(channelNumber, value, scheduleTime) {
|
|
2124
|
-
|
|
2173
|
+
if (!(0 <= scheduleTime))
|
|
2174
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2125
2175
|
const channel = this.channels[channelNumber];
|
|
2126
2176
|
const state = channel.state;
|
|
2127
2177
|
const intPart = Math.trunc(value);
|
|
@@ -2144,7 +2194,8 @@ class Midy {
|
|
|
2144
2194
|
};
|
|
2145
2195
|
}
|
|
2146
2196
|
setPan(channelNumber, value, scheduleTime) {
|
|
2147
|
-
|
|
2197
|
+
if (!(0 <= scheduleTime))
|
|
2198
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2148
2199
|
const channel = this.channels[channelNumber];
|
|
2149
2200
|
const state = channel.state;
|
|
2150
2201
|
const intPart = Math.trunc(value);
|
|
@@ -2160,7 +2211,8 @@ class Midy {
|
|
|
2160
2211
|
}
|
|
2161
2212
|
}
|
|
2162
2213
|
setExpression(channelNumber, value, scheduleTime) {
|
|
2163
|
-
|
|
2214
|
+
if (!(0 <= scheduleTime))
|
|
2215
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2164
2216
|
const channel = this.channels[channelNumber];
|
|
2165
2217
|
const state = channel.state;
|
|
2166
2218
|
const intPart = Math.trunc(value);
|
|
@@ -2217,7 +2269,8 @@ class Midy {
|
|
|
2217
2269
|
const channel = this.channels[channelNumber];
|
|
2218
2270
|
if (channel.isDrum)
|
|
2219
2271
|
return;
|
|
2220
|
-
|
|
2272
|
+
if (!(0 <= scheduleTime))
|
|
2273
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2221
2274
|
channel.state.sustainPedal = value / 127;
|
|
2222
2275
|
if (64 <= value) {
|
|
2223
2276
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2235,7 +2288,8 @@ class Midy {
|
|
|
2235
2288
|
const channel = this.channels[channelNumber];
|
|
2236
2289
|
if (channel.isDrum)
|
|
2237
2290
|
return;
|
|
2238
|
-
|
|
2291
|
+
if (!(0 <= scheduleTime))
|
|
2292
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2239
2293
|
channel.state.portamento = value / 127;
|
|
2240
2294
|
this.updatePortamento(channel, scheduleTime);
|
|
2241
2295
|
}
|
|
@@ -2243,7 +2297,8 @@ class Midy {
|
|
|
2243
2297
|
const channel = this.channels[channelNumber];
|
|
2244
2298
|
if (channel.isDrum)
|
|
2245
2299
|
return;
|
|
2246
|
-
|
|
2300
|
+
if (!(0 <= scheduleTime))
|
|
2301
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2247
2302
|
channel.state.sostenutoPedal = value / 127;
|
|
2248
2303
|
if (64 <= value) {
|
|
2249
2304
|
const sostenutoNotes = [];
|
|
@@ -2264,7 +2319,8 @@ class Midy {
|
|
|
2264
2319
|
if (channel.isDrum)
|
|
2265
2320
|
return;
|
|
2266
2321
|
const state = channel.state;
|
|
2267
|
-
|
|
2322
|
+
if (!(0 <= scheduleTime))
|
|
2323
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2268
2324
|
state.softPedal = softPedal / 127;
|
|
2269
2325
|
this.processScheduledNotes(channel, (note) => {
|
|
2270
2326
|
if (this.isPortamento(channel, note)) {
|
|
@@ -2281,7 +2337,8 @@ class Midy {
|
|
|
2281
2337
|
const channel = this.channels[channelNumber];
|
|
2282
2338
|
if (channel.isDrum)
|
|
2283
2339
|
return;
|
|
2284
|
-
|
|
2340
|
+
if (!(0 <= scheduleTime))
|
|
2341
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2285
2342
|
const state = channel.state;
|
|
2286
2343
|
state.filterResonance = ccValue / 127;
|
|
2287
2344
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2302,14 +2359,16 @@ class Midy {
|
|
|
2302
2359
|
const channel = this.channels[channelNumber];
|
|
2303
2360
|
if (channel.isDrum)
|
|
2304
2361
|
return;
|
|
2305
|
-
|
|
2362
|
+
if (!(0 <= scheduleTime))
|
|
2363
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2306
2364
|
channel.state.releaseTime = releaseTime / 127;
|
|
2307
2365
|
}
|
|
2308
2366
|
setAttackTime(channelNumber, attackTime, scheduleTime) {
|
|
2309
2367
|
const channel = this.channels[channelNumber];
|
|
2310
2368
|
if (channel.isDrum)
|
|
2311
2369
|
return;
|
|
2312
|
-
|
|
2370
|
+
if (!(0 <= scheduleTime))
|
|
2371
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2313
2372
|
channel.state.attackTime = attackTime / 127;
|
|
2314
2373
|
this.processScheduledNotes(channel, (note) => {
|
|
2315
2374
|
if (scheduleTime < note.startTime) {
|
|
@@ -2322,7 +2381,8 @@ class Midy {
|
|
|
2322
2381
|
if (channel.isDrum)
|
|
2323
2382
|
return;
|
|
2324
2383
|
const state = channel.state;
|
|
2325
|
-
|
|
2384
|
+
if (!(0 <= scheduleTime))
|
|
2385
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2326
2386
|
state.brightness = brightness / 127;
|
|
2327
2387
|
this.processScheduledNotes(channel, (note) => {
|
|
2328
2388
|
if (this.isPortamento(channel, note)) {
|
|
@@ -2337,7 +2397,8 @@ class Midy {
|
|
|
2337
2397
|
const channel = this.channels[channelNumber];
|
|
2338
2398
|
if (channel.isDrum)
|
|
2339
2399
|
return;
|
|
2340
|
-
|
|
2400
|
+
if (!(0 <= scheduleTime))
|
|
2401
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2341
2402
|
channel.state.decayTime = dacayTime / 127;
|
|
2342
2403
|
this.processScheduledNotes(channel, (note) => {
|
|
2343
2404
|
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
@@ -2347,7 +2408,8 @@ class Midy {
|
|
|
2347
2408
|
const channel = this.channels[channelNumber];
|
|
2348
2409
|
if (channel.isDrum)
|
|
2349
2410
|
return;
|
|
2350
|
-
|
|
2411
|
+
if (!(0 <= scheduleTime))
|
|
2412
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2351
2413
|
channel.state.vibratoRate = vibratoRate / 127;
|
|
2352
2414
|
if (channel.vibratoDepth <= 0)
|
|
2353
2415
|
return;
|
|
@@ -2359,7 +2421,8 @@ class Midy {
|
|
|
2359
2421
|
const channel = this.channels[channelNumber];
|
|
2360
2422
|
if (channel.isDrum)
|
|
2361
2423
|
return;
|
|
2362
|
-
|
|
2424
|
+
if (!(0 <= scheduleTime))
|
|
2425
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2363
2426
|
const prev = channel.state.vibratoDepth;
|
|
2364
2427
|
channel.state.vibratoDepth = vibratoDepth / 127;
|
|
2365
2428
|
if (0 < prev) {
|
|
@@ -2377,7 +2440,8 @@ class Midy {
|
|
|
2377
2440
|
const channel = this.channels[channelNumber];
|
|
2378
2441
|
if (channel.isDrum)
|
|
2379
2442
|
return;
|
|
2380
|
-
|
|
2443
|
+
if (!(0 <= scheduleTime))
|
|
2444
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2381
2445
|
channel.state.vibratoDelay = vibratoDelay / 127;
|
|
2382
2446
|
if (0 < channel.state.vibratoDepth) {
|
|
2383
2447
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2386,13 +2450,15 @@ class Midy {
|
|
|
2386
2450
|
}
|
|
2387
2451
|
}
|
|
2388
2452
|
setPortamentoNoteNumber(channelNumber, value, scheduleTime) {
|
|
2389
|
-
|
|
2453
|
+
if (!(0 <= scheduleTime))
|
|
2454
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2390
2455
|
const channel = this.channels[channelNumber];
|
|
2391
2456
|
channel.portamentoControl = true;
|
|
2392
2457
|
channel.state.portamentoNoteNumber = value / 127;
|
|
2393
2458
|
}
|
|
2394
2459
|
setReverbSendLevel(channelNumber, reverbSendLevel, scheduleTime) {
|
|
2395
|
-
|
|
2460
|
+
if (!(0 <= scheduleTime))
|
|
2461
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2396
2462
|
const channel = this.channels[channelNumber];
|
|
2397
2463
|
const state = channel.state;
|
|
2398
2464
|
state.reverbSendLevel = reverbSendLevel / 127;
|
|
@@ -2401,7 +2467,8 @@ class Midy {
|
|
|
2401
2467
|
});
|
|
2402
2468
|
}
|
|
2403
2469
|
setChorusSendLevel(channelNumber, chorusSendLevel, scheduleTime) {
|
|
2404
|
-
|
|
2470
|
+
if (!(0 <= scheduleTime))
|
|
2471
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2405
2472
|
const channel = this.channels[channelNumber];
|
|
2406
2473
|
const state = channel.state;
|
|
2407
2474
|
state.chorusSendLevel = chorusSendLevel / 127;
|
|
@@ -2461,12 +2528,14 @@ class Midy {
|
|
|
2461
2528
|
}
|
|
2462
2529
|
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp18.pdf
|
|
2463
2530
|
dataIncrement(channelNumber, scheduleTime) {
|
|
2464
|
-
|
|
2531
|
+
if (!(0 <= scheduleTime))
|
|
2532
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2465
2533
|
this.handleRPN(channelNumber, 1, scheduleTime);
|
|
2466
2534
|
}
|
|
2467
2535
|
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp18.pdf
|
|
2468
2536
|
dataDecrement(channelNumber, scheduleTime) {
|
|
2469
|
-
|
|
2537
|
+
if (!(0 <= scheduleTime))
|
|
2538
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2470
2539
|
this.handleRPN(channelNumber, -1, scheduleTime);
|
|
2471
2540
|
}
|
|
2472
2541
|
setRPNMSB(channelNumber, value) {
|
|
@@ -2489,7 +2558,8 @@ class Midy {
|
|
|
2489
2558
|
const channel = this.channels[channelNumber];
|
|
2490
2559
|
if (channel.isDrum)
|
|
2491
2560
|
return;
|
|
2492
|
-
|
|
2561
|
+
if (!(0 <= scheduleTime))
|
|
2562
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2493
2563
|
const state = channel.state;
|
|
2494
2564
|
const prev = state.pitchWheelSensitivity;
|
|
2495
2565
|
const next = value / 12800;
|
|
@@ -2509,7 +2579,8 @@ class Midy {
|
|
|
2509
2579
|
const channel = this.channels[channelNumber];
|
|
2510
2580
|
if (channel.isDrum)
|
|
2511
2581
|
return;
|
|
2512
|
-
|
|
2582
|
+
if (!(0 <= scheduleTime))
|
|
2583
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2513
2584
|
const prev = channel.fineTuning;
|
|
2514
2585
|
const next = value;
|
|
2515
2586
|
channel.fineTuning = next;
|
|
@@ -2526,7 +2597,8 @@ class Midy {
|
|
|
2526
2597
|
const channel = this.channels[channelNumber];
|
|
2527
2598
|
if (channel.isDrum)
|
|
2528
2599
|
return;
|
|
2529
|
-
|
|
2600
|
+
if (!(0 <= scheduleTime))
|
|
2601
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2530
2602
|
const prev = channel.coarseTuning;
|
|
2531
2603
|
const next = value;
|
|
2532
2604
|
channel.coarseTuning = next;
|
|
@@ -2543,12 +2615,18 @@ class Midy {
|
|
|
2543
2615
|
const channel = this.channels[channelNumber];
|
|
2544
2616
|
if (channel.isDrum)
|
|
2545
2617
|
return;
|
|
2546
|
-
|
|
2618
|
+
if (!(0 <= scheduleTime))
|
|
2619
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2547
2620
|
channel.modulationDepthRange = value;
|
|
2548
2621
|
this.updateModulation(channel, scheduleTime);
|
|
2549
2622
|
}
|
|
2550
|
-
|
|
2623
|
+
setRPGMakerLoop(_channelNumber, _value, scheduleTime) {
|
|
2551
2624
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2625
|
+
this.loopStart = scheduleTime + this.resumeTime - this.startTime;
|
|
2626
|
+
}
|
|
2627
|
+
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
2628
|
+
if (!(0 <= scheduleTime))
|
|
2629
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2552
2630
|
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
2553
2631
|
}
|
|
2554
2632
|
resetChannelStates(channelNumber) {
|
|
@@ -2610,7 +2688,8 @@ class Midy {
|
|
|
2610
2688
|
}
|
|
2611
2689
|
}
|
|
2612
2690
|
allNotesOff(channelNumber, _value, scheduleTime) {
|
|
2613
|
-
|
|
2691
|
+
if (!(0 <= scheduleTime))
|
|
2692
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2614
2693
|
return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
|
|
2615
2694
|
}
|
|
2616
2695
|
omniOff(channelNumber, value, scheduleTime) {
|
|
@@ -2662,7 +2741,8 @@ class Midy {
|
|
|
2662
2741
|
}
|
|
2663
2742
|
}
|
|
2664
2743
|
GM1SystemOn(scheduleTime) {
|
|
2665
|
-
|
|
2744
|
+
if (!(0 <= scheduleTime))
|
|
2745
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2666
2746
|
this.mode = "GM1";
|
|
2667
2747
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2668
2748
|
this.allSoundOff(i, 0, scheduleTime);
|
|
@@ -2675,7 +2755,8 @@ class Midy {
|
|
|
2675
2755
|
this.channels[9].isDrum = true;
|
|
2676
2756
|
}
|
|
2677
2757
|
GM2SystemOn(scheduleTime) {
|
|
2678
|
-
|
|
2758
|
+
if (!(0 <= scheduleTime))
|
|
2759
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2679
2760
|
this.mode = "GM2";
|
|
2680
2761
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2681
2762
|
this.allSoundOff(i, 0, scheduleTime);
|
|
@@ -2743,7 +2824,8 @@ class Midy {
|
|
|
2743
2824
|
this.setMasterVolume(volume, scheduleTime);
|
|
2744
2825
|
}
|
|
2745
2826
|
setMasterVolume(value, scheduleTime) {
|
|
2746
|
-
|
|
2827
|
+
if (!(0 <= scheduleTime))
|
|
2828
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2747
2829
|
this.masterVolume.gain
|
|
2748
2830
|
.cancelScheduledValues(scheduleTime)
|
|
2749
2831
|
.setValueAtTime(value * value, scheduleTime);
|