@marmooo/midy 0.0.9 → 0.1.0
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 +0 -2
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +5 -9
- package/esm/midy-GM2.d.ts +31 -19
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +193 -56
- package/esm/midy-GMLite.js +5 -5
- package/esm/midy.d.ts +31 -19
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +193 -56
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +0 -2
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +5 -9
- package/script/midy-GM2.d.ts +31 -19
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +193 -56
- package/script/midy-GMLite.js +5 -5
- package/script/midy.d.ts +31 -19
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +193 -56
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":"AAuBA;IAiCE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAOC;IAjHD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;MAKE;IACF,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IA8ClB;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;MAkBC;IAED,yCAiBC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAyDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgGC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MAiCC;IAED;;;;;;MAoCC;IAED,kDAsBC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,uDAcC;IAED,wHAqCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAiDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,mFAkEC;IAED,+CAEC;IAED,qCAcC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAGD,oDAEC;IAED,mEAOC;IAED,mEAIC;IAED,wDAWC;IAED,uDAGC;IAED,2DAGC;IAED,6DAGC;IAED,6DASC;IAED,kFAeC;IAED,2DAMC;IAED,gDAyBC;IAED,wCAEC;IAED,wCAEC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAUC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,wDAKC;IAED,6EAKC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAiDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,8CAeC;IAED,uCAOC;IAED,+BAOC;IAED,qDAiBC;IAED,gCAMC;IAED,kCAEC;IA2BD,4CAEC;IAED,uCAaC;IAED,+BAEC;IAED,mCAEC;IAED,oCAEC;IAED,oCAEC;IAED,wCAEC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA/xDD;IASE,gFAKC;IAbD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|
package/script/midy.js
CHANGED
|
@@ -67,12 +67,6 @@ class Midy {
|
|
|
67
67
|
writable: true,
|
|
68
68
|
value: 0
|
|
69
69
|
});
|
|
70
|
-
Object.defineProperty(this, "reverbFactor", {
|
|
71
|
-
enumerable: true,
|
|
72
|
-
configurable: true,
|
|
73
|
-
writable: true,
|
|
74
|
-
value: 0.1
|
|
75
|
-
});
|
|
76
70
|
Object.defineProperty(this, "masterFineTuning", {
|
|
77
71
|
enumerable: true,
|
|
78
72
|
configurable: true,
|
|
@@ -85,6 +79,26 @@ class Midy {
|
|
|
85
79
|
writable: true,
|
|
86
80
|
value: 0
|
|
87
81
|
}); // cb
|
|
82
|
+
Object.defineProperty(this, "reverb", {
|
|
83
|
+
enumerable: true,
|
|
84
|
+
configurable: true,
|
|
85
|
+
writable: true,
|
|
86
|
+
value: {
|
|
87
|
+
time: this.getReverbTime(64),
|
|
88
|
+
feedback: 0.2,
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
Object.defineProperty(this, "chorus", {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
configurable: true,
|
|
94
|
+
writable: true,
|
|
95
|
+
value: {
|
|
96
|
+
modRate: 3 * 0.122,
|
|
97
|
+
modDepth: (3 + 1) / 3.2,
|
|
98
|
+
feedback: 8 * 0.763,
|
|
99
|
+
sendToReverb: 0 * 0.787,
|
|
100
|
+
}
|
|
101
|
+
});
|
|
88
102
|
Object.defineProperty(this, "mono", {
|
|
89
103
|
enumerable: true,
|
|
90
104
|
configurable: true,
|
|
@@ -193,8 +207,19 @@ class Midy {
|
|
|
193
207
|
writable: true,
|
|
194
208
|
value: {
|
|
195
209
|
reverbAlgorithm: (audioContext) => {
|
|
196
|
-
|
|
197
|
-
|
|
210
|
+
const { time: rt60, feedback } = this.reverb;
|
|
211
|
+
// const delay = this.calcDelay(rt60, feedback);
|
|
212
|
+
// const impulse = this.createConvolutionReverbImpulse(
|
|
213
|
+
// audioContext,
|
|
214
|
+
// rt60,
|
|
215
|
+
// delay,
|
|
216
|
+
// );
|
|
217
|
+
// return this.createConvolutionReverb(audioContext, impulse);
|
|
218
|
+
const combFeedbacks = this.generateDistributedArray(feedback, 4);
|
|
219
|
+
const combDelays = combFeedbacks.map((feedback) => this.calcDelay(rt60, feedback));
|
|
220
|
+
const allpassFeedbacks = this.generateDistributedArray(feedback, 4);
|
|
221
|
+
const allpassDelays = allpassFeedbacks.map((feedback) => this.calcDelay(rt60, feedback));
|
|
222
|
+
return this.createSchroederReverb(audioContext, combFeedbacks, combDelays, allpassFeedbacks, allpassDelays);
|
|
198
223
|
},
|
|
199
224
|
}
|
|
200
225
|
});
|
|
@@ -599,12 +624,7 @@ class Midy {
|
|
|
599
624
|
}
|
|
600
625
|
return noteList[0];
|
|
601
626
|
}
|
|
602
|
-
|
|
603
|
-
const { decay = 0.8, preDecay = 0, } = options;
|
|
604
|
-
const input = new GainNode(audioContext);
|
|
605
|
-
const output = new GainNode(audioContext);
|
|
606
|
-
const dryGain = new GainNode(audioContext);
|
|
607
|
-
const wetGain = new GainNode(audioContext);
|
|
627
|
+
createConvolutionReverbImpulse(audioContext, decay, preDecay) {
|
|
608
628
|
const sampleRate = audioContext.sampleRate;
|
|
609
629
|
const length = sampleRate * decay;
|
|
610
630
|
const impulse = new AudioBuffer({
|
|
@@ -624,18 +644,17 @@ class Midy {
|
|
|
624
644
|
channelData[i] = (Math.random() * 2 - 1) * attenuation;
|
|
625
645
|
}
|
|
626
646
|
}
|
|
647
|
+
return impulse;
|
|
648
|
+
}
|
|
649
|
+
createConvolutionReverb(audioContext, impulse) {
|
|
650
|
+
const output = new GainNode(audioContext);
|
|
627
651
|
const convolverNode = new ConvolverNode(audioContext, {
|
|
628
652
|
buffer: impulse,
|
|
629
653
|
});
|
|
630
|
-
|
|
631
|
-
convolverNode.connect(wetGain);
|
|
632
|
-
wetGain.connect(output);
|
|
633
|
-
dryGain.connect(output);
|
|
654
|
+
convolverNode.connect(output);
|
|
634
655
|
return {
|
|
635
|
-
input,
|
|
656
|
+
input: convolverNode,
|
|
636
657
|
output,
|
|
637
|
-
dryGain,
|
|
638
|
-
wetGain,
|
|
639
658
|
convolverNode,
|
|
640
659
|
};
|
|
641
660
|
}
|
|
@@ -663,17 +682,24 @@ class Midy {
|
|
|
663
682
|
delayNode.connect(passGain);
|
|
664
683
|
return passGain;
|
|
665
684
|
}
|
|
685
|
+
generateDistributedArray(center, count, varianceRatio = 0.1, randomness = 0.05) {
|
|
686
|
+
const variance = center * varianceRatio;
|
|
687
|
+
const array = new Array(count);
|
|
688
|
+
for (let i = 0; i < count; i++) {
|
|
689
|
+
const fraction = i / (count - 1 || 1);
|
|
690
|
+
const value = center - variance + fraction * 2 * variance;
|
|
691
|
+
array[i] = value * (1 - (Math.random() * 2 - 1) * randomness);
|
|
692
|
+
}
|
|
693
|
+
return array;
|
|
694
|
+
}
|
|
666
695
|
// https://hajim.rochester.edu/ece/sites/zduan/teaching/ece472/reading/Schroeder_1962.pdf
|
|
667
696
|
// M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
|
|
668
|
-
createSchroederReverb(audioContext,
|
|
669
|
-
const { combDelays = [0.31, 0.34, 0.37, 0.40], combFeedbacks = [0.86, 0.87, 0.88, 0.89], allpassDelays = [0.02, 0.05], allpassFeedbacks = [0.7, 0.7], mix = 0.5, } = options;
|
|
697
|
+
createSchroederReverb(audioContext, combDelays, combFeedbacks, allpassDelays, allpassFeedbacks) {
|
|
670
698
|
const input = new GainNode(audioContext);
|
|
671
699
|
const output = new GainNode(audioContext);
|
|
672
700
|
const mergerGain = new GainNode(audioContext, {
|
|
673
701
|
gain: 1 / (combDelays.length * 2),
|
|
674
702
|
});
|
|
675
|
-
const dryGain = new GainNode(audioContext, { gain: 1 - mix });
|
|
676
|
-
const wetGain = new GainNode(audioContext, { gain: mix });
|
|
677
703
|
for (let i = 0; i < combDelays.length; i++) {
|
|
678
704
|
const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
|
|
679
705
|
comb.connect(mergerGain);
|
|
@@ -683,11 +709,8 @@ class Midy {
|
|
|
683
709
|
const allpass = this.createAllpassFilter(audioContext, (i === 0) ? mergerGain : allpasses.at(-1), allpassDelays[i], allpassFeedbacks[i]);
|
|
684
710
|
allpasses.push(allpass);
|
|
685
711
|
}
|
|
686
|
-
allpasses.at(-1).connect(
|
|
687
|
-
input
|
|
688
|
-
dryGain.connect(output);
|
|
689
|
-
wetGain.connect(output);
|
|
690
|
-
return { input, output, dryGain, wetGain };
|
|
712
|
+
allpasses.at(-1).connect(output);
|
|
713
|
+
return { input, output };
|
|
691
714
|
}
|
|
692
715
|
createChorusEffect(audioContext, options = {}) {
|
|
693
716
|
const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
|
|
@@ -722,11 +745,9 @@ class Midy {
|
|
|
722
745
|
}
|
|
723
746
|
connectEffects(channel, gainNode) {
|
|
724
747
|
gainNode.connect(channel.merger);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
else { // chorus
|
|
748
|
+
channel.merger.connect(this.masterGain);
|
|
749
|
+
if (channel.reverbSendLevel === 0) {
|
|
750
|
+
if (channel.chorusSendLevel !== 0) { // chorus
|
|
730
751
|
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
731
752
|
channel.merger.connect(delayNode);
|
|
732
753
|
});
|
|
@@ -734,7 +755,7 @@ class Midy {
|
|
|
734
755
|
}
|
|
735
756
|
}
|
|
736
757
|
else {
|
|
737
|
-
if (channel.
|
|
758
|
+
if (channel.chorusSendLevel === 0) { // reverb
|
|
738
759
|
channel.merger.connect(channel.reverbEffect.input);
|
|
739
760
|
channel.reverbEffect.output.connect(this.masterGain);
|
|
740
761
|
}
|
|
@@ -1190,23 +1211,22 @@ class Midy {
|
|
|
1190
1211
|
this.releaseSustainPedal(channelNumber, value);
|
|
1191
1212
|
}
|
|
1192
1213
|
}
|
|
1214
|
+
// TODO
|
|
1193
1215
|
setPortamento(channelNumber, value) {
|
|
1194
1216
|
this.channels[channelNumber].portamento = value >= 64;
|
|
1195
1217
|
}
|
|
1196
|
-
setReverbSendLevel(channelNumber,
|
|
1218
|
+
setReverbSendLevel(channelNumber, reverbSendLevel) {
|
|
1197
1219
|
const now = this.audioContext.currentTime;
|
|
1198
1220
|
const channel = this.channels[channelNumber];
|
|
1199
1221
|
const reverbEffect = channel.reverbEffect;
|
|
1200
|
-
channel.
|
|
1201
|
-
reverbEffect.
|
|
1202
|
-
reverbEffect.
|
|
1203
|
-
reverbEffect.wetGain.gain.cancelScheduledValues(now);
|
|
1204
|
-
reverbEffect.wetGain.gain.setValueAtTime(channel.reverb, now);
|
|
1222
|
+
channel.reverbSendLevel = reverbSendLevel / 127;
|
|
1223
|
+
reverbEffect.output.gain.cancelScheduledValues(now);
|
|
1224
|
+
reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
|
|
1205
1225
|
}
|
|
1206
|
-
setChorusSendLevel(channelNumber,
|
|
1226
|
+
setChorusSendLevel(channelNumber, chorusSendLevel) {
|
|
1207
1227
|
const channel = this.channels[channelNumber];
|
|
1208
|
-
channel.
|
|
1209
|
-
channel.chorusEffect.lfoGain = channel.
|
|
1228
|
+
channel.chorusSendLevel = chorusSendLevel / 127;
|
|
1229
|
+
channel.chorusEffect.lfoGain = channel.chorusSendLevel;
|
|
1210
1230
|
}
|
|
1211
1231
|
setSostenutoPedal(channelNumber, value) {
|
|
1212
1232
|
const isOn = value >= 64;
|
|
@@ -1430,11 +1450,11 @@ class Midy {
|
|
|
1430
1450
|
this.GM2SystemOn();
|
|
1431
1451
|
break;
|
|
1432
1452
|
default:
|
|
1433
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1453
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1434
1454
|
}
|
|
1435
1455
|
break;
|
|
1436
1456
|
default:
|
|
1437
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1457
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1438
1458
|
}
|
|
1439
1459
|
}
|
|
1440
1460
|
GM1SystemOn() {
|
|
@@ -1465,9 +1485,10 @@ class Midy {
|
|
|
1465
1485
|
return this.handleMasterFineTuningSysEx(data);
|
|
1466
1486
|
case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
|
|
1467
1487
|
return this.handleMasterCoarseTuningSysEx(data);
|
|
1468
|
-
|
|
1488
|
+
case 5:
|
|
1489
|
+
return this.handleGlobalParameterControl(data);
|
|
1469
1490
|
default:
|
|
1470
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1491
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1471
1492
|
}
|
|
1472
1493
|
break;
|
|
1473
1494
|
case 8:
|
|
@@ -1476,7 +1497,7 @@ class Midy {
|
|
|
1476
1497
|
// // TODO
|
|
1477
1498
|
// return this.handleScaleOctaveTuning1ByteFormat();
|
|
1478
1499
|
default:
|
|
1479
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1500
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1480
1501
|
}
|
|
1481
1502
|
break;
|
|
1482
1503
|
case 9:
|
|
@@ -1488,7 +1509,7 @@ class Midy {
|
|
|
1488
1509
|
// // TODO
|
|
1489
1510
|
// return this.setControlChange();
|
|
1490
1511
|
default:
|
|
1491
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1512
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1492
1513
|
}
|
|
1493
1514
|
break;
|
|
1494
1515
|
case 10:
|
|
@@ -1497,11 +1518,11 @@ class Midy {
|
|
|
1497
1518
|
// // TODO
|
|
1498
1519
|
// return this.handleKeyBasedInstrumentControl();
|
|
1499
1520
|
default:
|
|
1500
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1521
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1501
1522
|
}
|
|
1502
1523
|
break;
|
|
1503
1524
|
default:
|
|
1504
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1525
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1505
1526
|
}
|
|
1506
1527
|
}
|
|
1507
1528
|
handleMasterVolumeSysEx(data) {
|
|
@@ -1542,8 +1563,124 @@ class Midy {
|
|
|
1542
1563
|
this.masterCoarseTuning = coarseTuning - 64;
|
|
1543
1564
|
}
|
|
1544
1565
|
}
|
|
1566
|
+
handleGlobalParameterControl(data) {
|
|
1567
|
+
if (data[5] === 1) {
|
|
1568
|
+
switch (data[6]) {
|
|
1569
|
+
case 1:
|
|
1570
|
+
return this.handleReverbParameter(data);
|
|
1571
|
+
case 2:
|
|
1572
|
+
return this.handleChorusParameter(data);
|
|
1573
|
+
default:
|
|
1574
|
+
console.warn(`Unsupported Global Parameter Control Message: ${data}`);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
else {
|
|
1578
|
+
console.warn(`Unsupported Global Parameter Control Message: ${data}`);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
handleReverbParameter(data) {
|
|
1582
|
+
switch (data[7]) {
|
|
1583
|
+
case 0:
|
|
1584
|
+
return this.setReverbType(data[8]);
|
|
1585
|
+
case 1:
|
|
1586
|
+
return this.setReverbTime(data[8]);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
setReverbType(type) {
|
|
1590
|
+
this.reverb.time = this.getReverbTimeFromType(type);
|
|
1591
|
+
this.reverb.feedback = (type === 8) ? 0.1 : 0.2;
|
|
1592
|
+
const { audioContext, channels, options } = this;
|
|
1593
|
+
for (let i = 0; i < channels.length; i++) {
|
|
1594
|
+
channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
getReverbTimeFromType(type) {
|
|
1598
|
+
switch (type) {
|
|
1599
|
+
case 0:
|
|
1600
|
+
return this.getReverbTime(44);
|
|
1601
|
+
case 1:
|
|
1602
|
+
return this.getReverbTime(50);
|
|
1603
|
+
case 2:
|
|
1604
|
+
return this.getReverbTime(56);
|
|
1605
|
+
case 3:
|
|
1606
|
+
return this.getReverbTime(64);
|
|
1607
|
+
case 4:
|
|
1608
|
+
return this.getReverbTime(64);
|
|
1609
|
+
case 8:
|
|
1610
|
+
return this.getReverbTime(50);
|
|
1611
|
+
default:
|
|
1612
|
+
console.warn(`Unsupported Reverb Time: ${type}`);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
setReverbTime(value) {
|
|
1616
|
+
this.reverb.time = this.getReverbTime(value);
|
|
1617
|
+
const { audioContext, channels, options } = this;
|
|
1618
|
+
for (let i = 0; i < channels.length; i++) {
|
|
1619
|
+
channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
getReverbTime(value) {
|
|
1623
|
+
return Math.pow(Math.E, (value - 40) * 0.025);
|
|
1624
|
+
}
|
|
1625
|
+
// mean free path equation
|
|
1626
|
+
// https://repository.dl.itc.u-tokyo.ac.jp/record/8550/files/A31912.pdf
|
|
1627
|
+
// 江田和司, 拡散性制御に基づく室内音響設計に向けた音場解析に関する研究, 2015
|
|
1628
|
+
// V: room size (m^3)
|
|
1629
|
+
// S: room surface area (m^2)
|
|
1630
|
+
// meanFreePath = 4V / S (m)
|
|
1631
|
+
// delay estimation using mean free path
|
|
1632
|
+
// t: degree Celsius, generally used 20
|
|
1633
|
+
// c: speed of sound = 331.5 + 0.61t = 331.5 * 0.61 * 20 = 343.7 (m/s)
|
|
1634
|
+
// delay = meanFreePath / c (s)
|
|
1635
|
+
// feedback equation
|
|
1636
|
+
// RT60 means that the energy is reduced to Math.pow(10, -6).
|
|
1637
|
+
// Since energy is proportional to the square of the amplitude,
|
|
1638
|
+
// the amplitude is reduced to Math.pow(10, -3).
|
|
1639
|
+
// When this is done through n feedbacks,
|
|
1640
|
+
// Math.pow(feedback, n) = Math.pow(10, -3)
|
|
1641
|
+
// Math.pow(feedback, RT60 / delay) = Math.pow(10, -3)
|
|
1642
|
+
// RT60 / delay * Math.log10(feedback) = -3
|
|
1643
|
+
// RT60 = -3 * delay / Math.log10(feedback)
|
|
1644
|
+
// feedback = Math.pow(10, -3 * delay / RT60)
|
|
1645
|
+
// delay estimation using ideal feedback
|
|
1646
|
+
// A suitable average sound absorption coefficient is 0.18-0.28.
|
|
1647
|
+
// Since the structure of the hall is complex,
|
|
1648
|
+
// It would be easier to determine the delay based on the ideal feedback.
|
|
1649
|
+
// delay = -RT60 * Math.log10(feedback) / 3
|
|
1650
|
+
calcDelay(rt60, feedback) {
|
|
1651
|
+
return -rt60 * Math.log10(feedback) / 3;
|
|
1652
|
+
}
|
|
1653
|
+
handleChorusParameter(data) {
|
|
1654
|
+
switch (data[7]) {
|
|
1655
|
+
case 0:
|
|
1656
|
+
return this.setChorusType(data[8]);
|
|
1657
|
+
case 1:
|
|
1658
|
+
return this.setChorusModRate(data[8]);
|
|
1659
|
+
case 2:
|
|
1660
|
+
return this.setChorusModDepth(data[8]);
|
|
1661
|
+
case 3:
|
|
1662
|
+
return this.setChorusFeedback(data[8]);
|
|
1663
|
+
case 4:
|
|
1664
|
+
return this.setChorusSendToReverb(data[8]);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
setChorusType(type) {
|
|
1668
|
+
// TODO
|
|
1669
|
+
}
|
|
1670
|
+
setChorusModRate(value) {
|
|
1671
|
+
// TODO
|
|
1672
|
+
}
|
|
1673
|
+
setChorusModDepth(value) {
|
|
1674
|
+
// TODO
|
|
1675
|
+
}
|
|
1676
|
+
setChorusFeedback(value) {
|
|
1677
|
+
// TODO
|
|
1678
|
+
}
|
|
1679
|
+
setChorusSendToReverb(value) {
|
|
1680
|
+
// TODO
|
|
1681
|
+
}
|
|
1545
1682
|
handleExclusiveMessage(data) {
|
|
1546
|
-
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1683
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1547
1684
|
}
|
|
1548
1685
|
handleSysEx(data) {
|
|
1549
1686
|
switch (data[0]) {
|
|
@@ -1577,8 +1714,8 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
1577
1714
|
volume: 100 / 127,
|
|
1578
1715
|
pan: 64,
|
|
1579
1716
|
portamentoTime: 0,
|
|
1580
|
-
|
|
1581
|
-
|
|
1717
|
+
reverbSendLevel: 0,
|
|
1718
|
+
chorusSendLevel: 0,
|
|
1582
1719
|
vibratoRate: 5,
|
|
1583
1720
|
vibratoDepth: 0.5,
|
|
1584
1721
|
vibratoDelay: 2.5,
|