@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.
@@ -4,8 +4,8 @@ export class MidyGM2 {
4
4
  volume: number;
5
5
  pan: number;
6
6
  portamentoTime: number;
7
- reverb: number;
8
- chorus: number;
7
+ reverbSendLevel: number;
8
+ chorusSendLevel: number;
9
9
  bank: number;
10
10
  bankMSB: number;
11
11
  bankLSB: number;
@@ -41,15 +41,22 @@ export class MidyGM2 {
41
41
  reverbAlgorithm: (audioContext: any) => {
42
42
  input: any;
43
43
  output: any;
44
- dryGain: any;
45
- wetGain: any;
46
44
  };
47
45
  });
48
46
  ticksPerBeat: number;
49
47
  totalTime: number;
50
- reverbFactor: number;
51
48
  masterFineTuning: number;
52
49
  masterCoarseTuning: number;
50
+ reverb: {
51
+ time: number;
52
+ feedback: number;
53
+ };
54
+ chorus: {
55
+ modRate: number;
56
+ modDepth: number;
57
+ feedback: number;
58
+ sendToReverb: number;
59
+ };
53
60
  mono: boolean;
54
61
  omni: boolean;
55
62
  noteCheckInterval: number;
@@ -71,8 +78,6 @@ export class MidyGM2 {
71
78
  reverbAlgorithm: (audioContext: any) => {
72
79
  input: any;
73
80
  output: any;
74
- dryGain: any;
75
- wetGain: any;
76
81
  };
77
82
  };
78
83
  audioContext: any;
@@ -80,8 +85,6 @@ export class MidyGM2 {
80
85
  reverbAlgorithm: (audioContext: any) => {
81
86
  input: any;
82
87
  output: any;
83
- dryGain: any;
84
- wetGain: any;
85
88
  };
86
89
  };
87
90
  masterGain: any;
@@ -97,8 +100,6 @@ export class MidyGM2 {
97
100
  reverbEffect: {
98
101
  input: any;
99
102
  output: any;
100
- dryGain: any;
101
- wetGain: any;
102
103
  };
103
104
  chorusEffect: {
104
105
  lfo: any;
@@ -131,20 +132,18 @@ export class MidyGM2 {
131
132
  currentTime(): number;
132
133
  getActiveNotes(channel: any, time: any): Map<any, any>;
133
134
  getActiveNote(noteList: any, time: any): any;
134
- createConvolutionReverb(audioContext: any, options?: {}): {
135
+ createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
136
+ createConvolutionReverb(audioContext: any, impulse: any): {
135
137
  input: any;
136
138
  output: any;
137
- dryGain: any;
138
- wetGain: any;
139
139
  convolverNode: any;
140
140
  };
141
141
  createCombFilter(audioContext: any, input: any, delay: any, feedback: any): any;
142
142
  createAllpassFilter(audioContext: any, input: any, delay: any, feedback: any): any;
143
- createSchroederReverb(audioContext: any, options?: {}): {
143
+ generateDistributedArray(center: any, count: any, varianceRatio?: number, randomness?: number): any[];
144
+ createSchroederReverb(audioContext: any, combDelays: any, combFeedbacks: any, allpassDelays: any, allpassFeedbacks: any): {
144
145
  input: any;
145
146
  output: any;
146
- dryGain: any;
147
- wetGain: any;
148
147
  };
149
148
  createChorusEffect(audioContext: any, options?: {}): {
150
149
  lfo: any;
@@ -191,8 +190,8 @@ export class MidyGM2 {
191
190
  updateChannelGain(channel: any): void;
192
191
  setSustainPedal(channelNumber: any, value: any): void;
193
192
  setPortamento(channelNumber: any, value: any): void;
194
- setReverbSendLevel(channelNumber: any, reverb: any): void;
195
- setChorusSendLevel(channelNumber: any, chorus: any): void;
193
+ setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
194
+ setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
196
195
  setSostenutoPedal(channelNumber: any, value: any): void;
197
196
  setSoftPedal(channelNumber: any, softPedal: any): void;
198
197
  limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
@@ -227,6 +226,19 @@ export class MidyGM2 {
227
226
  setMasterFineTuning(fineTuning: any): void;
228
227
  handleMasterCoarseTuningSysEx(data: any): void;
229
228
  setMasterCoarseTuning(coarseTuning: any): void;
229
+ handleGlobalParameterControl(data: any): void;
230
+ handleReverbParameter(data: any): void;
231
+ setReverbType(type: any): void;
232
+ getReverbTimeFromType(type: any): number | undefined;
233
+ setReverbTime(value: any): void;
234
+ getReverbTime(value: any): number;
235
+ calcDelay(rt60: any, feedback: any): number;
236
+ handleChorusParameter(data: any): void;
237
+ setChorusType(type: any): void;
238
+ setChorusModRate(value: any): void;
239
+ setChorusModDepth(value: any): void;
240
+ setChorusFeedback(value: any): void;
241
+ setChorusSendToReverb(value: any): void;
230
242
  handleExclusiveMessage(data: any): void;
231
243
  handleSysEx(data: any): void;
232
244
  scheduleTask(callback: any, startTime: any): Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;MAiBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IASF;;;;;;;OAOC;IA9ED,qBAAmB;IACnB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IA2ClB;;;;;;;MAKE;IAGA,kBAAgC;IAChC;;;;;;;MAAqD;IACrD,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAkBC;IAED,yCAcC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAkDC;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;;;;;;MA4CC;IAED,gFAUC;IAED,mFAYC;IAID;;;;;MAuCC;IAED;;;;;;MAoCC;IAED,kDAuBC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHAiCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAiDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,mFAuDC;IAED,+CAEC;IAED,qCAcC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,oDAEC;IAED,0DASC;IAED,0DAIC;IAED,wDAWC;IAED,uDAGC;IAED,kFAeC;IAED,2DAMC;IAED,oCAqBC;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,yDAgDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA7hDD;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"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAuBA;IAiCE;;;;;;;;;;;;;;;;;MAiBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAOC;IA9GD,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;IA2ClB;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;MAkBC;IAED,yCAcC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAkDC;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,wHAiCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAiDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,mFAuDC;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,kFAeC;IAED,2DAMC;IAED,oCAqBC;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;AAhsDD;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"}
@@ -67,12 +67,6 @@ class MidyGM2 {
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 MidyGM2 {
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 MidyGM2 {
193
207
  writable: true,
194
208
  value: {
195
209
  reverbAlgorithm: (audioContext) => {
196
- // return this.createConvolutionReverb(audioContext);
197
- return this.createSchroederReverb(audioContext);
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
  });
@@ -593,12 +618,7 @@ class MidyGM2 {
593
618
  }
594
619
  return noteList[0];
595
620
  }
596
- createConvolutionReverb(audioContext, options = {}) {
597
- const { decay = 0.8, preDecay = 0, } = options;
598
- const input = new GainNode(audioContext);
599
- const output = new GainNode(audioContext);
600
- const dryGain = new GainNode(audioContext);
601
- const wetGain = new GainNode(audioContext);
621
+ createConvolutionReverbImpulse(audioContext, decay, preDecay) {
602
622
  const sampleRate = audioContext.sampleRate;
603
623
  const length = sampleRate * decay;
604
624
  const impulse = new AudioBuffer({
@@ -618,18 +638,17 @@ class MidyGM2 {
618
638
  channelData[i] = (Math.random() * 2 - 1) * attenuation;
619
639
  }
620
640
  }
641
+ return impulse;
642
+ }
643
+ createConvolutionReverb(audioContext, impulse) {
644
+ const output = new GainNode(audioContext);
621
645
  const convolverNode = new ConvolverNode(audioContext, {
622
646
  buffer: impulse,
623
647
  });
624
- input.connect(convolverNode);
625
- convolverNode.connect(wetGain);
626
- wetGain.connect(output);
627
- dryGain.connect(output);
648
+ convolverNode.connect(output);
628
649
  return {
629
- input,
650
+ input: convolverNode,
630
651
  output,
631
- dryGain,
632
- wetGain,
633
652
  convolverNode,
634
653
  };
635
654
  }
@@ -657,17 +676,24 @@ class MidyGM2 {
657
676
  delayNode.connect(passGain);
658
677
  return passGain;
659
678
  }
679
+ generateDistributedArray(center, count, varianceRatio = 0.1, randomness = 0.05) {
680
+ const variance = center * varianceRatio;
681
+ const array = new Array(count);
682
+ for (let i = 0; i < count; i++) {
683
+ const fraction = i / (count - 1 || 1);
684
+ const value = center - variance + fraction * 2 * variance;
685
+ array[i] = value * (1 - (Math.random() * 2 - 1) * randomness);
686
+ }
687
+ return array;
688
+ }
660
689
  // https://hajim.rochester.edu/ece/sites/zduan/teaching/ece472/reading/Schroeder_1962.pdf
661
690
  // M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
662
- createSchroederReverb(audioContext, options = {}) {
663
- 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;
691
+ createSchroederReverb(audioContext, combDelays, combFeedbacks, allpassDelays, allpassFeedbacks) {
664
692
  const input = new GainNode(audioContext);
665
693
  const output = new GainNode(audioContext);
666
694
  const mergerGain = new GainNode(audioContext, {
667
695
  gain: 1 / (combDelays.length * 2),
668
696
  });
669
- const dryGain = new GainNode(audioContext, { gain: 1 - mix });
670
- const wetGain = new GainNode(audioContext, { gain: mix });
671
697
  for (let i = 0; i < combDelays.length; i++) {
672
698
  const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
673
699
  comb.connect(mergerGain);
@@ -677,11 +703,8 @@ class MidyGM2 {
677
703
  const allpass = this.createAllpassFilter(audioContext, (i === 0) ? mergerGain : allpasses.at(-1), allpassDelays[i], allpassFeedbacks[i]);
678
704
  allpasses.push(allpass);
679
705
  }
680
- allpasses.at(-1).connect(wetGain);
681
- input.connect(dryGain);
682
- dryGain.connect(output);
683
- wetGain.connect(output);
684
- return { input, output, dryGain, wetGain };
706
+ allpasses.at(-1).connect(output);
707
+ return { input, output };
685
708
  }
686
709
  createChorusEffect(audioContext, options = {}) {
687
710
  const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
@@ -716,11 +739,9 @@ class MidyGM2 {
716
739
  }
717
740
  connectEffects(channel, gainNode) {
718
741
  gainNode.connect(channel.merger);
719
- if (channel.reverb === 0) {
720
- if (channel.chorus === 0) { // no effect
721
- channel.merger.connect(this.masterGain);
722
- }
723
- else { // chorus
742
+ channel.merger.connect(this.masterGain);
743
+ if (channel.reverbSendLevel === 0) {
744
+ if (channel.chorusSendLevel !== 0) { // chorus
724
745
  channel.chorusEffect.delayNodes.forEach((delayNode) => {
725
746
  channel.merger.connect(delayNode);
726
747
  });
@@ -728,7 +749,7 @@ class MidyGM2 {
728
749
  }
729
750
  }
730
751
  else {
731
- if (channel.chorus === 0) { // reverb
752
+ if (channel.chorusSendLevel === 0) { // reverb
732
753
  channel.merger.connect(channel.reverbEffect.input);
733
754
  channel.reverbEffect.output.connect(this.masterGain);
734
755
  }
@@ -1139,23 +1160,22 @@ class MidyGM2 {
1139
1160
  this.releaseSustainPedal(channelNumber, value);
1140
1161
  }
1141
1162
  }
1163
+ // TODO
1142
1164
  setPortamento(channelNumber, value) {
1143
1165
  this.channels[channelNumber].portamento = value >= 64;
1144
1166
  }
1145
- setReverbSendLevel(channelNumber, reverb) {
1167
+ setReverbSendLevel(channelNumber, reverbSendLevel) {
1146
1168
  const now = this.audioContext.currentTime;
1147
1169
  const channel = this.channels[channelNumber];
1148
1170
  const reverbEffect = channel.reverbEffect;
1149
- channel.reverb = reverb / 127 * this.reverbFactor;
1150
- reverbEffect.dryGain.gain.cancelScheduledValues(now);
1151
- reverbEffect.dryGain.gain.setValueAtTime(1 - channel.reverb, now);
1152
- reverbEffect.wetGain.gain.cancelScheduledValues(now);
1153
- reverbEffect.wetGain.gain.setValueAtTime(channel.reverb, now);
1171
+ channel.reverbSendLevel = reverbSendLevel / 127;
1172
+ reverbEffect.output.gain.cancelScheduledValues(now);
1173
+ reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1154
1174
  }
1155
- setChorusSendLevel(channelNumber, chorus) {
1175
+ setChorusSendLevel(channelNumber, chorusSendLevel) {
1156
1176
  const channel = this.channels[channelNumber];
1157
- channel.chorus = chorus / 127;
1158
- channel.chorusEffect.lfoGain = channel.chorus;
1177
+ channel.chorusSendLevel = chorusSendLevel / 127;
1178
+ channel.chorusEffect.lfoGain = channel.chorusSendLevel;
1159
1179
  }
1160
1180
  setSostenutoPedal(channelNumber, value) {
1161
1181
  const isOn = value >= 64;
@@ -1351,11 +1371,11 @@ class MidyGM2 {
1351
1371
  this.GM2SystemOn();
1352
1372
  break;
1353
1373
  default:
1354
- console.warn(`Unsupported Exclusive Message ${data}`);
1374
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1355
1375
  }
1356
1376
  break;
1357
1377
  default:
1358
- console.warn(`Unsupported Exclusive Message ${data}`);
1378
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1359
1379
  }
1360
1380
  }
1361
1381
  GM1SystemOn() {
@@ -1386,9 +1406,10 @@ class MidyGM2 {
1386
1406
  return this.handleMasterFineTuningSysEx(data);
1387
1407
  case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
1388
1408
  return this.handleMasterCoarseTuningSysEx(data);
1389
- // case 5: // TODO: Global Parameter Control
1409
+ case 5:
1410
+ return this.handleGlobalParameterControl(data);
1390
1411
  default:
1391
- console.warn(`Unsupported Exclusive Message ${data}`);
1412
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1392
1413
  }
1393
1414
  break;
1394
1415
  case 8:
@@ -1397,7 +1418,7 @@ class MidyGM2 {
1397
1418
  // // TODO
1398
1419
  // return this.handleScaleOctaveTuning1ByteFormat();
1399
1420
  default:
1400
- console.warn(`Unsupported Exclusive Message ${data}`);
1421
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1401
1422
  }
1402
1423
  break;
1403
1424
  case 9:
@@ -1409,7 +1430,7 @@ class MidyGM2 {
1409
1430
  // // TODO
1410
1431
  // return this.setControlChange();
1411
1432
  default:
1412
- console.warn(`Unsupported Exclusive Message ${data}`);
1433
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1413
1434
  }
1414
1435
  break;
1415
1436
  case 10:
@@ -1418,11 +1439,11 @@ class MidyGM2 {
1418
1439
  // // TODO
1419
1440
  // return this.handleKeyBasedInstrumentControl();
1420
1441
  default:
1421
- console.warn(`Unsupported Exclusive Message ${data}`);
1442
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1422
1443
  }
1423
1444
  break;
1424
1445
  default:
1425
- console.warn(`Unsupported Exclusive Message ${data}`);
1446
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1426
1447
  }
1427
1448
  }
1428
1449
  handleMasterVolumeSysEx(data) {
@@ -1463,8 +1484,124 @@ class MidyGM2 {
1463
1484
  this.masterCoarseTuning = coarseTuning - 64;
1464
1485
  }
1465
1486
  }
1487
+ handleGlobalParameterControl(data) {
1488
+ if (data[5] === 1) {
1489
+ switch (data[6]) {
1490
+ case 1:
1491
+ return this.handleReverbParameter(data);
1492
+ case 2:
1493
+ return this.handleChorusParameter(data);
1494
+ default:
1495
+ console.warn(`Unsupported Global Parameter Control Message: ${data}`);
1496
+ }
1497
+ }
1498
+ else {
1499
+ console.warn(`Unsupported Global Parameter Control Message: ${data}`);
1500
+ }
1501
+ }
1502
+ handleReverbParameter(data) {
1503
+ switch (data[7]) {
1504
+ case 0:
1505
+ return this.setReverbType(data[8]);
1506
+ case 1:
1507
+ return this.setReverbTime(data[8]);
1508
+ }
1509
+ }
1510
+ setReverbType(type) {
1511
+ this.reverb.time = this.getReverbTimeFromType(type);
1512
+ this.reverb.feedback = (type === 8) ? 0.1 : 0.2;
1513
+ const { audioContext, channels, options } = this;
1514
+ for (let i = 0; i < channels.length; i++) {
1515
+ channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1516
+ }
1517
+ }
1518
+ getReverbTimeFromType(type) {
1519
+ switch (type) {
1520
+ case 0:
1521
+ return this.getReverbTime(44);
1522
+ case 1:
1523
+ return this.getReverbTime(50);
1524
+ case 2:
1525
+ return this.getReverbTime(56);
1526
+ case 3:
1527
+ return this.getReverbTime(64);
1528
+ case 4:
1529
+ return this.getReverbTime(64);
1530
+ case 8:
1531
+ return this.getReverbTime(50);
1532
+ default:
1533
+ console.warn(`Unsupported Reverb Time: ${type}`);
1534
+ }
1535
+ }
1536
+ setReverbTime(value) {
1537
+ this.reverb.time = this.getReverbTime(value);
1538
+ const { audioContext, channels, options } = this;
1539
+ for (let i = 0; i < channels.length; i++) {
1540
+ channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1541
+ }
1542
+ }
1543
+ getReverbTime(value) {
1544
+ return Math.pow(Math.E, (value - 40) * 0.025);
1545
+ }
1546
+ // mean free path equation
1547
+ // https://repository.dl.itc.u-tokyo.ac.jp/record/8550/files/A31912.pdf
1548
+ // 江田和司, 拡散性制御に基づく室内音響設計に向けた音場解析に関する研究, 2015
1549
+ // V: room size (m^3)
1550
+ // S: room surface area (m^2)
1551
+ // meanFreePath = 4V / S (m)
1552
+ // delay estimation using mean free path
1553
+ // t: degree Celsius, generally used 20
1554
+ // c: speed of sound = 331.5 + 0.61t = 331.5 * 0.61 * 20 = 343.7 (m/s)
1555
+ // delay = meanFreePath / c (s)
1556
+ // feedback equation
1557
+ // RT60 means that the energy is reduced to Math.pow(10, -6).
1558
+ // Since energy is proportional to the square of the amplitude,
1559
+ // the amplitude is reduced to Math.pow(10, -3).
1560
+ // When this is done through n feedbacks,
1561
+ // Math.pow(feedback, n) = Math.pow(10, -3)
1562
+ // Math.pow(feedback, RT60 / delay) = Math.pow(10, -3)
1563
+ // RT60 / delay * Math.log10(feedback) = -3
1564
+ // RT60 = -3 * delay / Math.log10(feedback)
1565
+ // feedback = Math.pow(10, -3 * delay / RT60)
1566
+ // delay estimation using ideal feedback
1567
+ // A suitable average sound absorption coefficient is 0.18-0.28.
1568
+ // Since the structure of the hall is complex,
1569
+ // It would be easier to determine the delay based on the ideal feedback.
1570
+ // delay = -RT60 * Math.log10(feedback) / 3
1571
+ calcDelay(rt60, feedback) {
1572
+ return -rt60 * Math.log10(feedback) / 3;
1573
+ }
1574
+ handleChorusParameter(data) {
1575
+ switch (data[7]) {
1576
+ case 0:
1577
+ return this.setChorusType(data[8]);
1578
+ case 1:
1579
+ return this.setChorusModRate(data[8]);
1580
+ case 2:
1581
+ return this.setChorusModDepth(data[8]);
1582
+ case 3:
1583
+ return this.setChorusFeedback(data[8]);
1584
+ case 4:
1585
+ return this.setChorusSendToReverb(data[8]);
1586
+ }
1587
+ }
1588
+ setChorusType(type) {
1589
+ // TODO
1590
+ }
1591
+ setChorusModRate(value) {
1592
+ // TODO
1593
+ }
1594
+ setChorusModDepth(value) {
1595
+ // TODO
1596
+ }
1597
+ setChorusFeedback(value) {
1598
+ // TODO
1599
+ }
1600
+ setChorusSendToReverb(value) {
1601
+ // TODO
1602
+ }
1466
1603
  handleExclusiveMessage(data) {
1467
- console.warn(`Unsupported Exclusive Message ${data}`);
1604
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1468
1605
  }
1469
1606
  handleSysEx(data) {
1470
1607
  switch (data[0]) {
@@ -1498,8 +1635,8 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1498
1635
  volume: 100 / 127,
1499
1636
  pan: 64,
1500
1637
  portamentoTime: 0,
1501
- reverb: 0,
1502
- chorus: 0,
1638
+ reverbSendLevel: 0,
1639
+ chorusSendLevel: 0,
1503
1640
  bank: 121 * 128,
1504
1641
  bankMSB: 121,
1505
1642
  bankLSB: 0,
@@ -896,11 +896,11 @@ class MidyGMLite {
896
896
  case 2: // GM System Off
897
897
  break;
898
898
  default:
899
- console.warn(`Unsupported Exclusive Message ${data}`);
899
+ console.warn(`Unsupported Exclusive Message: ${data}`);
900
900
  }
901
901
  break;
902
902
  default:
903
- console.warn(`Unsupported Exclusive Message ${data}`);
903
+ console.warn(`Unsupported Exclusive Message: ${data}`);
904
904
  }
905
905
  }
906
906
  GM1SystemOn() {
@@ -919,11 +919,11 @@ class MidyGMLite {
919
919
  case 1:
920
920
  return this.handleMasterVolumeSysEx(data);
921
921
  default:
922
- console.warn(`Unsupported Exclusive Message ${data}`);
922
+ console.warn(`Unsupported Exclusive Message: ${data}`);
923
923
  }
924
924
  break;
925
925
  default:
926
- console.warn(`Unsupported Exclusive Message ${data}`);
926
+ console.warn(`Unsupported Exclusive Message: ${data}`);
927
927
  }
928
928
  }
929
929
  handleMasterVolumeSysEx(data) {
@@ -941,7 +941,7 @@ class MidyGMLite {
941
941
  }
942
942
  }
943
943
  handleExclusiveMessage(data) {
944
- console.warn(`Unsupported Exclusive Message ${data}`);
944
+ console.warn(`Unsupported Exclusive Message: ${data}`);
945
945
  }
946
946
  handleSysEx(data) {
947
947
  switch (data[0]) {
package/script/midy.d.ts CHANGED
@@ -4,8 +4,8 @@ export class Midy {
4
4
  volume: number;
5
5
  pan: number;
6
6
  portamentoTime: number;
7
- reverb: number;
8
- chorus: number;
7
+ reverbSendLevel: number;
8
+ chorusSendLevel: number;
9
9
  vibratoRate: number;
10
10
  vibratoDepth: number;
11
11
  vibratoDelay: number;
@@ -44,15 +44,22 @@ export class Midy {
44
44
  reverbAlgorithm: (audioContext: any) => {
45
45
  input: any;
46
46
  output: any;
47
- dryGain: any;
48
- wetGain: any;
49
47
  };
50
48
  });
51
49
  ticksPerBeat: number;
52
50
  totalTime: number;
53
- reverbFactor: number;
54
51
  masterFineTuning: number;
55
52
  masterCoarseTuning: number;
53
+ reverb: {
54
+ time: number;
55
+ feedback: number;
56
+ };
57
+ chorus: {
58
+ modRate: number;
59
+ modDepth: number;
60
+ feedback: number;
61
+ sendToReverb: number;
62
+ };
56
63
  mono: boolean;
57
64
  omni: boolean;
58
65
  noteCheckInterval: number;
@@ -74,8 +81,6 @@ export class Midy {
74
81
  reverbAlgorithm: (audioContext: any) => {
75
82
  input: any;
76
83
  output: any;
77
- dryGain: any;
78
- wetGain: any;
79
84
  };
80
85
  };
81
86
  audioContext: any;
@@ -83,8 +88,6 @@ export class Midy {
83
88
  reverbAlgorithm: (audioContext: any) => {
84
89
  input: any;
85
90
  output: any;
86
- dryGain: any;
87
- wetGain: any;
88
91
  };
89
92
  };
90
93
  masterGain: any;
@@ -100,8 +103,6 @@ export class Midy {
100
103
  reverbEffect: {
101
104
  input: any;
102
105
  output: any;
103
- dryGain: any;
104
- wetGain: any;
105
106
  };
106
107
  chorusEffect: {
107
108
  lfo: any;
@@ -134,20 +135,18 @@ export class Midy {
134
135
  currentTime(): number;
135
136
  getActiveNotes(channel: any, time: any): Map<any, any>;
136
137
  getActiveNote(noteList: any, time: any): any;
137
- createConvolutionReverb(audioContext: any, options?: {}): {
138
+ createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
139
+ createConvolutionReverb(audioContext: any, impulse: any): {
138
140
  input: any;
139
141
  output: any;
140
- dryGain: any;
141
- wetGain: any;
142
142
  convolverNode: any;
143
143
  };
144
144
  createCombFilter(audioContext: any, input: any, delay: any, feedback: any): any;
145
145
  createAllpassFilter(audioContext: any, input: any, delay: any, feedback: any): any;
146
- createSchroederReverb(audioContext: any, options?: {}): {
146
+ generateDistributedArray(center: any, count: any, varianceRatio?: number, randomness?: number): any[];
147
+ createSchroederReverb(audioContext: any, combDelays: any, combFeedbacks: any, allpassDelays: any, allpassFeedbacks: any): {
147
148
  input: any;
148
149
  output: any;
149
- dryGain: any;
150
- wetGain: any;
151
150
  };
152
151
  createChorusEffect(audioContext: any, options?: {}): {
153
152
  lfo: any;
@@ -196,8 +195,8 @@ export class Midy {
196
195
  updateChannelGain(channel: any): void;
197
196
  setSustainPedal(channelNumber: any, value: any): void;
198
197
  setPortamento(channelNumber: any, value: any): void;
199
- setReverbSendLevel(channelNumber: any, reverb: any): void;
200
- setChorusSendLevel(channelNumber: any, chorus: any): void;
198
+ setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
199
+ setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
201
200
  setSostenutoPedal(channelNumber: any, value: any): void;
202
201
  setSoftPedal(channelNumber: any, softPedal: any): void;
203
202
  setVibratoRate(channelNumber: any, vibratoRate: any): void;
@@ -237,6 +236,19 @@ export class Midy {
237
236
  setMasterFineTuning(fineTuning: any): void;
238
237
  handleMasterCoarseTuningSysEx(data: any): void;
239
238
  setMasterCoarseTuning(coarseTuning: any): void;
239
+ handleGlobalParameterControl(data: any): void;
240
+ handleReverbParameter(data: any): void;
241
+ setReverbType(type: any): void;
242
+ getReverbTimeFromType(type: any): number | undefined;
243
+ setReverbTime(value: any): void;
244
+ getReverbTime(value: any): number;
245
+ calcDelay(rt60: any, feedback: any): number;
246
+ handleChorusParameter(data: any): void;
247
+ setChorusType(type: any): void;
248
+ setChorusModRate(value: any): void;
249
+ setChorusModDepth(value: any): void;
250
+ setChorusFeedback(value: any): void;
251
+ setChorusSendToReverb(value: any): void;
240
252
  handleExclusiveMessage(data: any): void;
241
253
  handleSysEx(data: any): void;
242
254
  scheduleTask(callback: any, startTime: any): Promise<any>;