@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.js
CHANGED
|
@@ -243,13 +243,13 @@ class Midy {
|
|
|
243
243
|
configurable: true,
|
|
244
244
|
writable: true,
|
|
245
245
|
value: 0
|
|
246
|
-
}); //
|
|
246
|
+
}); // cent
|
|
247
247
|
Object.defineProperty(this, "masterCoarseTuning", {
|
|
248
248
|
enumerable: true,
|
|
249
249
|
configurable: true,
|
|
250
250
|
writable: true,
|
|
251
251
|
value: 0
|
|
252
|
-
}); //
|
|
252
|
+
}); // cent
|
|
253
253
|
Object.defineProperty(this, "reverb", {
|
|
254
254
|
enumerable: true,
|
|
255
255
|
configurable: true,
|
|
@@ -374,6 +374,12 @@ class Midy {
|
|
|
374
374
|
writable: true,
|
|
375
375
|
value: false
|
|
376
376
|
});
|
|
377
|
+
Object.defineProperty(this, "playPromise", {
|
|
378
|
+
enumerable: true,
|
|
379
|
+
configurable: true,
|
|
380
|
+
writable: true,
|
|
381
|
+
value: void 0
|
|
382
|
+
});
|
|
377
383
|
Object.defineProperty(this, "timeline", {
|
|
378
384
|
enumerable: true,
|
|
379
385
|
configurable: true,
|
|
@@ -543,7 +549,7 @@ class Midy {
|
|
|
543
549
|
channel.scaleOctaveTuningTable.fill(0); // [-100, 100] cent
|
|
544
550
|
channel.channelPressureTable.fill(-1);
|
|
545
551
|
channel.polyphonicKeyPressureTable.fill(-1);
|
|
546
|
-
channel.
|
|
552
|
+
channel.keyBasedTable.fill(-1);
|
|
547
553
|
}
|
|
548
554
|
createChannels(audioContext) {
|
|
549
555
|
const channels = Array.from({ length: this.numChannels }, () => {
|
|
@@ -560,7 +566,7 @@ class Midy {
|
|
|
560
566
|
scaleOctaveTuningTable: new Float32Array(12), // [-100, 100] cent
|
|
561
567
|
channelPressureTable: new Int8Array(6).fill(-1),
|
|
562
568
|
polyphonicKeyPressureTable: new Int8Array(6).fill(-1),
|
|
563
|
-
|
|
569
|
+
keyBasedTable: new Int8Array(128 * 128).fill(-1),
|
|
564
570
|
keyBasedGainLs: new Array(128),
|
|
565
571
|
keyBasedGainRs: new Array(128),
|
|
566
572
|
};
|
|
@@ -638,72 +644,80 @@ class Midy {
|
|
|
638
644
|
}
|
|
639
645
|
return 0;
|
|
640
646
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
647
|
+
resetAllStates() {
|
|
648
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
649
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
650
|
+
this.voiceCache.clear();
|
|
651
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
652
|
+
this.channels[i].scheduledNotes = [];
|
|
653
|
+
this.resetChannelStates(i);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
updateStates(queueIndex, nextQueueIndex) {
|
|
657
|
+
if (nextQueueIndex < queueIndex)
|
|
658
|
+
queueIndex = 0;
|
|
659
|
+
for (let i = queueIndex; i < nextQueueIndex; i++) {
|
|
660
|
+
const event = this.timeline[i];
|
|
661
|
+
switch (event.type) {
|
|
662
|
+
case "controller":
|
|
663
|
+
this.setControlChange(event.channel, event.controllerType, event.value, 0);
|
|
664
|
+
break;
|
|
665
|
+
case "programChange":
|
|
666
|
+
this.setProgramChange(event.channel, event.programNumber, 0);
|
|
667
|
+
break;
|
|
668
|
+
case "pitchBend":
|
|
669
|
+
this.setPitchBend(event.channel, event.value + 8192, 0);
|
|
670
|
+
break;
|
|
671
|
+
case "sysEx":
|
|
672
|
+
this.handleSysEx(event.data, 0);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
async playNotes() {
|
|
677
|
+
if (this.audioContext.state === "suspended") {
|
|
678
|
+
await this.audioContext.resume();
|
|
679
|
+
}
|
|
680
|
+
this.isPlaying = true;
|
|
681
|
+
this.isPaused = false;
|
|
682
|
+
this.startTime = this.audioContext.currentTime;
|
|
683
|
+
let queueIndex = this.getQueueIndex(this.resumeTime);
|
|
684
|
+
let resumeTime = this.resumeTime - this.startTime;
|
|
685
|
+
let finished = false;
|
|
686
|
+
this.notePromises = [];
|
|
687
|
+
while (queueIndex < this.timeline.length) {
|
|
688
|
+
const now = this.audioContext.currentTime;
|
|
689
|
+
const t = now + resumeTime;
|
|
690
|
+
queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
|
|
691
|
+
if (this.isPausing) {
|
|
692
|
+
await this.stopNotes(0, true, now);
|
|
693
|
+
await this.audioContext.suspend();
|
|
694
|
+
this.notePromises = [];
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
else if (this.isStopping) {
|
|
698
|
+
await this.stopNotes(0, true, now);
|
|
699
|
+
await this.audioContext.suspend();
|
|
700
|
+
finished = true;
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
else if (this.isSeeking) {
|
|
704
|
+
await this.stopNotes(0, true, now);
|
|
705
|
+
this.startTime = this.audioContext.currentTime;
|
|
706
|
+
const nextQueueIndex = this.getQueueIndex(this.resumeTime);
|
|
707
|
+
this.updateStates(queueIndex, nextQueueIndex);
|
|
708
|
+
queueIndex = nextQueueIndex;
|
|
709
|
+
resumeTime = this.resumeTime - this.startTime;
|
|
710
|
+
this.isSeeking = false;
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
const waitTime = now + this.noteCheckInterval;
|
|
714
|
+
await this.scheduleTask(() => { }, waitTime);
|
|
715
|
+
}
|
|
716
|
+
if (finished) {
|
|
648
717
|
this.notePromises = [];
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
this.notePromises = [];
|
|
653
|
-
this.exclusiveClassNotes.fill(undefined);
|
|
654
|
-
this.drumExclusiveClassNotes.fill(undefined);
|
|
655
|
-
this.voiceCache.clear();
|
|
656
|
-
for (let i = 0; i < this.channels.length; i++) {
|
|
657
|
-
this.channels[i].scheduledNotes = [];
|
|
658
|
-
this.resetAllStates(i);
|
|
659
|
-
}
|
|
660
|
-
resolve();
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
const now = this.audioContext.currentTime;
|
|
664
|
-
const t = now + resumeTime;
|
|
665
|
-
queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
|
|
666
|
-
if (this.isPausing) {
|
|
667
|
-
await this.stopNotes(0, true, now);
|
|
668
|
-
this.notePromises = [];
|
|
669
|
-
this.isPausing = false;
|
|
670
|
-
this.isPaused = true;
|
|
671
|
-
resolve();
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
else if (this.isStopping) {
|
|
675
|
-
await this.stopNotes(0, true, now);
|
|
676
|
-
this.notePromises = [];
|
|
677
|
-
this.exclusiveClassNotes.fill(undefined);
|
|
678
|
-
this.drumExclusiveClassNotes.fill(undefined);
|
|
679
|
-
this.voiceCache.clear();
|
|
680
|
-
for (let i = 0; i < this.channels.length; i++) {
|
|
681
|
-
this.channels[i].scheduledNotes = [];
|
|
682
|
-
this.resetAllStates(i);
|
|
683
|
-
}
|
|
684
|
-
this.isStopping = false;
|
|
685
|
-
this.isPaused = false;
|
|
686
|
-
resolve();
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
else if (this.isSeeking) {
|
|
690
|
-
this.stopNotes(0, true, now);
|
|
691
|
-
this.exclusiveClassNotes.fill(undefined);
|
|
692
|
-
this.drumExclusiveClassNotes.fill(undefined);
|
|
693
|
-
this.startTime = this.audioContext.currentTime;
|
|
694
|
-
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
695
|
-
resumeTime = this.resumeTime - this.startTime;
|
|
696
|
-
this.isSeeking = false;
|
|
697
|
-
await schedulePlayback();
|
|
698
|
-
}
|
|
699
|
-
else {
|
|
700
|
-
const waitTime = now + this.noteCheckInterval;
|
|
701
|
-
await this.scheduleTask(() => { }, waitTime);
|
|
702
|
-
await schedulePlayback();
|
|
703
|
-
}
|
|
704
|
-
};
|
|
705
|
-
schedulePlayback();
|
|
706
|
-
});
|
|
718
|
+
this.resetAllStates();
|
|
719
|
+
}
|
|
720
|
+
this.isPlaying = false;
|
|
707
721
|
}
|
|
708
722
|
ticksToSecond(ticks, secondsPerBeat) {
|
|
709
723
|
return ticks * secondsPerBeat / this.ticksPerBeat;
|
|
@@ -840,26 +854,32 @@ class Midy {
|
|
|
840
854
|
this.resumeTime = 0;
|
|
841
855
|
if (this.voiceCounter.size === 0)
|
|
842
856
|
this.cacheVoiceIds();
|
|
843
|
-
|
|
844
|
-
this.
|
|
857
|
+
this.playPromise = this.playNotes();
|
|
858
|
+
await this.playPromise;
|
|
845
859
|
}
|
|
846
|
-
stop() {
|
|
860
|
+
async stop() {
|
|
847
861
|
if (!this.isPlaying)
|
|
848
862
|
return;
|
|
849
863
|
this.isStopping = true;
|
|
864
|
+
await this.playPromise;
|
|
865
|
+
this.isStopping = false;
|
|
850
866
|
}
|
|
851
|
-
pause() {
|
|
867
|
+
async pause() {
|
|
852
868
|
if (!this.isPlaying || this.isPaused)
|
|
853
869
|
return;
|
|
854
870
|
const now = this.audioContext.currentTime;
|
|
855
871
|
this.resumeTime += now - this.startTime - this.startDelay;
|
|
856
872
|
this.isPausing = true;
|
|
873
|
+
await this.playPromise;
|
|
874
|
+
this.isPausing = false;
|
|
875
|
+
this.isPaused = true;
|
|
857
876
|
}
|
|
858
877
|
async resume() {
|
|
859
878
|
if (!this.isPaused)
|
|
860
879
|
return;
|
|
861
|
-
|
|
862
|
-
this.
|
|
880
|
+
this.playPromise = this.playNotes();
|
|
881
|
+
await this.playPromise;
|
|
882
|
+
this.isPaused = false;
|
|
863
883
|
}
|
|
864
884
|
seekTo(second) {
|
|
865
885
|
this.resumeTime = second;
|
|
@@ -1167,28 +1187,29 @@ class Midy {
|
|
|
1167
1187
|
return Math.exp(y);
|
|
1168
1188
|
}
|
|
1169
1189
|
setPortamentoVolumeEnvelope(channel, note, scheduleTime) {
|
|
1170
|
-
const state = channel.state;
|
|
1171
1190
|
const { voiceParams, startTime } = note;
|
|
1172
1191
|
const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation) *
|
|
1173
1192
|
(1 + this.getAmplitudeControl(channel, note));
|
|
1174
1193
|
const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
|
|
1175
1194
|
const volDelay = startTime + voiceParams.volDelay;
|
|
1176
|
-
const
|
|
1195
|
+
const attackTime = this.getRelativeKeyBasedValue(channel, note, 73) * 2;
|
|
1196
|
+
const volAttack = volDelay + voiceParams.volAttack * attackTime;
|
|
1177
1197
|
const volHold = volAttack + voiceParams.volHold;
|
|
1178
1198
|
note.volumeEnvelopeNode.gain
|
|
1179
1199
|
.cancelScheduledValues(scheduleTime)
|
|
1180
1200
|
.setValueAtTime(sustainVolume, volHold);
|
|
1181
1201
|
}
|
|
1182
1202
|
setVolumeEnvelope(channel, note, scheduleTime) {
|
|
1183
|
-
const state = channel.state;
|
|
1184
1203
|
const { voiceParams, startTime } = note;
|
|
1185
1204
|
const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation) *
|
|
1186
1205
|
(1 + this.getAmplitudeControl(channel, note));
|
|
1187
1206
|
const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
|
|
1188
1207
|
const volDelay = startTime + voiceParams.volDelay;
|
|
1189
|
-
const
|
|
1208
|
+
const attackTime = this.getRelativeKeyBasedValue(channel, note, 73) * 2;
|
|
1209
|
+
const volAttack = volDelay + voiceParams.volAttack * attackTime;
|
|
1190
1210
|
const volHold = volAttack + voiceParams.volHold;
|
|
1191
|
-
const
|
|
1211
|
+
const decayTime = this.getRelativeKeyBasedValue(channel, note, 75) * 2;
|
|
1212
|
+
const volDecay = volHold + voiceParams.volDecay * decayTime;
|
|
1192
1213
|
note.volumeEnvelopeNode.gain
|
|
1193
1214
|
.cancelScheduledValues(scheduleTime)
|
|
1194
1215
|
.setValueAtTime(0, startTime)
|
|
@@ -1231,14 +1252,13 @@ class Midy {
|
|
|
1231
1252
|
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
1232
1253
|
}
|
|
1233
1254
|
setPortamentoFilterEnvelope(channel, note, scheduleTime) {
|
|
1234
|
-
const state = channel.state;
|
|
1235
1255
|
const { voiceParams, startTime } = note;
|
|
1236
1256
|
const softPedalFactor = this.getSoftPedalFactor(channel, note);
|
|
1237
1257
|
const baseCent = voiceParams.initialFilterFc +
|
|
1238
1258
|
this.getFilterCutoffControl(channel, note);
|
|
1239
|
-
const
|
|
1240
|
-
|
|
1241
|
-
const peekFreq = this.centToHz(voiceParams.initialFilterFc + voiceParams.modEnvToFilterFc) *
|
|
1259
|
+
const brightness = this.getRelativeKeyBasedValue(channel, note, 74) * 2;
|
|
1260
|
+
const baseFreq = this.centToHz(baseCent) * softPedalFactor * brightness;
|
|
1261
|
+
const peekFreq = this.centToHz(voiceParams.initialFilterFc + voiceParams.modEnvToFilterFc) * brightness;
|
|
1242
1262
|
const sustainFreq = baseFreq +
|
|
1243
1263
|
(peekFreq - baseFreq) * (1 - voiceParams.modSustain);
|
|
1244
1264
|
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
@@ -1252,15 +1272,14 @@ class Midy {
|
|
|
1252
1272
|
.linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
|
|
1253
1273
|
}
|
|
1254
1274
|
setFilterEnvelope(channel, note, scheduleTime) {
|
|
1255
|
-
const state = channel.state;
|
|
1256
1275
|
const { voiceParams, startTime } = note;
|
|
1257
1276
|
const softPedalFactor = this.getSoftPedalFactor(channel, note);
|
|
1258
1277
|
const baseCent = voiceParams.initialFilterFc +
|
|
1259
1278
|
this.getFilterCutoffControl(channel, note);
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1279
|
+
const brightness = this.getRelativeKeyBasedValue(channel, note, 74) * 2;
|
|
1280
|
+
const baseFreq = this.centToHz(baseCent) * softPedalFactor * brightness;
|
|
1262
1281
|
const peekFreq = this.centToHz(baseCent + voiceParams.modEnvToFilterFc) *
|
|
1263
|
-
softPedalFactor *
|
|
1282
|
+
softPedalFactor * brightness;
|
|
1264
1283
|
const sustainFreq = baseFreq +
|
|
1265
1284
|
(peekFreq - baseFreq) * (1 - voiceParams.modSustain);
|
|
1266
1285
|
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
@@ -1300,11 +1319,12 @@ class Midy {
|
|
|
1300
1319
|
}
|
|
1301
1320
|
startVibrato(channel, note, scheduleTime) {
|
|
1302
1321
|
const { voiceParams } = note;
|
|
1303
|
-
const
|
|
1322
|
+
const vibratoRate = this.getRelativeKeyBasedValue(channel, note, 76) * 2;
|
|
1323
|
+
const vibratoDelay = this.getRelativeKeyBasedValue(channel, note, 78) * 2;
|
|
1304
1324
|
note.vibratoLFO = new OscillatorNode(this.audioContext, {
|
|
1305
|
-
frequency: this.centToHz(voiceParams.freqVibLFO) *
|
|
1325
|
+
frequency: this.centToHz(voiceParams.freqVibLFO) * vibratoRate,
|
|
1306
1326
|
});
|
|
1307
|
-
note.vibratoLFO.start(note.startTime + voiceParams.delayVibLFO *
|
|
1327
|
+
note.vibratoLFO.start(note.startTime + voiceParams.delayVibLFO * vibratoDelay);
|
|
1308
1328
|
note.vibratoDepth = new GainNode(this.audioContext);
|
|
1309
1329
|
this.setVibLfoToPitch(channel, note, scheduleTime);
|
|
1310
1330
|
note.vibratoLFO.connect(note.vibratoDepth);
|
|
@@ -1337,9 +1357,10 @@ class Midy {
|
|
|
1337
1357
|
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
|
|
1338
1358
|
note.bufferSource = this.createBufferSource(channel, noteNumber, voiceParams, audioBuffer);
|
|
1339
1359
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
1360
|
+
const filterResonance = this.getRelativeKeyBasedValue(channel, note, 71);
|
|
1340
1361
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
1341
1362
|
type: "lowpass",
|
|
1342
|
-
Q: voiceParams.initialFilterQ / 5 *
|
|
1363
|
+
Q: voiceParams.initialFilterQ / 5 * filterResonance, // dB
|
|
1343
1364
|
});
|
|
1344
1365
|
const prevNote = channel.scheduledNotes.at(-1);
|
|
1345
1366
|
if (prevNote && prevNote.noteNumber !== noteNumber) {
|
|
@@ -1484,8 +1505,8 @@ class Midy {
|
|
|
1484
1505
|
}
|
|
1485
1506
|
}
|
|
1486
1507
|
releaseNote(channel, note, endTime) {
|
|
1487
|
-
const
|
|
1488
|
-
|
|
1508
|
+
const releaseTime = this.getRelativeKeyBasedValue(channel, note, 72) * 2;
|
|
1509
|
+
const volRelease = endTime + note.voiceParams.volRelease * releaseTime;
|
|
1489
1510
|
const modRelease = endTime + note.voiceParams.modRelease;
|
|
1490
1511
|
const stopTime = Math.min(volRelease, modRelease);
|
|
1491
1512
|
note.filterNode.frequency
|
|
@@ -1630,6 +1651,7 @@ class Midy {
|
|
|
1630
1651
|
break;
|
|
1631
1652
|
}
|
|
1632
1653
|
}
|
|
1654
|
+
channel.keyBasedTable.fill(-1);
|
|
1633
1655
|
}
|
|
1634
1656
|
setChannelPressure(channelNumber, value, scheduleTime) {
|
|
1635
1657
|
const channel = this.channels[channelNumber];
|
|
@@ -1671,23 +1693,29 @@ class Midy {
|
|
|
1671
1693
|
const modLfoToPitch = note.voiceParams.modLfoToPitch +
|
|
1672
1694
|
this.getLFOPitchDepth(channel, note);
|
|
1673
1695
|
const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
|
|
1674
|
-
const
|
|
1696
|
+
const depth = baseDepth * Math.sign(modLfoToPitch);
|
|
1675
1697
|
note.modulationDepth.gain
|
|
1676
1698
|
.cancelScheduledValues(scheduleTime)
|
|
1677
|
-
.setValueAtTime(
|
|
1699
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1678
1700
|
}
|
|
1679
1701
|
else {
|
|
1680
1702
|
this.startModulation(channel, note, scheduleTime);
|
|
1681
1703
|
}
|
|
1682
1704
|
}
|
|
1683
1705
|
setVibLfoToPitch(channel, note, scheduleTime) {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
.
|
|
1690
|
-
.
|
|
1706
|
+
if (note.vibratoDepth) {
|
|
1707
|
+
const vibratoDepth = this.getKeyBasedValue(channel, note.noteNumber, 77) *
|
|
1708
|
+
2;
|
|
1709
|
+
const vibLfoToPitch = note.voiceParams.vibLfoToPitch;
|
|
1710
|
+
const baseDepth = Math.abs(vibLfoToPitch) * vibratoDepth;
|
|
1711
|
+
const depth = baseDepth * Math.sign(vibLfoToPitch);
|
|
1712
|
+
note.vibratoDepth.gain
|
|
1713
|
+
.cancelScheduledValues(scheduleTime)
|
|
1714
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1715
|
+
}
|
|
1716
|
+
else {
|
|
1717
|
+
this.startVibrato(channel, note, scheduleTime);
|
|
1718
|
+
}
|
|
1691
1719
|
}
|
|
1692
1720
|
setModLfoToFilterFc(channel, note, scheduleTime) {
|
|
1693
1721
|
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc +
|
|
@@ -1765,13 +1793,12 @@ class Midy {
|
|
|
1765
1793
|
}
|
|
1766
1794
|
}
|
|
1767
1795
|
}
|
|
1768
|
-
setDelayModLFO(note
|
|
1769
|
-
const startTime = note.startTime;
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
note.modulationLFO.connect(note.filterDepth);
|
|
1796
|
+
setDelayModLFO(note) {
|
|
1797
|
+
const startTime = note.startTime + note.voiceParams.delayModLFO;
|
|
1798
|
+
try {
|
|
1799
|
+
note.modulationLFO.start(startTime);
|
|
1800
|
+
}
|
|
1801
|
+
catch { /* empty */ }
|
|
1775
1802
|
}
|
|
1776
1803
|
setFreqModLFO(note, scheduleTime) {
|
|
1777
1804
|
const freqModLFO = note.voiceParams.freqModLFO;
|
|
@@ -1780,54 +1807,65 @@ class Midy {
|
|
|
1780
1807
|
.setValueAtTime(freqModLFO, scheduleTime);
|
|
1781
1808
|
}
|
|
1782
1809
|
setFreqVibLFO(channel, note, scheduleTime) {
|
|
1810
|
+
const vibratoRate = this.getRelativeKeyBasedValue(channel, note, 76) * 2;
|
|
1783
1811
|
const freqVibLFO = note.voiceParams.freqVibLFO;
|
|
1784
1812
|
note.vibratoLFO.frequency
|
|
1785
1813
|
.cancelScheduledValues(scheduleTime)
|
|
1786
|
-
.setValueAtTime(freqVibLFO *
|
|
1814
|
+
.setValueAtTime(freqVibLFO * vibratoRate, scheduleTime);
|
|
1815
|
+
}
|
|
1816
|
+
setDelayVibLFO(channel, note) {
|
|
1817
|
+
const vibratoDelay = this.getRelativeKeyBasedValue(channel, note, 78) * 2;
|
|
1818
|
+
const value = note.voiceParams.delayVibLFO;
|
|
1819
|
+
const startTime = note.startTime + value * vibratoDelay;
|
|
1820
|
+
try {
|
|
1821
|
+
note.vibratoLFO.start(startTime);
|
|
1822
|
+
}
|
|
1823
|
+
catch { /* empty */ }
|
|
1787
1824
|
}
|
|
1788
1825
|
createVoiceParamsHandlers() {
|
|
1789
1826
|
return {
|
|
1790
|
-
modLfoToPitch: (channel, note,
|
|
1827
|
+
modLfoToPitch: (channel, note, scheduleTime) => {
|
|
1791
1828
|
if (0 < channel.state.modulationDepth) {
|
|
1792
1829
|
this.setModLfoToPitch(channel, note, scheduleTime);
|
|
1793
1830
|
}
|
|
1794
1831
|
},
|
|
1795
|
-
vibLfoToPitch: (channel, note,
|
|
1832
|
+
vibLfoToPitch: (channel, note, scheduleTime) => {
|
|
1796
1833
|
if (0 < channel.state.vibratoDepth) {
|
|
1797
1834
|
this.setVibLfoToPitch(channel, note, scheduleTime);
|
|
1798
1835
|
}
|
|
1799
1836
|
},
|
|
1800
|
-
modLfoToFilterFc: (channel, note,
|
|
1837
|
+
modLfoToFilterFc: (channel, note, scheduleTime) => {
|
|
1801
1838
|
if (0 < channel.state.modulationDepth) {
|
|
1802
1839
|
this.setModLfoToFilterFc(channel, note, scheduleTime);
|
|
1803
1840
|
}
|
|
1804
1841
|
},
|
|
1805
|
-
modLfoToVolume: (channel, note,
|
|
1842
|
+
modLfoToVolume: (channel, note, scheduleTime) => {
|
|
1806
1843
|
if (0 < channel.state.modulationDepth) {
|
|
1807
1844
|
this.setModLfoToVolume(channel, note, scheduleTime);
|
|
1808
1845
|
}
|
|
1809
1846
|
},
|
|
1810
|
-
chorusEffectsSend: (channel, note,
|
|
1847
|
+
chorusEffectsSend: (channel, note, scheduleTime) => {
|
|
1811
1848
|
this.setChorusSend(channel, note, scheduleTime);
|
|
1812
1849
|
},
|
|
1813
|
-
reverbEffectsSend: (channel, note,
|
|
1850
|
+
reverbEffectsSend: (channel, note, scheduleTime) => {
|
|
1814
1851
|
this.setReverbSend(channel, note, scheduleTime);
|
|
1815
1852
|
},
|
|
1816
|
-
delayModLFO: (_channel, note,
|
|
1817
|
-
|
|
1818
|
-
|
|
1853
|
+
delayModLFO: (_channel, note, _scheduleTime) => {
|
|
1854
|
+
if (0 < channel.state.modulationDepth) {
|
|
1855
|
+
this.setDelayModLFO(note);
|
|
1856
|
+
}
|
|
1857
|
+
},
|
|
1858
|
+
freqModLFO: (_channel, note, scheduleTime) => {
|
|
1859
|
+
if (0 < channel.state.modulationDepth) {
|
|
1860
|
+
this.setFreqModLFO(note, scheduleTime);
|
|
1861
|
+
}
|
|
1862
|
+
},
|
|
1863
|
+
delayVibLFO: (channel, note, _scheduleTime) => {
|
|
1819
1864
|
if (0 < channel.state.vibratoDepth) {
|
|
1820
|
-
|
|
1821
|
-
const prevStartTime = note.startTime + prevValue * vibratoDelay;
|
|
1822
|
-
if (scheduleTime < prevStartTime)
|
|
1823
|
-
return;
|
|
1824
|
-
const value = note.voiceParams.delayVibLFO;
|
|
1825
|
-
const startTime = note.startTime + value * vibratoDelay;
|
|
1826
|
-
note.vibratoLFO.stop(scheduleTime);
|
|
1827
|
-
note.vibratoLFO.start(startTime);
|
|
1865
|
+
setDelayVibLFO(channel, note);
|
|
1828
1866
|
}
|
|
1829
1867
|
},
|
|
1830
|
-
freqVibLFO: (channel, note,
|
|
1868
|
+
freqVibLFO: (channel, note, scheduleTime) => {
|
|
1831
1869
|
if (0 < channel.state.vibratoDepth) {
|
|
1832
1870
|
this.setFreqVibLFO(channel, note, scheduleTime);
|
|
1833
1871
|
}
|
|
@@ -1856,7 +1894,7 @@ class Midy {
|
|
|
1856
1894
|
continue;
|
|
1857
1895
|
note.voiceParams[key] = value;
|
|
1858
1896
|
if (key in this.voiceParamsHandlers) {
|
|
1859
|
-
this.voiceParamsHandlers[key](channel, note,
|
|
1897
|
+
this.voiceParamsHandlers[key](channel, note, scheduleTime);
|
|
1860
1898
|
}
|
|
1861
1899
|
else {
|
|
1862
1900
|
if (volumeEnvelopeKeySet.has(key))
|
|
@@ -2035,13 +2073,13 @@ class Midy {
|
|
|
2035
2073
|
.setValueAtTime(volume * gainRight, scheduleTime);
|
|
2036
2074
|
}
|
|
2037
2075
|
updateKeyBasedVolume(channel, keyNumber, scheduleTime) {
|
|
2038
|
-
const state = channel.state;
|
|
2039
|
-
const defaultVolume = state.volume * state.expression;
|
|
2040
|
-
const defaultPan = state.pan;
|
|
2041
2076
|
const gainL = channel.keyBasedGainLs[keyNumber];
|
|
2042
|
-
const gainR = channel.keyBasedGainRs[keyNumber];
|
|
2043
2077
|
if (!gainL)
|
|
2044
2078
|
return;
|
|
2079
|
+
const gainR = channel.keyBasedGainRs[keyNumber];
|
|
2080
|
+
const state = channel.state;
|
|
2081
|
+
const defaultVolume = state.volume * state.expression;
|
|
2082
|
+
const defaultPan = state.pan;
|
|
2045
2083
|
const keyBasedVolume = this.getKeyBasedValue(channel, keyNumber, 7);
|
|
2046
2084
|
const volume = (0 <= keyBasedVolume)
|
|
2047
2085
|
? defaultVolume * keyBasedVolume / 64
|
|
@@ -2117,18 +2155,27 @@ class Midy {
|
|
|
2117
2155
|
}
|
|
2118
2156
|
});
|
|
2119
2157
|
}
|
|
2120
|
-
setFilterResonance(channelNumber,
|
|
2158
|
+
setFilterResonance(channelNumber, ccValue, scheduleTime) {
|
|
2121
2159
|
const channel = this.channels[channelNumber];
|
|
2122
2160
|
if (channel.isDrum)
|
|
2123
2161
|
return;
|
|
2124
2162
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2125
2163
|
const state = channel.state;
|
|
2126
|
-
state.filterResonance =
|
|
2164
|
+
state.filterResonance = ccValue / 127;
|
|
2165
|
+
const filterResonance = this.getRelativeKeyBasedValue(channel, note, 71);
|
|
2127
2166
|
this.processScheduledNotes(channel, (note) => {
|
|
2128
|
-
const Q = note.voiceParams.initialFilterQ / 5 *
|
|
2167
|
+
const Q = note.voiceParams.initialFilterQ / 5 * filterResonance;
|
|
2129
2168
|
note.filterNode.Q.setValueAtTime(Q, scheduleTime);
|
|
2130
2169
|
});
|
|
2131
2170
|
}
|
|
2171
|
+
getRelativeKeyBasedValue(channel, note, controllerType) {
|
|
2172
|
+
const ccState = channel.state.array[128 + controllerType];
|
|
2173
|
+
const keyBasedValue = this.getKeyBasedValue(channel, note.noteNumber, controllerType);
|
|
2174
|
+
if (keyBasedValue < 0)
|
|
2175
|
+
return ccState;
|
|
2176
|
+
const keyValue = ccState + keyBasedValue / 127 - 0.5;
|
|
2177
|
+
return keyValue < 0 ? keyValue : 0;
|
|
2178
|
+
}
|
|
2132
2179
|
setReleaseTime(channelNumber, releaseTime, scheduleTime) {
|
|
2133
2180
|
const channel = this.channels[channelNumber];
|
|
2134
2181
|
if (channel.isDrum)
|
|
@@ -2143,9 +2190,9 @@ class Midy {
|
|
|
2143
2190
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2144
2191
|
channel.state.attackTime = attackTime / 127;
|
|
2145
2192
|
this.processScheduledNotes(channel, (note) => {
|
|
2146
|
-
if (note.startTime
|
|
2147
|
-
|
|
2148
|
-
|
|
2193
|
+
if (scheduleTime < note.startTime) {
|
|
2194
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
2195
|
+
}
|
|
2149
2196
|
});
|
|
2150
2197
|
}
|
|
2151
2198
|
setBrightness(channelNumber, brightness, scheduleTime) {
|
|
@@ -2306,8 +2353,8 @@ class Midy {
|
|
|
2306
2353
|
}
|
|
2307
2354
|
handlePitchBendRangeRPN(channelNumber, scheduleTime) {
|
|
2308
2355
|
const channel = this.channels[channelNumber];
|
|
2309
|
-
this.limitData(channel, 0, 127, 0,
|
|
2310
|
-
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
2356
|
+
this.limitData(channel, 0, 127, 0, 127);
|
|
2357
|
+
const pitchBendRange = (channel.dataMSB + channel.dataLSB / 128) * 100;
|
|
2311
2358
|
this.setPitchBendRange(channelNumber, pitchBendRange, scheduleTime);
|
|
2312
2359
|
}
|
|
2313
2360
|
setPitchBendRange(channelNumber, value, scheduleTime) {
|
|
@@ -2317,7 +2364,7 @@ class Midy {
|
|
|
2317
2364
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2318
2365
|
const state = channel.state;
|
|
2319
2366
|
const prev = state.pitchWheelSensitivity;
|
|
2320
|
-
const next = value /
|
|
2367
|
+
const next = value / 12800;
|
|
2321
2368
|
state.pitchWheelSensitivity = next;
|
|
2322
2369
|
channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
|
|
2323
2370
|
this.updateChannelDetune(channel, scheduleTime);
|
|
@@ -2326,7 +2373,8 @@ class Midy {
|
|
|
2326
2373
|
handleFineTuningRPN(channelNumber, scheduleTime) {
|
|
2327
2374
|
const channel = this.channels[channelNumber];
|
|
2328
2375
|
this.limitData(channel, 0, 127, 0, 127);
|
|
2329
|
-
const
|
|
2376
|
+
const value = channel.dataMSB * 128 + channel.dataLSB;
|
|
2377
|
+
const fineTuning = (value - 8192) / 8192 * 100;
|
|
2330
2378
|
this.setFineTuning(channelNumber, fineTuning, scheduleTime);
|
|
2331
2379
|
}
|
|
2332
2380
|
setFineTuning(channelNumber, value, scheduleTime) {
|
|
@@ -2335,7 +2383,7 @@ class Midy {
|
|
|
2335
2383
|
return;
|
|
2336
2384
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2337
2385
|
const prev = channel.fineTuning;
|
|
2338
|
-
const next =
|
|
2386
|
+
const next = value;
|
|
2339
2387
|
channel.fineTuning = next;
|
|
2340
2388
|
channel.detune += next - prev;
|
|
2341
2389
|
this.updateChannelDetune(channel, scheduleTime);
|
|
@@ -2343,7 +2391,7 @@ class Midy {
|
|
|
2343
2391
|
handleCoarseTuningRPN(channelNumber, scheduleTime) {
|
|
2344
2392
|
const channel = this.channels[channelNumber];
|
|
2345
2393
|
this.limitDataMSB(channel, 0, 127);
|
|
2346
|
-
const coarseTuning = channel.dataMSB;
|
|
2394
|
+
const coarseTuning = (channel.dataMSB - 64) * 100;
|
|
2347
2395
|
this.setCoarseTuning(channelNumber, coarseTuning, scheduleTime);
|
|
2348
2396
|
}
|
|
2349
2397
|
setCoarseTuning(channelNumber, value, scheduleTime) {
|
|
@@ -2352,7 +2400,7 @@ class Midy {
|
|
|
2352
2400
|
return;
|
|
2353
2401
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2354
2402
|
const prev = channel.coarseTuning;
|
|
2355
|
-
const next =
|
|
2403
|
+
const next = value;
|
|
2356
2404
|
channel.coarseTuning = next;
|
|
2357
2405
|
channel.detune += next - prev;
|
|
2358
2406
|
this.updateChannelDetune(channel, scheduleTime);
|
|
@@ -2360,22 +2408,22 @@ class Midy {
|
|
|
2360
2408
|
handleModulationDepthRangeRPN(channelNumber, scheduleTime) {
|
|
2361
2409
|
const channel = this.channels[channelNumber];
|
|
2362
2410
|
this.limitData(channel, 0, 127, 0, 127);
|
|
2363
|
-
const
|
|
2364
|
-
this.setModulationDepthRange(channelNumber,
|
|
2411
|
+
const value = (channel.dataMSB + channel.dataLSB / 128) * 100;
|
|
2412
|
+
this.setModulationDepthRange(channelNumber, value, scheduleTime);
|
|
2365
2413
|
}
|
|
2366
|
-
setModulationDepthRange(channelNumber,
|
|
2414
|
+
setModulationDepthRange(channelNumber, value, scheduleTime) {
|
|
2367
2415
|
const channel = this.channels[channelNumber];
|
|
2368
2416
|
if (channel.isDrum)
|
|
2369
2417
|
return;
|
|
2370
2418
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2371
|
-
channel.modulationDepthRange =
|
|
2419
|
+
channel.modulationDepthRange = value;
|
|
2372
2420
|
this.updateModulation(channel, scheduleTime);
|
|
2373
2421
|
}
|
|
2374
2422
|
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
2375
2423
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2376
2424
|
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
2377
2425
|
}
|
|
2378
|
-
|
|
2426
|
+
resetChannelStates(channelNumber) {
|
|
2379
2427
|
const scheduleTime = this.audioContext.currentTime;
|
|
2380
2428
|
const channel = this.channels[channelNumber];
|
|
2381
2429
|
const state = channel.state;
|
|
@@ -2393,8 +2441,8 @@ class Midy {
|
|
|
2393
2441
|
}
|
|
2394
2442
|
this.resetChannelTable(channel);
|
|
2395
2443
|
this.mode = "GM2";
|
|
2396
|
-
this.masterFineTuning = 0; //
|
|
2397
|
-
this.masterCoarseTuning = 0; //
|
|
2444
|
+
this.masterFineTuning = 0; // cent
|
|
2445
|
+
this.masterCoarseTuning = 0; // cent
|
|
2398
2446
|
}
|
|
2399
2447
|
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
|
|
2400
2448
|
resetAllControllers(channelNumber, _value, scheduleTime) {
|
|
@@ -2580,12 +2628,13 @@ class Midy {
|
|
|
2580
2628
|
}
|
|
2581
2629
|
}
|
|
2582
2630
|
handleMasterFineTuningSysEx(data, scheduleTime) {
|
|
2583
|
-
const
|
|
2631
|
+
const value = (data[5] * 128 + data[4]) / 16383;
|
|
2632
|
+
const fineTuning = (value - 8192) / 8192 * 100;
|
|
2584
2633
|
this.setMasterFineTuning(fineTuning, scheduleTime);
|
|
2585
2634
|
}
|
|
2586
2635
|
setMasterFineTuning(value, scheduleTime) {
|
|
2587
2636
|
const prev = this.masterFineTuning;
|
|
2588
|
-
const next =
|
|
2637
|
+
const next = value;
|
|
2589
2638
|
this.masterFineTuning = next;
|
|
2590
2639
|
const detuneChange = next - prev;
|
|
2591
2640
|
for (let i = 0; i < this.channels.length; i++) {
|
|
@@ -2597,12 +2646,12 @@ class Midy {
|
|
|
2597
2646
|
}
|
|
2598
2647
|
}
|
|
2599
2648
|
handleMasterCoarseTuningSysEx(data, scheduleTime) {
|
|
2600
|
-
const coarseTuning = data[4];
|
|
2649
|
+
const coarseTuning = (data[4] - 64) * 100;
|
|
2601
2650
|
this.setMasterCoarseTuning(coarseTuning, scheduleTime);
|
|
2602
2651
|
}
|
|
2603
2652
|
setMasterCoarseTuning(value, scheduleTime) {
|
|
2604
2653
|
const prev = this.masterCoarseTuning;
|
|
2605
|
-
const next =
|
|
2654
|
+
const next = value;
|
|
2606
2655
|
this.masterCoarseTuning = next;
|
|
2607
2656
|
const detuneChange = next - prev;
|
|
2608
2657
|
for (let i = 0; i < this.channels.length; i++) {
|
|
@@ -2988,7 +3037,7 @@ class Midy {
|
|
|
2988
3037
|
}
|
|
2989
3038
|
getKeyBasedValue(channel, keyNumber, controllerType) {
|
|
2990
3039
|
const index = keyNumber * 128 + controllerType;
|
|
2991
|
-
const controlValue = channel.
|
|
3040
|
+
const controlValue = channel.keyBasedTable[index];
|
|
2992
3041
|
return controlValue;
|
|
2993
3042
|
}
|
|
2994
3043
|
handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
|
|
@@ -2997,7 +3046,7 @@ class Midy {
|
|
|
2997
3046
|
if (!channel.isDrum)
|
|
2998
3047
|
return;
|
|
2999
3048
|
const keyNumber = data[5];
|
|
3000
|
-
const table = channel.
|
|
3049
|
+
const table = channel.keyBasedTable;
|
|
3001
3050
|
for (let i = 6; i < data.length; i += 2) {
|
|
3002
3051
|
const controllerType = data[i];
|
|
3003
3052
|
const value = data[i + 1];
|
|
@@ -3008,8 +3057,89 @@ class Midy {
|
|
|
3008
3057
|
case 10:
|
|
3009
3058
|
this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
|
|
3010
3059
|
break;
|
|
3011
|
-
|
|
3012
|
-
this.
|
|
3060
|
+
case 71:
|
|
3061
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3062
|
+
const filterResonance = this.getRelativeKeyBasedValue(channel, note, 71);
|
|
3063
|
+
if (note.noteNumber === keyNumber) {
|
|
3064
|
+
const Q = note.voiceParams.initialFilterQ / 5 * filterResonance;
|
|
3065
|
+
note.filterNode.Q.setValueAtTime(Q, scheduleTime);
|
|
3066
|
+
}
|
|
3067
|
+
});
|
|
3068
|
+
break;
|
|
3069
|
+
case 73:
|
|
3070
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3071
|
+
if (note.noteNumber === keyNumber) {
|
|
3072
|
+
if (0.5 <= channel.state.portamento &&
|
|
3073
|
+
0 <= note.portamentoNoteNumber) {
|
|
3074
|
+
this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
|
|
3075
|
+
}
|
|
3076
|
+
else {
|
|
3077
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
});
|
|
3081
|
+
break;
|
|
3082
|
+
case 74:
|
|
3083
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3084
|
+
if (note.noteNumber === keyNumber) {
|
|
3085
|
+
if (0.5 <= channel.state.portamento &&
|
|
3086
|
+
0 <= note.portamentoNoteNumber) {
|
|
3087
|
+
this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
|
|
3088
|
+
}
|
|
3089
|
+
else {
|
|
3090
|
+
this.setFilterEnvelope(channel, note, scheduleTime);
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
});
|
|
3094
|
+
break;
|
|
3095
|
+
case 75:
|
|
3096
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3097
|
+
if (note.noteNumber === keyNumber) {
|
|
3098
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
3099
|
+
}
|
|
3100
|
+
});
|
|
3101
|
+
break;
|
|
3102
|
+
case 76:
|
|
3103
|
+
if (channel.state.vibratoDepth <= 0)
|
|
3104
|
+
break;
|
|
3105
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3106
|
+
if (note.noteNumber === keyNumber) {
|
|
3107
|
+
this.setFreqVibLFO(channel, note, scheduleTime);
|
|
3108
|
+
}
|
|
3109
|
+
});
|
|
3110
|
+
break;
|
|
3111
|
+
case 77:
|
|
3112
|
+
if (channel.state.vibratoDepth <= 0)
|
|
3113
|
+
break;
|
|
3114
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3115
|
+
if (note.noteNumber === keyNumber) {
|
|
3116
|
+
this.setVibLfoToPitch(channel, note, scheduleTime);
|
|
3117
|
+
}
|
|
3118
|
+
});
|
|
3119
|
+
break;
|
|
3120
|
+
case 78:
|
|
3121
|
+
if (channel.state.vibratoDepth <= 0)
|
|
3122
|
+
break;
|
|
3123
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3124
|
+
if (note.noteNumber === keyNumber) {
|
|
3125
|
+
this.setDelayVibLFO(channel, note);
|
|
3126
|
+
}
|
|
3127
|
+
});
|
|
3128
|
+
break;
|
|
3129
|
+
case 91:
|
|
3130
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3131
|
+
if (note.noteNumber === keyNumber) {
|
|
3132
|
+
this.setReverbSend(channel, note, scheduleTime);
|
|
3133
|
+
}
|
|
3134
|
+
});
|
|
3135
|
+
break;
|
|
3136
|
+
case 93:
|
|
3137
|
+
this.processScheduledNotes(channel, (note) => {
|
|
3138
|
+
if (note.noteNumber === keyNumber) {
|
|
3139
|
+
this.setChorusSend(channel, note, scheduleTime);
|
|
3140
|
+
}
|
|
3141
|
+
});
|
|
3142
|
+
break;
|
|
3013
3143
|
}
|
|
3014
3144
|
}
|
|
3015
3145
|
}
|
|
@@ -3061,7 +3191,7 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
3061
3191
|
rpnLSB: 127,
|
|
3062
3192
|
mono: false, // CC#124, CC#125
|
|
3063
3193
|
modulationDepthRange: 50, // cent
|
|
3064
|
-
fineTuning: 0, //
|
|
3065
|
-
coarseTuning: 0, //
|
|
3194
|
+
fineTuning: 0, // cent
|
|
3195
|
+
coarseTuning: 0, // cent
|
|
3066
3196
|
}
|
|
3067
3197
|
});
|