@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/esm/midy.js
CHANGED
|
@@ -26,12 +26,6 @@ class Note {
|
|
|
26
26
|
writable: true,
|
|
27
27
|
value: false
|
|
28
28
|
});
|
|
29
|
-
Object.defineProperty(this, "pending", {
|
|
30
|
-
enumerable: true,
|
|
31
|
-
configurable: true,
|
|
32
|
-
writable: true,
|
|
33
|
-
value: true
|
|
34
|
-
});
|
|
35
29
|
Object.defineProperty(this, "bufferSource", {
|
|
36
30
|
enumerable: true,
|
|
37
31
|
configurable: true,
|
|
@@ -113,6 +107,9 @@ class Note {
|
|
|
113
107
|
this.noteNumber = noteNumber;
|
|
114
108
|
this.velocity = velocity;
|
|
115
109
|
this.startTime = startTime;
|
|
110
|
+
this.ready = new Promise((resolve) => {
|
|
111
|
+
this.resolveReady = resolve;
|
|
112
|
+
});
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
const drumExclusiveClassesByKit = new Array(57);
|
|
@@ -190,6 +187,7 @@ const defaultControllerState = {
|
|
|
190
187
|
// dataDecrement: { type: 128 + 97, defaultValue: 0 },
|
|
191
188
|
// rpnLSB: { type: 128 + 100, defaultValue: 127 },
|
|
192
189
|
// rpnMSB: { type: 128 + 101, defaultValue: 127 },
|
|
190
|
+
// rpgMakerLoop: { type: 128 + 111, defaultValue: 0 },
|
|
193
191
|
// allSoundOff: { type: 128 + 120, defaultValue: 0 },
|
|
194
192
|
// resetAllControllers: { type: 128 + 121, defaultValue: 0 },
|
|
195
193
|
// allNotesOff: { type: 128 + 123, defaultValue: 0 },
|
|
@@ -249,8 +247,9 @@ const pitchEnvelopeKeys = [
|
|
|
249
247
|
"playbackRate",
|
|
250
248
|
];
|
|
251
249
|
const pitchEnvelopeKeySet = new Set(pitchEnvelopeKeys);
|
|
252
|
-
export class Midy {
|
|
250
|
+
export class Midy extends EventTarget {
|
|
253
251
|
constructor(audioContext) {
|
|
252
|
+
super();
|
|
254
253
|
Object.defineProperty(this, "mode", {
|
|
255
254
|
enumerable: true,
|
|
256
255
|
configurable: true,
|
|
@@ -411,6 +410,18 @@ export class Midy {
|
|
|
411
410
|
writable: true,
|
|
412
411
|
value: false
|
|
413
412
|
});
|
|
413
|
+
Object.defineProperty(this, "loop", {
|
|
414
|
+
enumerable: true,
|
|
415
|
+
configurable: true,
|
|
416
|
+
writable: true,
|
|
417
|
+
value: true
|
|
418
|
+
});
|
|
419
|
+
Object.defineProperty(this, "loopStart", {
|
|
420
|
+
enumerable: true,
|
|
421
|
+
configurable: true,
|
|
422
|
+
writable: true,
|
|
423
|
+
value: 0
|
|
424
|
+
});
|
|
414
425
|
Object.defineProperty(this, "playPromise", {
|
|
415
426
|
enumerable: true,
|
|
416
427
|
configurable: true,
|
|
@@ -632,7 +643,7 @@ export class Midy {
|
|
|
632
643
|
}
|
|
633
644
|
return bufferSource;
|
|
634
645
|
}
|
|
635
|
-
|
|
646
|
+
scheduleTimelineEvents(scheduleTime, queueIndex) {
|
|
636
647
|
const timeOffset = this.resumeTime - this.startTime;
|
|
637
648
|
const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
|
|
638
649
|
const schedulingOffset = this.startDelay - timeOffset;
|
|
@@ -644,7 +655,7 @@ export class Midy {
|
|
|
644
655
|
const startTime = event.startTime + schedulingOffset;
|
|
645
656
|
switch (event.type) {
|
|
646
657
|
case "noteOn":
|
|
647
|
-
|
|
658
|
+
this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
648
659
|
break;
|
|
649
660
|
case "noteOff": {
|
|
650
661
|
this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
@@ -691,22 +702,23 @@ export class Midy {
|
|
|
691
702
|
}
|
|
692
703
|
}
|
|
693
704
|
updateStates(queueIndex, nextQueueIndex) {
|
|
705
|
+
const now = this.audioContext.currentTime;
|
|
694
706
|
if (nextQueueIndex < queueIndex)
|
|
695
707
|
queueIndex = 0;
|
|
696
708
|
for (let i = queueIndex; i < nextQueueIndex; i++) {
|
|
697
709
|
const event = this.timeline[i];
|
|
698
710
|
switch (event.type) {
|
|
699
711
|
case "controller":
|
|
700
|
-
this.setControlChange(event.channel, event.controllerType, event.value,
|
|
712
|
+
this.setControlChange(event.channel, event.controllerType, event.value, now - this.resumeTime + event.startTime);
|
|
701
713
|
break;
|
|
702
714
|
case "programChange":
|
|
703
|
-
this.setProgramChange(event.channel, event.programNumber,
|
|
715
|
+
this.setProgramChange(event.channel, event.programNumber, now - this.resumeTime + event.startTime);
|
|
704
716
|
break;
|
|
705
717
|
case "pitchBend":
|
|
706
|
-
this.setPitchBend(event.channel, event.value + 8192,
|
|
718
|
+
this.setPitchBend(event.channel, event.value + 8192, now - this.resumeTime + event.startTime);
|
|
707
719
|
break;
|
|
708
720
|
case "sysEx":
|
|
709
|
-
this.handleSysEx(event.data,
|
|
721
|
+
this.handleSysEx(event.data, now - this.resumeTime + event.startTime);
|
|
710
722
|
}
|
|
711
723
|
}
|
|
712
724
|
}
|
|
@@ -714,58 +726,95 @@ export class Midy {
|
|
|
714
726
|
if (this.audioContext.state === "suspended") {
|
|
715
727
|
await this.audioContext.resume();
|
|
716
728
|
}
|
|
729
|
+
const paused = this.isPaused;
|
|
717
730
|
this.isPlaying = true;
|
|
718
731
|
this.isPaused = false;
|
|
719
732
|
this.startTime = this.audioContext.currentTime;
|
|
733
|
+
if (paused) {
|
|
734
|
+
this.dispatchEvent(new Event("resumed"));
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
this.dispatchEvent(new Event("started"));
|
|
738
|
+
}
|
|
720
739
|
let queueIndex = this.getQueueIndex(this.resumeTime);
|
|
721
|
-
let
|
|
740
|
+
let exitReason;
|
|
722
741
|
this.notePromises = [];
|
|
723
|
-
while (
|
|
742
|
+
while (true) {
|
|
724
743
|
const now = this.audioContext.currentTime;
|
|
725
744
|
if (0 < this.lastActiveSensing &&
|
|
726
745
|
this.activeSensingThreshold < performance.now() - this.lastActiveSensing) {
|
|
727
746
|
await this.stopNotes(0, true, now);
|
|
728
747
|
await this.audioContext.suspend();
|
|
729
|
-
|
|
748
|
+
exitReason = "aborted";
|
|
730
749
|
break;
|
|
731
750
|
}
|
|
751
|
+
if (this.timeline.length <= queueIndex) {
|
|
752
|
+
await this.stopNotes(0, true, now);
|
|
753
|
+
if (this.loop) {
|
|
754
|
+
this.notePromises = [];
|
|
755
|
+
this.resetAllStates();
|
|
756
|
+
this.startTime = this.audioContext.currentTime;
|
|
757
|
+
this.resumeTime = this.loopStart;
|
|
758
|
+
if (0 < this.loopStart) {
|
|
759
|
+
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
760
|
+
this.updateStates(queueIndex, nextQueueIndex);
|
|
761
|
+
queueIndex = nextQueueIndex;
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
queueIndex = 0;
|
|
765
|
+
}
|
|
766
|
+
this.dispatchEvent(new Event("looped"));
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
await this.audioContext.suspend();
|
|
771
|
+
exitReason = "ended";
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
732
775
|
if (this.isPausing) {
|
|
733
776
|
await this.stopNotes(0, true, now);
|
|
734
777
|
await this.audioContext.suspend();
|
|
735
778
|
this.notePromises = [];
|
|
779
|
+
this.isPausing = false;
|
|
780
|
+
exitReason = "paused";
|
|
736
781
|
break;
|
|
737
782
|
}
|
|
738
783
|
else if (this.isStopping) {
|
|
739
784
|
await this.stopNotes(0, true, now);
|
|
740
785
|
await this.audioContext.suspend();
|
|
741
|
-
|
|
786
|
+
this.isStopping = false;
|
|
787
|
+
exitReason = "stopped";
|
|
742
788
|
break;
|
|
743
789
|
}
|
|
744
790
|
else if (this.isSeeking) {
|
|
745
|
-
|
|
791
|
+
this.stopNotes(0, true, now);
|
|
746
792
|
this.startTime = this.audioContext.currentTime;
|
|
747
793
|
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
748
794
|
this.updateStates(queueIndex, nextQueueIndex);
|
|
749
795
|
queueIndex = nextQueueIndex;
|
|
750
796
|
this.isSeeking = false;
|
|
797
|
+
this.dispatchEvent(new Event("seeked"));
|
|
751
798
|
continue;
|
|
752
799
|
}
|
|
753
|
-
queueIndex =
|
|
800
|
+
queueIndex = this.scheduleTimelineEvents(now, queueIndex);
|
|
754
801
|
const waitTime = now + this.noteCheckInterval;
|
|
755
802
|
await this.scheduleTask(() => { }, waitTime);
|
|
756
803
|
}
|
|
757
|
-
if (
|
|
758
|
-
const now = this.audioContext.currentTime;
|
|
759
|
-
await this.stopNotes(0, true, now);
|
|
760
|
-
await this.audioContext.suspend();
|
|
761
|
-
finished = true;
|
|
762
|
-
}
|
|
763
|
-
if (finished) {
|
|
804
|
+
if (exitReason !== "paused") {
|
|
764
805
|
this.notePromises = [];
|
|
765
806
|
this.resetAllStates();
|
|
766
807
|
this.lastActiveSensing = 0;
|
|
767
808
|
}
|
|
768
809
|
this.isPlaying = false;
|
|
810
|
+
if (exitReason === "paused") {
|
|
811
|
+
this.isPaused = true;
|
|
812
|
+
this.dispatchEvent(new Event("paused"));
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
this.isPaused = false;
|
|
816
|
+
this.dispatchEvent(new Event(exitReason));
|
|
817
|
+
}
|
|
769
818
|
}
|
|
770
819
|
ticksToSecond(ticks, secondsPerBeat) {
|
|
771
820
|
return ticks * secondsPerBeat / this.ticksPerBeat;
|
|
@@ -902,24 +951,20 @@ export class Midy {
|
|
|
902
951
|
return;
|
|
903
952
|
this.isStopping = true;
|
|
904
953
|
await this.playPromise;
|
|
905
|
-
this.isStopping = false;
|
|
906
954
|
}
|
|
907
955
|
async pause() {
|
|
908
956
|
if (!this.isPlaying || this.isPaused)
|
|
909
957
|
return;
|
|
910
958
|
const now = this.audioContext.currentTime;
|
|
911
|
-
this.resumeTime = now
|
|
959
|
+
this.resumeTime = now + this.resumeTime - this.startTime;
|
|
912
960
|
this.isPausing = true;
|
|
913
961
|
await this.playPromise;
|
|
914
|
-
this.isPausing = false;
|
|
915
|
-
this.isPaused = true;
|
|
916
962
|
}
|
|
917
963
|
async resume() {
|
|
918
964
|
if (!this.isPaused)
|
|
919
965
|
return;
|
|
920
966
|
this.playPromise = this.playNotes();
|
|
921
967
|
await this.playPromise;
|
|
922
|
-
this.isPaused = false;
|
|
923
968
|
}
|
|
924
969
|
seekTo(second) {
|
|
925
970
|
this.resumeTime = second;
|
|
@@ -942,19 +987,23 @@ export class Midy {
|
|
|
942
987
|
const now = this.audioContext.currentTime;
|
|
943
988
|
return now + this.resumeTime - this.startTime;
|
|
944
989
|
}
|
|
945
|
-
processScheduledNotes(channel, callback) {
|
|
990
|
+
async processScheduledNotes(channel, callback) {
|
|
946
991
|
const scheduledNotes = channel.scheduledNotes;
|
|
992
|
+
const tasks = [];
|
|
947
993
|
for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
|
|
948
994
|
const note = scheduledNotes[i];
|
|
949
995
|
if (!note)
|
|
950
996
|
continue;
|
|
951
997
|
if (note.ending)
|
|
952
998
|
continue;
|
|
953
|
-
callback(note);
|
|
999
|
+
const task = note.ready.then(() => callback(note));
|
|
1000
|
+
tasks.push(task);
|
|
954
1001
|
}
|
|
1002
|
+
await Promise.all(tasks);
|
|
955
1003
|
}
|
|
956
|
-
processActiveNotes(channel, scheduleTime, callback) {
|
|
1004
|
+
async processActiveNotes(channel, scheduleTime, callback) {
|
|
957
1005
|
const scheduledNotes = channel.scheduledNotes;
|
|
1006
|
+
const tasks = [];
|
|
958
1007
|
for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
|
|
959
1008
|
const note = scheduledNotes[i];
|
|
960
1009
|
if (!note)
|
|
@@ -963,8 +1012,10 @@ export class Midy {
|
|
|
963
1012
|
continue;
|
|
964
1013
|
if (scheduleTime < note.startTime)
|
|
965
1014
|
break;
|
|
966
|
-
callback(note);
|
|
1015
|
+
const task = note.ready.then(() => callback(note));
|
|
1016
|
+
tasks.push(task);
|
|
967
1017
|
}
|
|
1018
|
+
await Promise.all(tasks);
|
|
968
1019
|
}
|
|
969
1020
|
createConvolutionReverbImpulse(audioContext, decay, preDecay) {
|
|
970
1021
|
const sampleRate = audioContext.sampleRate;
|
|
@@ -1544,11 +1595,7 @@ export class Midy {
|
|
|
1544
1595
|
return;
|
|
1545
1596
|
await this.setNoteAudioNode(channel, note, realtime);
|
|
1546
1597
|
this.setNoteRouting(channelNumber, note, startTime);
|
|
1547
|
-
note.
|
|
1548
|
-
const off = note.offEvent;
|
|
1549
|
-
if (off) {
|
|
1550
|
-
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
1551
|
-
}
|
|
1598
|
+
note.resolveReady();
|
|
1552
1599
|
}
|
|
1553
1600
|
disconnectNote(note) {
|
|
1554
1601
|
note.bufferSource.disconnect();
|
|
@@ -1593,7 +1640,7 @@ export class Midy {
|
|
|
1593
1640
|
}, stopTime);
|
|
1594
1641
|
});
|
|
1595
1642
|
}
|
|
1596
|
-
noteOff(channelNumber, noteNumber,
|
|
1643
|
+
noteOff(channelNumber, noteNumber, _velocity, endTime, force) {
|
|
1597
1644
|
const channel = this.channels[channelNumber];
|
|
1598
1645
|
const state = channel.state;
|
|
1599
1646
|
if (!force) {
|
|
@@ -1612,13 +1659,11 @@ export class Midy {
|
|
|
1612
1659
|
if (index < 0)
|
|
1613
1660
|
return;
|
|
1614
1661
|
const note = channel.scheduledNotes[index];
|
|
1615
|
-
if (note.pending) {
|
|
1616
|
-
note.offEvent = { velocity, startTime: endTime };
|
|
1617
|
-
return;
|
|
1618
|
-
}
|
|
1619
1662
|
note.ending = true;
|
|
1620
1663
|
this.setNoteIndex(channel, index);
|
|
1621
|
-
const promise =
|
|
1664
|
+
const promise = note.ready.then(() => {
|
|
1665
|
+
return this.releaseNote(channel, note, endTime);
|
|
1666
|
+
});
|
|
1622
1667
|
this.notePromises.push(promise);
|
|
1623
1668
|
return promise;
|
|
1624
1669
|
}
|
|
@@ -1719,7 +1764,7 @@ export class Midy {
|
|
|
1719
1764
|
this.setEffects(channel, note, table, scheduleTime);
|
|
1720
1765
|
}
|
|
1721
1766
|
});
|
|
1722
|
-
this.applyVoiceParams(channel, 10);
|
|
1767
|
+
this.applyVoiceParams(channel, 10, scheduleTime);
|
|
1723
1768
|
}
|
|
1724
1769
|
setProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
1725
1770
|
const channel = this.channels[channelNumber];
|
|
@@ -1752,7 +1797,7 @@ export class Midy {
|
|
|
1752
1797
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
1753
1798
|
this.setEffects(channel, note, table, scheduleTime);
|
|
1754
1799
|
});
|
|
1755
|
-
this.applyVoiceParams(channel, 13);
|
|
1800
|
+
this.applyVoiceParams(channel, 13, scheduleTime);
|
|
1756
1801
|
}
|
|
1757
1802
|
handlePitchBendMessage(channelNumber, lsb, msb, scheduleTime) {
|
|
1758
1803
|
const pitchBend = msb * 128 + lsb;
|
|
@@ -1762,7 +1807,8 @@ export class Midy {
|
|
|
1762
1807
|
const channel = this.channels[channelNumber];
|
|
1763
1808
|
if (channel.isDrum)
|
|
1764
1809
|
return;
|
|
1765
|
-
|
|
1810
|
+
if (!(0 <= scheduleTime))
|
|
1811
|
+
scheduleTime = this.audioContext.currentTime;
|
|
1766
1812
|
const state = channel.state;
|
|
1767
1813
|
const prev = state.pitchWheel * 2 - 1;
|
|
1768
1814
|
const next = (value - 8192) / 8192;
|
|
@@ -2040,6 +2086,7 @@ export class Midy {
|
|
|
2040
2086
|
handlers[97] = this.dataDecrement;
|
|
2041
2087
|
handlers[100] = this.setRPNLSB;
|
|
2042
2088
|
handlers[101] = this.setRPNMSB;
|
|
2089
|
+
handlers[111] = this.setRPGMakerLoop;
|
|
2043
2090
|
handlers[120] = this.allSoundOff;
|
|
2044
2091
|
handlers[121] = this.resetAllControllers;
|
|
2045
2092
|
handlers[123] = this.allNotesOff;
|
|
@@ -2081,7 +2128,8 @@ export class Midy {
|
|
|
2081
2128
|
const channel = this.channels[channelNumber];
|
|
2082
2129
|
if (channel.isDrum)
|
|
2083
2130
|
return;
|
|
2084
|
-
|
|
2131
|
+
if (!(0 <= scheduleTime))
|
|
2132
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2085
2133
|
const state = channel.state;
|
|
2086
2134
|
const intPart = Math.trunc(value);
|
|
2087
2135
|
state.modulationDepthMSB = intPart / 127;
|
|
@@ -2107,7 +2155,8 @@ export class Midy {
|
|
|
2107
2155
|
});
|
|
2108
2156
|
}
|
|
2109
2157
|
setPortamentoTime(channelNumber, value, scheduleTime) {
|
|
2110
|
-
|
|
2158
|
+
if (!(0 <= scheduleTime))
|
|
2159
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2111
2160
|
const channel = this.channels[channelNumber];
|
|
2112
2161
|
const state = channel.state;
|
|
2113
2162
|
const intPart = Math.trunc(value);
|
|
@@ -2118,7 +2167,8 @@ export class Midy {
|
|
|
2118
2167
|
this.updatePortamento(channel, scheduleTime);
|
|
2119
2168
|
}
|
|
2120
2169
|
setVolume(channelNumber, value, scheduleTime) {
|
|
2121
|
-
|
|
2170
|
+
if (!(0 <= scheduleTime))
|
|
2171
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2122
2172
|
const channel = this.channels[channelNumber];
|
|
2123
2173
|
const state = channel.state;
|
|
2124
2174
|
const intPart = Math.trunc(value);
|
|
@@ -2141,7 +2191,8 @@ export class Midy {
|
|
|
2141
2191
|
};
|
|
2142
2192
|
}
|
|
2143
2193
|
setPan(channelNumber, value, scheduleTime) {
|
|
2144
|
-
|
|
2194
|
+
if (!(0 <= scheduleTime))
|
|
2195
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2145
2196
|
const channel = this.channels[channelNumber];
|
|
2146
2197
|
const state = channel.state;
|
|
2147
2198
|
const intPart = Math.trunc(value);
|
|
@@ -2157,7 +2208,8 @@ export class Midy {
|
|
|
2157
2208
|
}
|
|
2158
2209
|
}
|
|
2159
2210
|
setExpression(channelNumber, value, scheduleTime) {
|
|
2160
|
-
|
|
2211
|
+
if (!(0 <= scheduleTime))
|
|
2212
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2161
2213
|
const channel = this.channels[channelNumber];
|
|
2162
2214
|
const state = channel.state;
|
|
2163
2215
|
const intPart = Math.trunc(value);
|
|
@@ -2214,7 +2266,8 @@ export class Midy {
|
|
|
2214
2266
|
const channel = this.channels[channelNumber];
|
|
2215
2267
|
if (channel.isDrum)
|
|
2216
2268
|
return;
|
|
2217
|
-
|
|
2269
|
+
if (!(0 <= scheduleTime))
|
|
2270
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2218
2271
|
channel.state.sustainPedal = value / 127;
|
|
2219
2272
|
if (64 <= value) {
|
|
2220
2273
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2232,7 +2285,8 @@ export class Midy {
|
|
|
2232
2285
|
const channel = this.channels[channelNumber];
|
|
2233
2286
|
if (channel.isDrum)
|
|
2234
2287
|
return;
|
|
2235
|
-
|
|
2288
|
+
if (!(0 <= scheduleTime))
|
|
2289
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2236
2290
|
channel.state.portamento = value / 127;
|
|
2237
2291
|
this.updatePortamento(channel, scheduleTime);
|
|
2238
2292
|
}
|
|
@@ -2240,7 +2294,8 @@ export class Midy {
|
|
|
2240
2294
|
const channel = this.channels[channelNumber];
|
|
2241
2295
|
if (channel.isDrum)
|
|
2242
2296
|
return;
|
|
2243
|
-
|
|
2297
|
+
if (!(0 <= scheduleTime))
|
|
2298
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2244
2299
|
channel.state.sostenutoPedal = value / 127;
|
|
2245
2300
|
if (64 <= value) {
|
|
2246
2301
|
const sostenutoNotes = [];
|
|
@@ -2261,7 +2316,8 @@ export class Midy {
|
|
|
2261
2316
|
if (channel.isDrum)
|
|
2262
2317
|
return;
|
|
2263
2318
|
const state = channel.state;
|
|
2264
|
-
|
|
2319
|
+
if (!(0 <= scheduleTime))
|
|
2320
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2265
2321
|
state.softPedal = softPedal / 127;
|
|
2266
2322
|
this.processScheduledNotes(channel, (note) => {
|
|
2267
2323
|
if (this.isPortamento(channel, note)) {
|
|
@@ -2278,7 +2334,8 @@ export class Midy {
|
|
|
2278
2334
|
const channel = this.channels[channelNumber];
|
|
2279
2335
|
if (channel.isDrum)
|
|
2280
2336
|
return;
|
|
2281
|
-
|
|
2337
|
+
if (!(0 <= scheduleTime))
|
|
2338
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2282
2339
|
const state = channel.state;
|
|
2283
2340
|
state.filterResonance = ccValue / 127;
|
|
2284
2341
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2299,14 +2356,16 @@ export class Midy {
|
|
|
2299
2356
|
const channel = this.channels[channelNumber];
|
|
2300
2357
|
if (channel.isDrum)
|
|
2301
2358
|
return;
|
|
2302
|
-
|
|
2359
|
+
if (!(0 <= scheduleTime))
|
|
2360
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2303
2361
|
channel.state.releaseTime = releaseTime / 127;
|
|
2304
2362
|
}
|
|
2305
2363
|
setAttackTime(channelNumber, attackTime, scheduleTime) {
|
|
2306
2364
|
const channel = this.channels[channelNumber];
|
|
2307
2365
|
if (channel.isDrum)
|
|
2308
2366
|
return;
|
|
2309
|
-
|
|
2367
|
+
if (!(0 <= scheduleTime))
|
|
2368
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2310
2369
|
channel.state.attackTime = attackTime / 127;
|
|
2311
2370
|
this.processScheduledNotes(channel, (note) => {
|
|
2312
2371
|
if (scheduleTime < note.startTime) {
|
|
@@ -2319,7 +2378,8 @@ export class Midy {
|
|
|
2319
2378
|
if (channel.isDrum)
|
|
2320
2379
|
return;
|
|
2321
2380
|
const state = channel.state;
|
|
2322
|
-
|
|
2381
|
+
if (!(0 <= scheduleTime))
|
|
2382
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2323
2383
|
state.brightness = brightness / 127;
|
|
2324
2384
|
this.processScheduledNotes(channel, (note) => {
|
|
2325
2385
|
if (this.isPortamento(channel, note)) {
|
|
@@ -2334,7 +2394,8 @@ export class Midy {
|
|
|
2334
2394
|
const channel = this.channels[channelNumber];
|
|
2335
2395
|
if (channel.isDrum)
|
|
2336
2396
|
return;
|
|
2337
|
-
|
|
2397
|
+
if (!(0 <= scheduleTime))
|
|
2398
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2338
2399
|
channel.state.decayTime = dacayTime / 127;
|
|
2339
2400
|
this.processScheduledNotes(channel, (note) => {
|
|
2340
2401
|
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
@@ -2344,7 +2405,8 @@ export class Midy {
|
|
|
2344
2405
|
const channel = this.channels[channelNumber];
|
|
2345
2406
|
if (channel.isDrum)
|
|
2346
2407
|
return;
|
|
2347
|
-
|
|
2408
|
+
if (!(0 <= scheduleTime))
|
|
2409
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2348
2410
|
channel.state.vibratoRate = vibratoRate / 127;
|
|
2349
2411
|
if (channel.vibratoDepth <= 0)
|
|
2350
2412
|
return;
|
|
@@ -2356,7 +2418,8 @@ export class Midy {
|
|
|
2356
2418
|
const channel = this.channels[channelNumber];
|
|
2357
2419
|
if (channel.isDrum)
|
|
2358
2420
|
return;
|
|
2359
|
-
|
|
2421
|
+
if (!(0 <= scheduleTime))
|
|
2422
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2360
2423
|
const prev = channel.state.vibratoDepth;
|
|
2361
2424
|
channel.state.vibratoDepth = vibratoDepth / 127;
|
|
2362
2425
|
if (0 < prev) {
|
|
@@ -2374,7 +2437,8 @@ export class Midy {
|
|
|
2374
2437
|
const channel = this.channels[channelNumber];
|
|
2375
2438
|
if (channel.isDrum)
|
|
2376
2439
|
return;
|
|
2377
|
-
|
|
2440
|
+
if (!(0 <= scheduleTime))
|
|
2441
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2378
2442
|
channel.state.vibratoDelay = vibratoDelay / 127;
|
|
2379
2443
|
if (0 < channel.state.vibratoDepth) {
|
|
2380
2444
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2383,13 +2447,15 @@ export class Midy {
|
|
|
2383
2447
|
}
|
|
2384
2448
|
}
|
|
2385
2449
|
setPortamentoNoteNumber(channelNumber, value, scheduleTime) {
|
|
2386
|
-
|
|
2450
|
+
if (!(0 <= scheduleTime))
|
|
2451
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2387
2452
|
const channel = this.channels[channelNumber];
|
|
2388
2453
|
channel.portamentoControl = true;
|
|
2389
2454
|
channel.state.portamentoNoteNumber = value / 127;
|
|
2390
2455
|
}
|
|
2391
2456
|
setReverbSendLevel(channelNumber, reverbSendLevel, scheduleTime) {
|
|
2392
|
-
|
|
2457
|
+
if (!(0 <= scheduleTime))
|
|
2458
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2393
2459
|
const channel = this.channels[channelNumber];
|
|
2394
2460
|
const state = channel.state;
|
|
2395
2461
|
state.reverbSendLevel = reverbSendLevel / 127;
|
|
@@ -2398,7 +2464,8 @@ export class Midy {
|
|
|
2398
2464
|
});
|
|
2399
2465
|
}
|
|
2400
2466
|
setChorusSendLevel(channelNumber, chorusSendLevel, scheduleTime) {
|
|
2401
|
-
|
|
2467
|
+
if (!(0 <= scheduleTime))
|
|
2468
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2402
2469
|
const channel = this.channels[channelNumber];
|
|
2403
2470
|
const state = channel.state;
|
|
2404
2471
|
state.chorusSendLevel = chorusSendLevel / 127;
|
|
@@ -2458,12 +2525,14 @@ export class Midy {
|
|
|
2458
2525
|
}
|
|
2459
2526
|
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp18.pdf
|
|
2460
2527
|
dataIncrement(channelNumber, scheduleTime) {
|
|
2461
|
-
|
|
2528
|
+
if (!(0 <= scheduleTime))
|
|
2529
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2462
2530
|
this.handleRPN(channelNumber, 1, scheduleTime);
|
|
2463
2531
|
}
|
|
2464
2532
|
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp18.pdf
|
|
2465
2533
|
dataDecrement(channelNumber, scheduleTime) {
|
|
2466
|
-
|
|
2534
|
+
if (!(0 <= scheduleTime))
|
|
2535
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2467
2536
|
this.handleRPN(channelNumber, -1, scheduleTime);
|
|
2468
2537
|
}
|
|
2469
2538
|
setRPNMSB(channelNumber, value) {
|
|
@@ -2486,7 +2555,8 @@ export class Midy {
|
|
|
2486
2555
|
const channel = this.channels[channelNumber];
|
|
2487
2556
|
if (channel.isDrum)
|
|
2488
2557
|
return;
|
|
2489
|
-
|
|
2558
|
+
if (!(0 <= scheduleTime))
|
|
2559
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2490
2560
|
const state = channel.state;
|
|
2491
2561
|
const prev = state.pitchWheelSensitivity;
|
|
2492
2562
|
const next = value / 12800;
|
|
@@ -2506,7 +2576,8 @@ export class Midy {
|
|
|
2506
2576
|
const channel = this.channels[channelNumber];
|
|
2507
2577
|
if (channel.isDrum)
|
|
2508
2578
|
return;
|
|
2509
|
-
|
|
2579
|
+
if (!(0 <= scheduleTime))
|
|
2580
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2510
2581
|
const prev = channel.fineTuning;
|
|
2511
2582
|
const next = value;
|
|
2512
2583
|
channel.fineTuning = next;
|
|
@@ -2523,7 +2594,8 @@ export class Midy {
|
|
|
2523
2594
|
const channel = this.channels[channelNumber];
|
|
2524
2595
|
if (channel.isDrum)
|
|
2525
2596
|
return;
|
|
2526
|
-
|
|
2597
|
+
if (!(0 <= scheduleTime))
|
|
2598
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2527
2599
|
const prev = channel.coarseTuning;
|
|
2528
2600
|
const next = value;
|
|
2529
2601
|
channel.coarseTuning = next;
|
|
@@ -2540,12 +2612,18 @@ export class Midy {
|
|
|
2540
2612
|
const channel = this.channels[channelNumber];
|
|
2541
2613
|
if (channel.isDrum)
|
|
2542
2614
|
return;
|
|
2543
|
-
|
|
2615
|
+
if (!(0 <= scheduleTime))
|
|
2616
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2544
2617
|
channel.modulationDepthRange = value;
|
|
2545
2618
|
this.updateModulation(channel, scheduleTime);
|
|
2546
2619
|
}
|
|
2547
|
-
|
|
2620
|
+
setRPGMakerLoop(_channelNumber, _value, scheduleTime) {
|
|
2548
2621
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2622
|
+
this.loopStart = scheduleTime + this.resumeTime - this.startTime;
|
|
2623
|
+
}
|
|
2624
|
+
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
2625
|
+
if (!(0 <= scheduleTime))
|
|
2626
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2549
2627
|
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
2550
2628
|
}
|
|
2551
2629
|
resetChannelStates(channelNumber) {
|
|
@@ -2607,7 +2685,8 @@ export class Midy {
|
|
|
2607
2685
|
}
|
|
2608
2686
|
}
|
|
2609
2687
|
allNotesOff(channelNumber, _value, scheduleTime) {
|
|
2610
|
-
|
|
2688
|
+
if (!(0 <= scheduleTime))
|
|
2689
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2611
2690
|
return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
|
|
2612
2691
|
}
|
|
2613
2692
|
omniOff(channelNumber, value, scheduleTime) {
|
|
@@ -2659,7 +2738,8 @@ export class Midy {
|
|
|
2659
2738
|
}
|
|
2660
2739
|
}
|
|
2661
2740
|
GM1SystemOn(scheduleTime) {
|
|
2662
|
-
|
|
2741
|
+
if (!(0 <= scheduleTime))
|
|
2742
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2663
2743
|
this.mode = "GM1";
|
|
2664
2744
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2665
2745
|
this.allSoundOff(i, 0, scheduleTime);
|
|
@@ -2672,7 +2752,8 @@ export class Midy {
|
|
|
2672
2752
|
this.channels[9].isDrum = true;
|
|
2673
2753
|
}
|
|
2674
2754
|
GM2SystemOn(scheduleTime) {
|
|
2675
|
-
|
|
2755
|
+
if (!(0 <= scheduleTime))
|
|
2756
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2676
2757
|
this.mode = "GM2";
|
|
2677
2758
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2678
2759
|
this.allSoundOff(i, 0, scheduleTime);
|
|
@@ -2740,7 +2821,8 @@ export class Midy {
|
|
|
2740
2821
|
this.setMasterVolume(volume, scheduleTime);
|
|
2741
2822
|
}
|
|
2742
2823
|
setMasterVolume(value, scheduleTime) {
|
|
2743
|
-
|
|
2824
|
+
if (!(0 <= scheduleTime))
|
|
2825
|
+
scheduleTime = this.audioContext.currentTime;
|
|
2744
2826
|
this.masterVolume.gain
|
|
2745
2827
|
.cancelScheduledValues(scheduleTime)
|
|
2746
2828
|
.setValueAtTime(value * value, scheduleTime);
|