@marmooo/midy 0.0.8 → 0.0.9
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 +6 -43
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +38 -32
- package/esm/midy-GM2.d.ts +41 -102
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +130 -61
- package/esm/midy-GMLite.d.ts +4 -39
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +34 -32
- package/esm/midy.d.ts +41 -124
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +130 -65
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +6 -43
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +38 -32
- package/script/midy-GM2.d.ts +41 -102
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +130 -61
- package/script/midy-GMLite.d.ts +4 -39
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +34 -32
- package/script/midy.d.ts +41 -124
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +130 -65
package/esm/midy.d.ts
CHANGED
|
@@ -40,7 +40,14 @@ export class Midy {
|
|
|
40
40
|
lfoFilterDepth: number;
|
|
41
41
|
lfoAmplitudeDepth: number;
|
|
42
42
|
};
|
|
43
|
-
constructor(audioContext: any
|
|
43
|
+
constructor(audioContext: any, options?: {
|
|
44
|
+
reverbAlgorithm: (audioContext: any) => {
|
|
45
|
+
input: any;
|
|
46
|
+
output: any;
|
|
47
|
+
dryGain: any;
|
|
48
|
+
wetGain: any;
|
|
49
|
+
};
|
|
50
|
+
});
|
|
44
51
|
ticksPerBeat: number;
|
|
45
52
|
totalTime: number;
|
|
46
53
|
reverbFactor: number;
|
|
@@ -63,69 +70,25 @@ export class Midy {
|
|
|
63
70
|
timeline: any[];
|
|
64
71
|
instruments: any[];
|
|
65
72
|
notePromises: any[];
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
sostenutoNotes: Map<any, any>;
|
|
71
|
-
polyphonicKeyPressure: {
|
|
72
|
-
pitchControl: number;
|
|
73
|
-
filterCutoffControl: number;
|
|
74
|
-
amplitudeControl: number;
|
|
75
|
-
lfoPitchDepth: number;
|
|
76
|
-
lfoFilterDepth: number;
|
|
77
|
-
lfoAmplitudeDepth: number;
|
|
78
|
-
};
|
|
79
|
-
channelPressure: {
|
|
80
|
-
pitchControl: number;
|
|
81
|
-
filterCutoffControl: number;
|
|
82
|
-
amplitudeControl: number;
|
|
83
|
-
lfoPitchDepth: number;
|
|
84
|
-
lfoFilterDepth: number;
|
|
85
|
-
lfoAmplitudeDepth: number;
|
|
86
|
-
};
|
|
87
|
-
gainL: any;
|
|
88
|
-
gainR: any;
|
|
89
|
-
reverbEffect: {
|
|
90
|
-
convolverNode: any;
|
|
73
|
+
defaultOptions: {
|
|
74
|
+
reverbAlgorithm: (audioContext: any) => {
|
|
75
|
+
input: any;
|
|
76
|
+
output: any;
|
|
91
77
|
dryGain: any;
|
|
92
78
|
wetGain: any;
|
|
93
79
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
80
|
+
};
|
|
81
|
+
audioContext: any;
|
|
82
|
+
options: {
|
|
83
|
+
reverbAlgorithm: (audioContext: any) => {
|
|
84
|
+
input: any;
|
|
85
|
+
output: any;
|
|
86
|
+
dryGain: any;
|
|
87
|
+
wetGain: any;
|
|
99
88
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
portamento: boolean;
|
|
104
|
-
sostenutoPedal: boolean;
|
|
105
|
-
softPedal: number;
|
|
106
|
-
rpnMSB: number;
|
|
107
|
-
rpnLSB: number;
|
|
108
|
-
pitchBendRange: number;
|
|
109
|
-
currentBufferSource: null;
|
|
110
|
-
volume: number;
|
|
111
|
-
pan: number;
|
|
112
|
-
portamentoTime: number;
|
|
113
|
-
reverb: number;
|
|
114
|
-
chorus: number;
|
|
115
|
-
vibratoRate: number;
|
|
116
|
-
vibratoDepth: number;
|
|
117
|
-
vibratoDelay: number;
|
|
118
|
-
bank: number;
|
|
119
|
-
bankMSB: number;
|
|
120
|
-
bankLSB: number;
|
|
121
|
-
dataMSB: number;
|
|
122
|
-
dataLSB: number;
|
|
123
|
-
program: number;
|
|
124
|
-
pitchBend: number;
|
|
125
|
-
fineTuning: number;
|
|
126
|
-
coarseTuning: number;
|
|
127
|
-
modulationDepthRange: number;
|
|
128
|
-
}[];
|
|
89
|
+
};
|
|
90
|
+
masterGain: any;
|
|
91
|
+
channels: any[];
|
|
129
92
|
initSoundFontTable(): any[];
|
|
130
93
|
addSoundFont(soundFont: any): void;
|
|
131
94
|
loadSoundFont(soundFontUrl: any): Promise<void>;
|
|
@@ -133,8 +96,10 @@ export class Midy {
|
|
|
133
96
|
setChannelAudioNodes(audioContext: any): {
|
|
134
97
|
gainL: any;
|
|
135
98
|
gainR: any;
|
|
99
|
+
merger: any;
|
|
136
100
|
reverbEffect: {
|
|
137
|
-
|
|
101
|
+
input: any;
|
|
102
|
+
output: any;
|
|
138
103
|
dryGain: any;
|
|
139
104
|
wetGain: any;
|
|
140
105
|
};
|
|
@@ -143,69 +108,10 @@ export class Midy {
|
|
|
143
108
|
lfoGain: any;
|
|
144
109
|
delayNodes: any[];
|
|
145
110
|
chorusGains: any[];
|
|
111
|
+
output: any;
|
|
146
112
|
};
|
|
147
113
|
};
|
|
148
|
-
createChannels(audioContext: any):
|
|
149
|
-
scheduledNotes: Map<any, any>;
|
|
150
|
-
sostenutoNotes: Map<any, any>;
|
|
151
|
-
polyphonicKeyPressure: {
|
|
152
|
-
pitchControl: number;
|
|
153
|
-
filterCutoffControl: number;
|
|
154
|
-
amplitudeControl: number;
|
|
155
|
-
lfoPitchDepth: number;
|
|
156
|
-
lfoFilterDepth: number;
|
|
157
|
-
lfoAmplitudeDepth: number;
|
|
158
|
-
};
|
|
159
|
-
channelPressure: {
|
|
160
|
-
pitchControl: number;
|
|
161
|
-
filterCutoffControl: number;
|
|
162
|
-
amplitudeControl: number;
|
|
163
|
-
lfoPitchDepth: number;
|
|
164
|
-
lfoFilterDepth: number;
|
|
165
|
-
lfoAmplitudeDepth: number;
|
|
166
|
-
};
|
|
167
|
-
gainL: any;
|
|
168
|
-
gainR: any;
|
|
169
|
-
reverbEffect: {
|
|
170
|
-
convolverNode: any;
|
|
171
|
-
dryGain: any;
|
|
172
|
-
wetGain: any;
|
|
173
|
-
};
|
|
174
|
-
chorusEffect: {
|
|
175
|
-
lfo: any;
|
|
176
|
-
lfoGain: any;
|
|
177
|
-
delayNodes: any[];
|
|
178
|
-
chorusGains: any[];
|
|
179
|
-
};
|
|
180
|
-
expression: number;
|
|
181
|
-
modulation: number;
|
|
182
|
-
sustainPedal: boolean;
|
|
183
|
-
portamento: boolean;
|
|
184
|
-
sostenutoPedal: boolean;
|
|
185
|
-
softPedal: number;
|
|
186
|
-
rpnMSB: number;
|
|
187
|
-
rpnLSB: number;
|
|
188
|
-
pitchBendRange: number;
|
|
189
|
-
currentBufferSource: null;
|
|
190
|
-
volume: number;
|
|
191
|
-
pan: number;
|
|
192
|
-
portamentoTime: number;
|
|
193
|
-
reverb: number;
|
|
194
|
-
chorus: number;
|
|
195
|
-
vibratoRate: number;
|
|
196
|
-
vibratoDepth: number;
|
|
197
|
-
vibratoDelay: number;
|
|
198
|
-
bank: number;
|
|
199
|
-
bankMSB: number;
|
|
200
|
-
bankLSB: number;
|
|
201
|
-
dataMSB: number;
|
|
202
|
-
dataLSB: number;
|
|
203
|
-
program: number;
|
|
204
|
-
pitchBend: number;
|
|
205
|
-
fineTuning: number;
|
|
206
|
-
coarseTuning: number;
|
|
207
|
-
modulationDepthRange: number;
|
|
208
|
-
}[];
|
|
114
|
+
createChannels(audioContext: any): any[];
|
|
209
115
|
createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
|
|
210
116
|
createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
|
|
211
117
|
convertToFloat32Array(uint8Array: any): Float32Array;
|
|
@@ -228,8 +134,18 @@ export class Midy {
|
|
|
228
134
|
currentTime(): number;
|
|
229
135
|
getActiveNotes(channel: any, time: any): Map<any, any>;
|
|
230
136
|
getActiveNote(noteList: any, time: any): any;
|
|
231
|
-
|
|
137
|
+
createConvolutionReverb(audioContext: any, options?: {}): {
|
|
138
|
+
input: any;
|
|
139
|
+
output: any;
|
|
140
|
+
dryGain: any;
|
|
141
|
+
wetGain: any;
|
|
232
142
|
convolverNode: any;
|
|
143
|
+
};
|
|
144
|
+
createCombFilter(audioContext: any, input: any, delay: any, feedback: any): any;
|
|
145
|
+
createAllpassFilter(audioContext: any, input: any, delay: any, feedback: any): any;
|
|
146
|
+
createSchroederReverb(audioContext: any, options?: {}): {
|
|
147
|
+
input: any;
|
|
148
|
+
output: any;
|
|
233
149
|
dryGain: any;
|
|
234
150
|
wetGain: any;
|
|
235
151
|
};
|
|
@@ -238,8 +154,9 @@ export class Midy {
|
|
|
238
154
|
lfoGain: any;
|
|
239
155
|
delayNodes: any[];
|
|
240
156
|
chorusGains: any[];
|
|
157
|
+
output: any;
|
|
241
158
|
};
|
|
242
|
-
|
|
159
|
+
connectEffects(channel: any, gainNode: any): void;
|
|
243
160
|
cbToRatio(cb: any): number;
|
|
244
161
|
centToHz(cent: any): number;
|
|
245
162
|
calcSemitoneOffset(channel: any): any;
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IASF;;;;;;;OAOC;IAjFD,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;IA8ClB;;;;;;;MAKE;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;;;;;;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,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;IAED,oDAEC;IAED,0DASC;IAED,0DAIC;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,yDAgDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA5nDD;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/esm/midy.js
CHANGED
|
@@ -51,7 +51,7 @@ class Note {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
export class Midy {
|
|
54
|
-
constructor(audioContext) {
|
|
54
|
+
constructor(audioContext, options = this.defaultOptions) {
|
|
55
55
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
56
56
|
enumerable: true,
|
|
57
57
|
configurable: true,
|
|
@@ -184,7 +184,19 @@ export class Midy {
|
|
|
184
184
|
writable: true,
|
|
185
185
|
value: []
|
|
186
186
|
});
|
|
187
|
+
Object.defineProperty(this, "defaultOptions", {
|
|
188
|
+
enumerable: true,
|
|
189
|
+
configurable: true,
|
|
190
|
+
writable: true,
|
|
191
|
+
value: {
|
|
192
|
+
reverbAlgorithm: (audioContext) => {
|
|
193
|
+
// return this.createConvolutionReverb(audioContext);
|
|
194
|
+
return this.createSchroederReverb(audioContext);
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
});
|
|
187
198
|
this.audioContext = audioContext;
|
|
199
|
+
this.options = { ...this.defaultOptions, ...options };
|
|
188
200
|
this.masterGain = new GainNode(audioContext);
|
|
189
201
|
this.masterGain.connect(audioContext.destination);
|
|
190
202
|
this.channels = this.createChannels(audioContext);
|
|
@@ -225,23 +237,18 @@ export class Midy {
|
|
|
225
237
|
this.totalTime = this.calcTotalTime();
|
|
226
238
|
}
|
|
227
239
|
setChannelAudioNodes(audioContext) {
|
|
228
|
-
const { gainLeft, gainRight } = this.panToGain(
|
|
240
|
+
const { gainLeft, gainRight } = this.panToGain(this.constructor.channelSettings.pan);
|
|
229
241
|
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
230
242
|
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
231
243
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
232
244
|
gainL.connect(merger, 0, 0);
|
|
233
245
|
gainR.connect(merger, 0, 1);
|
|
234
|
-
|
|
235
|
-
const reverbEffect = this.createReverbEffect(audioContext);
|
|
246
|
+
const reverbEffect = this.options.reverbAlgorithm(audioContext);
|
|
236
247
|
const chorusEffect = this.createChorusEffect(audioContext);
|
|
237
|
-
chorusEffect.lfo.start();
|
|
238
|
-
reverbEffect.dryGain.connect(gainL);
|
|
239
|
-
reverbEffect.dryGain.connect(gainR);
|
|
240
|
-
reverbEffect.wetGain.connect(gainL);
|
|
241
|
-
reverbEffect.wetGain.connect(gainR);
|
|
242
248
|
return {
|
|
243
249
|
gainL,
|
|
244
250
|
gainR,
|
|
251
|
+
merger,
|
|
245
252
|
reverbEffect,
|
|
246
253
|
chorusEffect,
|
|
247
254
|
};
|
|
@@ -249,16 +256,16 @@ export class Midy {
|
|
|
249
256
|
createChannels(audioContext) {
|
|
250
257
|
const channels = Array.from({ length: 16 }, () => {
|
|
251
258
|
return {
|
|
252
|
-
...
|
|
253
|
-
...
|
|
259
|
+
...this.constructor.channelSettings,
|
|
260
|
+
...this.constructor.effectSettings,
|
|
254
261
|
...this.setChannelAudioNodes(audioContext),
|
|
255
262
|
scheduledNotes: new Map(),
|
|
256
263
|
sostenutoNotes: new Map(),
|
|
257
264
|
polyphonicKeyPressure: {
|
|
258
|
-
...
|
|
265
|
+
...this.constructor.controllerDestinationSettings,
|
|
259
266
|
},
|
|
260
267
|
channelPressure: {
|
|
261
|
-
...
|
|
268
|
+
...this.constructor.controllerDestinationSettings,
|
|
262
269
|
},
|
|
263
270
|
};
|
|
264
271
|
});
|
|
@@ -589,8 +596,12 @@ export class Midy {
|
|
|
589
596
|
}
|
|
590
597
|
return noteList[0];
|
|
591
598
|
}
|
|
592
|
-
|
|
599
|
+
createConvolutionReverb(audioContext, options = {}) {
|
|
593
600
|
const { decay = 0.8, preDecay = 0, } = options;
|
|
601
|
+
const input = new GainNode(audioContext);
|
|
602
|
+
const output = new GainNode(audioContext);
|
|
603
|
+
const dryGain = new GainNode(audioContext);
|
|
604
|
+
const wetGain = new GainNode(audioContext);
|
|
594
605
|
const sampleRate = audioContext.sampleRate;
|
|
595
606
|
const length = sampleRate * decay;
|
|
596
607
|
const impulse = new AudioBuffer({
|
|
@@ -604,27 +615,82 @@ export class Midy {
|
|
|
604
615
|
for (let i = 0; i < preDecayLength; i++) {
|
|
605
616
|
channelData[i] = Math.random() * 2 - 1;
|
|
606
617
|
}
|
|
618
|
+
const attenuationFactor = 1 / (sampleRate * decay);
|
|
607
619
|
for (let i = preDecayLength; i < length; i++) {
|
|
608
|
-
const attenuation = Math.exp(-(i - preDecayLength)
|
|
620
|
+
const attenuation = Math.exp(-(i - preDecayLength) * attenuationFactor);
|
|
609
621
|
channelData[i] = (Math.random() * 2 - 1) * attenuation;
|
|
610
622
|
}
|
|
611
623
|
}
|
|
612
624
|
const convolverNode = new ConvolverNode(audioContext, {
|
|
613
625
|
buffer: impulse,
|
|
614
626
|
});
|
|
615
|
-
|
|
616
|
-
const wetGain = new GainNode(audioContext);
|
|
627
|
+
input.connect(convolverNode);
|
|
617
628
|
convolverNode.connect(wetGain);
|
|
629
|
+
wetGain.connect(output);
|
|
630
|
+
dryGain.connect(output);
|
|
618
631
|
return {
|
|
619
|
-
|
|
632
|
+
input,
|
|
633
|
+
output,
|
|
620
634
|
dryGain,
|
|
621
635
|
wetGain,
|
|
636
|
+
convolverNode,
|
|
622
637
|
};
|
|
623
638
|
}
|
|
639
|
+
createCombFilter(audioContext, input, delay, feedback) {
|
|
640
|
+
const delayNode = new DelayNode(audioContext, {
|
|
641
|
+
maxDelayTime: delay,
|
|
642
|
+
delayTime: delay,
|
|
643
|
+
});
|
|
644
|
+
const feedbackGain = new GainNode(audioContext, { gain: feedback });
|
|
645
|
+
input.connect(delayNode);
|
|
646
|
+
delayNode.connect(feedbackGain);
|
|
647
|
+
feedbackGain.connect(delayNode);
|
|
648
|
+
return delayNode;
|
|
649
|
+
}
|
|
650
|
+
createAllpassFilter(audioContext, input, delay, feedback) {
|
|
651
|
+
const delayNode = new DelayNode(audioContext, {
|
|
652
|
+
maxDelayTime: delay,
|
|
653
|
+
delayTime: delay,
|
|
654
|
+
});
|
|
655
|
+
const feedbackGain = new GainNode(audioContext, { gain: feedback });
|
|
656
|
+
const passGain = new GainNode(audioContext, { gain: 1 - feedback });
|
|
657
|
+
input.connect(delayNode);
|
|
658
|
+
delayNode.connect(feedbackGain);
|
|
659
|
+
feedbackGain.connect(delayNode);
|
|
660
|
+
delayNode.connect(passGain);
|
|
661
|
+
return passGain;
|
|
662
|
+
}
|
|
663
|
+
// https://hajim.rochester.edu/ece/sites/zduan/teaching/ece472/reading/Schroeder_1962.pdf
|
|
664
|
+
// M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
|
|
665
|
+
createSchroederReverb(audioContext, options = {}) {
|
|
666
|
+
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;
|
|
667
|
+
const input = new GainNode(audioContext);
|
|
668
|
+
const output = new GainNode(audioContext);
|
|
669
|
+
const mergerGain = new GainNode(audioContext, {
|
|
670
|
+
gain: 1 / (combDelays.length * 2),
|
|
671
|
+
});
|
|
672
|
+
const dryGain = new GainNode(audioContext, { gain: 1 - mix });
|
|
673
|
+
const wetGain = new GainNode(audioContext, { gain: mix });
|
|
674
|
+
for (let i = 0; i < combDelays.length; i++) {
|
|
675
|
+
const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
|
|
676
|
+
comb.connect(mergerGain);
|
|
677
|
+
}
|
|
678
|
+
const allpasses = [];
|
|
679
|
+
for (let i = 0; i < allpassDelays.length; i++) {
|
|
680
|
+
const allpass = this.createAllpassFilter(audioContext, (i === 0) ? mergerGain : allpasses.at(-1), allpassDelays[i], allpassFeedbacks[i]);
|
|
681
|
+
allpasses.push(allpass);
|
|
682
|
+
}
|
|
683
|
+
allpasses.at(-1).connect(wetGain);
|
|
684
|
+
input.connect(dryGain);
|
|
685
|
+
dryGain.connect(output);
|
|
686
|
+
wetGain.connect(output);
|
|
687
|
+
return { input, output, dryGain, wetGain };
|
|
688
|
+
}
|
|
624
689
|
createChorusEffect(audioContext, options = {}) {
|
|
625
690
|
const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
|
|
626
691
|
const lfo = new OscillatorNode(audioContext, { frequency: chorusRate });
|
|
627
692
|
const lfoGain = new GainNode(audioContext, { gain: chorusDepth });
|
|
693
|
+
const output = new GainNode(audioContext);
|
|
628
694
|
const chorusGains = [];
|
|
629
695
|
const delayNodes = [];
|
|
630
696
|
const baseGain = 1 / chorusCount;
|
|
@@ -634,50 +700,47 @@ export class Midy {
|
|
|
634
700
|
const delayNode = new DelayNode(audioContext, {
|
|
635
701
|
maxDelayTime: delayTime,
|
|
636
702
|
});
|
|
637
|
-
delayNodes.push(delayNode);
|
|
638
703
|
const chorusGain = new GainNode(audioContext, { gain: baseGain });
|
|
704
|
+
delayNodes.push(delayNode);
|
|
639
705
|
chorusGains.push(chorusGain);
|
|
640
|
-
lfo.connect(lfoGain);
|
|
641
706
|
lfoGain.connect(delayNode.delayTime);
|
|
642
707
|
delayNode.connect(chorusGain);
|
|
708
|
+
chorusGain.connect(output);
|
|
643
709
|
}
|
|
710
|
+
lfo.connect(lfoGain);
|
|
711
|
+
lfo.start();
|
|
644
712
|
return {
|
|
645
713
|
lfo,
|
|
646
714
|
lfoGain,
|
|
647
715
|
delayNodes,
|
|
648
716
|
chorusGains,
|
|
717
|
+
output,
|
|
649
718
|
};
|
|
650
719
|
}
|
|
651
|
-
|
|
720
|
+
connectEffects(channel, gainNode) {
|
|
721
|
+
gainNode.connect(channel.merger);
|
|
652
722
|
if (channel.reverb === 0) {
|
|
653
723
|
if (channel.chorus === 0) { // no effect
|
|
654
|
-
|
|
655
|
-
gainNode.connect(channel.gainR);
|
|
724
|
+
channel.merger.connect(this.masterGain);
|
|
656
725
|
}
|
|
657
726
|
else { // chorus
|
|
658
727
|
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
659
|
-
|
|
660
|
-
});
|
|
661
|
-
channel.chorusEffect.chorusGains.forEach((chorusGain) => {
|
|
662
|
-
chorusGain.connect(channel.gainL);
|
|
663
|
-
chorusGain.connect(channel.gainR);
|
|
728
|
+
channel.merger.connect(delayNode);
|
|
664
729
|
});
|
|
730
|
+
channel.chorusEffect.output.connect(this.masterGain);
|
|
665
731
|
}
|
|
666
732
|
}
|
|
667
733
|
else {
|
|
668
734
|
if (channel.chorus === 0) { // reverb
|
|
669
|
-
|
|
670
|
-
|
|
735
|
+
channel.merger.connect(channel.reverbEffect.input);
|
|
736
|
+
channel.reverbEffect.output.connect(this.masterGain);
|
|
671
737
|
}
|
|
672
738
|
else { // reverb + chorus
|
|
673
|
-
gainNode.connect(channel.reverbEffect.convolverNode);
|
|
674
|
-
gainNode.connect(channel.reverbEffect.dryGain);
|
|
675
739
|
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
676
|
-
|
|
677
|
-
});
|
|
678
|
-
channel.chorusEffect.chorusGains.forEach((chorusGain) => {
|
|
679
|
-
chorusGain.connect(channel.reverbEffect.convolverNode);
|
|
740
|
+
channel.merger.connect(delayNode);
|
|
680
741
|
});
|
|
742
|
+
channel.merger.connect(channel.reverbEffect.input);
|
|
743
|
+
channel.reverbEffect.output.connect(this.masterGain);
|
|
681
744
|
}
|
|
682
745
|
}
|
|
683
746
|
}
|
|
@@ -817,7 +880,7 @@ export class Midy {
|
|
|
817
880
|
if (!instrumentKey)
|
|
818
881
|
return;
|
|
819
882
|
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
820
|
-
this.
|
|
883
|
+
this.connectEffects(channel, note.gainNode);
|
|
821
884
|
if (channel.sostenutoPedal) {
|
|
822
885
|
channel.sostenutoNotes.set(noteNumber, note);
|
|
823
886
|
}
|
|
@@ -841,46 +904,48 @@ export class Midy {
|
|
|
841
904
|
return;
|
|
842
905
|
if (!channel.scheduledNotes.has(noteNumber))
|
|
843
906
|
return;
|
|
844
|
-
const
|
|
845
|
-
for (let i = 0; i <
|
|
846
|
-
const
|
|
847
|
-
if (!
|
|
907
|
+
const scheduledNotes = channel.scheduledNotes.get(noteNumber);
|
|
908
|
+
for (let i = 0; i < scheduledNotes.length; i++) {
|
|
909
|
+
const note = scheduledNotes[i];
|
|
910
|
+
if (!note)
|
|
848
911
|
continue;
|
|
849
|
-
if (
|
|
912
|
+
if (note.ending)
|
|
850
913
|
continue;
|
|
851
|
-
const { bufferSource, filterNode, gainNode, modLFO, modLFOGain, vibLFO, vibLFOGain, instrumentKey, } = targetNote;
|
|
852
914
|
const velocityRate = (velocity + 127) / 127;
|
|
853
|
-
const volEndTime = stopTime +
|
|
854
|
-
|
|
855
|
-
gainNode.gain
|
|
915
|
+
const volEndTime = stopTime +
|
|
916
|
+
note.instrumentKey.volRelease * velocityRate;
|
|
917
|
+
note.gainNode.gain
|
|
918
|
+
.cancelScheduledValues(stopTime)
|
|
919
|
+
.linearRampToValueAtTime(0, volEndTime);
|
|
856
920
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
857
|
-
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
921
|
+
const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
|
|
858
922
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
859
|
-
const modEndTime = stopTime +
|
|
860
|
-
|
|
923
|
+
const modEndTime = stopTime +
|
|
924
|
+
note.instrumentKey.modRelease * velocityRate;
|
|
925
|
+
note.filterNode.frequency
|
|
861
926
|
.cancelScheduledValues(stopTime)
|
|
862
927
|
.linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
|
|
863
|
-
|
|
928
|
+
note.ending = true;
|
|
864
929
|
this.scheduleTask(() => {
|
|
865
|
-
bufferSource.loop = false;
|
|
930
|
+
note.bufferSource.loop = false;
|
|
866
931
|
}, stopTime);
|
|
867
932
|
return new Promise((resolve) => {
|
|
868
|
-
bufferSource.onended = () => {
|
|
869
|
-
|
|
870
|
-
bufferSource.disconnect(
|
|
871
|
-
filterNode.disconnect(
|
|
872
|
-
gainNode.disconnect(
|
|
873
|
-
if (modLFOGain)
|
|
874
|
-
modLFOGain.disconnect(
|
|
875
|
-
if (vibLFOGain)
|
|
876
|
-
vibLFOGain.disconnect(
|
|
877
|
-
if (modLFO)
|
|
878
|
-
modLFO.stop();
|
|
879
|
-
if (vibLFO)
|
|
880
|
-
vibLFO.stop();
|
|
933
|
+
note.bufferSource.onended = () => {
|
|
934
|
+
scheduledNotes[i] = null;
|
|
935
|
+
note.bufferSource.disconnect();
|
|
936
|
+
note.filterNode.disconnect();
|
|
937
|
+
note.gainNode.disconnect();
|
|
938
|
+
if (note.modLFOGain)
|
|
939
|
+
note.modLFOGain.disconnect();
|
|
940
|
+
if (note.vibLFOGain)
|
|
941
|
+
note.vibLFOGain.disconnect();
|
|
942
|
+
if (note.modLFO)
|
|
943
|
+
note.modLFO.stop();
|
|
944
|
+
if (note.vibLFO)
|
|
945
|
+
note.vibLFO.stop();
|
|
881
946
|
resolve();
|
|
882
947
|
};
|
|
883
|
-
bufferSource.stop(volEndTime);
|
|
948
|
+
note.bufferSource.stop(volEndTime);
|
|
884
949
|
});
|
|
885
950
|
}
|
|
886
951
|
}
|
package/package.json
CHANGED
package/script/midy-GM1.d.ts
CHANGED
|
@@ -39,27 +39,7 @@ export class MidyGM1 {
|
|
|
39
39
|
notePromises: any[];
|
|
40
40
|
audioContext: any;
|
|
41
41
|
masterGain: any;
|
|
42
|
-
channels:
|
|
43
|
-
scheduledNotes: Map<any, any>;
|
|
44
|
-
gainL: any;
|
|
45
|
-
gainR: any;
|
|
46
|
-
expression: number;
|
|
47
|
-
modulation: number;
|
|
48
|
-
sustainPedal: boolean;
|
|
49
|
-
rpnMSB: number;
|
|
50
|
-
rpnLSB: number;
|
|
51
|
-
pitchBendRange: number;
|
|
52
|
-
volume: number;
|
|
53
|
-
pan: number;
|
|
54
|
-
bank: number;
|
|
55
|
-
dataMSB: number;
|
|
56
|
-
dataLSB: number;
|
|
57
|
-
program: number;
|
|
58
|
-
pitchBend: number;
|
|
59
|
-
fineTuning: number;
|
|
60
|
-
coarseTuning: number;
|
|
61
|
-
modulationDepthRange: number;
|
|
62
|
-
}[];
|
|
42
|
+
channels: any[];
|
|
63
43
|
initSoundFontTable(): any[];
|
|
64
44
|
addSoundFont(soundFont: any): void;
|
|
65
45
|
loadSoundFont(soundFontUrl: any): Promise<void>;
|
|
@@ -67,28 +47,11 @@ export class MidyGM1 {
|
|
|
67
47
|
setChannelAudioNodes(audioContext: any): {
|
|
68
48
|
gainL: any;
|
|
69
49
|
gainR: any;
|
|
50
|
+
merger: any;
|
|
51
|
+
reverbEffect: any;
|
|
52
|
+
chorusEffect: any;
|
|
70
53
|
};
|
|
71
|
-
createChannels(audioContext: any):
|
|
72
|
-
scheduledNotes: Map<any, any>;
|
|
73
|
-
gainL: any;
|
|
74
|
-
gainR: any;
|
|
75
|
-
expression: number;
|
|
76
|
-
modulation: number;
|
|
77
|
-
sustainPedal: boolean;
|
|
78
|
-
rpnMSB: number;
|
|
79
|
-
rpnLSB: number;
|
|
80
|
-
pitchBendRange: number;
|
|
81
|
-
volume: number;
|
|
82
|
-
pan: number;
|
|
83
|
-
bank: number;
|
|
84
|
-
dataMSB: number;
|
|
85
|
-
dataLSB: number;
|
|
86
|
-
program: number;
|
|
87
|
-
pitchBend: number;
|
|
88
|
-
fineTuning: number;
|
|
89
|
-
coarseTuning: number;
|
|
90
|
-
modulationDepthRange: number;
|
|
91
|
-
}[];
|
|
54
|
+
createChannels(audioContext: any): any[];
|
|
92
55
|
createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
|
|
93
56
|
createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
|
|
94
57
|
convertToFloat32Array(uint8Array: any): Float32Array;
|
|
@@ -111,7 +74,7 @@ export class MidyGM1 {
|
|
|
111
74
|
currentTime(): number;
|
|
112
75
|
getActiveNotes(channel: any, time: any): Map<any, any>;
|
|
113
76
|
getActiveNote(noteList: any, time: any): any;
|
|
114
|
-
|
|
77
|
+
connectEffects(channel: any, gainNode: any): void;
|
|
115
78
|
cbToRatio(cb: any): number;
|
|
116
79
|
centToHz(cent: any): number;
|
|
117
80
|
calcSemitoneOffset(channel: any): any;
|
package/script/midy-GM1.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA9CD,qBAAmB;IACnB,kBAAc;IACd,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;IAyBhB,kBAAgC;IAChC,gBAA4C;IAE5C
|
|
1
|
+
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA9CD,qBAAmB;IACnB,kBAAc;IACd,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;IAyBhB,kBAAgC;IAChC,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAkBC;IAED,yCAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,kDAGC;IAED,2BAEC;IAED,4BAEC;IAED,sCAGC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHA6BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIA8CC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED,mFA+BC;IAED,qCAcC;IAED,yDAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAUC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAvjCD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|