@marmooo/midy 0.2.9 → 0.3.1
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/README.md +2 -1
- package/esm/midy-GM1.d.ts +11 -7
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +114 -74
- package/esm/midy-GM2.d.ts +17 -11
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +250 -124
- package/esm/midy-GMLite.d.ts +14 -9
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +167 -81
- package/esm/midy.d.ts +20 -14
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +257 -129
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +11 -7
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +114 -74
- package/script/midy-GM2.d.ts +17 -11
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +250 -124
- package/script/midy-GMLite.d.ts +14 -9
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +167 -81
- package/script/midy.d.ts +20 -14
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +257 -129
package/script/midy-GM1.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export class MidyGM1 {
|
|
2
2
|
static channelSettings: {
|
|
3
|
-
currentBufferSource: null;
|
|
4
|
-
isDrum: boolean;
|
|
5
3
|
detune: number;
|
|
6
|
-
|
|
4
|
+
programNumber: number;
|
|
7
5
|
bank: number;
|
|
8
6
|
dataMSB: number;
|
|
9
7
|
dataLSB: number;
|
|
@@ -15,6 +13,7 @@ export class MidyGM1 {
|
|
|
15
13
|
};
|
|
16
14
|
constructor(audioContext: any);
|
|
17
15
|
mode: string;
|
|
16
|
+
numChannels: number;
|
|
18
17
|
ticksPerBeat: number;
|
|
19
18
|
totalTime: number;
|
|
20
19
|
noteCheckInterval: number;
|
|
@@ -34,7 +33,7 @@ export class MidyGM1 {
|
|
|
34
33
|
timeline: any[];
|
|
35
34
|
instruments: any[];
|
|
36
35
|
notePromises: any[];
|
|
37
|
-
|
|
36
|
+
exclusiveClassNotes: any[];
|
|
38
37
|
audioContext: any;
|
|
39
38
|
masterVolume: any;
|
|
40
39
|
scheduler: any;
|
|
@@ -88,6 +87,7 @@ export class MidyGM1 {
|
|
|
88
87
|
instruments: Set<any>;
|
|
89
88
|
timeline: any[];
|
|
90
89
|
};
|
|
90
|
+
stopActiveNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
91
91
|
stopChannelNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
92
92
|
stopNotes(velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
93
93
|
start(): Promise<void>;
|
|
@@ -112,16 +112,19 @@ export class MidyGM1 {
|
|
|
112
112
|
clampCutoffFrequency(frequency: any): number;
|
|
113
113
|
setFilterEnvelope(note: any, scheduleTime: any): void;
|
|
114
114
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
115
|
-
getAudioBuffer(
|
|
115
|
+
getAudioBuffer(programNumber: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
116
116
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
117
|
+
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
117
118
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
118
119
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
119
|
-
|
|
120
|
+
disconnectNote(note: any): void;
|
|
121
|
+
stopNote(endTime: any, stopTime: any, noteList: any, index: any): Promise<any>;
|
|
122
|
+
findNoteOffTarget(noteList: any): any[] | undefined;
|
|
120
123
|
scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
121
124
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
|
|
122
125
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
123
126
|
handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
|
|
124
|
-
handleProgramChange(channelNumber: any,
|
|
127
|
+
handleProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
|
|
125
128
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
|
|
126
129
|
setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
|
|
127
130
|
setModLfoToPitch(channel: any, note: any, scheduleTime: any): void;
|
|
@@ -183,6 +186,7 @@ export class MidyGM1 {
|
|
|
183
186
|
handleCoarseTuningRPN(channelNumber: any, scheduleTime: any): void;
|
|
184
187
|
setCoarseTuning(channelNumber: any, value: any, scheduleTime: any): void;
|
|
185
188
|
allSoundOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
189
|
+
resetAllStates(channelNumber: any): void;
|
|
186
190
|
resetAllControllers(channelNumber: any): void;
|
|
187
191
|
allNotesOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
188
192
|
handleUniversalNonRealTimeExclusiveMessage(data: any, scheduleTime: 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":"AAiJA;
|
|
1
|
+
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAiJA;IAwBE;;;;;;;;;;;MAWE;IAEF,+BAcC;IAlDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,2BAAqC;IAgBnC,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAaC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,kGAiBC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDASC;IAED,2DASC;IAED,qDAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,+GA0BC;IAED,gHAwCC;IAED,0EAiBC;IAED,kGAsCC;IAED,6FAQC;IAED,gCASC;IAED,+EAiBC;IAED,oDAOC;IAED,yHAsBC;IAED,yGASC;IAED,4GAeC;IAED,mGA2BC;IAED,sFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAQC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MA2BC;IAED,oFAMC;IAED,6EA2CC;IAED;;;;;;;;;;;;;MAeC;IAED,kGAWC;IAED,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAKC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,yCAUC;IAGD,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA3/CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|
package/script/midy-GM1.js
CHANGED
|
@@ -179,6 +179,12 @@ class MidyGM1 {
|
|
|
179
179
|
writable: true,
|
|
180
180
|
value: "GM1"
|
|
181
181
|
});
|
|
182
|
+
Object.defineProperty(this, "numChannels", {
|
|
183
|
+
enumerable: true,
|
|
184
|
+
configurable: true,
|
|
185
|
+
writable: true,
|
|
186
|
+
value: 16
|
|
187
|
+
});
|
|
182
188
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
183
189
|
enumerable: true,
|
|
184
190
|
configurable: true,
|
|
@@ -293,11 +299,11 @@ class MidyGM1 {
|
|
|
293
299
|
writable: true,
|
|
294
300
|
value: []
|
|
295
301
|
});
|
|
296
|
-
Object.defineProperty(this, "
|
|
302
|
+
Object.defineProperty(this, "exclusiveClassNotes", {
|
|
297
303
|
enumerable: true,
|
|
298
304
|
configurable: true,
|
|
299
305
|
writable: true,
|
|
300
|
-
value: new
|
|
306
|
+
value: new Array(128)
|
|
301
307
|
});
|
|
302
308
|
this.audioContext = audioContext;
|
|
303
309
|
this.masterVolume = new GainNode(audioContext);
|
|
@@ -364,8 +370,10 @@ class MidyGM1 {
|
|
|
364
370
|
};
|
|
365
371
|
}
|
|
366
372
|
createChannels(audioContext) {
|
|
367
|
-
const channels = Array.from({ length:
|
|
373
|
+
const channels = Array.from({ length: this.numChannels }, () => {
|
|
368
374
|
return {
|
|
375
|
+
currentBufferSource: null,
|
|
376
|
+
isDrum: false,
|
|
369
377
|
...this.constructor.channelSettings,
|
|
370
378
|
state: new ControllerState(),
|
|
371
379
|
...this.setChannelAudioNodes(audioContext),
|
|
@@ -422,7 +430,7 @@ class MidyGM1 {
|
|
|
422
430
|
const startTime = event.startTime + this.startDelay - offset;
|
|
423
431
|
switch (event.type) {
|
|
424
432
|
case "noteOn":
|
|
425
|
-
if (event.velocity
|
|
433
|
+
if (0 < event.velocity) {
|
|
426
434
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
427
435
|
break;
|
|
428
436
|
}
|
|
@@ -470,7 +478,7 @@ class MidyGM1 {
|
|
|
470
478
|
if (queueIndex >= this.timeline.length) {
|
|
471
479
|
await Promise.all(this.notePromises);
|
|
472
480
|
this.notePromises = [];
|
|
473
|
-
this.
|
|
481
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
474
482
|
this.audioBufferCache.clear();
|
|
475
483
|
resolve();
|
|
476
484
|
return;
|
|
@@ -489,7 +497,7 @@ class MidyGM1 {
|
|
|
489
497
|
else if (this.isStopping) {
|
|
490
498
|
await this.stopNotes(0, true, now);
|
|
491
499
|
this.notePromises = [];
|
|
492
|
-
this.
|
|
500
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
493
501
|
this.audioBufferCache.clear();
|
|
494
502
|
resolve();
|
|
495
503
|
this.isStopping = false;
|
|
@@ -498,7 +506,7 @@ class MidyGM1 {
|
|
|
498
506
|
}
|
|
499
507
|
else if (this.isSeeking) {
|
|
500
508
|
this.stopNotes(0, true, now);
|
|
501
|
-
this.
|
|
509
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
502
510
|
this.startTime = this.audioContext.currentTime;
|
|
503
511
|
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
504
512
|
offset = this.resumeTime - this.startTime;
|
|
@@ -526,7 +534,7 @@ class MidyGM1 {
|
|
|
526
534
|
extractMidiData(midi) {
|
|
527
535
|
const instruments = new Set();
|
|
528
536
|
const timeline = [];
|
|
529
|
-
const tmpChannels = new Array(
|
|
537
|
+
const tmpChannels = new Array(this.channels.length);
|
|
530
538
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
531
539
|
tmpChannels[i] = {
|
|
532
540
|
programNumber: -1,
|
|
@@ -589,6 +597,17 @@ class MidyGM1 {
|
|
|
589
597
|
}
|
|
590
598
|
return { instruments, timeline };
|
|
591
599
|
}
|
|
600
|
+
stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
|
|
601
|
+
const channel = this.channels[channelNumber];
|
|
602
|
+
const promises = [];
|
|
603
|
+
const activeNotes = this.getActiveNotes(channel, scheduleTime);
|
|
604
|
+
activeNotes.forEach((note) => {
|
|
605
|
+
const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
|
|
606
|
+
this.notePromises.push(promise);
|
|
607
|
+
promises.push(promise);
|
|
608
|
+
});
|
|
609
|
+
return Promise.all(promises);
|
|
610
|
+
}
|
|
592
611
|
stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
|
|
593
612
|
const channel = this.channels[channelNumber];
|
|
594
613
|
const promises = [];
|
|
@@ -618,6 +637,9 @@ class MidyGM1 {
|
|
|
618
637
|
if (!this.isPlaying)
|
|
619
638
|
return;
|
|
620
639
|
this.isStopping = true;
|
|
640
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
641
|
+
this.resetAllStates(i);
|
|
642
|
+
}
|
|
621
643
|
}
|
|
622
644
|
pause() {
|
|
623
645
|
if (!this.isPlaying || this.isPaused)
|
|
@@ -657,6 +679,8 @@ class MidyGM1 {
|
|
|
657
679
|
const note = noteList[i];
|
|
658
680
|
if (!note)
|
|
659
681
|
continue;
|
|
682
|
+
if (note.ending)
|
|
683
|
+
continue;
|
|
660
684
|
callback(note);
|
|
661
685
|
}
|
|
662
686
|
});
|
|
@@ -795,8 +819,8 @@ class MidyGM1 {
|
|
|
795
819
|
note.modulationLFO.connect(note.volumeDepth);
|
|
796
820
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
797
821
|
}
|
|
798
|
-
async getAudioBuffer(
|
|
799
|
-
const audioBufferId = this.getAudioBufferId(
|
|
822
|
+
async getAudioBuffer(programNumber, noteNumber, velocity, voiceParams, isSF3) {
|
|
823
|
+
const audioBufferId = this.getAudioBufferId(programNumber, noteNumber, velocity);
|
|
800
824
|
const cache = this.audioBufferCache.get(audioBufferId);
|
|
801
825
|
if (cache) {
|
|
802
826
|
cache.counter += 1;
|
|
@@ -819,7 +843,7 @@ class MidyGM1 {
|
|
|
819
843
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
820
844
|
const voiceParams = voice.getAllParams(controllerState);
|
|
821
845
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
822
|
-
const audioBuffer = await this.getAudioBuffer(channel.
|
|
846
|
+
const audioBuffer = await this.getAudioBuffer(channel.programNumber, noteNumber, velocity, voiceParams, isSF3);
|
|
823
847
|
note.bufferSource = this.createBufferSource(audioBuffer, voiceParams);
|
|
824
848
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
825
849
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
@@ -837,14 +861,28 @@ class MidyGM1 {
|
|
|
837
861
|
note.bufferSource.start(startTime);
|
|
838
862
|
return note;
|
|
839
863
|
}
|
|
864
|
+
handleExclusiveClass(note, channelNumber, startTime) {
|
|
865
|
+
const exclusiveClass = note.voiceParams.exclusiveClass;
|
|
866
|
+
if (exclusiveClass === 0)
|
|
867
|
+
return;
|
|
868
|
+
const prev = this.exclusiveClassNotes[exclusiveClass];
|
|
869
|
+
if (prev) {
|
|
870
|
+
const [prevNote, prevChannelNumber] = prev;
|
|
871
|
+
if (prevNote && !prevNote.ending) {
|
|
872
|
+
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
873
|
+
startTime, true);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
this.exclusiveClassNotes[exclusiveClass] = [note, channelNumber];
|
|
877
|
+
}
|
|
840
878
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
841
879
|
const channel = this.channels[channelNumber];
|
|
842
880
|
const bankNumber = channel.bank;
|
|
843
|
-
const soundFontIndex = this.soundFontTable[channel.
|
|
881
|
+
const soundFontIndex = this.soundFontTable[channel.programNumber].get(bankNumber);
|
|
844
882
|
if (soundFontIndex === undefined)
|
|
845
883
|
return;
|
|
846
884
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
847
|
-
const voice = soundFont.getVoice(bankNumber, channel.
|
|
885
|
+
const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
|
|
848
886
|
if (!voice)
|
|
849
887
|
return;
|
|
850
888
|
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
@@ -854,32 +892,33 @@ class MidyGM1 {
|
|
|
854
892
|
if (0.5 <= channel.state.sustainPedal) {
|
|
855
893
|
channel.sustainNotes.push(note);
|
|
856
894
|
}
|
|
857
|
-
|
|
858
|
-
if (exclusiveClass !== 0) {
|
|
859
|
-
if (this.exclusiveClassMap.has(exclusiveClass)) {
|
|
860
|
-
const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
|
|
861
|
-
const [prevNote, prevChannelNumber] = prevEntry;
|
|
862
|
-
if (prevNote && !prevNote.ending) {
|
|
863
|
-
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
864
|
-
startTime, true);
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
|
|
868
|
-
}
|
|
895
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
869
896
|
const scheduledNotes = channel.scheduledNotes;
|
|
870
|
-
|
|
871
|
-
|
|
897
|
+
let noteList = scheduledNotes.get(noteNumber);
|
|
898
|
+
if (noteList) {
|
|
899
|
+
noteList.push(note);
|
|
872
900
|
}
|
|
873
901
|
else {
|
|
874
|
-
|
|
902
|
+
noteList = [note];
|
|
903
|
+
scheduledNotes.set(noteNumber, noteList);
|
|
875
904
|
}
|
|
876
905
|
}
|
|
877
906
|
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
878
907
|
scheduleTime ??= this.audioContext.currentTime;
|
|
879
908
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime);
|
|
880
909
|
}
|
|
881
|
-
|
|
882
|
-
|
|
910
|
+
disconnectNote(note) {
|
|
911
|
+
note.bufferSource.disconnect();
|
|
912
|
+
note.filterNode.disconnect();
|
|
913
|
+
note.volumeEnvelopeNode.disconnect();
|
|
914
|
+
if (note.modulationDepth) {
|
|
915
|
+
note.volumeDepth.disconnect();
|
|
916
|
+
note.modulationDepth.disconnect();
|
|
917
|
+
note.modulationLFO.stop();
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
stopNote(endTime, stopTime, noteList, index) {
|
|
921
|
+
const note = noteList[index];
|
|
883
922
|
note.volumeEnvelopeNode.gain
|
|
884
923
|
.cancelScheduledValues(endTime)
|
|
885
924
|
.linearRampToValueAtTime(0, stopTime);
|
|
@@ -889,41 +928,43 @@ class MidyGM1 {
|
|
|
889
928
|
}, stopTime);
|
|
890
929
|
return new Promise((resolve) => {
|
|
891
930
|
note.bufferSource.onended = () => {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
note.filterNode.disconnect();
|
|
895
|
-
note.volumeEnvelopeNode.disconnect();
|
|
896
|
-
if (note.modulationDepth) {
|
|
897
|
-
note.volumeDepth.disconnect();
|
|
898
|
-
note.modulationDepth.disconnect();
|
|
899
|
-
note.modulationLFO.stop();
|
|
900
|
-
}
|
|
931
|
+
noteList[index] = undefined;
|
|
932
|
+
this.disconnectNote(note);
|
|
901
933
|
resolve();
|
|
902
934
|
};
|
|
903
935
|
note.bufferSource.stop(stopTime);
|
|
904
936
|
});
|
|
905
937
|
}
|
|
938
|
+
findNoteOffTarget(noteList) {
|
|
939
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
940
|
+
const note = noteList[i];
|
|
941
|
+
if (!note)
|
|
942
|
+
continue;
|
|
943
|
+
if (note.ending)
|
|
944
|
+
continue;
|
|
945
|
+
return [note, i];
|
|
946
|
+
}
|
|
947
|
+
}
|
|
906
948
|
scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
|
|
907
949
|
const channel = this.channels[channelNumber];
|
|
908
950
|
if (!force && 0.5 <= channel.state.sustainPedal)
|
|
909
951
|
return;
|
|
910
952
|
if (!channel.scheduledNotes.has(noteNumber))
|
|
911
953
|
return;
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
}
|
|
954
|
+
const noteList = channel.scheduledNotes.get(noteNumber);
|
|
955
|
+
if (!noteList)
|
|
956
|
+
return; // be careful with drum channel
|
|
957
|
+
const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
|
|
958
|
+
if (!noteOffTarget)
|
|
959
|
+
return;
|
|
960
|
+
const [note, i] = noteOffTarget;
|
|
961
|
+
const volRelease = endTime + note.voiceParams.volRelease;
|
|
962
|
+
const modRelease = endTime + note.voiceParams.modRelease;
|
|
963
|
+
note.filterNode.frequency
|
|
964
|
+
.cancelScheduledValues(endTime)
|
|
965
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
966
|
+
const stopTime = Math.min(volRelease, modRelease);
|
|
967
|
+
return this.stopNote(endTime, stopTime, noteList, i);
|
|
927
968
|
}
|
|
928
969
|
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
929
970
|
scheduleTime ??= this.audioContext.currentTime;
|
|
@@ -958,9 +999,9 @@ class MidyGM1 {
|
|
|
958
999
|
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
959
1000
|
}
|
|
960
1001
|
}
|
|
961
|
-
handleProgramChange(channelNumber,
|
|
1002
|
+
handleProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
962
1003
|
const channel = this.channels[channelNumber];
|
|
963
|
-
channel.
|
|
1004
|
+
channel.programNumber = programNumber;
|
|
964
1005
|
}
|
|
965
1006
|
handlePitchBendMessage(channelNumber, lsb, msb, scheduleTime) {
|
|
966
1007
|
const pitchBend = msb * 128 + lsb;
|
|
@@ -968,8 +1009,6 @@ class MidyGM1 {
|
|
|
968
1009
|
}
|
|
969
1010
|
setPitchBend(channelNumber, value, scheduleTime) {
|
|
970
1011
|
const channel = this.channels[channelNumber];
|
|
971
|
-
if (channel.isDrum)
|
|
972
|
-
return;
|
|
973
1012
|
scheduleTime ??= this.audioContext.currentTime;
|
|
974
1013
|
const state = channel.state;
|
|
975
1014
|
const prev = state.pitchWheel * 2 - 1;
|
|
@@ -1132,8 +1171,6 @@ class MidyGM1 {
|
|
|
1132
1171
|
}
|
|
1133
1172
|
setModulationDepth(channelNumber, modulation, scheduleTime) {
|
|
1134
1173
|
const channel = this.channels[channelNumber];
|
|
1135
|
-
if (channel.isDrum)
|
|
1136
|
-
return;
|
|
1137
1174
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1138
1175
|
channel.state.modulationDepth = modulation / 127;
|
|
1139
1176
|
this.updateModulation(channel, scheduleTime);
|
|
@@ -1180,8 +1217,6 @@ class MidyGM1 {
|
|
|
1180
1217
|
}
|
|
1181
1218
|
setSustainPedal(channelNumber, value, scheduleTime) {
|
|
1182
1219
|
const channel = this.channels[channelNumber];
|
|
1183
|
-
if (channel.isDrum)
|
|
1184
|
-
return;
|
|
1185
1220
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1186
1221
|
channel.state.sustainPedal = value / 127;
|
|
1187
1222
|
if (64 <= value) {
|
|
@@ -1254,8 +1289,6 @@ class MidyGM1 {
|
|
|
1254
1289
|
}
|
|
1255
1290
|
setPitchBendRange(channelNumber, value, scheduleTime) {
|
|
1256
1291
|
const channel = this.channels[channelNumber];
|
|
1257
|
-
if (channel.isDrum)
|
|
1258
|
-
return;
|
|
1259
1292
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1260
1293
|
const state = channel.state;
|
|
1261
1294
|
const prev = state.pitchWheelSensitivity;
|
|
@@ -1273,8 +1306,6 @@ class MidyGM1 {
|
|
|
1273
1306
|
}
|
|
1274
1307
|
setFineTuning(channelNumber, value, scheduleTime) {
|
|
1275
1308
|
const channel = this.channels[channelNumber];
|
|
1276
|
-
if (channel.isDrum)
|
|
1277
|
-
return;
|
|
1278
1309
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1279
1310
|
const prev = channel.fineTuning;
|
|
1280
1311
|
const next = (value - 8192) / 8.192; // cent
|
|
@@ -1290,8 +1321,6 @@ class MidyGM1 {
|
|
|
1290
1321
|
}
|
|
1291
1322
|
setCoarseTuning(channelNumber, value, scheduleTime) {
|
|
1292
1323
|
const channel = this.channels[channelNumber];
|
|
1293
|
-
if (channel.isDrum)
|
|
1294
|
-
return;
|
|
1295
1324
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1296
1325
|
const prev = channel.coarseTuning;
|
|
1297
1326
|
const next = (value - 64) * 100; // cent
|
|
@@ -1301,14 +1330,26 @@ class MidyGM1 {
|
|
|
1301
1330
|
}
|
|
1302
1331
|
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
1303
1332
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1304
|
-
return this.
|
|
1333
|
+
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
1334
|
+
}
|
|
1335
|
+
resetAllStates(channelNumber) {
|
|
1336
|
+
const channel = this.channels[channelNumber];
|
|
1337
|
+
const state = channel.state;
|
|
1338
|
+
for (const type of Object.keys(defaultControllerState)) {
|
|
1339
|
+
state[type] = defaultControllerState[type].defaultValue;
|
|
1340
|
+
}
|
|
1341
|
+
for (const type of Object.keys(this.constructor.channelSettings)) {
|
|
1342
|
+
channel[type] = this.constructor.channelSettings[type];
|
|
1343
|
+
}
|
|
1344
|
+
this.mode = "GM1";
|
|
1305
1345
|
}
|
|
1346
|
+
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
|
|
1306
1347
|
resetAllControllers(channelNumber) {
|
|
1307
1348
|
const stateTypes = [
|
|
1349
|
+
"pitchWheel",
|
|
1308
1350
|
"expression",
|
|
1309
1351
|
"modulationDepth",
|
|
1310
1352
|
"sustainPedal",
|
|
1311
|
-
"pitchWheelSensitivity",
|
|
1312
1353
|
];
|
|
1313
1354
|
const channel = this.channels[channelNumber];
|
|
1314
1355
|
const state = channel.state;
|
|
@@ -1327,7 +1368,7 @@ class MidyGM1 {
|
|
|
1327
1368
|
}
|
|
1328
1369
|
allNotesOff(channelNumber, _value, scheduleTime) {
|
|
1329
1370
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1330
|
-
return this.
|
|
1371
|
+
return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
|
|
1331
1372
|
}
|
|
1332
1373
|
handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
|
|
1333
1374
|
switch (data[2]) {
|
|
@@ -1397,6 +1438,7 @@ class MidyGM1 {
|
|
|
1397
1438
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
1398
1439
|
}
|
|
1399
1440
|
}
|
|
1441
|
+
// https://github.com/marmooo/js-timer-benchmark
|
|
1400
1442
|
scheduleTask(callback, scheduleTime) {
|
|
1401
1443
|
return new Promise((resolve) => {
|
|
1402
1444
|
const bufferSource = new AudioBufferSourceNode(this.audioContext, {
|
|
@@ -1422,10 +1464,8 @@ Object.defineProperty(MidyGM1, "channelSettings", {
|
|
|
1422
1464
|
configurable: true,
|
|
1423
1465
|
writable: true,
|
|
1424
1466
|
value: {
|
|
1425
|
-
currentBufferSource: null,
|
|
1426
|
-
isDrum: false,
|
|
1427
1467
|
detune: 0,
|
|
1428
|
-
|
|
1468
|
+
programNumber: 0,
|
|
1429
1469
|
bank: 0,
|
|
1430
1470
|
dataMSB: 0,
|
|
1431
1471
|
dataLSB: 0,
|
package/script/midy-GM2.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export class MidyGM2 {
|
|
2
2
|
static channelSettings: {
|
|
3
|
-
currentBufferSource: null;
|
|
4
|
-
isDrum: boolean;
|
|
5
3
|
detune: number;
|
|
6
|
-
|
|
4
|
+
programNumber: number;
|
|
7
5
|
bank: number;
|
|
8
6
|
bankMSB: number;
|
|
9
7
|
bankLSB: number;
|
|
@@ -23,8 +21,6 @@ export class MidyGM2 {
|
|
|
23
21
|
};
|
|
24
22
|
});
|
|
25
23
|
mode: string;
|
|
26
|
-
ticksPerBeat: number;
|
|
27
|
-
totalTime: number;
|
|
28
24
|
masterFineTuning: number;
|
|
29
25
|
masterCoarseTuning: number;
|
|
30
26
|
reverb: {
|
|
@@ -38,6 +34,9 @@ export class MidyGM2 {
|
|
|
38
34
|
sendToReverb: number;
|
|
39
35
|
delayTimes: any[];
|
|
40
36
|
};
|
|
37
|
+
numChannels: number;
|
|
38
|
+
ticksPerBeat: number;
|
|
39
|
+
totalTime: number;
|
|
41
40
|
noteCheckInterval: number;
|
|
42
41
|
lookAhead: number;
|
|
43
42
|
startDelay: number;
|
|
@@ -55,7 +54,8 @@ export class MidyGM2 {
|
|
|
55
54
|
timeline: any[];
|
|
56
55
|
instruments: any[];
|
|
57
56
|
notePromises: any[];
|
|
58
|
-
|
|
57
|
+
exclusiveClassNotes: any[];
|
|
58
|
+
drumExclusiveClassNotes: any[];
|
|
59
59
|
defaultOptions: {
|
|
60
60
|
reverbAlgorithm: (audioContext: any) => {
|
|
61
61
|
input: any;
|
|
@@ -135,8 +135,7 @@ export class MidyGM2 {
|
|
|
135
135
|
};
|
|
136
136
|
createChannels(audioContext: any): any[];
|
|
137
137
|
createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
|
|
138
|
-
|
|
139
|
-
createBufferSource(channel: any, note: any, voiceParams: any, audioBuffer: any): any;
|
|
138
|
+
createBufferSource(voiceParams: any, audioBuffer: any): any;
|
|
140
139
|
findPortamentoTarget(queueIndex: any): any;
|
|
141
140
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
142
141
|
getQueueIndex(second: any): number;
|
|
@@ -148,6 +147,7 @@ export class MidyGM2 {
|
|
|
148
147
|
instruments: Set<any>;
|
|
149
148
|
timeline: any[];
|
|
150
149
|
};
|
|
150
|
+
stopActiveNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
151
151
|
stopChannelNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
152
152
|
stopNotes(velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
153
153
|
start(): Promise<void>;
|
|
@@ -199,18 +199,23 @@ export class MidyGM2 {
|
|
|
199
199
|
setFilterEnvelope(channel: any, note: any, scheduleTime: any): void;
|
|
200
200
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
201
201
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
202
|
-
getAudioBuffer(
|
|
202
|
+
getAudioBuffer(programNumber: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
203
203
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
|
|
204
204
|
calcBank(channel: any): any;
|
|
205
|
+
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
206
|
+
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
207
|
+
isDrumNoteOffException(channel: any, noteNumber: any): boolean;
|
|
205
208
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
|
|
206
209
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
207
|
-
|
|
210
|
+
disconnectNote(note: any): void;
|
|
211
|
+
stopNote(endTime: any, stopTime: any, noteList: any, index: any): Promise<any>;
|
|
212
|
+
findNoteOffTarget(noteList: any): any[] | undefined;
|
|
208
213
|
scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any, portamentoNoteNumber: any): Promise<any> | undefined;
|
|
209
214
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
|
|
210
215
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
211
216
|
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): any[];
|
|
212
217
|
handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
|
|
213
|
-
handleProgramChange(channelNumber: any,
|
|
218
|
+
handleProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
|
|
214
219
|
handleChannelPressure(channelNumber: any, value: any, scheduleTime: any): void;
|
|
215
220
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
|
|
216
221
|
setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
|
|
@@ -301,6 +306,7 @@ export class MidyGM2 {
|
|
|
301
306
|
handleModulationDepthRangeRPN(channelNumber: any, scheduleTime: any): void;
|
|
302
307
|
setModulationDepthRange(channelNumber: any, modulationDepthRange: any, scheduleTime: any): void;
|
|
303
308
|
allSoundOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
309
|
+
resetAllStates(channelNumber: any): void;
|
|
304
310
|
resetAllControllers(channelNumber: any): void;
|
|
305
311
|
allNotesOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
306
312
|
omniOff(channelNumber: any, value: any, scheduleTime: any): void;
|
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":"
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
|