@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/esm/midy-GMLite.js
CHANGED
|
@@ -183,17 +183,16 @@ export class MidyGMLite {
|
|
|
183
183
|
this.totalTime = this.calcTotalTime();
|
|
184
184
|
}
|
|
185
185
|
setChannelAudioNodes(audioContext) {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
});
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
gainNode.connect(this.masterGain);
|
|
186
|
+
const { gainLeft, gainRight } = this.panToGain(MidyGMLite.channelSettings.pan);
|
|
187
|
+
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
188
|
+
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
189
|
+
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
190
|
+
gainL.connect(merger, 0, 0);
|
|
191
|
+
gainR.connect(merger, 0, 1);
|
|
192
|
+
merger.connect(this.masterGain);
|
|
194
193
|
return {
|
|
195
|
-
|
|
196
|
-
|
|
194
|
+
gainL,
|
|
195
|
+
gainR,
|
|
197
196
|
};
|
|
198
197
|
}
|
|
199
198
|
createChannels(audioContext) {
|
|
@@ -278,7 +277,7 @@ export class MidyGMLite {
|
|
|
278
277
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
279
278
|
break;
|
|
280
279
|
case "pitchBend":
|
|
281
|
-
this.
|
|
280
|
+
this.setPitchBend(event.channel, event.value);
|
|
282
281
|
break;
|
|
283
282
|
case "sysEx":
|
|
284
283
|
this.handleSysEx(event.data);
|
|
@@ -358,7 +357,6 @@ export class MidyGMLite {
|
|
|
358
357
|
const tmpChannels = new Array(16);
|
|
359
358
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
360
359
|
tmpChannels[i] = {
|
|
361
|
-
durationTicks: new Map(),
|
|
362
360
|
programNumber: -1,
|
|
363
361
|
bank: this.channels[i].bank,
|
|
364
362
|
};
|
|
@@ -375,16 +373,6 @@ export class MidyGMLite {
|
|
|
375
373
|
instruments.add(`${channel.bank}:0`);
|
|
376
374
|
channel.programNumber = 0;
|
|
377
375
|
}
|
|
378
|
-
channel.durationTicks.set(event.noteNumber, {
|
|
379
|
-
ticks: event.ticks,
|
|
380
|
-
noteOn: event,
|
|
381
|
-
});
|
|
382
|
-
break;
|
|
383
|
-
}
|
|
384
|
-
case "noteOff": {
|
|
385
|
-
const { ticks, noteOn } = tmpChannels[event.channel].durationTicks
|
|
386
|
-
.get(event.noteNumber);
|
|
387
|
-
noteOn.durationTicks = event.ticks - ticks;
|
|
388
376
|
break;
|
|
389
377
|
}
|
|
390
378
|
case "programChange": {
|
|
@@ -398,8 +386,8 @@ export class MidyGMLite {
|
|
|
398
386
|
});
|
|
399
387
|
});
|
|
400
388
|
const priority = {
|
|
401
|
-
|
|
402
|
-
|
|
389
|
+
controller: 0,
|
|
390
|
+
sysEx: 1,
|
|
403
391
|
};
|
|
404
392
|
timeline.sort((a, b) => {
|
|
405
393
|
if (a.ticks !== b.ticks)
|
|
@@ -521,9 +509,7 @@ export class MidyGMLite {
|
|
|
521
509
|
}
|
|
522
510
|
setVolumeEnvelope(channel, note) {
|
|
523
511
|
const { instrumentKey, startTime, velocity } = note;
|
|
524
|
-
note.gainNode = new GainNode(this.audioContext, {
|
|
525
|
-
gain: 0,
|
|
526
|
-
});
|
|
512
|
+
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
527
513
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
528
514
|
if (volume === 0)
|
|
529
515
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
@@ -713,20 +699,22 @@ export class MidyGMLite {
|
|
|
713
699
|
}
|
|
714
700
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
715
701
|
const pitchBend = msb * 128 + lsb;
|
|
716
|
-
this.
|
|
702
|
+
this.setPitchBend(channelNumber, pitchBend);
|
|
717
703
|
}
|
|
718
|
-
|
|
704
|
+
setPitchBend(channelNumber, pitchBend) {
|
|
719
705
|
const now = this.audioContext.currentTime;
|
|
720
706
|
const channel = this.channels[channelNumber];
|
|
707
|
+
const prevPitchBend = channel.pitchBend;
|
|
721
708
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
722
|
-
const
|
|
709
|
+
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
710
|
+
channel.pitchBendRange * 100;
|
|
723
711
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
724
712
|
activeNotes.forEach((activeNote) => {
|
|
725
|
-
const { bufferSource
|
|
726
|
-
const
|
|
727
|
-
bufferSource.
|
|
713
|
+
const { bufferSource } = activeNote;
|
|
714
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
715
|
+
bufferSource.detune
|
|
728
716
|
.cancelScheduledValues(now)
|
|
729
|
-
.setValueAtTime(
|
|
717
|
+
.setValueAtTime(detune, now);
|
|
730
718
|
});
|
|
731
719
|
}
|
|
732
720
|
handleControlChange(channelNumber, controller, value) {
|
|
@@ -780,12 +768,17 @@ export class MidyGMLite {
|
|
|
780
768
|
channel.volume = volume / 127;
|
|
781
769
|
this.updateChannelGain(channel);
|
|
782
770
|
}
|
|
771
|
+
panToGain(pan) {
|
|
772
|
+
const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
|
|
773
|
+
return {
|
|
774
|
+
gainLeft: Math.cos(theta),
|
|
775
|
+
gainRight: Math.sin(theta),
|
|
776
|
+
};
|
|
777
|
+
}
|
|
783
778
|
setPan(channelNumber, pan) {
|
|
784
|
-
const now = this.audioContext.currentTime;
|
|
785
779
|
const channel = this.channels[channelNumber];
|
|
786
|
-
channel.pan = pan
|
|
787
|
-
|
|
788
|
-
channel.pannerNode.pan.setValueAtTime(channel.pan, now);
|
|
780
|
+
channel.pan = pan;
|
|
781
|
+
this.updateChannelGain(channel);
|
|
789
782
|
}
|
|
790
783
|
setExpression(channelNumber, expression) {
|
|
791
784
|
const channel = this.channels[channelNumber];
|
|
@@ -795,8 +788,13 @@ export class MidyGMLite {
|
|
|
795
788
|
updateChannelGain(channel) {
|
|
796
789
|
const now = this.audioContext.currentTime;
|
|
797
790
|
const volume = channel.volume * channel.expression;
|
|
798
|
-
channel.
|
|
799
|
-
channel.
|
|
791
|
+
const { gainLeft, gainRight } = this.panToGain(channel.pan);
|
|
792
|
+
channel.gainL.gain
|
|
793
|
+
.cancelScheduledValues(now)
|
|
794
|
+
.setValueAtTime(volume * gainLeft, now);
|
|
795
|
+
channel.gainR.gain
|
|
796
|
+
.cancelScheduledValues(now)
|
|
797
|
+
.setValueAtTime(volume * gainRight, now);
|
|
800
798
|
}
|
|
801
799
|
setSustainPedal(channelNumber, value) {
|
|
802
800
|
const isOn = value >= 64;
|
|
@@ -818,12 +816,31 @@ export class MidyGMLite {
|
|
|
818
816
|
const { dataMSB, dataLSB } = channel;
|
|
819
817
|
switch (rpn) {
|
|
820
818
|
case 0:
|
|
821
|
-
|
|
822
|
-
break;
|
|
819
|
+
return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
|
|
823
820
|
default:
|
|
824
821
|
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
825
822
|
}
|
|
826
823
|
}
|
|
824
|
+
handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
|
|
825
|
+
const pitchBendRange = dataMSB + dataLSB / 100;
|
|
826
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
827
|
+
}
|
|
828
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
829
|
+
const now = this.audioContext.currentTime;
|
|
830
|
+
const channel = this.channels[channelNumber];
|
|
831
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
832
|
+
channel.pitchBendRange = pitchBendRange;
|
|
833
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
834
|
+
channel.pitchBend * 100;
|
|
835
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
836
|
+
activeNotes.forEach((activeNote) => {
|
|
837
|
+
const { bufferSource } = activeNote;
|
|
838
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
839
|
+
bufferSource.detune
|
|
840
|
+
.cancelScheduledValues(now)
|
|
841
|
+
.setValueAtTime(detune, now);
|
|
842
|
+
});
|
|
843
|
+
}
|
|
827
844
|
allSoundOff(channelNumber) {
|
|
828
845
|
const now = this.audioContext.currentTime;
|
|
829
846
|
const channel = this.channels[channelNumber];
|
|
@@ -899,9 +916,9 @@ export class MidyGMLite {
|
|
|
899
916
|
}
|
|
900
917
|
handleMasterVolumeSysEx(data) {
|
|
901
918
|
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
902
|
-
this.
|
|
919
|
+
this.setMasterVolume(volume);
|
|
903
920
|
}
|
|
904
|
-
|
|
921
|
+
setMasterVolume(volume) {
|
|
905
922
|
if (volume < 0 && 1 < volume) {
|
|
906
923
|
console.error("Master Volume is out of range");
|
|
907
924
|
}
|
|
@@ -942,7 +959,7 @@ Object.defineProperty(MidyGMLite, "channelSettings", {
|
|
|
942
959
|
writable: true,
|
|
943
960
|
value: {
|
|
944
961
|
volume: 100 / 127,
|
|
945
|
-
pan:
|
|
962
|
+
pan: 64,
|
|
946
963
|
bank: 0,
|
|
947
964
|
dataMSB: 0,
|
|
948
965
|
dataLSB: 0,
|
package/esm/midy.d.ts
CHANGED
|
@@ -84,8 +84,8 @@ export class Midy {
|
|
|
84
84
|
lfoFilterDepth: number;
|
|
85
85
|
lfoAmplitudeDepth: number;
|
|
86
86
|
};
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
gainL: any;
|
|
88
|
+
gainR: any;
|
|
89
89
|
reverbEffect: {
|
|
90
90
|
convolverNode: any;
|
|
91
91
|
dryGain: any;
|
|
@@ -131,8 +131,8 @@ export class Midy {
|
|
|
131
131
|
loadSoundFont(soundFontUrl: any): Promise<void>;
|
|
132
132
|
loadMIDI(midiUrl: any): Promise<void>;
|
|
133
133
|
setChannelAudioNodes(audioContext: any): {
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
gainL: any;
|
|
135
|
+
gainR: any;
|
|
136
136
|
reverbEffect: {
|
|
137
137
|
convolverNode: any;
|
|
138
138
|
dryGain: any;
|
|
@@ -164,8 +164,8 @@ export class Midy {
|
|
|
164
164
|
lfoFilterDepth: number;
|
|
165
165
|
lfoAmplitudeDepth: number;
|
|
166
166
|
};
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
gainL: any;
|
|
168
|
+
gainR: any;
|
|
169
169
|
reverbEffect: {
|
|
170
170
|
convolverNode: any;
|
|
171
171
|
dryGain: any;
|
|
@@ -261,12 +261,16 @@ export class Midy {
|
|
|
261
261
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
262
262
|
handleChannelPressure(channelNumber: any, pressure: any): void;
|
|
263
263
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
264
|
-
|
|
264
|
+
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
265
265
|
handleControlChange(channelNumber: any, controller: any, value: any): any;
|
|
266
266
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
267
267
|
setModulation(channelNumber: any, modulation: any): void;
|
|
268
268
|
setPortamentoTime(channelNumber: any, portamentoTime: any): void;
|
|
269
269
|
setVolume(channelNumber: any, volume: any): void;
|
|
270
|
+
panToGain(pan: any): {
|
|
271
|
+
gainLeft: number;
|
|
272
|
+
gainRight: number;
|
|
273
|
+
};
|
|
270
274
|
setPan(channelNumber: any, pan: any): void;
|
|
271
275
|
setExpression(channelNumber: any, expression: any): void;
|
|
272
276
|
setBankLSB(channelNumber: any, lsb: any): void;
|
|
@@ -285,6 +289,8 @@ export class Midy {
|
|
|
285
289
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
286
290
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
287
291
|
setDataEntry(channelNumber: any, value: any, isMSB: any): void;
|
|
292
|
+
handlePitchBendRangeMessage(channelNumber: any, dataMSB: any, dataLSB: any): void;
|
|
293
|
+
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
288
294
|
allSoundOff(channelNumber: any): any[];
|
|
289
295
|
resetAllControllers(channelNumber: any): void;
|
|
290
296
|
allNotesOff(channelNumber: any): any[];
|
|
@@ -297,11 +303,11 @@ export class Midy {
|
|
|
297
303
|
GM2SystemOn(): void;
|
|
298
304
|
handleUniversalRealTimeExclusiveMessage(data: any): void;
|
|
299
305
|
handleMasterVolumeSysEx(data: any): void;
|
|
300
|
-
|
|
306
|
+
setMasterVolume(volume: any): void;
|
|
301
307
|
handleMasterFineTuningSysEx(data: any): void;
|
|
302
|
-
|
|
308
|
+
setMasterFineTuning(fineTuning: any): void;
|
|
303
309
|
handleMasterCoarseTuningSysEx(data: any): void;
|
|
304
|
-
|
|
310
|
+
setMasterCoarseTuning(coarseTuning: any): void;
|
|
305
311
|
handleExclusiveMessage(data: any): void;
|
|
306
312
|
handleSysEx(data: any): void;
|
|
307
313
|
scheduleTask(callback: any, startTime: any): Promise<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;IAEF,+BAMC;IAzED,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;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,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;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAqBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;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;;;;MAoCC;IAED;;;;;MAqCC;IAED,sDA2BC;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,sIAwDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAeC;IAED,0EAkEC;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,2DAGC;IAED,6DAGC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+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;AAxgDD;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
|
@@ -225,22 +225,23 @@ export class Midy {
|
|
|
225
225
|
this.totalTime = this.calcTotalTime();
|
|
226
226
|
}
|
|
227
227
|
setChannelAudioNodes(audioContext) {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
});
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
228
|
+
const { gainLeft, gainRight } = this.panToGain(Midy.channelSettings.pan);
|
|
229
|
+
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
230
|
+
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
231
|
+
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
232
|
+
gainL.connect(merger, 0, 0);
|
|
233
|
+
gainR.connect(merger, 0, 1);
|
|
234
|
+
merger.connect(this.masterGain);
|
|
234
235
|
const reverbEffect = this.createReverbEffect(audioContext);
|
|
235
236
|
const chorusEffect = this.createChorusEffect(audioContext);
|
|
236
237
|
chorusEffect.lfo.start();
|
|
237
|
-
reverbEffect.dryGain.connect(
|
|
238
|
-
reverbEffect.
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
reverbEffect.dryGain.connect(gainL);
|
|
239
|
+
reverbEffect.dryGain.connect(gainR);
|
|
240
|
+
reverbEffect.wetGain.connect(gainL);
|
|
241
|
+
reverbEffect.wetGain.connect(gainR);
|
|
241
242
|
return {
|
|
242
|
-
|
|
243
|
-
|
|
243
|
+
gainL,
|
|
244
|
+
gainR,
|
|
244
245
|
reverbEffect,
|
|
245
246
|
chorusEffect,
|
|
246
247
|
};
|
|
@@ -340,7 +341,7 @@ export class Midy {
|
|
|
340
341
|
this.handleChannelPressure(event.channel, event.amount);
|
|
341
342
|
break;
|
|
342
343
|
case "pitchBend":
|
|
343
|
-
this.
|
|
344
|
+
this.setPitchBend(event.channel, event.value);
|
|
344
345
|
break;
|
|
345
346
|
case "sysEx":
|
|
346
347
|
this.handleSysEx(event.data);
|
|
@@ -420,7 +421,6 @@ export class Midy {
|
|
|
420
421
|
const tmpChannels = new Array(16);
|
|
421
422
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
422
423
|
tmpChannels[i] = {
|
|
423
|
-
durationTicks: new Map(),
|
|
424
424
|
programNumber: -1,
|
|
425
425
|
bankMSB: this.channels[i].bankMSB,
|
|
426
426
|
bankLSB: this.channels[i].bankLSB,
|
|
@@ -450,16 +450,6 @@ export class Midy {
|
|
|
450
450
|
}
|
|
451
451
|
channel.programNumber = 0;
|
|
452
452
|
}
|
|
453
|
-
channel.durationTicks.set(event.noteNumber, {
|
|
454
|
-
ticks: event.ticks,
|
|
455
|
-
noteOn: event,
|
|
456
|
-
});
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
case "noteOff": {
|
|
460
|
-
const { ticks, noteOn } = tmpChannels[event.channel].durationTicks
|
|
461
|
-
.get(event.noteNumber);
|
|
462
|
-
noteOn.durationTicks = event.ticks - ticks;
|
|
463
453
|
break;
|
|
464
454
|
}
|
|
465
455
|
case "controller":
|
|
@@ -494,8 +484,8 @@ export class Midy {
|
|
|
494
484
|
});
|
|
495
485
|
});
|
|
496
486
|
const priority = {
|
|
497
|
-
|
|
498
|
-
|
|
487
|
+
controller: 0,
|
|
488
|
+
sysEx: 1,
|
|
499
489
|
};
|
|
500
490
|
timeline.sort((a, b) => {
|
|
501
491
|
if (a.ticks !== b.ticks)
|
|
@@ -633,12 +623,8 @@ export class Midy {
|
|
|
633
623
|
}
|
|
634
624
|
createChorusEffect(audioContext, options = {}) {
|
|
635
625
|
const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
|
|
636
|
-
const lfo = new OscillatorNode(audioContext, {
|
|
637
|
-
|
|
638
|
-
});
|
|
639
|
-
const lfoGain = new GainNode(audioContext, {
|
|
640
|
-
gain: chorusDepth,
|
|
641
|
-
});
|
|
626
|
+
const lfo = new OscillatorNode(audioContext, { frequency: chorusRate });
|
|
627
|
+
const lfoGain = new GainNode(audioContext, { gain: chorusDepth });
|
|
642
628
|
const chorusGains = [];
|
|
643
629
|
const delayNodes = [];
|
|
644
630
|
const baseGain = 1 / chorusCount;
|
|
@@ -649,9 +635,7 @@ export class Midy {
|
|
|
649
635
|
maxDelayTime: delayTime,
|
|
650
636
|
});
|
|
651
637
|
delayNodes.push(delayNode);
|
|
652
|
-
const chorusGain = new GainNode(audioContext, {
|
|
653
|
-
gain: baseGain,
|
|
654
|
-
});
|
|
638
|
+
const chorusGain = new GainNode(audioContext, { gain: baseGain });
|
|
655
639
|
chorusGains.push(chorusGain);
|
|
656
640
|
lfo.connect(lfoGain);
|
|
657
641
|
lfoGain.connect(delayNode.delayTime);
|
|
@@ -713,9 +697,7 @@ export class Midy {
|
|
|
713
697
|
}
|
|
714
698
|
setVolumeEnvelope(channel, note) {
|
|
715
699
|
const { instrumentKey, startTime, velocity } = note;
|
|
716
|
-
note.gainNode = new GainNode(this.audioContext, {
|
|
717
|
-
gain: 0,
|
|
718
|
-
});
|
|
700
|
+
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
719
701
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
720
702
|
if (volume === 0)
|
|
721
703
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
@@ -992,20 +974,22 @@ export class Midy {
|
|
|
992
974
|
}
|
|
993
975
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
994
976
|
const pitchBend = msb * 128 + lsb;
|
|
995
|
-
this.
|
|
977
|
+
this.setPitchBend(channelNumber, pitchBend);
|
|
996
978
|
}
|
|
997
|
-
|
|
979
|
+
setPitchBend(channelNumber, pitchBend) {
|
|
998
980
|
const now = this.audioContext.currentTime;
|
|
999
981
|
const channel = this.channels[channelNumber];
|
|
982
|
+
const prevPitchBend = channel.pitchBend;
|
|
1000
983
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
1001
|
-
const
|
|
984
|
+
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
985
|
+
channel.pitchBendRange * 100;
|
|
1002
986
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
1003
987
|
activeNotes.forEach((activeNote) => {
|
|
1004
|
-
const { bufferSource
|
|
1005
|
-
const
|
|
1006
|
-
bufferSource.
|
|
988
|
+
const { bufferSource } = activeNote;
|
|
989
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
990
|
+
bufferSource.detune
|
|
1007
991
|
.cancelScheduledValues(now)
|
|
1008
|
-
.setValueAtTime(
|
|
992
|
+
.setValueAtTime(detune, now);
|
|
1009
993
|
});
|
|
1010
994
|
}
|
|
1011
995
|
handleControlChange(channelNumber, controller, value) {
|
|
@@ -1100,12 +1084,17 @@ export class Midy {
|
|
|
1100
1084
|
channel.volume = volume / 127;
|
|
1101
1085
|
this.updateChannelGain(channel);
|
|
1102
1086
|
}
|
|
1087
|
+
panToGain(pan) {
|
|
1088
|
+
const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
|
|
1089
|
+
return {
|
|
1090
|
+
gainLeft: Math.cos(theta),
|
|
1091
|
+
gainRight: Math.sin(theta),
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1103
1094
|
setPan(channelNumber, pan) {
|
|
1104
|
-
const now = this.audioContext.currentTime;
|
|
1105
1095
|
const channel = this.channels[channelNumber];
|
|
1106
|
-
channel.pan = pan
|
|
1107
|
-
|
|
1108
|
-
channel.pannerNode.pan.setValueAtTime(channel.pan, now);
|
|
1096
|
+
channel.pan = pan;
|
|
1097
|
+
this.updateChannelGain(channel);
|
|
1109
1098
|
}
|
|
1110
1099
|
setExpression(channelNumber, expression) {
|
|
1111
1100
|
const channel = this.channels[channelNumber];
|
|
@@ -1118,8 +1107,13 @@ export class Midy {
|
|
|
1118
1107
|
updateChannelGain(channel) {
|
|
1119
1108
|
const now = this.audioContext.currentTime;
|
|
1120
1109
|
const volume = channel.volume * channel.expression;
|
|
1121
|
-
channel.
|
|
1122
|
-
channel.
|
|
1110
|
+
const { gainLeft, gainRight } = this.panToGain(channel.pan);
|
|
1111
|
+
channel.gainL.gain
|
|
1112
|
+
.cancelScheduledValues(now)
|
|
1113
|
+
.setValueAtTime(volume * gainLeft, now);
|
|
1114
|
+
channel.gainR.gain
|
|
1115
|
+
.cancelScheduledValues(now)
|
|
1116
|
+
.setValueAtTime(volume * gainRight, now);
|
|
1123
1117
|
}
|
|
1124
1118
|
setSustainPedal(channelNumber, value) {
|
|
1125
1119
|
const isOn = value >= 64;
|
|
@@ -1229,8 +1223,7 @@ export class Midy {
|
|
|
1229
1223
|
const { dataMSB, dataLSB } = channel;
|
|
1230
1224
|
switch (rpn) {
|
|
1231
1225
|
case 0:
|
|
1232
|
-
|
|
1233
|
-
break;
|
|
1226
|
+
return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
|
|
1234
1227
|
case 1:
|
|
1235
1228
|
channel.fineTuning = (dataMSB * 128 + dataLSB - 8192) / 8192;
|
|
1236
1229
|
break;
|
|
@@ -1244,6 +1237,26 @@ export class Midy {
|
|
|
1244
1237
|
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
1245
1238
|
}
|
|
1246
1239
|
}
|
|
1240
|
+
handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
|
|
1241
|
+
const pitchBendRange = dataMSB + dataLSB / 100;
|
|
1242
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1243
|
+
}
|
|
1244
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
1245
|
+
const now = this.audioContext.currentTime;
|
|
1246
|
+
const channel = this.channels[channelNumber];
|
|
1247
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
1248
|
+
channel.pitchBendRange = pitchBendRange;
|
|
1249
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
1250
|
+
channel.pitchBend * 100;
|
|
1251
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
1252
|
+
activeNotes.forEach((activeNote) => {
|
|
1253
|
+
const { bufferSource } = activeNote;
|
|
1254
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
1255
|
+
bufferSource.detune
|
|
1256
|
+
.cancelScheduledValues(now)
|
|
1257
|
+
.setValueAtTime(detune, now);
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1247
1260
|
allSoundOff(channelNumber) {
|
|
1248
1261
|
const now = this.audioContext.currentTime;
|
|
1249
1262
|
const channel = this.channels[channelNumber];
|
|
@@ -1334,9 +1347,9 @@ export class Midy {
|
|
|
1334
1347
|
case 1:
|
|
1335
1348
|
return this.handleMasterVolumeSysEx(data);
|
|
1336
1349
|
case 3:
|
|
1337
|
-
return this.
|
|
1350
|
+
return this.handleMasterFineTuningSysEx(data);
|
|
1338
1351
|
case 4:
|
|
1339
|
-
return this.
|
|
1352
|
+
return this.handleMasterCoarseTuningSysEx(data);
|
|
1340
1353
|
// case 5: // TODO: Global Parameter Control
|
|
1341
1354
|
default:
|
|
1342
1355
|
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
@@ -1378,9 +1391,9 @@ export class Midy {
|
|
|
1378
1391
|
}
|
|
1379
1392
|
handleMasterVolumeSysEx(data) {
|
|
1380
1393
|
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
1381
|
-
this.
|
|
1394
|
+
this.setMasterVolume(volume);
|
|
1382
1395
|
}
|
|
1383
|
-
|
|
1396
|
+
setMasterVolume(volume) {
|
|
1384
1397
|
if (volume < 0 && 1 < volume) {
|
|
1385
1398
|
console.error("Master Volume is out of range");
|
|
1386
1399
|
}
|
|
@@ -1392,9 +1405,9 @@ export class Midy {
|
|
|
1392
1405
|
}
|
|
1393
1406
|
handleMasterFineTuningSysEx(data) {
|
|
1394
1407
|
const fineTuning = (data[5] * 128 + data[4] - 8192) / 8192;
|
|
1395
|
-
this.
|
|
1408
|
+
this.setMasterFineTuning(fineTuning);
|
|
1396
1409
|
}
|
|
1397
|
-
|
|
1410
|
+
setMasterFineTuning(fineTuning) {
|
|
1398
1411
|
if (fineTuning < -1 && 1 < fineTuning) {
|
|
1399
1412
|
console.error("Master Fine Tuning value is out of range");
|
|
1400
1413
|
}
|
|
@@ -1404,9 +1417,9 @@ export class Midy {
|
|
|
1404
1417
|
}
|
|
1405
1418
|
handleMasterCoarseTuningSysEx(data) {
|
|
1406
1419
|
const coarseTuning = data[4];
|
|
1407
|
-
this.
|
|
1420
|
+
this.setMasterCoarseTuning(coarseTuning);
|
|
1408
1421
|
}
|
|
1409
|
-
|
|
1422
|
+
setMasterCoarseTuning(coarseTuning) {
|
|
1410
1423
|
if (coarseTuning < 0 && 127 < coarseTuning) {
|
|
1411
1424
|
console.error("Master Coarse Tuning value is out of range");
|
|
1412
1425
|
}
|
|
@@ -1446,7 +1459,7 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
1446
1459
|
value: {
|
|
1447
1460
|
currentBufferSource: null,
|
|
1448
1461
|
volume: 100 / 127,
|
|
1449
|
-
pan:
|
|
1462
|
+
pan: 64,
|
|
1450
1463
|
portamentoTime: 0,
|
|
1451
1464
|
reverb: 0,
|
|
1452
1465
|
chorus: 0,
|
package/package.json
CHANGED
package/script/midy-GM1.d.ts
CHANGED
|
@@ -41,8 +41,8 @@ export class MidyGM1 {
|
|
|
41
41
|
masterGain: any;
|
|
42
42
|
channels: {
|
|
43
43
|
scheduledNotes: Map<any, any>;
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
gainL: any;
|
|
45
|
+
gainR: any;
|
|
46
46
|
expression: number;
|
|
47
47
|
modulation: number;
|
|
48
48
|
sustainPedal: boolean;
|
|
@@ -65,13 +65,13 @@ export class MidyGM1 {
|
|
|
65
65
|
loadSoundFont(soundFontUrl: any): Promise<void>;
|
|
66
66
|
loadMIDI(midiUrl: any): Promise<void>;
|
|
67
67
|
setChannelAudioNodes(audioContext: any): {
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
gainL: any;
|
|
69
|
+
gainR: any;
|
|
70
70
|
};
|
|
71
71
|
createChannels(audioContext: any): {
|
|
72
72
|
scheduledNotes: Map<any, any>;
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
gainL: any;
|
|
74
|
+
gainR: any;
|
|
75
75
|
expression: number;
|
|
76
76
|
modulation: number;
|
|
77
77
|
sustainPedal: boolean;
|
|
@@ -128,10 +128,14 @@ export class MidyGM1 {
|
|
|
128
128
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
|
|
129
129
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
130
130
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
131
|
-
|
|
131
|
+
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
132
132
|
handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
|
|
133
133
|
setModulation(channelNumber: any, modulation: any): void;
|
|
134
134
|
setVolume(channelNumber: any, volume: any): void;
|
|
135
|
+
panToGain(pan: any): {
|
|
136
|
+
gainLeft: number;
|
|
137
|
+
gainRight: number;
|
|
138
|
+
};
|
|
135
139
|
setPan(channelNumber: any, pan: any): void;
|
|
136
140
|
setExpression(channelNumber: any, expression: any): void;
|
|
137
141
|
updateChannelGain(channel: any): void;
|
|
@@ -139,6 +143,8 @@ export class MidyGM1 {
|
|
|
139
143
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
140
144
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
141
145
|
setDataEntry(channelNumber: any, value: any, isMSB: any): void;
|
|
146
|
+
handlePitchBendRangeMessage(channelNumber: any, dataMSB: any, dataLSB: any): void;
|
|
147
|
+
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
142
148
|
allSoundOff(channelNumber: any): any[];
|
|
143
149
|
resetAllControllers(channelNumber: any): void;
|
|
144
150
|
allNotesOff(channelNumber: any): any[];
|
|
@@ -146,7 +152,7 @@ export class MidyGM1 {
|
|
|
146
152
|
GM1SystemOn(): void;
|
|
147
153
|
handleUniversalRealTimeExclusiveMessage(data: any): void;
|
|
148
154
|
handleMasterVolumeSysEx(data: any): void;
|
|
149
|
-
|
|
155
|
+
setMasterVolume(volume: any): void;
|
|
150
156
|
handleExclusiveMessage(data: any): void;
|
|
151
157
|
handleSysEx(data: any): void;
|
|
152
158
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
|
@@ -158,8 +164,6 @@ declare class Note {
|
|
|
158
164
|
filterNode: any;
|
|
159
165
|
modLFO: any;
|
|
160
166
|
modLFOGain: any;
|
|
161
|
-
vibLFO: any;
|
|
162
|
-
vibLFOGain: any;
|
|
163
167
|
noteNumber: any;
|
|
164
168
|
velocity: any;
|
|
165
169
|
startTime: 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":"
|
|
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;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAYC;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,sCAGC;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,+DAuBC;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;AAz/BD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|