@marmooo/midy 0.0.5 → 0.0.6
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 +14 -10
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +62 -57
- package/esm/midy-GM2.d.ts +10 -4
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +63 -50
- package/esm/midy-GMLite.d.ts +14 -8
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +62 -45
- package/esm/midy.d.ts +16 -10
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +75 -62
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +14 -10
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +62 -57
- package/script/midy-GM2.d.ts +10 -4
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +63 -50
- package/script/midy-GMLite.d.ts +14 -8
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +62 -45
- package/script/midy.d.ts +16 -10
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +75 -62
package/script/midy-GM1.js
CHANGED
|
@@ -35,18 +35,6 @@ class Note {
|
|
|
35
35
|
writable: true,
|
|
36
36
|
value: void 0
|
|
37
37
|
});
|
|
38
|
-
Object.defineProperty(this, "vibLFO", {
|
|
39
|
-
enumerable: true,
|
|
40
|
-
configurable: true,
|
|
41
|
-
writable: true,
|
|
42
|
-
value: void 0
|
|
43
|
-
});
|
|
44
|
-
Object.defineProperty(this, "vibLFOGain", {
|
|
45
|
-
enumerable: true,
|
|
46
|
-
configurable: true,
|
|
47
|
-
writable: true,
|
|
48
|
-
value: void 0
|
|
49
|
-
});
|
|
50
38
|
this.noteNumber = noteNumber;
|
|
51
39
|
this.velocity = velocity;
|
|
52
40
|
this.startTime = startTime;
|
|
@@ -198,17 +186,16 @@ class MidyGM1 {
|
|
|
198
186
|
this.totalTime = this.calcTotalTime();
|
|
199
187
|
}
|
|
200
188
|
setChannelAudioNodes(audioContext) {
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
});
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
gainNode.connect(this.masterGain);
|
|
189
|
+
const { gainLeft, gainRight } = this.panToGain(MidyGM1.channelSettings.pan);
|
|
190
|
+
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
191
|
+
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
192
|
+
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
193
|
+
gainL.connect(merger, 0, 0);
|
|
194
|
+
gainR.connect(merger, 0, 1);
|
|
195
|
+
merger.connect(this.masterGain);
|
|
209
196
|
return {
|
|
210
|
-
|
|
211
|
-
|
|
197
|
+
gainL,
|
|
198
|
+
gainR,
|
|
212
199
|
};
|
|
213
200
|
}
|
|
214
201
|
createChannels(audioContext) {
|
|
@@ -293,7 +280,7 @@ class MidyGM1 {
|
|
|
293
280
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
294
281
|
break;
|
|
295
282
|
case "pitchBend":
|
|
296
|
-
this.
|
|
283
|
+
this.setPitchBend(event.channel, event.value);
|
|
297
284
|
break;
|
|
298
285
|
case "sysEx":
|
|
299
286
|
this.handleSysEx(event.data);
|
|
@@ -373,7 +360,6 @@ class MidyGM1 {
|
|
|
373
360
|
const tmpChannels = new Array(16);
|
|
374
361
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
375
362
|
tmpChannels[i] = {
|
|
376
|
-
durationTicks: new Map(),
|
|
377
363
|
programNumber: -1,
|
|
378
364
|
bank: this.channels[i].bank,
|
|
379
365
|
};
|
|
@@ -390,16 +376,6 @@ class MidyGM1 {
|
|
|
390
376
|
instruments.add(`${channel.bank}:0`);
|
|
391
377
|
channel.programNumber = 0;
|
|
392
378
|
}
|
|
393
|
-
channel.durationTicks.set(event.noteNumber, {
|
|
394
|
-
ticks: event.ticks,
|
|
395
|
-
noteOn: event,
|
|
396
|
-
});
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
case "noteOff": {
|
|
400
|
-
const { ticks, noteOn } = tmpChannels[event.channel].durationTicks
|
|
401
|
-
.get(event.noteNumber);
|
|
402
|
-
noteOn.durationTicks = event.ticks - ticks;
|
|
403
379
|
break;
|
|
404
380
|
}
|
|
405
381
|
case "programChange": {
|
|
@@ -413,8 +389,8 @@ class MidyGM1 {
|
|
|
413
389
|
});
|
|
414
390
|
});
|
|
415
391
|
const priority = {
|
|
416
|
-
|
|
417
|
-
|
|
392
|
+
controller: 0,
|
|
393
|
+
sysEx: 1,
|
|
418
394
|
};
|
|
419
395
|
timeline.sort((a, b) => {
|
|
420
396
|
if (a.ticks !== b.ticks)
|
|
@@ -537,9 +513,7 @@ class MidyGM1 {
|
|
|
537
513
|
}
|
|
538
514
|
setVolumeEnvelope(channel, note) {
|
|
539
515
|
const { instrumentKey, startTime, velocity } = note;
|
|
540
|
-
note.gainNode = new GainNode(this.audioContext, {
|
|
541
|
-
gain: 0,
|
|
542
|
-
});
|
|
516
|
+
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
543
517
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
544
518
|
if (volume === 0)
|
|
545
519
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
@@ -729,20 +703,22 @@ class MidyGM1 {
|
|
|
729
703
|
}
|
|
730
704
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
731
705
|
const pitchBend = msb * 128 + lsb;
|
|
732
|
-
this.
|
|
706
|
+
this.setPitchBend(channelNumber, pitchBend);
|
|
733
707
|
}
|
|
734
|
-
|
|
708
|
+
setPitchBend(channelNumber, pitchBend) {
|
|
735
709
|
const now = this.audioContext.currentTime;
|
|
736
710
|
const channel = this.channels[channelNumber];
|
|
711
|
+
const prevPitchBend = channel.pitchBend;
|
|
737
712
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
738
|
-
const
|
|
713
|
+
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
714
|
+
channel.pitchBendRange * 100;
|
|
739
715
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
740
716
|
activeNotes.forEach((activeNote) => {
|
|
741
|
-
const { bufferSource
|
|
742
|
-
const
|
|
743
|
-
bufferSource.
|
|
717
|
+
const { bufferSource } = activeNote;
|
|
718
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
719
|
+
bufferSource.detune
|
|
744
720
|
.cancelScheduledValues(now)
|
|
745
|
-
.setValueAtTime(
|
|
721
|
+
.setValueAtTime(detune, now);
|
|
746
722
|
});
|
|
747
723
|
}
|
|
748
724
|
handleControlChange(channelNumber, controller, value) {
|
|
@@ -796,12 +772,17 @@ class MidyGM1 {
|
|
|
796
772
|
channel.volume = volume / 127;
|
|
797
773
|
this.updateChannelGain(channel);
|
|
798
774
|
}
|
|
775
|
+
panToGain(pan) {
|
|
776
|
+
const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
|
|
777
|
+
return {
|
|
778
|
+
gainLeft: Math.cos(theta),
|
|
779
|
+
gainRight: Math.sin(theta),
|
|
780
|
+
};
|
|
781
|
+
}
|
|
799
782
|
setPan(channelNumber, pan) {
|
|
800
|
-
const now = this.audioContext.currentTime;
|
|
801
783
|
const channel = this.channels[channelNumber];
|
|
802
|
-
channel.pan = pan
|
|
803
|
-
|
|
804
|
-
channel.pannerNode.pan.setValueAtTime(channel.pan, now);
|
|
784
|
+
channel.pan = pan;
|
|
785
|
+
this.updateChannelGain(channel);
|
|
805
786
|
}
|
|
806
787
|
setExpression(channelNumber, expression) {
|
|
807
788
|
const channel = this.channels[channelNumber];
|
|
@@ -811,8 +792,13 @@ class MidyGM1 {
|
|
|
811
792
|
updateChannelGain(channel) {
|
|
812
793
|
const now = this.audioContext.currentTime;
|
|
813
794
|
const volume = channel.volume * channel.expression;
|
|
814
|
-
channel.
|
|
815
|
-
channel.
|
|
795
|
+
const { gainLeft, gainRight } = this.panToGain(channel.pan);
|
|
796
|
+
channel.gainL.gain
|
|
797
|
+
.cancelScheduledValues(now)
|
|
798
|
+
.setValueAtTime(volume * gainLeft, now);
|
|
799
|
+
channel.gainR.gain
|
|
800
|
+
.cancelScheduledValues(now)
|
|
801
|
+
.setValueAtTime(volume * gainRight, now);
|
|
816
802
|
}
|
|
817
803
|
setSustainPedal(channelNumber, value) {
|
|
818
804
|
const isOn = value >= 64;
|
|
@@ -834,8 +820,7 @@ class MidyGM1 {
|
|
|
834
820
|
const { dataMSB, dataLSB } = channel;
|
|
835
821
|
switch (rpn) {
|
|
836
822
|
case 0:
|
|
837
|
-
|
|
838
|
-
break;
|
|
823
|
+
return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
|
|
839
824
|
case 1:
|
|
840
825
|
channel.fineTuning = (dataMSB * 128 + dataLSB - 8192) / 8192;
|
|
841
826
|
break;
|
|
@@ -846,6 +831,26 @@ class MidyGM1 {
|
|
|
846
831
|
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
847
832
|
}
|
|
848
833
|
}
|
|
834
|
+
handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
|
|
835
|
+
const pitchBendRange = dataMSB + dataLSB / 100;
|
|
836
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
837
|
+
}
|
|
838
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
839
|
+
const now = this.audioContext.currentTime;
|
|
840
|
+
const channel = this.channels[channelNumber];
|
|
841
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
842
|
+
channel.pitchBendRange = pitchBendRange;
|
|
843
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
844
|
+
channel.pitchBend * 100;
|
|
845
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
846
|
+
activeNotes.forEach((activeNote) => {
|
|
847
|
+
const { bufferSource } = activeNote;
|
|
848
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
849
|
+
bufferSource.detune
|
|
850
|
+
.cancelScheduledValues(now)
|
|
851
|
+
.setValueAtTime(detune, now);
|
|
852
|
+
});
|
|
853
|
+
}
|
|
849
854
|
allSoundOff(channelNumber) {
|
|
850
855
|
const now = this.audioContext.currentTime;
|
|
851
856
|
const channel = this.channels[channelNumber];
|
|
@@ -921,9 +926,9 @@ class MidyGM1 {
|
|
|
921
926
|
}
|
|
922
927
|
handleMasterVolumeSysEx(data) {
|
|
923
928
|
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
924
|
-
this.
|
|
929
|
+
this.setMasterVolume(volume);
|
|
925
930
|
}
|
|
926
|
-
|
|
931
|
+
setMasterVolume(volume) {
|
|
927
932
|
if (volume < 0 && 1 < volume) {
|
|
928
933
|
console.error("Master Volume is out of range");
|
|
929
934
|
}
|
|
@@ -965,7 +970,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
|
|
|
965
970
|
writable: true,
|
|
966
971
|
value: {
|
|
967
972
|
volume: 100 / 127,
|
|
968
|
-
pan:
|
|
973
|
+
pan: 64,
|
|
969
974
|
bank: 0,
|
|
970
975
|
dataMSB: 0,
|
|
971
976
|
dataLSB: 0,
|
package/script/midy-GM2.d.ts
CHANGED
|
@@ -234,12 +234,16 @@ export class MidyGM2 {
|
|
|
234
234
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
235
235
|
handleChannelPressure(channelNumber: any, pressure: any): void;
|
|
236
236
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
237
|
-
|
|
237
|
+
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
238
238
|
handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
|
|
239
239
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
240
240
|
setModulation(channelNumber: any, modulation: any): void;
|
|
241
241
|
setPortamentoTime(channelNumber: any, portamentoTime: any): void;
|
|
242
242
|
setVolume(channelNumber: any, volume: any): void;
|
|
243
|
+
panToGain(pan: any): {
|
|
244
|
+
gainLeft: number;
|
|
245
|
+
gainRight: number;
|
|
246
|
+
};
|
|
243
247
|
setPan(channelNumber: any, pan: any): void;
|
|
244
248
|
setExpression(channelNumber: any, expression: any): void;
|
|
245
249
|
setBankLSB(channelNumber: any, lsb: any): void;
|
|
@@ -253,6 +257,8 @@ export class MidyGM2 {
|
|
|
253
257
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
254
258
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
255
259
|
setDataEntry(channelNumber: any, value: any, isMSB: any): void;
|
|
260
|
+
handlePitchBendRangeMessage(channelNumber: any, dataMSB: any, dataLSB: any): void;
|
|
261
|
+
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
256
262
|
allSoundOff(channelNumber: any): any[];
|
|
257
263
|
resetAllControllers(channelNumber: any): void;
|
|
258
264
|
allNotesOff(channelNumber: any): any[];
|
|
@@ -265,11 +271,11 @@ export class MidyGM2 {
|
|
|
265
271
|
GM2SystemOn(): void;
|
|
266
272
|
handleUniversalRealTimeExclusiveMessage(data: any): void;
|
|
267
273
|
handleMasterVolumeSysEx(data: any): void;
|
|
268
|
-
|
|
274
|
+
setMasterVolume(volume: any): void;
|
|
269
275
|
handleMasterFineTuningSysEx(data: any): void;
|
|
270
|
-
|
|
276
|
+
setMasterFineTuning(fineTuning: any): void;
|
|
271
277
|
handleMasterCoarseTuningSysEx(data: any): void;
|
|
272
|
-
|
|
278
|
+
setMasterCoarseTuning(coarseTuning: any): void;
|
|
273
279
|
handleExclusiveMessage(data: any): void;
|
|
274
280
|
handleSysEx(data: any): void;
|
|
275
281
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
package/script/midy-GM2.d.ts.map
CHANGED
|
@@ -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;IAEF,+BAMC;IAtED,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;IA4ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAoBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAcC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAkDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;MAiBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAtED,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;IA4ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAoBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAcC;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;;;;MAoCC;IAED;;;;;MAqCC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHAiCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAoDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAeC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAiBC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,sCAUC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAWC;IAED,uDAGC;IAED,gDAEC;IAED,gDAEC;IAED,+DA0BC;IAED,kFAGC;IAED,iEAeC;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;AAv4CD;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-GM2.js
CHANGED
|
@@ -337,7 +337,7 @@ class MidyGM2 {
|
|
|
337
337
|
this.handleChannelPressure(event.channel, event.amount);
|
|
338
338
|
break;
|
|
339
339
|
case "pitchBend":
|
|
340
|
-
this.
|
|
340
|
+
this.setPitchBend(event.channel, event.value);
|
|
341
341
|
break;
|
|
342
342
|
case "sysEx":
|
|
343
343
|
this.handleSysEx(event.data);
|
|
@@ -417,7 +417,6 @@ class MidyGM2 {
|
|
|
417
417
|
const tmpChannels = new Array(16);
|
|
418
418
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
419
419
|
tmpChannels[i] = {
|
|
420
|
-
durationTicks: new Map(),
|
|
421
420
|
programNumber: -1,
|
|
422
421
|
bankMSB: this.channels[i].bankMSB,
|
|
423
422
|
bankLSB: this.channels[i].bankLSB,
|
|
@@ -447,16 +446,6 @@ class MidyGM2 {
|
|
|
447
446
|
}
|
|
448
447
|
channel.programNumber = 0;
|
|
449
448
|
}
|
|
450
|
-
channel.durationTicks.set(event.noteNumber, {
|
|
451
|
-
ticks: event.ticks,
|
|
452
|
-
noteOn: event,
|
|
453
|
-
});
|
|
454
|
-
break;
|
|
455
|
-
}
|
|
456
|
-
case "noteOff": {
|
|
457
|
-
const { ticks, noteOn } = tmpChannels[event.channel].durationTicks
|
|
458
|
-
.get(event.noteNumber);
|
|
459
|
-
noteOn.durationTicks = event.ticks - ticks;
|
|
460
449
|
break;
|
|
461
450
|
}
|
|
462
451
|
case "controller":
|
|
@@ -491,8 +480,8 @@ class MidyGM2 {
|
|
|
491
480
|
});
|
|
492
481
|
});
|
|
493
482
|
const priority = {
|
|
494
|
-
|
|
495
|
-
|
|
483
|
+
controller: 0,
|
|
484
|
+
sysEx: 1,
|
|
496
485
|
};
|
|
497
486
|
timeline.sort((a, b) => {
|
|
498
487
|
if (a.ticks !== b.ticks)
|
|
@@ -630,12 +619,8 @@ class MidyGM2 {
|
|
|
630
619
|
}
|
|
631
620
|
createChorusEffect(audioContext, options = {}) {
|
|
632
621
|
const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
|
|
633
|
-
const lfo = new OscillatorNode(audioContext, {
|
|
634
|
-
|
|
635
|
-
});
|
|
636
|
-
const lfoGain = new GainNode(audioContext, {
|
|
637
|
-
gain: chorusDepth,
|
|
638
|
-
});
|
|
622
|
+
const lfo = new OscillatorNode(audioContext, { frequency: chorusRate });
|
|
623
|
+
const lfoGain = new GainNode(audioContext, { gain: chorusDepth });
|
|
639
624
|
const chorusGains = [];
|
|
640
625
|
const delayNodes = [];
|
|
641
626
|
const baseGain = 1 / chorusCount;
|
|
@@ -646,9 +631,7 @@ class MidyGM2 {
|
|
|
646
631
|
maxDelayTime: delayTime,
|
|
647
632
|
});
|
|
648
633
|
delayNodes.push(delayNode);
|
|
649
|
-
const chorusGain = new GainNode(audioContext, {
|
|
650
|
-
gain: baseGain,
|
|
651
|
-
});
|
|
634
|
+
const chorusGain = new GainNode(audioContext, { gain: baseGain });
|
|
652
635
|
chorusGains.push(chorusGain);
|
|
653
636
|
lfo.connect(lfoGain);
|
|
654
637
|
lfoGain.connect(delayNode.delayTime);
|
|
@@ -710,9 +693,7 @@ class MidyGM2 {
|
|
|
710
693
|
}
|
|
711
694
|
setVolumeEnvelope(channel, note) {
|
|
712
695
|
const { instrumentKey, startTime, velocity } = note;
|
|
713
|
-
note.gainNode = new GainNode(this.audioContext, {
|
|
714
|
-
gain: 0,
|
|
715
|
-
});
|
|
696
|
+
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
716
697
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
717
698
|
if (volume === 0)
|
|
718
699
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
@@ -951,20 +932,22 @@ class MidyGM2 {
|
|
|
951
932
|
}
|
|
952
933
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
953
934
|
const pitchBend = msb * 128 + lsb;
|
|
954
|
-
this.
|
|
935
|
+
this.setPitchBend(channelNumber, pitchBend);
|
|
955
936
|
}
|
|
956
|
-
|
|
937
|
+
setPitchBend(channelNumber, pitchBend) {
|
|
957
938
|
const now = this.audioContext.currentTime;
|
|
958
939
|
const channel = this.channels[channelNumber];
|
|
940
|
+
const prevPitchBend = channel.pitchBend;
|
|
959
941
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
960
|
-
const
|
|
942
|
+
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
943
|
+
channel.pitchBendRange * 100;
|
|
961
944
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
962
945
|
activeNotes.forEach((activeNote) => {
|
|
963
|
-
const { bufferSource
|
|
964
|
-
const
|
|
965
|
-
bufferSource.
|
|
946
|
+
const { bufferSource } = activeNote;
|
|
947
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
948
|
+
bufferSource.detune
|
|
966
949
|
.cancelScheduledValues(now)
|
|
967
|
-
.setValueAtTime(
|
|
950
|
+
.setValueAtTime(detune, now);
|
|
968
951
|
});
|
|
969
952
|
}
|
|
970
953
|
handleControlChange(channelNumber, controller, value) {
|
|
@@ -1048,12 +1031,17 @@ class MidyGM2 {
|
|
|
1048
1031
|
channel.volume = volume / 127;
|
|
1049
1032
|
this.updateChannelGain(channel);
|
|
1050
1033
|
}
|
|
1034
|
+
panToGain(pan) {
|
|
1035
|
+
const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
|
|
1036
|
+
return {
|
|
1037
|
+
gainLeft: Math.cos(theta),
|
|
1038
|
+
gainRight: Math.sin(theta),
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1051
1041
|
setPan(channelNumber, pan) {
|
|
1052
|
-
const now = this.audioContext.currentTime;
|
|
1053
1042
|
const channel = this.channels[channelNumber];
|
|
1054
|
-
channel.pan = pan
|
|
1055
|
-
|
|
1056
|
-
channel.pannerNode.pan.setValueAtTime(channel.pan, now);
|
|
1043
|
+
channel.pan = pan;
|
|
1044
|
+
this.updateChannelGain(channel);
|
|
1057
1045
|
}
|
|
1058
1046
|
setExpression(channelNumber, expression) {
|
|
1059
1047
|
const channel = this.channels[channelNumber];
|
|
@@ -1066,8 +1054,13 @@ class MidyGM2 {
|
|
|
1066
1054
|
updateChannelGain(channel) {
|
|
1067
1055
|
const now = this.audioContext.currentTime;
|
|
1068
1056
|
const volume = channel.volume * channel.expression;
|
|
1069
|
-
channel.
|
|
1070
|
-
channel.
|
|
1057
|
+
const { gainLeft, gainRight } = this.panToGain(channel.pan);
|
|
1058
|
+
channel.gainL.gain
|
|
1059
|
+
.cancelScheduledValues(now)
|
|
1060
|
+
.setValueAtTime(volume * gainLeft, now);
|
|
1061
|
+
channel.gainR.gain
|
|
1062
|
+
.cancelScheduledValues(now)
|
|
1063
|
+
.setValueAtTime(volume * gainRight, now);
|
|
1071
1064
|
}
|
|
1072
1065
|
setSustainPedal(channelNumber, value) {
|
|
1073
1066
|
const isOn = value >= 64;
|
|
@@ -1099,7 +1092,8 @@ class MidyGM2 {
|
|
|
1099
1092
|
const channel = this.channels[channelNumber];
|
|
1100
1093
|
channel.sostenutoPedal = isOn;
|
|
1101
1094
|
if (isOn) {
|
|
1102
|
-
const
|
|
1095
|
+
const now = this.audioContext.currentTime;
|
|
1096
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
1103
1097
|
channel.sostenutoNotes = new Map(activeNotes);
|
|
1104
1098
|
}
|
|
1105
1099
|
else {
|
|
@@ -1123,8 +1117,7 @@ class MidyGM2 {
|
|
|
1123
1117
|
const { dataMSB, dataLSB } = channel;
|
|
1124
1118
|
switch (rpn) {
|
|
1125
1119
|
case 0:
|
|
1126
|
-
|
|
1127
|
-
break;
|
|
1120
|
+
return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
|
|
1128
1121
|
case 1:
|
|
1129
1122
|
channel.fineTuning = (dataMSB * 128 + dataLSB - 8192) / 8192;
|
|
1130
1123
|
break;
|
|
@@ -1138,6 +1131,26 @@ class MidyGM2 {
|
|
|
1138
1131
|
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
1139
1132
|
}
|
|
1140
1133
|
}
|
|
1134
|
+
handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
|
|
1135
|
+
const pitchBendRange = dataMSB + dataLSB / 100;
|
|
1136
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1137
|
+
}
|
|
1138
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
1139
|
+
const now = this.audioContext.currentTime;
|
|
1140
|
+
const channel = this.channels[channelNumber];
|
|
1141
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
1142
|
+
channel.pitchBendRange = pitchBendRange;
|
|
1143
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
1144
|
+
channel.pitchBend * 100;
|
|
1145
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
1146
|
+
activeNotes.forEach((activeNote) => {
|
|
1147
|
+
const { bufferSource } = activeNote;
|
|
1148
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
1149
|
+
bufferSource.detune
|
|
1150
|
+
.cancelScheduledValues(now)
|
|
1151
|
+
.setValueAtTime(detune, now);
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1141
1154
|
allSoundOff(channelNumber) {
|
|
1142
1155
|
const now = this.audioContext.currentTime;
|
|
1143
1156
|
const channel = this.channels[channelNumber];
|
|
@@ -1228,9 +1241,9 @@ class MidyGM2 {
|
|
|
1228
1241
|
case 1:
|
|
1229
1242
|
return this.handleMasterVolumeSysEx(data);
|
|
1230
1243
|
case 3:
|
|
1231
|
-
return this.
|
|
1244
|
+
return this.handleMasterFineTuningSysEx(data);
|
|
1232
1245
|
case 4:
|
|
1233
|
-
return this.
|
|
1246
|
+
return this.handleMasterCoarseTuningSysEx(data);
|
|
1234
1247
|
// case 5: // TODO: Global Parameter Control
|
|
1235
1248
|
default:
|
|
1236
1249
|
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
@@ -1272,9 +1285,9 @@ class MidyGM2 {
|
|
|
1272
1285
|
}
|
|
1273
1286
|
handleMasterVolumeSysEx(data) {
|
|
1274
1287
|
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
1275
|
-
this.
|
|
1288
|
+
this.setMasterVolume(volume);
|
|
1276
1289
|
}
|
|
1277
|
-
|
|
1290
|
+
setMasterVolume(volume) {
|
|
1278
1291
|
if (volume < 0 && 1 < volume) {
|
|
1279
1292
|
console.error("Master Volume is out of range");
|
|
1280
1293
|
}
|
|
@@ -1286,9 +1299,9 @@ class MidyGM2 {
|
|
|
1286
1299
|
}
|
|
1287
1300
|
handleMasterFineTuningSysEx(data) {
|
|
1288
1301
|
const fineTuning = (data[5] * 128 + data[4] - 8192) / 8192;
|
|
1289
|
-
this.
|
|
1302
|
+
this.setMasterFineTuning(fineTuning);
|
|
1290
1303
|
}
|
|
1291
|
-
|
|
1304
|
+
setMasterFineTuning(fineTuning) {
|
|
1292
1305
|
if (fineTuning < -1 && 1 < fineTuning) {
|
|
1293
1306
|
console.error("Master Fine Tuning value is out of range");
|
|
1294
1307
|
}
|
|
@@ -1298,9 +1311,9 @@ class MidyGM2 {
|
|
|
1298
1311
|
}
|
|
1299
1312
|
handleMasterCoarseTuningSysEx(data) {
|
|
1300
1313
|
const coarseTuning = data[4];
|
|
1301
|
-
this.
|
|
1314
|
+
this.setMasterCoarseTuning(coarseTuning);
|
|
1302
1315
|
}
|
|
1303
|
-
|
|
1316
|
+
setMasterCoarseTuning(coarseTuning) {
|
|
1304
1317
|
if (coarseTuning < 0 && 127 < coarseTuning) {
|
|
1305
1318
|
console.error("Master Coarse Tuning value is out of range");
|
|
1306
1319
|
}
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -39,8 +39,8 @@ export class MidyGMLite {
|
|
|
39
39
|
masterGain: any;
|
|
40
40
|
channels: {
|
|
41
41
|
scheduledNotes: Map<any, any>;
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
gainL: any;
|
|
43
|
+
gainR: any;
|
|
44
44
|
expression: number;
|
|
45
45
|
modulation: number;
|
|
46
46
|
sustainPedal: boolean;
|
|
@@ -61,13 +61,13 @@ export class MidyGMLite {
|
|
|
61
61
|
loadSoundFont(soundFontUrl: any): Promise<void>;
|
|
62
62
|
loadMIDI(midiUrl: any): Promise<void>;
|
|
63
63
|
setChannelAudioNodes(audioContext: any): {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
gainL: any;
|
|
65
|
+
gainR: any;
|
|
66
66
|
};
|
|
67
67
|
createChannels(audioContext: any): {
|
|
68
68
|
scheduledNotes: Map<any, any>;
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
gainL: any;
|
|
70
|
+
gainR: any;
|
|
71
71
|
expression: number;
|
|
72
72
|
modulation: number;
|
|
73
73
|
sustainPedal: boolean;
|
|
@@ -122,10 +122,14 @@ export class MidyGMLite {
|
|
|
122
122
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
|
|
123
123
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
124
124
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
125
|
-
|
|
125
|
+
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
126
126
|
handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
|
|
127
127
|
setModulation(channelNumber: any, modulation: any): void;
|
|
128
128
|
setVolume(channelNumber: any, volume: any): void;
|
|
129
|
+
panToGain(pan: any): {
|
|
130
|
+
gainLeft: number;
|
|
131
|
+
gainRight: number;
|
|
132
|
+
};
|
|
129
133
|
setPan(channelNumber: any, pan: any): void;
|
|
130
134
|
setExpression(channelNumber: any, expression: any): void;
|
|
131
135
|
updateChannelGain(channel: any): void;
|
|
@@ -133,6 +137,8 @@ export class MidyGMLite {
|
|
|
133
137
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
134
138
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
135
139
|
setDataEntry(channelNumber: any, value: any, isMSB: any): void;
|
|
140
|
+
handlePitchBendRangeMessage(channelNumber: any, dataMSB: any, dataLSB: any): void;
|
|
141
|
+
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
136
142
|
allSoundOff(channelNumber: any): any[];
|
|
137
143
|
resetAllControllers(channelNumber: any): void;
|
|
138
144
|
allNotesOff(channelNumber: any): any[];
|
|
@@ -140,7 +146,7 @@ export class MidyGMLite {
|
|
|
140
146
|
GM1SystemOn(): void;
|
|
141
147
|
handleUniversalRealTimeExclusiveMessage(data: any): void;
|
|
142
148
|
handleMasterVolumeSysEx(data: any): void;
|
|
143
|
-
|
|
149
|
+
setMasterVolume(volume: any): void;
|
|
144
150
|
handleExclusiveMessage(data: any): void;
|
|
145
151
|
handleSysEx(data: any): void;
|
|
146
152
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,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;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,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;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAcC;IAED;;;;;;;;;;;;;;;;;;QAUC;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,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHA6BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIAmDC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAeC;IAED,mFA+BC;IAED,yDAiBC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,sCAUC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAiBC;IAED,kFAGC;IAED,iEAeC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAl/BD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|