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