@marmooo/midy 0.1.0 → 0.1.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/esm/midy-GM1.d.ts +1 -2
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +11 -17
- package/esm/midy-GM2.d.ts +29 -20
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +169 -104
- package/esm/midy-GMLite.d.ts +1 -2
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +11 -17
- package/esm/midy.d.ts +29 -20
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +169 -104
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +1 -2
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +11 -17
- package/script/midy-GM2.d.ts +29 -20
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +169 -104
- package/script/midy-GMLite.d.ts +1 -2
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +11 -17
- package/script/midy.d.ts +29 -20
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +169 -104
package/script/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|
package/script/midy.js
CHANGED
|
@@ -85,7 +85,7 @@ class Midy {
|
|
|
85
85
|
writable: true,
|
|
86
86
|
value: {
|
|
87
87
|
time: this.getReverbTime(64),
|
|
88
|
-
feedback: 0.
|
|
88
|
+
feedback: 0.8,
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
Object.defineProperty(this, "chorus", {
|
|
@@ -93,10 +93,11 @@ class Midy {
|
|
|
93
93
|
configurable: true,
|
|
94
94
|
writable: true,
|
|
95
95
|
value: {
|
|
96
|
-
modRate: 3
|
|
97
|
-
modDepth: (
|
|
98
|
-
feedback: 8
|
|
99
|
-
sendToReverb: 0
|
|
96
|
+
modRate: this.getChorusModRate(3),
|
|
97
|
+
modDepth: this.getChorusModDepth(19),
|
|
98
|
+
feedback: this.getChorusFeedback(8),
|
|
99
|
+
sendToReverb: this.getChorusSendToReverb(0),
|
|
100
|
+
delayTimes: this.generateDistributedArray(0.02, 2, 0.5),
|
|
100
101
|
}
|
|
101
102
|
});
|
|
102
103
|
Object.defineProperty(this, "mono", {
|
|
@@ -226,8 +227,12 @@ class Midy {
|
|
|
226
227
|
this.audioContext = audioContext;
|
|
227
228
|
this.options = { ...this.defaultOptions, ...options };
|
|
228
229
|
this.masterGain = new GainNode(audioContext);
|
|
229
|
-
this.masterGain.connect(audioContext.destination);
|
|
230
230
|
this.channels = this.createChannels(audioContext);
|
|
231
|
+
this.reverbEffect = this.options.reverbAlgorithm(audioContext);
|
|
232
|
+
this.chorusEffect = this.createChorusEffect(audioContext);
|
|
233
|
+
this.chorusEffect.output.connect(this.masterGain);
|
|
234
|
+
this.reverbEffect.output.connect(this.masterGain);
|
|
235
|
+
this.masterGain.connect(audioContext.destination);
|
|
231
236
|
this.GM2SystemOn();
|
|
232
237
|
}
|
|
233
238
|
initSoundFontTable() {
|
|
@@ -271,14 +276,11 @@ class Midy {
|
|
|
271
276
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
272
277
|
gainL.connect(merger, 0, 0);
|
|
273
278
|
gainR.connect(merger, 0, 1);
|
|
274
|
-
|
|
275
|
-
const chorusEffect = this.createChorusEffect(audioContext);
|
|
279
|
+
merger.connect(this.masterGain);
|
|
276
280
|
return {
|
|
277
281
|
gainL,
|
|
278
282
|
gainR,
|
|
279
283
|
merger,
|
|
280
|
-
reverbEffect,
|
|
281
|
-
chorusEffect,
|
|
282
284
|
};
|
|
283
285
|
}
|
|
284
286
|
createChannels(audioContext) {
|
|
@@ -694,12 +696,10 @@ class Midy {
|
|
|
694
696
|
}
|
|
695
697
|
// https://hajim.rochester.edu/ece/sites/zduan/teaching/ece472/reading/Schroeder_1962.pdf
|
|
696
698
|
// M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
|
|
697
|
-
createSchroederReverb(audioContext, combDelays,
|
|
699
|
+
createSchroederReverb(audioContext, combFeedbacks, combDelays, allpassFeedbacks, allpassDelays) {
|
|
698
700
|
const input = new GainNode(audioContext);
|
|
699
701
|
const output = new GainNode(audioContext);
|
|
700
|
-
const mergerGain = new GainNode(audioContext
|
|
701
|
-
gain: 1 / (combDelays.length * 2),
|
|
702
|
-
});
|
|
702
|
+
const mergerGain = new GainNode(audioContext);
|
|
703
703
|
for (let i = 0; i < combDelays.length; i++) {
|
|
704
704
|
const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
|
|
705
705
|
comb.connect(mergerGain);
|
|
@@ -712,62 +712,49 @@ class Midy {
|
|
|
712
712
|
allpasses.at(-1).connect(output);
|
|
713
713
|
return { input, output };
|
|
714
714
|
}
|
|
715
|
-
createChorusEffect(audioContext
|
|
716
|
-
const
|
|
717
|
-
const lfo = new OscillatorNode(audioContext, { frequency: chorusRate });
|
|
718
|
-
const lfoGain = new GainNode(audioContext, { gain: chorusDepth });
|
|
715
|
+
createChorusEffect(audioContext) {
|
|
716
|
+
const input = new GainNode(audioContext);
|
|
719
717
|
const output = new GainNode(audioContext);
|
|
720
|
-
const
|
|
718
|
+
const sendGain = new GainNode(audioContext);
|
|
719
|
+
const lfo = new OscillatorNode(audioContext, {
|
|
720
|
+
frequency: this.chorus.modRate,
|
|
721
|
+
});
|
|
722
|
+
const lfoGain = new GainNode(audioContext, {
|
|
723
|
+
gain: this.chorus.modDepth / 2,
|
|
724
|
+
});
|
|
725
|
+
const delayTimes = this.chorus.delayTimes;
|
|
721
726
|
const delayNodes = [];
|
|
722
|
-
const
|
|
723
|
-
for (let i = 0; i <
|
|
724
|
-
const
|
|
725
|
-
const delayTime = (i + 1) * delay + randomDelayFactor;
|
|
727
|
+
const feedbackGains = [];
|
|
728
|
+
for (let i = 0; i < delayTimes.length; i++) {
|
|
729
|
+
const delayTime = delayTimes[i];
|
|
726
730
|
const delayNode = new DelayNode(audioContext, {
|
|
727
|
-
maxDelayTime: delayTime
|
|
731
|
+
maxDelayTime: 0.1, // generally, 5ms < delayTime < 50ms
|
|
732
|
+
delayTime,
|
|
733
|
+
});
|
|
734
|
+
const feedbackGain = new GainNode(audioContext, {
|
|
735
|
+
gain: this.chorus.feedback,
|
|
728
736
|
});
|
|
729
|
-
const chorusGain = new GainNode(audioContext, { gain: baseGain });
|
|
730
737
|
delayNodes.push(delayNode);
|
|
731
|
-
|
|
738
|
+
feedbackGains.push(feedbackGain);
|
|
739
|
+
input.connect(delayNode);
|
|
732
740
|
lfoGain.connect(delayNode.delayTime);
|
|
733
|
-
delayNode.connect(
|
|
734
|
-
|
|
741
|
+
delayNode.connect(feedbackGain);
|
|
742
|
+
feedbackGain.connect(delayNode);
|
|
743
|
+
delayNode.connect(output);
|
|
735
744
|
}
|
|
745
|
+
output.connect(sendGain);
|
|
736
746
|
lfo.connect(lfoGain);
|
|
737
747
|
lfo.start();
|
|
738
748
|
return {
|
|
749
|
+
input,
|
|
750
|
+
output,
|
|
751
|
+
sendGain,
|
|
739
752
|
lfo,
|
|
740
753
|
lfoGain,
|
|
741
754
|
delayNodes,
|
|
742
|
-
|
|
743
|
-
output,
|
|
755
|
+
feedbackGains,
|
|
744
756
|
};
|
|
745
757
|
}
|
|
746
|
-
connectEffects(channel, gainNode) {
|
|
747
|
-
gainNode.connect(channel.merger);
|
|
748
|
-
channel.merger.connect(this.masterGain);
|
|
749
|
-
if (channel.reverbSendLevel === 0) {
|
|
750
|
-
if (channel.chorusSendLevel !== 0) { // chorus
|
|
751
|
-
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
752
|
-
channel.merger.connect(delayNode);
|
|
753
|
-
});
|
|
754
|
-
channel.chorusEffect.output.connect(this.masterGain);
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
else {
|
|
758
|
-
if (channel.chorusSendLevel === 0) { // reverb
|
|
759
|
-
channel.merger.connect(channel.reverbEffect.input);
|
|
760
|
-
channel.reverbEffect.output.connect(this.masterGain);
|
|
761
|
-
}
|
|
762
|
-
else { // reverb + chorus
|
|
763
|
-
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
764
|
-
channel.merger.connect(delayNode);
|
|
765
|
-
});
|
|
766
|
-
channel.merger.connect(channel.reverbEffect.input);
|
|
767
|
-
channel.reverbEffect.output.connect(this.masterGain);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
758
|
cbToRatio(cb) {
|
|
772
759
|
return Math.pow(10, cb / 200);
|
|
773
760
|
}
|
|
@@ -784,14 +771,10 @@ class Midy {
|
|
|
784
771
|
return instrumentKey.playbackRate(noteNumber) *
|
|
785
772
|
Math.pow(2, semitoneOffset / 12);
|
|
786
773
|
}
|
|
787
|
-
setVolumeEnvelope(
|
|
788
|
-
const { instrumentKey, startTime
|
|
774
|
+
setVolumeEnvelope(note) {
|
|
775
|
+
const { instrumentKey, startTime } = note;
|
|
789
776
|
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
790
|
-
|
|
791
|
-
if (volume === 0)
|
|
792
|
-
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
793
|
-
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation) *
|
|
794
|
-
volume;
|
|
777
|
+
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
795
778
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
796
779
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
797
780
|
const volAttack = volDelay + instrumentKey.volAttack;
|
|
@@ -864,7 +847,7 @@ class Midy {
|
|
|
864
847
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
865
848
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
866
849
|
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
867
|
-
this.setVolumeEnvelope(
|
|
850
|
+
this.setVolumeEnvelope(note);
|
|
868
851
|
this.setFilterEnvelope(channel, note);
|
|
869
852
|
if (channel.modulation > 0) {
|
|
870
853
|
const delayModLFO = startTime + instrumentKey.delayModLFO;
|
|
@@ -904,7 +887,8 @@ class Midy {
|
|
|
904
887
|
if (!instrumentKey)
|
|
905
888
|
return;
|
|
906
889
|
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
907
|
-
|
|
890
|
+
note.gainNode.connect(channel.gainL);
|
|
891
|
+
note.gainNode.connect(channel.gainR);
|
|
908
892
|
if (channel.sostenutoPedal) {
|
|
909
893
|
channel.sostenutoNotes.set(noteNumber, note);
|
|
910
894
|
}
|
|
@@ -1064,13 +1048,13 @@ class Midy {
|
|
|
1064
1048
|
}
|
|
1065
1049
|
}
|
|
1066
1050
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
1067
|
-
const pitchBend = msb * 128 + lsb;
|
|
1051
|
+
const pitchBend = msb * 128 + lsb - 8192;
|
|
1068
1052
|
this.setPitchBend(channelNumber, pitchBend);
|
|
1069
1053
|
}
|
|
1070
1054
|
setPitchBend(channelNumber, pitchBend) {
|
|
1071
1055
|
const channel = this.channels[channelNumber];
|
|
1072
1056
|
const prevPitchBend = channel.pitchBend;
|
|
1073
|
-
channel.pitchBend =
|
|
1057
|
+
channel.pitchBend = pitchBend / 8192;
|
|
1074
1058
|
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
1075
1059
|
channel.pitchBendRange * 100;
|
|
1076
1060
|
this.updateDetune(channel, detuneChange);
|
|
@@ -1216,17 +1200,30 @@ class Midy {
|
|
|
1216
1200
|
this.channels[channelNumber].portamento = value >= 64;
|
|
1217
1201
|
}
|
|
1218
1202
|
setReverbSendLevel(channelNumber, reverbSendLevel) {
|
|
1219
|
-
const now = this.audioContext.currentTime;
|
|
1220
1203
|
const channel = this.channels[channelNumber];
|
|
1221
|
-
const reverbEffect =
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1204
|
+
const reverbEffect = this.reverbEffect;
|
|
1205
|
+
if (0 < reverbSendLevel) {
|
|
1206
|
+
const now = this.audioContext.currentTime;
|
|
1207
|
+
channel.reverbSendLevel = reverbSendLevel / 127;
|
|
1208
|
+
reverbEffect.output.gain.cancelScheduledValues(now);
|
|
1209
|
+
reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
|
|
1210
|
+
}
|
|
1211
|
+
else if (channel.reverbSendLevel !== 0) {
|
|
1212
|
+
channel.merger.disconnect(reverbEffect.input);
|
|
1213
|
+
}
|
|
1225
1214
|
}
|
|
1226
1215
|
setChorusSendLevel(channelNumber, chorusSendLevel) {
|
|
1227
1216
|
const channel = this.channels[channelNumber];
|
|
1228
|
-
|
|
1229
|
-
|
|
1217
|
+
const chorusEffect = this.chorusEffect;
|
|
1218
|
+
if (0 < chorusSendLevel) {
|
|
1219
|
+
const now = this.audioContext.currentTime;
|
|
1220
|
+
channel.chorusSendLevel = chorusSendLevel / 127;
|
|
1221
|
+
chorusEffect.output.gain.cancelScheduledValues(now);
|
|
1222
|
+
chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
|
|
1223
|
+
}
|
|
1224
|
+
else if (channel.chorusSendLevel !== 0) {
|
|
1225
|
+
channel.merger.disconnect(chorusEffect.input);
|
|
1226
|
+
}
|
|
1230
1227
|
}
|
|
1231
1228
|
setSostenutoPedal(channelNumber, value) {
|
|
1232
1229
|
const isOn = value >= 64;
|
|
@@ -1419,7 +1416,7 @@ class Midy {
|
|
|
1419
1416
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1420
1417
|
const activeNote = this.getActiveNote(noteList, now);
|
|
1421
1418
|
if (activeNote) {
|
|
1422
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
1419
|
+
const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
|
|
1423
1420
|
promises.push(notePromise);
|
|
1424
1421
|
}
|
|
1425
1422
|
});
|
|
@@ -1486,7 +1483,7 @@ class Midy {
|
|
|
1486
1483
|
case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
|
|
1487
1484
|
return this.handleMasterCoarseTuningSysEx(data);
|
|
1488
1485
|
case 5:
|
|
1489
|
-
return this.
|
|
1486
|
+
return this.handleGlobalParameterControlSysEx(data);
|
|
1490
1487
|
default:
|
|
1491
1488
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1492
1489
|
}
|
|
@@ -1563,13 +1560,13 @@ class Midy {
|
|
|
1563
1560
|
this.masterCoarseTuning = coarseTuning - 64;
|
|
1564
1561
|
}
|
|
1565
1562
|
}
|
|
1566
|
-
|
|
1567
|
-
if (data[
|
|
1568
|
-
switch (data[
|
|
1563
|
+
handleGlobalParameterControlSysEx(data) {
|
|
1564
|
+
if (data[7] === 1) {
|
|
1565
|
+
switch (data[8]) {
|
|
1569
1566
|
case 1:
|
|
1570
|
-
return this.
|
|
1567
|
+
return this.handleReverbParameterSysEx(data);
|
|
1571
1568
|
case 2:
|
|
1572
|
-
return this.
|
|
1569
|
+
return this.handleChorusParameterSysEx(data);
|
|
1573
1570
|
default:
|
|
1574
1571
|
console.warn(`Unsupported Global Parameter Control Message: ${data}`);
|
|
1575
1572
|
}
|
|
@@ -1578,21 +1575,19 @@ class Midy {
|
|
|
1578
1575
|
console.warn(`Unsupported Global Parameter Control Message: ${data}`);
|
|
1579
1576
|
}
|
|
1580
1577
|
}
|
|
1581
|
-
|
|
1582
|
-
switch (data[
|
|
1578
|
+
handleReverbParameterSysEx(data) {
|
|
1579
|
+
switch (data[9]) {
|
|
1583
1580
|
case 0:
|
|
1584
|
-
return this.setReverbType(data[
|
|
1581
|
+
return this.setReverbType(data[10]);
|
|
1585
1582
|
case 1:
|
|
1586
|
-
return this.setReverbTime(data[
|
|
1583
|
+
return this.setReverbTime(data[10]);
|
|
1587
1584
|
}
|
|
1588
1585
|
}
|
|
1589
1586
|
setReverbType(type) {
|
|
1590
1587
|
this.reverb.time = this.getReverbTimeFromType(type);
|
|
1591
|
-
this.reverb.feedback = (type === 8) ? 0.
|
|
1592
|
-
const { audioContext,
|
|
1593
|
-
|
|
1594
|
-
channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
|
|
1595
|
-
}
|
|
1588
|
+
this.reverb.feedback = (type === 8) ? 0.9 : 0.8;
|
|
1589
|
+
const { audioContext, options } = this;
|
|
1590
|
+
this.reverbEffect = options.reverbAlgorithm(audioContext);
|
|
1596
1591
|
}
|
|
1597
1592
|
getReverbTimeFromType(type) {
|
|
1598
1593
|
switch (type) {
|
|
@@ -1643,41 +1638,111 @@ class Midy {
|
|
|
1643
1638
|
// RT60 = -3 * delay / Math.log10(feedback)
|
|
1644
1639
|
// feedback = Math.pow(10, -3 * delay / RT60)
|
|
1645
1640
|
// delay estimation using ideal feedback
|
|
1646
|
-
//
|
|
1647
|
-
//
|
|
1648
|
-
// It
|
|
1641
|
+
// The structure of a concert hall is complex,
|
|
1642
|
+
// so estimates based on mean free path are unstable.
|
|
1643
|
+
// It is easier to determine the delay based on ideal feedback.
|
|
1644
|
+
// The average sound absorption coefficient
|
|
1645
|
+
// suitable for playing musical instruments is 0.18 to 0.28.
|
|
1649
1646
|
// delay = -RT60 * Math.log10(feedback) / 3
|
|
1650
1647
|
calcDelay(rt60, feedback) {
|
|
1651
1648
|
return -rt60 * Math.log10(feedback) / 3;
|
|
1652
1649
|
}
|
|
1653
|
-
|
|
1654
|
-
switch (data[
|
|
1650
|
+
handleChorusParameterSysEx(data) {
|
|
1651
|
+
switch (data[9]) {
|
|
1655
1652
|
case 0:
|
|
1656
|
-
return this.setChorusType(data[
|
|
1653
|
+
return this.setChorusType(data[10]);
|
|
1657
1654
|
case 1:
|
|
1658
|
-
return this.setChorusModRate(data[
|
|
1655
|
+
return this.setChorusModRate(data[10]);
|
|
1659
1656
|
case 2:
|
|
1660
|
-
return this.setChorusModDepth(data[
|
|
1657
|
+
return this.setChorusModDepth(data[10]);
|
|
1661
1658
|
case 3:
|
|
1662
|
-
return this.setChorusFeedback(data[
|
|
1659
|
+
return this.setChorusFeedback(data[10]);
|
|
1663
1660
|
case 4:
|
|
1664
|
-
return this.setChorusSendToReverb(data[
|
|
1661
|
+
return this.setChorusSendToReverb(data[10]);
|
|
1665
1662
|
}
|
|
1666
1663
|
}
|
|
1667
1664
|
setChorusType(type) {
|
|
1668
|
-
|
|
1665
|
+
switch (type) {
|
|
1666
|
+
case 0:
|
|
1667
|
+
return this.setChorusParameter(3, 5, 0, 0);
|
|
1668
|
+
case 1:
|
|
1669
|
+
return this.setChorusParameter(9, 19, 5, 0);
|
|
1670
|
+
case 2:
|
|
1671
|
+
return this.setChorusParameter(3, 19, 8, 0);
|
|
1672
|
+
case 3:
|
|
1673
|
+
return this.setChorusParameter(9, 16, 16, 0);
|
|
1674
|
+
case 4:
|
|
1675
|
+
return this.setChorusParameter(2, 24, 64, 0);
|
|
1676
|
+
case 5:
|
|
1677
|
+
return this.setChorusParameter(1, 5, 112, 0);
|
|
1678
|
+
default:
|
|
1679
|
+
console.warn(`Unsupported Chorus Type: ${type}`);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
setChorusParameter(modRate, modDepth, feedback, sendToReverb) {
|
|
1683
|
+
this.setChorusModRate(modRate);
|
|
1684
|
+
this.setChorusModDepth(modDepth);
|
|
1685
|
+
this.setChorusFeedback(feedback);
|
|
1686
|
+
this.setChorusSendToReverb(sendToReverb);
|
|
1669
1687
|
}
|
|
1670
1688
|
setChorusModRate(value) {
|
|
1671
|
-
|
|
1689
|
+
const now = this.audioContext.currentTime;
|
|
1690
|
+
const modRate = this.getChorusModRate(value);
|
|
1691
|
+
this.chorus.modRate = modRate;
|
|
1692
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1693
|
+
const lfo = this.channels[i].chorusEffect.lfo;
|
|
1694
|
+
lfo.frequency.setValueAtTime(modRate, now);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
getChorusModRate(value) {
|
|
1698
|
+
return value * 0.122; // Hz
|
|
1672
1699
|
}
|
|
1673
1700
|
setChorusModDepth(value) {
|
|
1674
|
-
|
|
1701
|
+
const now = this.audioContext.currentTime;
|
|
1702
|
+
const modDepth = this.getChorusModDepth(value);
|
|
1703
|
+
this.chorus.modDepth = modDepth;
|
|
1704
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1705
|
+
const chorusEffect = this.channels[i].chorusEffect;
|
|
1706
|
+
chorusEffect.lfoGain.gain
|
|
1707
|
+
.cancelScheduledValues(now)
|
|
1708
|
+
.setValueAtTime(modDepth / 2, now);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
getChorusModDepth(value) {
|
|
1712
|
+
return (value + 1) / 3200; // second
|
|
1675
1713
|
}
|
|
1676
1714
|
setChorusFeedback(value) {
|
|
1677
|
-
|
|
1715
|
+
const now = this.audioContext.currentTime;
|
|
1716
|
+
const feedback = this.getChorusFeedback(value);
|
|
1717
|
+
this.chorus.feedback = feedback;
|
|
1718
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1719
|
+
const chorusEffect = this.channels[i].chorusEffect;
|
|
1720
|
+
for (let j = 0; j < chorusEffect.feedbackGains.length; j++) {
|
|
1721
|
+
const feedbackGain = chorusEffect.feedbackGains[j];
|
|
1722
|
+
feedbackGain.gain
|
|
1723
|
+
.cancelScheduledValues(now)
|
|
1724
|
+
.setValueAtTime(feedback, now);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
getChorusFeedback(value) {
|
|
1729
|
+
return value * 0.00763;
|
|
1678
1730
|
}
|
|
1679
1731
|
setChorusSendToReverb(value) {
|
|
1680
|
-
|
|
1732
|
+
const sendToReverb = this.getChorusSendToReverb(value);
|
|
1733
|
+
if (0 < sendToReverb) {
|
|
1734
|
+
const now = this.audioContext.currentTime;
|
|
1735
|
+
this.chorus.sendToReverb = sendToReverb;
|
|
1736
|
+
this.chorusEffect.sendGain.gain
|
|
1737
|
+
.cancelScheduledValues(now)
|
|
1738
|
+
.setValueAtTime(sendToReverb, now);
|
|
1739
|
+
}
|
|
1740
|
+
else if (this.chorus.sendToReverb !== 0) {
|
|
1741
|
+
this.chorusEffect.sendGain.disconnect(this.reverbEffect.input);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
getChorusSendToReverb(value) {
|
|
1745
|
+
return value * 0.00787;
|
|
1681
1746
|
}
|
|
1682
1747
|
handleExclusiveMessage(data) {
|
|
1683
1748
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|