@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.
@@ -1,9 +1,7 @@
1
1
  export class MidyGM1 {
2
2
  static channelSettings: {
3
- currentBufferSource: null;
4
- isDrum: boolean;
5
3
  detune: number;
6
- program: number;
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
- exclusiveClassMap: SparseMap;
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(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
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
- stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
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, program: any, _scheduleTime: any): void;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAiJA;IAuBE;;;;;;;;;;;;;MAaE;IAEF,+BAcC;IAnDD,aAAa;IACb,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,6BAAuC;IAkBrC,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,yCAWC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;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,yGAgBC;IAED,gHAwCC;IAED,kGAkDC;IAED,6FAQC;IAED,qFAwBC;IAED,yHAuBC;IAED,yGASC;IAED,4GAeC;IAED,mGA2BC;IAED,gFAGC;IAED,wFAGC;IAED,sEAWC;IAED,mEAQC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MA2BC;IAED,oFAMC;IAED,6EA2CC;IAED;;;;;;;;;;;;;MAeC;IAED,kGAWC;IAED,wDAUC;IAED,iFAMC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAYC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAWC;IAED,iEAKC;IAED,uEASC;IAED,mEAKC;IAED,yEASC;IAED,gFAGC;IAED,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAED,6DAgBC;CACF;AA97CD;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"}
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"}
@@ -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, "exclusiveClassMap", {
302
+ Object.defineProperty(this, "exclusiveClassNotes", {
297
303
  enumerable: true,
298
304
  configurable: true,
299
305
  writable: true,
300
- value: new SparseMap(128)
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: 16 }, () => {
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 !== 0) {
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.exclusiveClassMap.clear();
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.exclusiveClassMap.clear();
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.exclusiveClassMap.clear();
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(16);
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(program, noteNumber, velocity, voiceParams, isSF3) {
799
- const audioBufferId = this.getAudioBufferId(program, noteNumber, velocity);
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.program, noteNumber, velocity, voiceParams, isSF3);
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.program].get(bankNumber);
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.program, noteNumber, velocity);
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
- const exclusiveClass = note.voiceParams.exclusiveClass;
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
- if (scheduledNotes.has(noteNumber)) {
871
- scheduledNotes.get(noteNumber).push(note);
897
+ let noteList = scheduledNotes.get(noteNumber);
898
+ if (noteList) {
899
+ noteList.push(note);
872
900
  }
873
901
  else {
874
- scheduledNotes.set(noteNumber, [note]);
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
- stopNote(endTime, stopTime, scheduledNotes, index) {
882
- const note = scheduledNotes[index];
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
- scheduledNotes[index] = null;
893
- note.bufferSource.disconnect();
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 scheduledNotes = channel.scheduledNotes.get(noteNumber);
913
- for (let i = 0; i < scheduledNotes.length; i++) {
914
- const note = scheduledNotes[i];
915
- if (!note)
916
- continue;
917
- if (note.ending)
918
- continue;
919
- const volRelease = endTime + note.voiceParams.volRelease;
920
- const modRelease = endTime + note.voiceParams.modRelease;
921
- note.filterNode.frequency
922
- .cancelScheduledValues(endTime)
923
- .linearRampToValueAtTime(0, modRelease);
924
- const stopTime = Math.min(volRelease, modRelease);
925
- return this.stopNote(endTime, stopTime, scheduledNotes, i);
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, program, _scheduleTime) {
1002
+ handleProgramChange(channelNumber, programNumber, _scheduleTime) {
962
1003
  const channel = this.channels[channelNumber];
963
- channel.program = program;
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.stopChannelNotes(channelNumber, 0, true, scheduleTime);
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.stopChannelNotes(channelNumber, 0, false, scheduleTime);
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
- program: 0,
1468
+ programNumber: 0,
1429
1469
  bank: 0,
1430
1470
  dataMSB: 0,
1431
1471
  dataLSB: 0,
@@ -1,9 +1,7 @@
1
1
  export class MidyGM2 {
2
2
  static channelSettings: {
3
- currentBufferSource: null;
4
- isDrum: boolean;
5
3
  detune: number;
6
- program: number;
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
- exclusiveClassMap: SparseMap;
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
- calcLoopMode(channel: any, note: any, voiceParams: any): boolean;
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(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
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
- stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
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, program: any, _scheduleTime: any): void;
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;
@@ -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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"}