@marmooo/midy 0.0.3 → 0.0.4
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 +4 -3
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +41 -38
- package/esm/midy-GM2.d.ts +14 -100
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +79 -40
- package/esm/midy-GMLite.d.ts +4 -3
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +40 -37
- package/esm/midy.d.ts +45 -3
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +96 -34
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +4 -3
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +41 -38
- package/script/midy-GM2.d.ts +14 -100
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +79 -40
- package/script/midy-GMLite.d.ts +4 -3
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +40 -37
- package/script/midy.d.ts +45 -3
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +96 -34
package/esm/midy-GMLite.js
CHANGED
|
@@ -223,9 +223,6 @@ export class MidyGMLite {
|
|
|
223
223
|
if (event.startTime > t + this.lookAhead)
|
|
224
224
|
break;
|
|
225
225
|
switch (event.type) {
|
|
226
|
-
case "controller":
|
|
227
|
-
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
228
|
-
break;
|
|
229
226
|
case "noteOn":
|
|
230
227
|
if (event.velocity !== 0) {
|
|
231
228
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
@@ -239,9 +236,15 @@ export class MidyGMLite {
|
|
|
239
236
|
}
|
|
240
237
|
break;
|
|
241
238
|
}
|
|
239
|
+
case "controller":
|
|
240
|
+
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
241
|
+
break;
|
|
242
242
|
case "programChange":
|
|
243
243
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
244
244
|
break;
|
|
245
|
+
case "pitchBend":
|
|
246
|
+
this.handlePitchBend(event.channel, event.value);
|
|
247
|
+
break;
|
|
245
248
|
case "sysEx":
|
|
246
249
|
this.handleSysEx(event.data);
|
|
247
250
|
}
|
|
@@ -478,12 +481,16 @@ export class MidyGMLite {
|
|
|
478
481
|
centToHz(cent) {
|
|
479
482
|
return 8.176 * Math.pow(2, cent / 1200);
|
|
480
483
|
}
|
|
484
|
+
calcSemitoneOffset(channel) {
|
|
485
|
+
return channel.pitchBend * channel.pitchBendRange + tuning;
|
|
486
|
+
}
|
|
487
|
+
calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
|
|
488
|
+
return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
|
|
489
|
+
}
|
|
481
490
|
async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
|
|
482
|
-
const semitoneOffset = channel.pitchBend * channel.pitchBendRange;
|
|
483
|
-
const playbackRate = noteInfo.playbackRate(noteNumber) *
|
|
484
|
-
Math.pow(2, semitoneOffset / 12);
|
|
485
491
|
const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
|
|
486
|
-
|
|
492
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
493
|
+
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
487
494
|
// volume envelope
|
|
488
495
|
const gainNode = new GainNode(this.audioContext, {
|
|
489
496
|
gain: 0,
|
|
@@ -649,46 +656,37 @@ export class MidyGMLite {
|
|
|
649
656
|
return this.releaseNote(channelNumber, data1, data2);
|
|
650
657
|
case 0x90:
|
|
651
658
|
return this.noteOn(channelNumber, data1, data2);
|
|
652
|
-
case 0xA0:
|
|
653
|
-
return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
|
|
654
659
|
case 0xB0:
|
|
655
660
|
return this.handleControlChange(channelNumber, data1, data2);
|
|
656
661
|
case 0xC0:
|
|
657
662
|
return this.handleProgramChange(channelNumber, data1);
|
|
658
|
-
case 0xD0:
|
|
659
|
-
return this.handleChannelPressure(channelNumber, data1);
|
|
660
663
|
case 0xE0:
|
|
661
|
-
return this.
|
|
664
|
+
return this.handlePitchBendMessage(channelNumber, data1, data2);
|
|
662
665
|
default:
|
|
663
666
|
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
664
667
|
}
|
|
665
668
|
}
|
|
666
|
-
handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
|
|
667
|
-
const now = this.audioContext.currentTime;
|
|
668
|
-
const channel = this.channels[channelNumber];
|
|
669
|
-
const scheduledNotes = channel.scheduledNotes.get(noteNumber);
|
|
670
|
-
pressure /= 127;
|
|
671
|
-
if (scheduledNotes) {
|
|
672
|
-
scheduledNotes.forEach((scheduledNote) => {
|
|
673
|
-
if (scheduledNote) {
|
|
674
|
-
const { initialAttenuation } = scheduledNote.noteInfo;
|
|
675
|
-
const gain = this.cbToRatio(-initialAttenuation) * pressure;
|
|
676
|
-
scheduledNote.gainNode.gain.cancelScheduledValues(now);
|
|
677
|
-
scheduledNote.gainNode.gain.setValueAtTime(gain, now);
|
|
678
|
-
}
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
669
|
handleProgramChange(channelNumber, program) {
|
|
683
670
|
const channel = this.channels[channelNumber];
|
|
684
671
|
channel.program = program;
|
|
685
672
|
}
|
|
686
|
-
|
|
687
|
-
|
|
673
|
+
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
674
|
+
const pitchBend = msb * 128 + lsb;
|
|
675
|
+
this.handlePitchBend(channelNumber, pitchBend);
|
|
688
676
|
}
|
|
689
|
-
handlePitchBend(channelNumber,
|
|
690
|
-
const
|
|
691
|
-
this.channels[channelNumber]
|
|
677
|
+
handlePitchBend(channelNumber, pitchBend) {
|
|
678
|
+
const now = this.audioContext.currentTime;
|
|
679
|
+
const channel = this.channels[channelNumber];
|
|
680
|
+
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
681
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
682
|
+
const activeNotes = this.getActiveNotes(channel);
|
|
683
|
+
activeNotes.forEach((activeNote) => {
|
|
684
|
+
const { bufferSource, noteInfo, noteNumber } = activeNote;
|
|
685
|
+
const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
686
|
+
bufferSource.playbackRate
|
|
687
|
+
.cancelScheduledValues(now)
|
|
688
|
+
.setValueAtTime(playbackRate * pressure, now);
|
|
689
|
+
});
|
|
692
690
|
}
|
|
693
691
|
handleControlChange(channelNumber, controller, value) {
|
|
694
692
|
switch (controller) {
|
|
@@ -848,13 +846,18 @@ export class MidyGMLite {
|
|
|
848
846
|
}
|
|
849
847
|
}
|
|
850
848
|
handleMasterVolumeSysEx(data) {
|
|
851
|
-
const volume = (data[5] * 128 + data[4]
|
|
849
|
+
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
852
850
|
this.handleMasterVolume(volume);
|
|
853
851
|
}
|
|
854
852
|
handleMasterVolume(volume) {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
853
|
+
if (volume < 0 && 1 < volume) {
|
|
854
|
+
console.error("Master Volume is out of range");
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
const now = this.audioContext.currentTime;
|
|
858
|
+
this.masterGain.gain.cancelScheduledValues(now);
|
|
859
|
+
this.masterGain.gain.setValueAtTime(volume * volume, now);
|
|
860
|
+
}
|
|
858
861
|
}
|
|
859
862
|
handleExclusiveMessage(data) {
|
|
860
863
|
console.warn(`Unsupported Exclusive Message ${data}`);
|
package/esm/midy.d.ts
CHANGED
|
@@ -32,6 +32,14 @@ export class Midy {
|
|
|
32
32
|
channelPressure: number;
|
|
33
33
|
pitchBendRange: number;
|
|
34
34
|
};
|
|
35
|
+
static controllerDestinationSettings: {
|
|
36
|
+
pitchControl: number;
|
|
37
|
+
filterCutoffControl: number;
|
|
38
|
+
amplitudeControl: number;
|
|
39
|
+
lfoPitchDepth: number;
|
|
40
|
+
lfoFilterDepth: number;
|
|
41
|
+
lfoAmplitudeDepth: number;
|
|
42
|
+
};
|
|
35
43
|
constructor(audioContext: any);
|
|
36
44
|
ticksPerBeat: number;
|
|
37
45
|
totalTime: number;
|
|
@@ -60,6 +68,22 @@ export class Midy {
|
|
|
60
68
|
channels: {
|
|
61
69
|
scheduledNotes: Map<any, any>;
|
|
62
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
|
+
};
|
|
63
87
|
gainNode: any;
|
|
64
88
|
pannerNode: any;
|
|
65
89
|
modulationEffect: {
|
|
@@ -84,7 +108,6 @@ export class Midy {
|
|
|
84
108
|
softPedal: number;
|
|
85
109
|
rpnMSB: number;
|
|
86
110
|
rpnLSB: number;
|
|
87
|
-
channelPressure: number;
|
|
88
111
|
pitchBendRange: number;
|
|
89
112
|
currentBufferSource: null;
|
|
90
113
|
volume: number;
|
|
@@ -131,6 +154,22 @@ export class Midy {
|
|
|
131
154
|
createChannels(audioContext: any): {
|
|
132
155
|
scheduledNotes: Map<any, any>;
|
|
133
156
|
sostenutoNotes: Map<any, any>;
|
|
157
|
+
polyphonicKeyPressure: {
|
|
158
|
+
pitchControl: number;
|
|
159
|
+
filterCutoffControl: number;
|
|
160
|
+
amplitudeControl: number;
|
|
161
|
+
lfoPitchDepth: number;
|
|
162
|
+
lfoFilterDepth: number;
|
|
163
|
+
lfoAmplitudeDepth: number;
|
|
164
|
+
};
|
|
165
|
+
channelPressure: {
|
|
166
|
+
pitchControl: number;
|
|
167
|
+
filterCutoffControl: number;
|
|
168
|
+
amplitudeControl: number;
|
|
169
|
+
lfoPitchDepth: number;
|
|
170
|
+
lfoFilterDepth: number;
|
|
171
|
+
lfoAmplitudeDepth: number;
|
|
172
|
+
};
|
|
134
173
|
gainNode: any;
|
|
135
174
|
pannerNode: any;
|
|
136
175
|
modulationEffect: {
|
|
@@ -155,7 +194,6 @@ export class Midy {
|
|
|
155
194
|
softPedal: number;
|
|
156
195
|
rpnMSB: number;
|
|
157
196
|
rpnLSB: number;
|
|
158
|
-
channelPressure: number;
|
|
159
197
|
pitchBendRange: number;
|
|
160
198
|
currentBufferSource: null;
|
|
161
199
|
volume: number;
|
|
@@ -216,10 +254,13 @@ export class Midy {
|
|
|
216
254
|
connectNoteEffects(channel: any, gainNode: any): void;
|
|
217
255
|
cbToRatio(cb: any): number;
|
|
218
256
|
centToHz(cent: any): number;
|
|
257
|
+
calcSemitoneOffset(channel: any): any;
|
|
258
|
+
calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
|
|
219
259
|
createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
|
|
220
260
|
bufferSource: any;
|
|
221
261
|
gainNode: any;
|
|
222
262
|
filterNode: any;
|
|
263
|
+
lfoGain: any;
|
|
223
264
|
}>;
|
|
224
265
|
calcBank(channel: any, channelNumber: any): any;
|
|
225
266
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
@@ -232,7 +273,8 @@ export class Midy {
|
|
|
232
273
|
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
233
274
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
234
275
|
handleChannelPressure(channelNumber: any, pressure: any): void;
|
|
235
|
-
|
|
276
|
+
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
277
|
+
handlePitchBend(channelNumber: any, pitchBend: any): void;
|
|
236
278
|
handleControlChange(channelNumber: any, controller: any, value: any): any;
|
|
237
279
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
238
280
|
setModulation(channelNumber: any, modulation: any): void;
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;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;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EAyDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,8EAEC;IAED;;;;;OAqFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,0DAiBC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,2DAOC;IAED,6DAOC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;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,sCAQC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
|
package/esm/midy.js
CHANGED
|
@@ -206,6 +206,12 @@ export class Midy {
|
|
|
206
206
|
...this.setChannelAudioNodes(audioContext),
|
|
207
207
|
scheduledNotes: new Map(),
|
|
208
208
|
sostenutoNotes: new Map(),
|
|
209
|
+
polyphonicKeyPressure: {
|
|
210
|
+
...Midy.controllerDestinationSettings,
|
|
211
|
+
},
|
|
212
|
+
channelPressure: {
|
|
213
|
+
...Midy.controllerDestinationSettings,
|
|
214
|
+
},
|
|
209
215
|
};
|
|
210
216
|
});
|
|
211
217
|
return channels;
|
|
@@ -260,9 +266,6 @@ export class Midy {
|
|
|
260
266
|
if (event.startTime > t + this.lookAhead)
|
|
261
267
|
break;
|
|
262
268
|
switch (event.type) {
|
|
263
|
-
case "controller":
|
|
264
|
-
this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
|
|
265
|
-
break;
|
|
266
269
|
case "noteOn":
|
|
267
270
|
if (event.velocity !== 0) {
|
|
268
271
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
@@ -276,9 +279,21 @@ export class Midy {
|
|
|
276
279
|
}
|
|
277
280
|
break;
|
|
278
281
|
}
|
|
282
|
+
case "noteAftertouch":
|
|
283
|
+
this.handlePolyphonicKeyPressure(event.channel, event.noteNumber, event.amount);
|
|
284
|
+
break;
|
|
285
|
+
case "controller":
|
|
286
|
+
this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
|
|
287
|
+
break;
|
|
279
288
|
case "programChange":
|
|
280
289
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
281
290
|
break;
|
|
291
|
+
case "channelAftertouch":
|
|
292
|
+
this.handleChannelPressure(event.channel, event.amount);
|
|
293
|
+
break;
|
|
294
|
+
case "pitchBend":
|
|
295
|
+
this.handlePitchBend(event.channel, event.value);
|
|
296
|
+
break;
|
|
282
297
|
case "sysEx":
|
|
283
298
|
this.handleSysEx(event.data);
|
|
284
299
|
}
|
|
@@ -642,15 +657,19 @@ export class Midy {
|
|
|
642
657
|
centToHz(cent) {
|
|
643
658
|
return 8.176 * Math.pow(2, cent / 1200);
|
|
644
659
|
}
|
|
645
|
-
|
|
660
|
+
calcSemitoneOffset(channel) {
|
|
646
661
|
const masterTuning = this.masterCoarseTuning + this.masterFineTuning;
|
|
647
662
|
const channelTuning = channel.coarseTuning + channel.fineTuning;
|
|
648
663
|
const tuning = masterTuning + channelTuning;
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
664
|
+
return channel.pitchBend * channel.pitchBendRange + tuning;
|
|
665
|
+
}
|
|
666
|
+
calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
|
|
667
|
+
return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
|
|
668
|
+
}
|
|
669
|
+
async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
|
|
652
670
|
const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
|
|
653
|
-
|
|
671
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
672
|
+
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
654
673
|
// volume envelope
|
|
655
674
|
const gainNode = new GainNode(this.audioContext, {
|
|
656
675
|
gain: 0,
|
|
@@ -714,7 +733,7 @@ export class Midy {
|
|
|
714
733
|
channel.currentBufferSource = bufferSource;
|
|
715
734
|
}
|
|
716
735
|
bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
|
|
717
|
-
return { bufferSource, gainNode, filterNode };
|
|
736
|
+
return { bufferSource, gainNode, filterNode, lfoGain };
|
|
718
737
|
}
|
|
719
738
|
calcBank(channel, channelNumber) {
|
|
720
739
|
if (channel.bankMSB === 121) {
|
|
@@ -736,7 +755,7 @@ export class Midy {
|
|
|
736
755
|
const noteInfo = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
|
|
737
756
|
if (!noteInfo)
|
|
738
757
|
return;
|
|
739
|
-
const { bufferSource, gainNode, filterNode } = await this
|
|
758
|
+
const { bufferSource, gainNode, filterNode, lfoGain } = await this
|
|
740
759
|
.createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3);
|
|
741
760
|
this.connectNoteEffects(channel, gainNode);
|
|
742
761
|
if (channel.sostenutoPedal) {
|
|
@@ -856,7 +875,7 @@ export class Midy {
|
|
|
856
875
|
case 0x90:
|
|
857
876
|
return this.noteOn(channelNumber, data1, data2);
|
|
858
877
|
case 0xA0:
|
|
859
|
-
return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
|
|
878
|
+
return; // this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
|
|
860
879
|
case 0xB0:
|
|
861
880
|
return this.handleControlChange(channelNumber, data1, data2);
|
|
862
881
|
case 0xC0:
|
|
@@ -864,7 +883,7 @@ export class Midy {
|
|
|
864
883
|
case 0xD0:
|
|
865
884
|
return this.handleChannelPressure(channelNumber, data1);
|
|
866
885
|
case 0xE0:
|
|
867
|
-
return this.
|
|
886
|
+
return this.handlePitchBendMessage(channelNumber, data1, data2);
|
|
868
887
|
default:
|
|
869
888
|
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
870
889
|
}
|
|
@@ -872,17 +891,16 @@ export class Midy {
|
|
|
872
891
|
handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
|
|
873
892
|
const now = this.audioContext.currentTime;
|
|
874
893
|
const channel = this.channels[channelNumber];
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
});
|
|
894
|
+
pressure /= 64;
|
|
895
|
+
const activeNotes = this.getActiveNotes(channel);
|
|
896
|
+
if (channel.polyphonicKeyPressure.amplitudeControl !== 1) {
|
|
897
|
+
if (activeNotes.has(noteNumber)) {
|
|
898
|
+
const activeNote = activeNotes.get(noteNumber);
|
|
899
|
+
const gain = activeNote.gainNode.gain.value;
|
|
900
|
+
activeNote.gainNode.gain
|
|
901
|
+
.cancelScheduledValues(now)
|
|
902
|
+
.setValueAtTime(gain * pressure, now);
|
|
903
|
+
}
|
|
886
904
|
}
|
|
887
905
|
}
|
|
888
906
|
handleProgramChange(channelNumber, program) {
|
|
@@ -891,11 +909,37 @@ export class Midy {
|
|
|
891
909
|
channel.program = program;
|
|
892
910
|
}
|
|
893
911
|
handleChannelPressure(channelNumber, pressure) {
|
|
894
|
-
this.
|
|
912
|
+
const now = this.audioContext.currentTime;
|
|
913
|
+
const channel = this.channels[channelNumber];
|
|
914
|
+
pressure /= 64;
|
|
915
|
+
channel.channelPressure = pressure;
|
|
916
|
+
const activeNotes = this.getActiveNotes(channel);
|
|
917
|
+
if (channel.channelPressure.amplitudeControl !== 1) {
|
|
918
|
+
activeNotes.forEach((activeNote) => {
|
|
919
|
+
const gain = activeNote.gainNode.gain.value;
|
|
920
|
+
activeNote.gainNode.gain
|
|
921
|
+
.cancelScheduledValues(now)
|
|
922
|
+
.setValueAtTime(gain * pressure, now);
|
|
923
|
+
});
|
|
924
|
+
}
|
|
895
925
|
}
|
|
896
|
-
|
|
897
|
-
const pitchBend =
|
|
898
|
-
this.
|
|
926
|
+
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
927
|
+
const pitchBend = msb * 128 + lsb;
|
|
928
|
+
this.handlePitchBend(channelNumber, pitchBend);
|
|
929
|
+
}
|
|
930
|
+
handlePitchBend(channelNumber, pitchBend) {
|
|
931
|
+
const now = this.audioContext.currentTime;
|
|
932
|
+
const channel = this.channels[channelNumber];
|
|
933
|
+
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
934
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
935
|
+
const activeNotes = this.getActiveNotes(channel);
|
|
936
|
+
activeNotes.forEach((activeNote) => {
|
|
937
|
+
const { bufferSource, noteInfo, noteNumber } = activeNote;
|
|
938
|
+
const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
939
|
+
bufferSource.playbackRate
|
|
940
|
+
.cancelScheduledValues(now)
|
|
941
|
+
.setValueAtTime(playbackRate * pressure, now);
|
|
942
|
+
});
|
|
899
943
|
}
|
|
900
944
|
handleControlChange(channelNumber, controller, value) {
|
|
901
945
|
switch (controller) {
|
|
@@ -1240,10 +1284,10 @@ export class Midy {
|
|
|
1240
1284
|
switch (data[3]) {
|
|
1241
1285
|
// case 1:
|
|
1242
1286
|
// // TODO
|
|
1243
|
-
// return this.
|
|
1287
|
+
// return this.setChannelPressure();
|
|
1244
1288
|
// case 3:
|
|
1245
1289
|
// // TODO
|
|
1246
|
-
// return this.
|
|
1290
|
+
// return this.setControlChange();
|
|
1247
1291
|
default:
|
|
1248
1292
|
console.warn(`Unsupported Exclusive Message ${data}`);
|
|
1249
1293
|
}
|
|
@@ -1262,20 +1306,25 @@ export class Midy {
|
|
|
1262
1306
|
}
|
|
1263
1307
|
}
|
|
1264
1308
|
handleMasterVolumeSysEx(data) {
|
|
1265
|
-
const volume = (data[5] * 128 + data[4]
|
|
1309
|
+
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
1266
1310
|
this.handleMasterVolume(volume);
|
|
1267
1311
|
}
|
|
1268
1312
|
handleMasterVolume(volume) {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1313
|
+
if (volume < 0 && 1 < volume) {
|
|
1314
|
+
console.error("Master Volume is out of range");
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
const now = this.audioContext.currentTime;
|
|
1318
|
+
this.masterGain.gain.cancelScheduledValues(now);
|
|
1319
|
+
this.masterGain.gain.setValueAtTime(volume * volume, now);
|
|
1320
|
+
}
|
|
1272
1321
|
}
|
|
1273
1322
|
handleMasterFineTuningSysEx(data) {
|
|
1274
1323
|
const fineTuning = (data[5] * 128 + data[4] - 8192) / 8192;
|
|
1275
1324
|
this.handleMasterFineTuning(fineTuning);
|
|
1276
1325
|
}
|
|
1277
1326
|
handleMasterFineTuning(fineTuning) {
|
|
1278
|
-
if (fineTuning <
|
|
1327
|
+
if (fineTuning < -1 && 1 < fineTuning) {
|
|
1279
1328
|
console.error("Master Fine Tuning value is out of range");
|
|
1280
1329
|
}
|
|
1281
1330
|
else {
|
|
@@ -1362,3 +1411,16 @@ Object.defineProperty(Midy, "effectSettings", {
|
|
|
1362
1411
|
pitchBendRange: 2,
|
|
1363
1412
|
}
|
|
1364
1413
|
});
|
|
1414
|
+
Object.defineProperty(Midy, "controllerDestinationSettings", {
|
|
1415
|
+
enumerable: true,
|
|
1416
|
+
configurable: true,
|
|
1417
|
+
writable: true,
|
|
1418
|
+
value: {
|
|
1419
|
+
pitchControl: 0,
|
|
1420
|
+
filterCutoffControl: 0,
|
|
1421
|
+
amplitudeControl: 1,
|
|
1422
|
+
lfoPitchDepth: 0,
|
|
1423
|
+
lfoFilterDepth: 0,
|
|
1424
|
+
lfoAmplitudeDepth: 0,
|
|
1425
|
+
}
|
|
1426
|
+
});
|
package/package.json
CHANGED
package/script/midy-GM1.d.ts
CHANGED
|
@@ -137,6 +137,8 @@ export class MidyGM1 {
|
|
|
137
137
|
connectNoteEffects(channel: any, gainNode: any): void;
|
|
138
138
|
cbToRatio(cb: any): number;
|
|
139
139
|
centToHz(cent: any): number;
|
|
140
|
+
calcSemitoneOffset(channel: any): any;
|
|
141
|
+
calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
|
|
140
142
|
createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
|
|
141
143
|
bufferSource: any;
|
|
142
144
|
gainNode: any;
|
|
@@ -149,10 +151,9 @@ export class MidyGM1 {
|
|
|
149
151
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
150
152
|
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
151
153
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
|
|
152
|
-
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
153
154
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
154
|
-
|
|
155
|
-
handlePitchBend(channelNumber: any,
|
|
155
|
+
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
156
|
+
handlePitchBend(channelNumber: any, pitchBend: any): void;
|
|
156
157
|
handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
|
|
157
158
|
setModulation(channelNumber: any, modulation: any): void;
|
|
158
159
|
setVolume(channelNumber: any, volume: any): void;
|
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":"AAMA;IAmBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAjDD,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,
|
|
1
|
+
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;IAmBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAjDD,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAyEC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED,sCAGC;IAED,8EAEC;IAED;;;;;OA8EC;IAED,kGAuCC;IAED,0EAGC;IAED,sIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,0DAiBC;IAED,mFA+BC;IAED,yDAIC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAoBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
|
package/script/midy-GM1.js
CHANGED
|
@@ -226,9 +226,6 @@ class MidyGM1 {
|
|
|
226
226
|
if (event.startTime > t + this.lookAhead)
|
|
227
227
|
break;
|
|
228
228
|
switch (event.type) {
|
|
229
|
-
case "controller":
|
|
230
|
-
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
231
|
-
break;
|
|
232
229
|
case "noteOn":
|
|
233
230
|
if (event.velocity !== 0) {
|
|
234
231
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
@@ -242,9 +239,15 @@ class MidyGM1 {
|
|
|
242
239
|
}
|
|
243
240
|
break;
|
|
244
241
|
}
|
|
242
|
+
case "controller":
|
|
243
|
+
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
244
|
+
break;
|
|
245
245
|
case "programChange":
|
|
246
246
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
247
247
|
break;
|
|
248
|
+
case "pitchBend":
|
|
249
|
+
this.handlePitchBend(event.channel, event.value);
|
|
250
|
+
break;
|
|
248
251
|
case "sysEx":
|
|
249
252
|
this.handleSysEx(event.data);
|
|
250
253
|
}
|
|
@@ -481,13 +484,17 @@ class MidyGM1 {
|
|
|
481
484
|
centToHz(cent) {
|
|
482
485
|
return 8.176 * Math.pow(2, cent / 1200);
|
|
483
486
|
}
|
|
484
|
-
|
|
487
|
+
calcSemitoneOffset(channel) {
|
|
485
488
|
const tuning = channel.coarseTuning + channel.fineTuning;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
+
return channel.pitchBend * channel.pitchBendRange + tuning;
|
|
490
|
+
}
|
|
491
|
+
calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
|
|
492
|
+
return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
|
|
493
|
+
}
|
|
494
|
+
async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
|
|
489
495
|
const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
|
|
490
|
-
|
|
496
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
497
|
+
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
491
498
|
// volume envelope
|
|
492
499
|
const gainNode = new GainNode(this.audioContext, {
|
|
493
500
|
gain: 0,
|
|
@@ -653,46 +660,37 @@ class MidyGM1 {
|
|
|
653
660
|
return this.releaseNote(channelNumber, data1, data2);
|
|
654
661
|
case 0x90:
|
|
655
662
|
return this.noteOn(channelNumber, data1, data2);
|
|
656
|
-
case 0xA0:
|
|
657
|
-
return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
|
|
658
663
|
case 0xB0:
|
|
659
664
|
return this.handleControlChange(channelNumber, data1, data2);
|
|
660
665
|
case 0xC0:
|
|
661
666
|
return this.handleProgramChange(channelNumber, data1);
|
|
662
|
-
case 0xD0:
|
|
663
|
-
return this.handleChannelPressure(channelNumber, data1);
|
|
664
667
|
case 0xE0:
|
|
665
|
-
return this.
|
|
668
|
+
return this.handlePitchBendMessage(channelNumber, data1, data2);
|
|
666
669
|
default:
|
|
667
670
|
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
668
671
|
}
|
|
669
672
|
}
|
|
670
|
-
handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
|
|
671
|
-
const now = this.audioContext.currentTime;
|
|
672
|
-
const channel = this.channels[channelNumber];
|
|
673
|
-
const scheduledNotes = channel.scheduledNotes.get(noteNumber);
|
|
674
|
-
pressure /= 127;
|
|
675
|
-
if (scheduledNotes) {
|
|
676
|
-
scheduledNotes.forEach((scheduledNote) => {
|
|
677
|
-
if (scheduledNote) {
|
|
678
|
-
const { initialAttenuation } = scheduledNote.noteInfo;
|
|
679
|
-
const gain = this.cbToRatio(-initialAttenuation) * pressure;
|
|
680
|
-
scheduledNote.gainNode.gain.cancelScheduledValues(now);
|
|
681
|
-
scheduledNote.gainNode.gain.setValueAtTime(gain, now);
|
|
682
|
-
}
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
673
|
handleProgramChange(channelNumber, program) {
|
|
687
674
|
const channel = this.channels[channelNumber];
|
|
688
675
|
channel.program = program;
|
|
689
676
|
}
|
|
690
|
-
|
|
691
|
-
|
|
677
|
+
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
678
|
+
const pitchBend = msb * 128 + lsb;
|
|
679
|
+
this.handlePitchBend(channelNumber, pitchBend);
|
|
692
680
|
}
|
|
693
|
-
handlePitchBend(channelNumber,
|
|
694
|
-
const
|
|
695
|
-
this.channels[channelNumber]
|
|
681
|
+
handlePitchBend(channelNumber, pitchBend) {
|
|
682
|
+
const now = this.audioContext.currentTime;
|
|
683
|
+
const channel = this.channels[channelNumber];
|
|
684
|
+
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
685
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
686
|
+
const activeNotes = this.getActiveNotes(channel);
|
|
687
|
+
activeNotes.forEach((activeNote) => {
|
|
688
|
+
const { bufferSource, noteInfo, noteNumber } = activeNote;
|
|
689
|
+
const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
690
|
+
bufferSource.playbackRate
|
|
691
|
+
.cancelScheduledValues(now)
|
|
692
|
+
.setValueAtTime(playbackRate * pressure, now);
|
|
693
|
+
});
|
|
696
694
|
}
|
|
697
695
|
handleControlChange(channelNumber, controller, value) {
|
|
698
696
|
switch (controller) {
|
|
@@ -858,13 +856,18 @@ class MidyGM1 {
|
|
|
858
856
|
}
|
|
859
857
|
}
|
|
860
858
|
handleMasterVolumeSysEx(data) {
|
|
861
|
-
const volume = (data[5] * 128 + data[4]
|
|
859
|
+
const volume = (data[5] * 128 + data[4]) / 16383;
|
|
862
860
|
this.handleMasterVolume(volume);
|
|
863
861
|
}
|
|
864
862
|
handleMasterVolume(volume) {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
863
|
+
if (volume < 0 && 1 < volume) {
|
|
864
|
+
console.error("Master Volume is out of range");
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
const now = this.audioContext.currentTime;
|
|
868
|
+
this.masterGain.gain.cancelScheduledValues(now);
|
|
869
|
+
this.masterGain.gain.setValueAtTime(volume * volume, now);
|
|
870
|
+
}
|
|
868
871
|
}
|
|
869
872
|
handleExclusiveMessage(data) {
|
|
870
873
|
console.warn(`Unsupported Exclusive Message ${data}`);
|