@marmooo/midy 0.1.0 → 0.1.1
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-GM2.d.ts +18 -8
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +141 -69
- package/esm/midy.d.ts +18 -8
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +141 -69
- package/package.json +1 -1
- package/script/midy-GM2.d.ts +18 -8
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +141 -69
- package/script/midy.d.ts +18 -8
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +141 -69
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.25,
|
|
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", {
|
|
@@ -697,9 +698,7 @@ class Midy {
|
|
|
697
698
|
createSchroederReverb(audioContext, combDelays, combFeedbacks, allpassDelays, allpassFeedbacks) {
|
|
698
699
|
const input = new GainNode(audioContext);
|
|
699
700
|
const output = new GainNode(audioContext);
|
|
700
|
-
const mergerGain = new GainNode(audioContext
|
|
701
|
-
gain: 1 / (combDelays.length * 2),
|
|
702
|
-
});
|
|
701
|
+
const mergerGain = new GainNode(audioContext);
|
|
703
702
|
for (let i = 0; i < combDelays.length; i++) {
|
|
704
703
|
const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
|
|
705
704
|
comb.connect(mergerGain);
|
|
@@ -712,60 +711,62 @@ class Midy {
|
|
|
712
711
|
allpasses.at(-1).connect(output);
|
|
713
712
|
return { input, output };
|
|
714
713
|
}
|
|
715
|
-
createChorusEffect(audioContext
|
|
716
|
-
const
|
|
717
|
-
const lfo = new OscillatorNode(audioContext, { frequency: chorusRate });
|
|
718
|
-
const lfoGain = new GainNode(audioContext, { gain: chorusDepth });
|
|
714
|
+
createChorusEffect(audioContext) {
|
|
715
|
+
const input = new GainNode(audioContext);
|
|
719
716
|
const output = new GainNode(audioContext);
|
|
720
|
-
const
|
|
717
|
+
const sendGain = new GainNode(audioContext);
|
|
718
|
+
const lfo = new OscillatorNode(audioContext, {
|
|
719
|
+
frequency: this.chorus.modRate,
|
|
720
|
+
});
|
|
721
|
+
const lfoGain = new GainNode(audioContext, {
|
|
722
|
+
gain: this.chorus.modDepth / 2,
|
|
723
|
+
});
|
|
724
|
+
const delayTimes = this.chorus.delayTimes;
|
|
721
725
|
const delayNodes = [];
|
|
722
|
-
const
|
|
723
|
-
for (let i = 0; i <
|
|
724
|
-
const
|
|
725
|
-
const delayTime = (i + 1) * delay + randomDelayFactor;
|
|
726
|
+
const feedbackGains = [];
|
|
727
|
+
for (let i = 0; i < delayTimes.length; i++) {
|
|
728
|
+
const delayTime = delayTimes[i];
|
|
726
729
|
const delayNode = new DelayNode(audioContext, {
|
|
727
|
-
maxDelayTime: delayTime
|
|
730
|
+
maxDelayTime: 0.1, // generally, 5ms < delayTime < 50ms
|
|
731
|
+
delayTime,
|
|
732
|
+
});
|
|
733
|
+
const feedbackGain = new GainNode(audioContext, {
|
|
734
|
+
gain: this.chorus.feedback,
|
|
728
735
|
});
|
|
729
|
-
const chorusGain = new GainNode(audioContext, { gain: baseGain });
|
|
730
736
|
delayNodes.push(delayNode);
|
|
731
|
-
|
|
737
|
+
feedbackGains.push(feedbackGain);
|
|
738
|
+
input.connect(delayNode);
|
|
732
739
|
lfoGain.connect(delayNode.delayTime);
|
|
733
|
-
delayNode.connect(
|
|
734
|
-
|
|
740
|
+
delayNode.connect(feedbackGain);
|
|
741
|
+
feedbackGain.connect(delayNode);
|
|
742
|
+
delayNode.connect(output);
|
|
735
743
|
}
|
|
744
|
+
output.connect(sendGain);
|
|
736
745
|
lfo.connect(lfoGain);
|
|
737
746
|
lfo.start();
|
|
738
747
|
return {
|
|
748
|
+
input,
|
|
749
|
+
output,
|
|
750
|
+
sendGain,
|
|
739
751
|
lfo,
|
|
740
752
|
lfoGain,
|
|
741
753
|
delayNodes,
|
|
742
|
-
|
|
743
|
-
output,
|
|
754
|
+
feedbackGains,
|
|
744
755
|
};
|
|
745
756
|
}
|
|
746
757
|
connectEffects(channel, gainNode) {
|
|
747
758
|
gainNode.connect(channel.merger);
|
|
748
759
|
channel.merger.connect(this.masterGain);
|
|
749
|
-
if (channel.reverbSendLevel
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
channel.merger.connect(delayNode);
|
|
753
|
-
});
|
|
754
|
-
channel.chorusEffect.output.connect(this.masterGain);
|
|
755
|
-
}
|
|
760
|
+
if (0 < channel.reverbSendLevel) {
|
|
761
|
+
channel.merger.connect(channel.reverbEffect.input);
|
|
762
|
+
channel.reverbEffect.output.connect(this.masterGain);
|
|
756
763
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
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
|
-
}
|
|
764
|
+
if (0 < channel.chorusSendLevel) {
|
|
765
|
+
channel.merger.connect(channel.chorusEffect.input);
|
|
766
|
+
channel.reverbEffect.output.connect(this.masterGain);
|
|
767
|
+
}
|
|
768
|
+
if (0 < this.chorus.sendToReverb) {
|
|
769
|
+
channel.chorusEffect.sendGain.connect(channel.reverbEffect.input);
|
|
769
770
|
}
|
|
770
771
|
}
|
|
771
772
|
cbToRatio(cb) {
|
|
@@ -1224,9 +1225,12 @@ class Midy {
|
|
|
1224
1225
|
reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
|
|
1225
1226
|
}
|
|
1226
1227
|
setChorusSendLevel(channelNumber, chorusSendLevel) {
|
|
1228
|
+
const now = this.audioContext.currentTime;
|
|
1227
1229
|
const channel = this.channels[channelNumber];
|
|
1230
|
+
const chorusEffect = channel.chorusEffect;
|
|
1228
1231
|
channel.chorusSendLevel = chorusSendLevel / 127;
|
|
1229
|
-
|
|
1232
|
+
chorusEffect.output.gain.cancelScheduledValues(now);
|
|
1233
|
+
chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
|
|
1230
1234
|
}
|
|
1231
1235
|
setSostenutoPedal(channelNumber, value) {
|
|
1232
1236
|
const isOn = value >= 64;
|
|
@@ -1486,7 +1490,7 @@ class Midy {
|
|
|
1486
1490
|
case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
|
|
1487
1491
|
return this.handleMasterCoarseTuningSysEx(data);
|
|
1488
1492
|
case 5:
|
|
1489
|
-
return this.
|
|
1493
|
+
return this.handleGlobalParameterControlSysEx(data);
|
|
1490
1494
|
default:
|
|
1491
1495
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1492
1496
|
}
|
|
@@ -1563,13 +1567,13 @@ class Midy {
|
|
|
1563
1567
|
this.masterCoarseTuning = coarseTuning - 64;
|
|
1564
1568
|
}
|
|
1565
1569
|
}
|
|
1566
|
-
|
|
1567
|
-
if (data[
|
|
1568
|
-
switch (data[
|
|
1570
|
+
handleGlobalParameterControlSysEx(data) {
|
|
1571
|
+
if (data[7] === 1) {
|
|
1572
|
+
switch (data[8]) {
|
|
1569
1573
|
case 1:
|
|
1570
|
-
return this.
|
|
1574
|
+
return this.handleReverbParameterSysEx(data);
|
|
1571
1575
|
case 2:
|
|
1572
|
-
return this.
|
|
1576
|
+
return this.handleChorusParameterSysEx(data);
|
|
1573
1577
|
default:
|
|
1574
1578
|
console.warn(`Unsupported Global Parameter Control Message: ${data}`);
|
|
1575
1579
|
}
|
|
@@ -1578,12 +1582,12 @@ class Midy {
|
|
|
1578
1582
|
console.warn(`Unsupported Global Parameter Control Message: ${data}`);
|
|
1579
1583
|
}
|
|
1580
1584
|
}
|
|
1581
|
-
|
|
1582
|
-
switch (data[
|
|
1585
|
+
handleReverbParameterSysEx(data) {
|
|
1586
|
+
switch (data[9]) {
|
|
1583
1587
|
case 0:
|
|
1584
|
-
return this.setReverbType(data[
|
|
1588
|
+
return this.setReverbType(data[10]);
|
|
1585
1589
|
case 1:
|
|
1586
|
-
return this.setReverbTime(data[
|
|
1590
|
+
return this.setReverbTime(data[10]);
|
|
1587
1591
|
}
|
|
1588
1592
|
}
|
|
1589
1593
|
setReverbType(type) {
|
|
@@ -1643,41 +1647,109 @@ class Midy {
|
|
|
1643
1647
|
// RT60 = -3 * delay / Math.log10(feedback)
|
|
1644
1648
|
// feedback = Math.pow(10, -3 * delay / RT60)
|
|
1645
1649
|
// delay estimation using ideal feedback
|
|
1646
|
-
//
|
|
1647
|
-
//
|
|
1648
|
-
// It
|
|
1650
|
+
// The structure of a concert hall is complex,
|
|
1651
|
+
// so estimates based on mean free path are unstable.
|
|
1652
|
+
// It is easier to determine the delay based on ideal feedback.
|
|
1653
|
+
// The average sound absorption coefficient
|
|
1654
|
+
// suitable for playing musical instruments is 0.18 to 0.28.
|
|
1649
1655
|
// delay = -RT60 * Math.log10(feedback) / 3
|
|
1650
1656
|
calcDelay(rt60, feedback) {
|
|
1651
1657
|
return -rt60 * Math.log10(feedback) / 3;
|
|
1652
1658
|
}
|
|
1653
|
-
|
|
1654
|
-
switch (data[
|
|
1659
|
+
handleChorusParameterSysEx(data) {
|
|
1660
|
+
switch (data[9]) {
|
|
1655
1661
|
case 0:
|
|
1656
|
-
return this.setChorusType(data[
|
|
1662
|
+
return this.setChorusType(data[10]);
|
|
1657
1663
|
case 1:
|
|
1658
|
-
return this.setChorusModRate(data[
|
|
1664
|
+
return this.setChorusModRate(data[10]);
|
|
1659
1665
|
case 2:
|
|
1660
|
-
return this.setChorusModDepth(data[
|
|
1666
|
+
return this.setChorusModDepth(data[10]);
|
|
1661
1667
|
case 3:
|
|
1662
|
-
return this.setChorusFeedback(data[
|
|
1668
|
+
return this.setChorusFeedback(data[10]);
|
|
1663
1669
|
case 4:
|
|
1664
|
-
return this.setChorusSendToReverb(data[
|
|
1670
|
+
return this.setChorusSendToReverb(data[10]);
|
|
1665
1671
|
}
|
|
1666
1672
|
}
|
|
1667
1673
|
setChorusType(type) {
|
|
1668
|
-
|
|
1674
|
+
switch (type) {
|
|
1675
|
+
case 0:
|
|
1676
|
+
return this.setChorusParameter(3, 5, 0, 0);
|
|
1677
|
+
case 1:
|
|
1678
|
+
return this.setChorusParameter(9, 19, 5, 0);
|
|
1679
|
+
case 2:
|
|
1680
|
+
return this.setChorusParameter(3, 19, 8, 0);
|
|
1681
|
+
case 3:
|
|
1682
|
+
return this.setChorusParameter(9, 16, 16, 0);
|
|
1683
|
+
case 4:
|
|
1684
|
+
return this.setChorusParameter(2, 24, 64, 0);
|
|
1685
|
+
case 5:
|
|
1686
|
+
return this.setChorusParameter(1, 5, 112, 0);
|
|
1687
|
+
default:
|
|
1688
|
+
console.warn(`Unsupported Chorus Type: ${type}`);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
setChorusParameter(modRate, modDepth, feedback, sendToReverb) {
|
|
1692
|
+
this.setChorusModRate(modRate);
|
|
1693
|
+
this.setChorusModDepth(modDepth);
|
|
1694
|
+
this.setChorusFeedback(feedback);
|
|
1695
|
+
this.setChorusSendToReverb(sendToReverb);
|
|
1669
1696
|
}
|
|
1670
1697
|
setChorusModRate(value) {
|
|
1671
|
-
|
|
1698
|
+
const now = this.audioContext.currentTime;
|
|
1699
|
+
const modRate = this.getChorusModRate(value);
|
|
1700
|
+
this.chorus.modRate = modRate;
|
|
1701
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1702
|
+
const lfo = this.channels[i].chorusEffect.lfo;
|
|
1703
|
+
lfo.frequency.setValueAtTime(modRate, now);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
getChorusModRate(value) {
|
|
1707
|
+
return value * 0.122; // Hz
|
|
1672
1708
|
}
|
|
1673
1709
|
setChorusModDepth(value) {
|
|
1674
|
-
|
|
1710
|
+
const now = this.audioContext.currentTime;
|
|
1711
|
+
const modDepth = this.getChorusModDepth(value);
|
|
1712
|
+
this.chorus.modDepth = modDepth;
|
|
1713
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1714
|
+
const chorusEffect = this.channels[i].chorusEffect;
|
|
1715
|
+
chorusEffect.lfoGain.gain
|
|
1716
|
+
.cancelScheduledValues(now)
|
|
1717
|
+
.setValueAtTime(modDepth / 2, now);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
getChorusModDepth(value) {
|
|
1721
|
+
return (value + 1) / 3200; // second
|
|
1675
1722
|
}
|
|
1676
1723
|
setChorusFeedback(value) {
|
|
1677
|
-
|
|
1724
|
+
const now = this.audioContext.currentTime;
|
|
1725
|
+
const feedback = this.getChorusFeedback(value);
|
|
1726
|
+
this.chorus.feedback = feedback;
|
|
1727
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1728
|
+
const chorusEffect = this.channels[i].chorusEffect;
|
|
1729
|
+
for (let j = 0; j < chorusEffect.feedbackGains.length; j++) {
|
|
1730
|
+
const feedbackGain = chorusEffect.feedbackGains[j];
|
|
1731
|
+
feedbackGain.gain
|
|
1732
|
+
.cancelScheduledValues(now)
|
|
1733
|
+
.setValueAtTime(feedback, now);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
getChorusFeedback(value) {
|
|
1738
|
+
return value * 0.00763;
|
|
1678
1739
|
}
|
|
1679
1740
|
setChorusSendToReverb(value) {
|
|
1680
|
-
|
|
1741
|
+
const now = this.audioContext.currentTime;
|
|
1742
|
+
const sendToReverb = this.getChorusSendToReverb(value);
|
|
1743
|
+
this.chorus.sendToReverb = sendToReverb;
|
|
1744
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1745
|
+
const chorusEffect = this.channels[i].chorusEffect;
|
|
1746
|
+
chorusEffect.sendGain.gain
|
|
1747
|
+
.cancelScheduledValues(now)
|
|
1748
|
+
.setValueAtTime(sendToReverb, now);
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
getChorusSendToReverb(value) {
|
|
1752
|
+
return value * 0.00787;
|
|
1681
1753
|
}
|
|
1682
1754
|
handleExclusiveMessage(data) {
|
|
1683
1755
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|