@marmooo/midy 0.1.6 → 0.1.7

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.
Files changed (37) hide show
  1. package/esm/midy-GM1.d.ts +5 -4
  2. package/esm/midy-GM1.d.ts.map +1 -1
  3. package/esm/midy-GM1.js +45 -16
  4. package/esm/midy-GM2.d.ts +5 -2
  5. package/esm/midy-GM2.d.ts.map +1 -1
  6. package/esm/midy-GM2.js +176 -66
  7. package/esm/midy-GMLite.d.ts +5 -4
  8. package/esm/midy-GMLite.d.ts.map +1 -1
  9. package/esm/midy-GMLite.js +45 -16
  10. package/esm/midy.d.ts +5 -2
  11. package/esm/midy.d.ts.map +1 -1
  12. package/esm/midy.js +177 -67
  13. package/package.json +5 -1
  14. package/script/midy-GM1.d.ts +5 -4
  15. package/script/midy-GM1.d.ts.map +1 -1
  16. package/script/midy-GM1.js +48 -19
  17. package/script/midy-GM2.d.ts +5 -2
  18. package/script/midy-GM2.d.ts.map +1 -1
  19. package/script/midy-GM2.js +179 -69
  20. package/script/midy-GMLite.d.ts +5 -4
  21. package/script/midy-GMLite.d.ts.map +1 -1
  22. package/script/midy-GMLite.js +48 -19
  23. package/script/midy.d.ts +5 -2
  24. package/script/midy.d.ts.map +1 -1
  25. package/script/midy.js +180 -70
  26. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts +0 -149
  27. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +0 -1
  28. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +0 -180
  29. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts +0 -84
  30. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts.map +0 -1
  31. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js +0 -216
  32. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts +0 -149
  33. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +0 -1
  34. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +0 -190
  35. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts +0 -84
  36. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts.map +0 -1
  37. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js +0 -221
package/esm/midy-GM1.d.ts CHANGED
@@ -37,6 +37,7 @@ export class MidyGM1 {
37
37
  timeline: any[];
38
38
  instruments: any[];
39
39
  notePromises: any[];
40
+ exclusiveClassMap: Map<any, any>;
40
41
  audioContext: any;
41
42
  masterGain: any;
42
43
  controlChangeHandlers: {
@@ -98,11 +99,11 @@ export class MidyGM1 {
98
99
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
99
100
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
100
101
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
101
- stopNote(stopTime: any, endTime: any, scheduledNotes: any, index: any): Promise<any>;
102
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, force: any): void;
103
- releaseNote(channelNumber: any, noteNumber: any, velocity: any): void;
102
+ stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
103
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
104
+ releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
104
105
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
105
- handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<void>;
106
+ handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
106
107
  handleProgramChange(channelNumber: any, program: any): void;
107
108
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
108
109
  setPitchBend(channelNumber: any, pitchBend: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAwBA;IAmBE;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA/CD,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;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAuBC;IAED,mEAWC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgEC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,sCAGC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAgCC;IAED,kGA8BC;IAED,0EAGC;IAED,qFA4BC;IAED,0GAsBC;IAED,sEAGC;IAED,kEAeC;IAED,iFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED;;;;;;;;;;;;;MAeC;IAED,2EASC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAUC;IAED,sDAMC;IAED,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBASC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAnjCD;IAUE,gFAKC;IAdD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
1
+ {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAqBA;IAoBE;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IAhDD,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;IAClB,iCAA8B;IAyB5B,kBAAgC;IAChC,gBAA4C;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DA2BC;IAED,mEAWC;IAED,2EA+CC;IAED,mCAOC;IAED,0BAkDC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgEC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,sCAGC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAgCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFA4BC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED;;;;;;;;;;;;;MAeC;IAED,2EASC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAUC;IAED,sDAMC;IAED,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBASC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA9kCD;IAUE,gFAKC;IAdD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
package/esm/midy-GM1.js CHANGED
@@ -1,5 +1,5 @@
1
- import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
2
- import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js";
1
+ import { parseMidi } from "midi-file";
2
+ import { parse, SoundFont } from "@marmooo/soundfont-parser";
3
3
  class Note {
4
4
  constructor(noteNumber, velocity, startTime, instrumentKey) {
5
5
  Object.defineProperty(this, "bufferSource", {
@@ -160,6 +160,12 @@ export class MidyGM1 {
160
160
  writable: true,
161
161
  value: []
162
162
  });
163
+ Object.defineProperty(this, "exclusiveClassMap", {
164
+ enumerable: true,
165
+ configurable: true,
166
+ writable: true,
167
+ value: new Map()
168
+ });
163
169
  this.audioContext = audioContext;
164
170
  this.masterGain = new GainNode(audioContext);
165
171
  this.controlChangeHandlers = this.createControlChangeHandlers();
@@ -232,19 +238,25 @@ export class MidyGM1 {
232
238
  const sampleStart = instrumentKey.start;
233
239
  const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
234
240
  if (isSF3) {
235
- const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
236
- const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
241
+ const sample = instrumentKey.sample;
242
+ const start = sample.byteOffset + sampleStart;
243
+ const end = sample.byteOffset + sampleEnd;
244
+ const buffer = sample.buffer.slice(start, end);
245
+ const audioBuffer = await this.audioContext.decodeAudioData(buffer);
237
246
  return audioBuffer;
238
247
  }
239
248
  else {
240
- const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
249
+ const sample = instrumentKey.sample;
250
+ const start = sample.byteOffset + sampleStart;
251
+ const end = sample.byteOffset + sampleEnd;
252
+ const buffer = sample.buffer.slice(start, end);
241
253
  const audioBuffer = new AudioBuffer({
242
254
  numberOfChannels: 1,
243
255
  length: sample.length,
244
256
  sampleRate: instrumentKey.sampleRate,
245
257
  });
246
258
  const channelData = audioBuffer.getChannelData(0);
247
- const int16Array = new Int16Array(sample.buffer);
259
+ const int16Array = new Int16Array(buffer);
248
260
  for (let i = 0; i < int16Array.length; i++) {
249
261
  channelData[i] = int16Array[i] / 32768;
250
262
  }
@@ -318,6 +330,7 @@ export class MidyGM1 {
318
330
  if (queueIndex >= this.timeline.length) {
319
331
  await Promise.all(this.notePromises);
320
332
  this.notePromises = [];
333
+ this.exclusiveClassMap.clear();
321
334
  resolve();
322
335
  return;
323
336
  }
@@ -333,6 +346,7 @@ export class MidyGM1 {
333
346
  }
334
347
  else if (this.isStopping) {
335
348
  await this.stopNotes(0, true);
349
+ this.exclusiveClassMap.clear();
336
350
  this.notePromises = [];
337
351
  resolve();
338
352
  this.isStopping = false;
@@ -341,6 +355,7 @@ export class MidyGM1 {
341
355
  }
342
356
  else if (this.isSeeking) {
343
357
  this.stopNotes(0, true);
358
+ this.exclusiveClassMap.clear();
344
359
  this.startTime = this.audioContext.currentTime;
345
360
  queueIndex = this.getQueueIndex(this.resumeTime);
346
361
  offset = this.resumeTime - this.startTime;
@@ -647,6 +662,19 @@ export class MidyGM1 {
647
662
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
648
663
  note.volumeNode.connect(channel.gainL);
649
664
  note.volumeNode.connect(channel.gainR);
665
+ const exclusiveClass = instrumentKey.exclusiveClass;
666
+ if (exclusiveClass !== 0) {
667
+ if (this.exclusiveClassMap.has(exclusiveClass)) {
668
+ const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
669
+ const [prevNote, prevChannelNumber] = prevEntry;
670
+ if (!prevNote.ending) {
671
+ this.scheduleNoteRelease(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
672
+ startTime, undefined, // portamentoNoteNumber
673
+ true);
674
+ }
675
+ }
676
+ this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
677
+ }
650
678
  const scheduledNotes = channel.scheduledNotes;
651
679
  if (scheduledNotes.has(noteNumber)) {
652
680
  scheduledNotes.get(noteNumber).push(note);
@@ -659,15 +687,15 @@ export class MidyGM1 {
659
687
  const now = this.audioContext.currentTime;
660
688
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
661
689
  }
662
- stopNote(stopTime, endTime, scheduledNotes, index) {
690
+ stopNote(endTime, stopTime, scheduledNotes, index) {
663
691
  const note = scheduledNotes[index];
664
692
  note.volumeNode.gain
665
- .cancelScheduledValues(stopTime)
666
- .linearRampToValueAtTime(0, endTime);
693
+ .cancelScheduledValues(endTime)
694
+ .linearRampToValueAtTime(0, stopTime);
667
695
  note.ending = true;
668
696
  this.scheduleTask(() => {
669
697
  note.bufferSource.loop = false;
670
- }, endTime);
698
+ }, stopTime);
671
699
  return new Promise((resolve) => {
672
700
  note.bufferSource.onended = () => {
673
701
  scheduledNotes[index] = null;
@@ -685,10 +713,10 @@ export class MidyGM1 {
685
713
  }
686
714
  resolve();
687
715
  };
688
- note.bufferSource.stop(endTime);
716
+ note.bufferSource.stop(stopTime);
689
717
  });
690
718
  }
691
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, force) {
719
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, endTime, force) {
692
720
  const channel = this.channels[channelNumber];
693
721
  if (!force && channel.sustainPedal)
694
722
  return;
@@ -701,12 +729,13 @@ export class MidyGM1 {
701
729
  continue;
702
730
  if (note.ending)
703
731
  continue;
704
- const volEndTime = stopTime + note.instrumentKey.volRelease;
705
- const modRelease = stopTime + note.instrumentKey.modRelease;
732
+ const volRelease = endTime + note.instrumentKey.volRelease;
733
+ const modRelease = endTime + note.instrumentKey.modRelease;
706
734
  note.filterNode.frequency
707
- .cancelScheduledValues(stopTime)
735
+ .cancelScheduledValues(endTime)
708
736
  .linearRampToValueAtTime(0, modRelease);
709
- this.stopNote(stopTime, volEndTime, scheduledNotes, i);
737
+ const stopTime = Math.min(volRelease, modRelease);
738
+ return this.stopNote(endTime, stopTime, scheduledNotes, i);
710
739
  }
711
740
  }
712
741
  releaseNote(channelNumber, noteNumber, velocity) {
package/esm/midy-GM2.d.ts CHANGED
@@ -78,6 +78,7 @@ export class MidyGM2 {
78
78
  timeline: any[];
79
79
  instruments: any[];
80
80
  notePromises: any[];
81
+ exclusiveClassMap: Map<any, any>;
81
82
  defaultOptions: {
82
83
  reverbAlgorithm: (audioContext: any) => {
83
84
  input: any;
@@ -203,8 +204,8 @@ export class MidyGM2 {
203
204
  calcBank(channel: any, channelNumber: any): any;
204
205
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
205
206
  noteOn(channelNumber: any, noteNumber: any, velocity: any, portamento: any): Promise<void>;
206
- stopNote(stopTime: any, endTime: any, scheduledNotes: any, index: any): Promise<any>;
207
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, portamentoNoteNumber: any, force: any): Promise<any> | undefined;
207
+ stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
208
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, portamentoNoteNumber: any, force: any): Promise<any> | undefined;
208
209
  releaseNote(channelNumber: any, noteNumber: any, velocity: any, portamentoNoteNumber: any): Promise<any> | undefined;
209
210
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
210
211
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
@@ -324,6 +325,8 @@ declare class Note {
324
325
  modulationDepth: any;
325
326
  vibratoLFO: any;
326
327
  vibratoDepth: any;
328
+ reverbEffectsSend: any;
329
+ chorusEffectsSend: any;
327
330
  noteNumber: any;
328
331
  velocity: any;
329
332
  startTime: any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
package/esm/midy-GM2.js CHANGED
@@ -1,5 +1,5 @@
1
- import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
2
- import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js";
1
+ import { parseMidi } from "midi-file";
2
+ import { parse, SoundFont } from "@marmooo/soundfont-parser";
3
3
  class Note {
4
4
  constructor(noteNumber, velocity, startTime, instrumentKey) {
5
5
  Object.defineProperty(this, "bufferSource", {
@@ -50,6 +50,18 @@ class Note {
50
50
  writable: true,
51
51
  value: void 0
52
52
  });
53
+ Object.defineProperty(this, "reverbEffectsSend", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: void 0
58
+ });
59
+ Object.defineProperty(this, "chorusEffectsSend", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: void 0
64
+ });
53
65
  this.noteNumber = noteNumber;
54
66
  this.velocity = velocity;
55
67
  this.startTime = startTime;
@@ -205,6 +217,12 @@ export class MidyGM2 {
205
217
  writable: true,
206
218
  value: []
207
219
  });
220
+ Object.defineProperty(this, "exclusiveClassMap", {
221
+ enumerable: true,
222
+ configurable: true,
223
+ writable: true,
224
+ value: new Map()
225
+ });
208
226
  Object.defineProperty(this, "defaultOptions", {
209
227
  enumerable: true,
210
228
  configurable: true,
@@ -308,19 +326,25 @@ export class MidyGM2 {
308
326
  const sampleStart = instrumentKey.start;
309
327
  const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
310
328
  if (isSF3) {
311
- const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
312
- const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
329
+ const sample = instrumentKey.sample;
330
+ const start = sample.byteOffset + sampleStart;
331
+ const end = sample.byteOffset + sampleEnd;
332
+ const buffer = sample.buffer.slice(start, end);
333
+ const audioBuffer = await this.audioContext.decodeAudioData(buffer);
313
334
  return audioBuffer;
314
335
  }
315
336
  else {
316
- const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
337
+ const sample = instrumentKey.sample;
338
+ const start = sample.byteOffset + sampleStart;
339
+ const end = sample.byteOffset + sampleEnd;
340
+ const buffer = sample.buffer.slice(start, end);
317
341
  const audioBuffer = new AudioBuffer({
318
342
  numberOfChannels: 1,
319
343
  length: sample.length,
320
344
  sampleRate: instrumentKey.sampleRate,
321
345
  });
322
346
  const channelData = audioBuffer.getChannelData(0);
323
- const int16Array = new Int16Array(sample.buffer);
347
+ const int16Array = new Int16Array(buffer);
324
348
  for (let i = 0; i < int16Array.length; i++) {
325
349
  channelData[i] = int16Array[i] / 32768;
326
350
  }
@@ -418,6 +442,7 @@ export class MidyGM2 {
418
442
  if (queueIndex >= this.timeline.length) {
419
443
  await Promise.all(this.notePromises);
420
444
  this.notePromises = [];
445
+ this.exclusiveClassMap.clear();
421
446
  resolve();
422
447
  return;
423
448
  }
@@ -433,6 +458,7 @@ export class MidyGM2 {
433
458
  }
434
459
  else if (this.isStopping) {
435
460
  await this.stopNotes(0, true);
461
+ this.exclusiveClassMap.clear();
436
462
  this.notePromises = [];
437
463
  resolve();
438
464
  this.isStopping = false;
@@ -441,6 +467,7 @@ export class MidyGM2 {
441
467
  }
442
468
  else if (this.isSeeking) {
443
469
  this.stopNotes(0, true);
470
+ this.exclusiveClassMap.clear();
444
471
  this.startTime = this.audioContext.currentTime;
445
472
  queueIndex = this.getQueueIndex(this.resumeTime);
446
473
  offset = this.resumeTime - this.startTime;
@@ -669,14 +696,14 @@ export class MidyGM2 {
669
696
  return impulse;
670
697
  }
671
698
  createConvolutionReverb(audioContext, impulse) {
672
- const output = new GainNode(audioContext);
699
+ const input = new GainNode(audioContext);
673
700
  const convolverNode = new ConvolverNode(audioContext, {
674
701
  buffer: impulse,
675
702
  });
676
- convolverNode.connect(output);
703
+ input.connect(convolverNode);
677
704
  return {
678
- input: convolverNode,
679
- output,
705
+ input,
706
+ output: convolverNode,
680
707
  convolverNode,
681
708
  };
682
709
  }
@@ -718,7 +745,6 @@ export class MidyGM2 {
718
745
  // M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
719
746
  createSchroederReverb(audioContext, combFeedbacks, combDelays, allpassFeedbacks, allpassDelays) {
720
747
  const input = new GainNode(audioContext);
721
- const output = new GainNode(audioContext);
722
748
  const mergerGain = new GainNode(audioContext);
723
749
  for (let i = 0; i < combDelays.length; i++) {
724
750
  const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
@@ -729,7 +755,7 @@ export class MidyGM2 {
729
755
  const allpass = this.createAllpassFilter(audioContext, (i === 0) ? mergerGain : allpasses.at(-1), allpassDelays[i], allpassFeedbacks[i]);
730
756
  allpasses.push(allpass);
731
757
  }
732
- allpasses.at(-1).connect(output);
758
+ const output = allpasses.at(-1);
733
759
  return { input, output };
734
760
  }
735
761
  createChorusEffect(audioContext) {
@@ -960,6 +986,20 @@ export class MidyGM2 {
960
986
  }
961
987
  note.bufferSource.connect(note.filterNode);
962
988
  note.filterNode.connect(note.volumeNode);
989
+ if (0 < channel.reverbSendLevel && 0 < instrumentKey.reverbEffectsSend) {
990
+ note.reverbEffectsSend = new GainNode(this.audioContext, {
991
+ gain: instrumentKey.reverbEffectsSend,
992
+ });
993
+ note.volumeNode.connect(note.reverbEffectsSend);
994
+ note.reverbEffectsSend.connect(this.reverbEffect.input);
995
+ }
996
+ if (0 < channel.chorusSendLevel && 0 < instrumentKey.chorusEffectsSend) {
997
+ note.chorusEffectsSend = new GainNode(this.audioContext, {
998
+ gain: instrumentKey.chorusEffectsSend,
999
+ });
1000
+ note.volumeNode.connect(note.chorusEffectsSend);
1001
+ note.chorusEffectsSend.connect(this.chorusEffect.input);
1002
+ }
963
1003
  note.bufferSource.start(startTime);
964
1004
  return note;
965
1005
  }
@@ -989,6 +1029,19 @@ export class MidyGM2 {
989
1029
  if (channel.sostenutoPedal) {
990
1030
  channel.sostenutoNotes.set(noteNumber, note);
991
1031
  }
1032
+ const exclusiveClass = instrumentKey.exclusiveClass;
1033
+ if (exclusiveClass !== 0) {
1034
+ if (this.exclusiveClassMap.has(exclusiveClass)) {
1035
+ const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
1036
+ const [prevNote, prevChannelNumber] = prevEntry;
1037
+ if (!prevNote.ending) {
1038
+ this.scheduleNoteRelease(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
1039
+ startTime, undefined, // portamentoNoteNumber
1040
+ true);
1041
+ }
1042
+ }
1043
+ this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
1044
+ }
992
1045
  const scheduledNotes = channel.scheduledNotes;
993
1046
  if (scheduledNotes.has(noteNumber)) {
994
1047
  scheduledNotes.get(noteNumber).push(note);
@@ -1001,15 +1054,15 @@ export class MidyGM2 {
1001
1054
  const now = this.audioContext.currentTime;
1002
1055
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now, portamento);
1003
1056
  }
1004
- stopNote(stopTime, endTime, scheduledNotes, index) {
1057
+ stopNote(endTime, stopTime, scheduledNotes, index) {
1005
1058
  const note = scheduledNotes[index];
1006
1059
  note.volumeNode.gain
1007
- .cancelScheduledValues(stopTime)
1008
- .linearRampToValueAtTime(0, endTime);
1060
+ .cancelScheduledValues(endTime)
1061
+ .linearRampToValueAtTime(0, stopTime);
1009
1062
  note.ending = true;
1010
1063
  this.scheduleTask(() => {
1011
1064
  note.bufferSource.loop = false;
1012
- }, endTime);
1065
+ }, stopTime);
1013
1066
  return new Promise((resolve) => {
1014
1067
  note.bufferSource.onended = () => {
1015
1068
  scheduledNotes[index] = null;
@@ -1025,12 +1078,18 @@ export class MidyGM2 {
1025
1078
  note.vibratoDepth.disconnect();
1026
1079
  note.vibratoLFO.stop();
1027
1080
  }
1081
+ if (note.reverbEffectsSend) {
1082
+ note.reverbEffectsSend.disconnect();
1083
+ }
1084
+ if (note.chorusEffectsSend) {
1085
+ note.chorusEffectsSend.disconnect();
1086
+ }
1028
1087
  resolve();
1029
1088
  };
1030
- note.bufferSource.stop(endTime);
1089
+ note.bufferSource.stop(stopTime);
1031
1090
  });
1032
1091
  }
1033
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, portamentoNoteNumber, force) {
1092
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, endTime, portamentoNoteNumber, force) {
1034
1093
  const channel = this.channels[channelNumber];
1035
1094
  if (!force) {
1036
1095
  if (channel.sustainPedal)
@@ -1048,21 +1107,22 @@ export class MidyGM2 {
1048
1107
  if (note.ending)
1049
1108
  continue;
1050
1109
  if (portamentoNoteNumber === undefined) {
1051
- const volEndTime = stopTime + note.instrumentKey.volRelease;
1052
- const modRelease = stopTime + note.instrumentKey.modRelease;
1110
+ const volRelease = endTime + note.instrumentKey.volRelease;
1111
+ const modRelease = endTime + note.instrumentKey.modRelease;
1053
1112
  note.filterNode.frequency
1054
- .cancelScheduledValues(stopTime)
1113
+ .cancelScheduledValues(endTime)
1055
1114
  .linearRampToValueAtTime(0, modRelease);
1056
- return this.stopNote(stopTime, volEndTime, scheduledNotes, i);
1115
+ const stopTime = Math.min(volRelease, modRelease);
1116
+ return this.stopNote(endTime, stopTime, scheduledNotes, i);
1057
1117
  }
1058
1118
  else {
1059
- const portamentoTime = stopTime + channel.portamentoTime;
1119
+ const portamentoTime = endTime + channel.portamentoTime;
1060
1120
  const detuneChange = (portamentoNoteNumber - noteNumber) * 100;
1061
1121
  const detune = note.bufferSource.detune.value + detuneChange;
1062
1122
  note.bufferSource.detune
1063
- .cancelScheduledValues(stopTime)
1123
+ .cancelScheduledValues(endTime)
1064
1124
  .linearRampToValueAtTime(detune, portamentoTime);
1065
- return this.stopNote(stopTime, portamentoTime, scheduledNotes, i);
1125
+ return this.stopNote(endTime, portamentoTime, scheduledNotes, i);
1066
1126
  }
1067
1127
  }
1068
1128
  }
@@ -1277,20 +1337,44 @@ export class MidyGM2 {
1277
1337
  if (0 < reverbSendLevel) {
1278
1338
  const now = this.audioContext.currentTime;
1279
1339
  channel.reverbSendLevel = reverbSendLevel / 127;
1280
- reverbEffect.output.gain.cancelScheduledValues(now);
1281
- reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1340
+ reverbEffect.input.gain.cancelScheduledValues(now);
1341
+ reverbEffect.input.gain.setValueAtTime(channel.reverbSendLevel, now);
1282
1342
  }
1283
1343
  else {
1284
- channel.merger.disconnect(reverbEffect.input);
1344
+ channel.scheduledNotes.forEach((noteList) => {
1345
+ for (let i = 0; i < noteList.length; i++) {
1346
+ const note = noteList[i];
1347
+ if (!note)
1348
+ continue;
1349
+ if (note.instrumentKey.reverbEffectsSend <= 0)
1350
+ continue;
1351
+ note.reverbEffectsSend.disconnect();
1352
+ }
1353
+ });
1285
1354
  }
1286
1355
  }
1287
1356
  else {
1288
1357
  if (0 < reverbSendLevel) {
1289
- channel.merger.connect(reverbEffect.input);
1290
1358
  const now = this.audioContext.currentTime;
1359
+ channel.scheduledNotes.forEach((noteList) => {
1360
+ for (let i = 0; i < noteList.length; i++) {
1361
+ const note = noteList[i];
1362
+ if (!note)
1363
+ continue;
1364
+ if (note.instrumentKey.reverbEffectsSend <= 0)
1365
+ continue;
1366
+ if (!note.reverbEffectsSend) {
1367
+ note.reverbEffectsSend = new GainNode(this.audioContext, {
1368
+ gain: note.instrumentKey.reverbEffectsSend,
1369
+ });
1370
+ note.volumeNode.connect(note.reverbEffectsSend);
1371
+ }
1372
+ note.reverbEffectsSend.connect(reverbEffect.input);
1373
+ }
1374
+ });
1291
1375
  channel.reverbSendLevel = reverbSendLevel / 127;
1292
- reverbEffect.output.gain.cancelScheduledValues(now);
1293
- reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1376
+ reverbEffect.input.gain.cancelScheduledValues(now);
1377
+ reverbEffect.input.gain.setValueAtTime(channel.reverbSendLevel, now);
1294
1378
  }
1295
1379
  }
1296
1380
  }
@@ -1301,20 +1385,44 @@ export class MidyGM2 {
1301
1385
  if (0 < chorusSendLevel) {
1302
1386
  const now = this.audioContext.currentTime;
1303
1387
  channel.chorusSendLevel = chorusSendLevel / 127;
1304
- chorusEffect.output.gain.cancelScheduledValues(now);
1305
- chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1388
+ chorusEffect.input.gain.cancelScheduledValues(now);
1389
+ chorusEffect.input.gain.setValueAtTime(channel.chorusSendLevel, now);
1306
1390
  }
1307
1391
  else {
1308
- channel.merger.disconnect(chorusEffect.input);
1392
+ channel.scheduledNotes.forEach((noteList) => {
1393
+ for (let i = 0; i < noteList.length; i++) {
1394
+ const note = noteList[i];
1395
+ if (!note)
1396
+ continue;
1397
+ if (note.instrumentKey.chorusEffectsSend <= 0)
1398
+ continue;
1399
+ note.chorusEffectsSend.disconnect();
1400
+ }
1401
+ });
1309
1402
  }
1310
1403
  }
1311
1404
  else {
1312
1405
  if (0 < chorusSendLevel) {
1313
- channel.merger.connect(chorusEffect.input);
1314
1406
  const now = this.audioContext.currentTime;
1407
+ channel.scheduledNotes.forEach((noteList) => {
1408
+ for (let i = 0; i < noteList.length; i++) {
1409
+ const note = noteList[i];
1410
+ if (!note)
1411
+ continue;
1412
+ if (note.instrumentKey.chorusEffectsSend <= 0)
1413
+ continue;
1414
+ if (!note.chorusEffectsSend) {
1415
+ note.chorusEffectsSend = new GainNode(this.audioContext, {
1416
+ gain: note.instrumentKey.chorusEffectsSend,
1417
+ });
1418
+ note.volumeNode.connect(note.chorusEffectsSend);
1419
+ }
1420
+ note.chorusEffectsSend.connect(chorusEffect.input);
1421
+ }
1422
+ });
1315
1423
  channel.chorusSendLevel = chorusSendLevel / 127;
1316
- chorusEffect.output.gain.cancelScheduledValues(now);
1317
- chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1424
+ chorusEffect.input.gain.cancelScheduledValues(now);
1425
+ chorusEffect.input.gain.setValueAtTime(channel.chorusSendLevel, now);
1318
1426
  }
1319
1427
  }
1320
1428
  }
@@ -1656,10 +1764,8 @@ export class MidyGM2 {
1656
1764
  }
1657
1765
  setReverbTime(value) {
1658
1766
  this.reverb.time = this.getReverbTime(value);
1659
- const { audioContext, channels, options } = this;
1660
- for (let i = 0; i < channels.length; i++) {
1661
- channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1662
- }
1767
+ const { audioContext, options } = this;
1768
+ this.reverbEffect = options.reverbAlgorithm(audioContext);
1663
1769
  }
1664
1770
  getReverbTime(value) {
1665
1771
  return Math.pow(Math.E, (value - 40) * 0.025);
@@ -1736,10 +1842,7 @@ export class MidyGM2 {
1736
1842
  const now = this.audioContext.currentTime;
1737
1843
  const modRate = this.getChorusModRate(value);
1738
1844
  this.chorus.modRate = modRate;
1739
- for (let i = 0; i < this.channels.length; i++) {
1740
- const lfo = this.channels[i].chorusEffect.lfo;
1741
- lfo.frequency.setValueAtTime(modRate, now);
1742
- }
1845
+ this.chorusEffect.lfo.frequency.setValueAtTime(modRate, now);
1743
1846
  }
1744
1847
  getChorusModRate(value) {
1745
1848
  return value * 0.122; // Hz
@@ -1748,12 +1851,9 @@ export class MidyGM2 {
1748
1851
  const now = this.audioContext.currentTime;
1749
1852
  const modDepth = this.getChorusModDepth(value);
1750
1853
  this.chorus.modDepth = modDepth;
1751
- for (let i = 0; i < this.channels.length; i++) {
1752
- const chorusEffect = this.channels[i].chorusEffect;
1753
- chorusEffect.lfoGain.gain
1754
- .cancelScheduledValues(now)
1755
- .setValueAtTime(modDepth / 2, now);
1756
- }
1854
+ this.chorusEffect.lfoGain.gain
1855
+ .cancelScheduledValues(now)
1856
+ .setValueAtTime(modDepth / 2, now);
1757
1857
  }
1758
1858
  getChorusModDepth(value) {
1759
1859
  return (value + 1) / 3200; // second
@@ -1762,14 +1862,11 @@ export class MidyGM2 {
1762
1862
  const now = this.audioContext.currentTime;
1763
1863
  const feedback = this.getChorusFeedback(value);
1764
1864
  this.chorus.feedback = feedback;
1765
- for (let i = 0; i < this.channels.length; i++) {
1766
- const chorusEffect = this.channels[i].chorusEffect;
1767
- for (let j = 0; j < chorusEffect.feedbackGains.length; j++) {
1768
- const feedbackGain = chorusEffect.feedbackGains[j];
1769
- feedbackGain.gain
1770
- .cancelScheduledValues(now)
1771
- .setValueAtTime(feedback, now);
1772
- }
1865
+ const chorusEffect = this.chorusEffect;
1866
+ for (let i = 0; i < chorusEffect.feedbackGains.length; i++) {
1867
+ chorusEffect.feedbackGains[i].gain
1868
+ .cancelScheduledValues(now)
1869
+ .setValueAtTime(feedback, now);
1773
1870
  }
1774
1871
  }
1775
1872
  getChorusFeedback(value) {
@@ -1777,15 +1874,28 @@ export class MidyGM2 {
1777
1874
  }
1778
1875
  setChorusSendToReverb(value) {
1779
1876
  const sendToReverb = this.getChorusSendToReverb(value);
1780
- if (0 < sendToReverb) {
1781
- const now = this.audioContext.currentTime;
1877
+ const sendGain = this.chorusEffect.sendGain;
1878
+ if (0 < this.chorus.sendToReverb) {
1782
1879
  this.chorus.sendToReverb = sendToReverb;
1783
- this.chorusEffect.sendGain.gain
1784
- .cancelScheduledValues(now)
1785
- .setValueAtTime(sendToReverb, now);
1880
+ if (0 < sendToReverb) {
1881
+ const now = this.audioContext.currentTime;
1882
+ sendGain.gain
1883
+ .cancelScheduledValues(now)
1884
+ .setValueAtTime(sendToReverb, now);
1885
+ }
1886
+ else {
1887
+ sendGain.disconnect();
1888
+ }
1786
1889
  }
1787
- else if (this.chorus.sendToReverb !== 0) {
1788
- this.chorusEffect.sendGain.disconnect(this.reverbEffect.input);
1890
+ else {
1891
+ this.chorus.sendToReverb = sendToReverb;
1892
+ if (0 < sendToReverb) {
1893
+ const now = this.audioContext.currentTime;
1894
+ sendGain.connect(this.reverbEffect.input);
1895
+ sendGain.gain
1896
+ .cancelScheduledValues(now)
1897
+ .setValueAtTime(sendToReverb, now);
1898
+ }
1789
1899
  }
1790
1900
  }
1791
1901
  getChorusSendToReverb(value) {