@marmooo/midy 0.2.3 → 0.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midy",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "A MIDI player/synthesizer written in JavaScript that supports GM-Lite/GM1 and SF2/SF3.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,6 +22,8 @@ export class MidyGM1 {
22
22
  resumeTime: number;
23
23
  soundFonts: any[];
24
24
  soundFontTable: any[];
25
+ audioBufferCounter: Map<any, any>;
26
+ audioBufferCache: Map<any, any>;
25
27
  isPlaying: boolean;
26
28
  isPausing: boolean;
27
29
  isPaused: boolean;
@@ -30,7 +32,7 @@ export class MidyGM1 {
30
32
  timeline: any[];
31
33
  instruments: any[];
32
34
  notePromises: any[];
33
- exclusiveClassMap: Map<any, any>;
35
+ exclusiveClassMap: SparseMap;
34
36
  audioContext: any;
35
37
  masterVolume: any;
36
38
  voiceParamsHandlers: {
@@ -71,12 +73,13 @@ export class MidyGM1 {
71
73
  };
72
74
  createChannels(audioContext: any): any[];
73
75
  createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
74
- createNoteBufferNode(voiceParams: any, isSF3: any): Promise<any>;
76
+ createNoteBufferNode(audioBuffer: any, voiceParams: any): any;
75
77
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
76
78
  getQueueIndex(second: any): number;
77
79
  playNotes(): Promise<any>;
78
80
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
79
81
  secondToTicks(second: any, secondsPerBeat: any): number;
82
+ getAudioBufferId(programNumber: any, noteNumber: any, velocity: any): string;
80
83
  extractMidiData(midi: any): {
81
84
  instruments: Set<any>;
82
85
  timeline: any[];
@@ -90,19 +93,21 @@ export class MidyGM1 {
90
93
  seekTo(second: any): void;
91
94
  calcTotalTime(): number;
92
95
  currentTime(): number;
93
- getActiveNotes(channel: any, time: any): Map<any, any>;
96
+ getActiveNotes(channel: any, time: any): SparseMap;
94
97
  getActiveNote(noteList: any, time: any): any;
95
98
  cbToRatio(cb: any): number;
96
99
  rateToCent(rate: any): number;
97
100
  centToRate(cent: any): number;
98
101
  centToHz(cent: any): number;
99
102
  calcChannelDetune(channel: any): any;
100
- updateDetune(channel: any): void;
103
+ updateChannelDetune(channel: any): void;
104
+ updateDetune(channel: any, note: any): void;
101
105
  setVolumeEnvelope(note: any): void;
102
106
  setPitchEnvelope(note: any): void;
103
107
  clampCutoffFrequency(frequency: any): number;
104
108
  setFilterEnvelope(note: any): void;
105
109
  startModulation(channel: any, note: any, startTime: any): void;
110
+ getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
106
111
  createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
107
112
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
108
113
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
@@ -185,6 +190,19 @@ export class MidyGM1 {
185
190
  handleSysEx(data: any): void;
186
191
  scheduleTask(callback: any, startTime: any): Promise<any>;
187
192
  }
193
+ declare class SparseMap {
194
+ constructor(size: any);
195
+ data: any[];
196
+ activeIndices: any[];
197
+ set(key: any, value: any): void;
198
+ get(key: any): any;
199
+ delete(key: any): boolean;
200
+ has(key: any): boolean;
201
+ get size(): number;
202
+ clear(): void;
203
+ forEach(callback: any): void;
204
+ [Symbol.iterator](): Generator<any[], void, unknown>;
205
+ }
188
206
  declare class Note {
189
207
  constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
190
208
  bufferSource: any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAqFA;IAoBE;;;;;;;;;;;;MAYE;IAEF,+BAQC;IAzCD,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;IAiB5B,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,iEAUC;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,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,iCAWC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,gHA2BC;IAED,kGAgDC;IAED,0EAGC;IAED,qFA4BC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MA4CC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+EAWC;IAED,qCAeC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,8CAKC;IAED,oDAOC;IAED,gDAKC;IAED,sDAOC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAjzCD;IAUE,0FAMC;IAfD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IAGX,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":"AAkJA;IAsBE;;;;;;;;;;;;MAYE;IAEF,+BAQC;IA3CD,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;IAiBrC,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,8DASC;IAED,2EA+CC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,mDASC;IAED,6CAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,yGAgBC;IAED,gHAuCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFA4BC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MA4CC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+EAWC;IAED,qCAeC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,8CAKC;IAED,oDAOC;IAED,gDAKC;IAED,sDAOC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAl6CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAUE,0FAMC;IAfD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
@@ -3,6 +3,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGM1 = void 0;
4
4
  const midi_file_1 = require("midi-file");
5
5
  const soundfont_parser_1 = require("@marmooo/soundfont-parser");
6
+ // 2-3 times faster than Map
7
+ class SparseMap {
8
+ constructor(size) {
9
+ this.data = new Array(size);
10
+ this.activeIndices = [];
11
+ }
12
+ set(key, value) {
13
+ if (this.data[key] === undefined) {
14
+ this.activeIndices.push(key);
15
+ }
16
+ this.data[key] = value;
17
+ }
18
+ get(key) {
19
+ return this.data[key];
20
+ }
21
+ delete(key) {
22
+ if (this.data[key] !== undefined) {
23
+ this.data[key] = undefined;
24
+ const index = this.activeIndices.indexOf(key);
25
+ if (index !== -1) {
26
+ this.activeIndices.splice(index, 1);
27
+ }
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+ has(key) {
33
+ return this.data[key] !== undefined;
34
+ }
35
+ get size() {
36
+ return this.activeIndices.length;
37
+ }
38
+ clear() {
39
+ for (let i = 0; i < this.activeIndices.length; i++) {
40
+ const key = this.activeIndices[i];
41
+ this.data[key] = undefined;
42
+ }
43
+ this.activeIndices = [];
44
+ }
45
+ *[Symbol.iterator]() {
46
+ for (let i = 0; i < this.activeIndices.length; i++) {
47
+ const key = this.activeIndices[i];
48
+ yield [key, this.data[key]];
49
+ }
50
+ }
51
+ forEach(callback) {
52
+ for (let i = 0; i < this.activeIndices.length; i++) {
53
+ const key = this.activeIndices[i];
54
+ callback(this.data[key], key, this);
55
+ }
56
+ }
57
+ }
6
58
  class Note {
7
59
  constructor(noteNumber, velocity, startTime, voice, voiceParams) {
8
60
  Object.defineProperty(this, "bufferSource", {
@@ -181,6 +233,18 @@ class MidyGM1 {
181
233
  writable: true,
182
234
  value: this.initSoundFontTable()
183
235
  });
236
+ Object.defineProperty(this, "audioBufferCounter", {
237
+ enumerable: true,
238
+ configurable: true,
239
+ writable: true,
240
+ value: new Map()
241
+ });
242
+ Object.defineProperty(this, "audioBufferCache", {
243
+ enumerable: true,
244
+ configurable: true,
245
+ writable: true,
246
+ value: new Map()
247
+ });
184
248
  Object.defineProperty(this, "isPlaying", {
185
249
  enumerable: true,
186
250
  configurable: true,
@@ -233,7 +297,7 @@ class MidyGM1 {
233
297
  enumerable: true,
234
298
  configurable: true,
235
299
  writable: true,
236
- value: new Map()
300
+ value: new SparseMap(128)
237
301
  });
238
302
  this.audioContext = audioContext;
239
303
  this.masterVolume = new GainNode(audioContext);
@@ -246,7 +310,7 @@ class MidyGM1 {
246
310
  initSoundFontTable() {
247
311
  const table = new Array(128);
248
312
  for (let i = 0; i < 128; i++) {
249
- table[i] = new Map();
313
+ table[i] = new SparseMap(128);
250
314
  }
251
315
  return table;
252
316
  }
@@ -299,7 +363,7 @@ class MidyGM1 {
299
363
  ...this.constructor.channelSettings,
300
364
  state: new ControllerState(),
301
365
  ...this.setChannelAudioNodes(audioContext),
302
- scheduledNotes: new Map(),
366
+ scheduledNotes: new SparseMap(128),
303
367
  };
304
368
  });
305
369
  return channels;
@@ -333,9 +397,8 @@ class MidyGM1 {
333
397
  return audioBuffer;
334
398
  }
335
399
  }
336
- async createNoteBufferNode(voiceParams, isSF3) {
400
+ createNoteBufferNode(audioBuffer, voiceParams) {
337
401
  const bufferSource = new AudioBufferSourceNode(this.audioContext);
338
- const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
339
402
  bufferSource.buffer = audioBuffer;
340
403
  bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
341
404
  if (bufferSource.loop) {
@@ -400,6 +463,7 @@ class MidyGM1 {
400
463
  await Promise.all(this.notePromises);
401
464
  this.notePromises = [];
402
465
  this.exclusiveClassMap.clear();
466
+ this.audioBufferCache.clear();
403
467
  resolve();
404
468
  return;
405
469
  }
@@ -415,8 +479,9 @@ class MidyGM1 {
415
479
  }
416
480
  else if (this.isStopping) {
417
481
  await this.stopNotes(0, true);
418
- this.exclusiveClassMap.clear();
419
482
  this.notePromises = [];
483
+ this.exclusiveClassMap.clear();
484
+ this.audioBufferCache.clear();
420
485
  resolve();
421
486
  this.isStopping = false;
422
487
  this.isPaused = false;
@@ -447,6 +512,9 @@ class MidyGM1 {
447
512
  secondToTicks(second, secondsPerBeat) {
448
513
  return second * this.ticksPerBeat / secondsPerBeat;
449
514
  }
515
+ getAudioBufferId(programNumber, noteNumber, velocity) {
516
+ return `${programNumber}:${noteNumber}:${velocity}`;
517
+ }
450
518
  extractMidiData(midi) {
451
519
  const instruments = new Set();
452
520
  const timeline = [];
@@ -467,6 +535,8 @@ class MidyGM1 {
467
535
  switch (event.type) {
468
536
  case "noteOn": {
469
537
  const channel = tmpChannels[event.channel];
538
+ const audioBufferId = this.getAudioBufferId(channel.programNumber, event.noteNumber, event.velocity);
539
+ this.audioBufferCounter.set(audioBufferId, (this.audioBufferCounter.get(audioBufferId) ?? 0) + 1);
470
540
  if (channel.programNumber < 0) {
471
541
  instruments.add(`${channel.bank}:0`);
472
542
  channel.programNumber = 0;
@@ -483,6 +553,10 @@ class MidyGM1 {
483
553
  timeline.push(event);
484
554
  }
485
555
  }
556
+ for (const [audioBufferId, count] of this.audioBufferCounter) {
557
+ if (count === 1)
558
+ this.audioBufferCounter.delete(audioBufferId);
559
+ }
486
560
  const priority = {
487
561
  controller: 0,
488
562
  sysEx: 1,
@@ -573,7 +647,7 @@ class MidyGM1 {
573
647
  return this.resumeTime + now - this.startTime - this.startDelay;
574
648
  }
575
649
  getActiveNotes(channel, time) {
576
- const activeNotes = new Map();
650
+ const activeNotes = new SparseMap(128);
577
651
  channel.scheduledNotes.forEach((noteList) => {
578
652
  const activeNote = this.getActiveNote(noteList, time);
579
653
  if (activeNote) {
@@ -612,19 +686,22 @@ class MidyGM1 {
612
686
  const pitch = pitchWheel * pitchWheelSensitivity;
613
687
  return tuning + pitch;
614
688
  }
615
- updateDetune(channel) {
616
- const now = this.audioContext.currentTime;
689
+ updateChannelDetune(channel) {
617
690
  channel.scheduledNotes.forEach((noteList) => {
618
691
  for (let i = 0; i < noteList.length; i++) {
619
692
  const note = noteList[i];
620
693
  if (!note)
621
694
  continue;
622
- note.bufferSource.detune
623
- .cancelScheduledValues(now)
624
- .setValueAtTime(channel.detune, now);
695
+ this.updateDetune(channel, note);
625
696
  }
626
697
  });
627
698
  }
699
+ updateDetune(channel, note) {
700
+ const now = this.audioContext.currentTime;
701
+ note.bufferSource.detune
702
+ .cancelScheduledValues(now)
703
+ .setValueAtTime(channel.detune, now);
704
+ }
628
705
  setVolumeEnvelope(note) {
629
706
  const now = this.audioContext.currentTime;
630
707
  const { voiceParams, startTime } = note;
@@ -712,11 +789,31 @@ class MidyGM1 {
712
789
  note.modulationLFO.connect(note.volumeDepth);
713
790
  note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
714
791
  }
792
+ async getAudioBuffer(program, noteNumber, velocity, voiceParams, isSF3) {
793
+ const audioBufferId = this.getAudioBufferId(program, noteNumber, velocity);
794
+ const cache = this.audioBufferCache.get(audioBufferId);
795
+ if (cache) {
796
+ cache.counter += 1;
797
+ if (cache.maxCount <= cache.counter) {
798
+ this.audioBufferCache.delete(audioBufferId);
799
+ }
800
+ return cache.audioBuffer;
801
+ }
802
+ else {
803
+ const maxCount = this.audioBufferCounter.get(audioBufferId) ?? 0;
804
+ const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
805
+ const cache = { audioBuffer, maxCount, counter: 1 };
806
+ this.audioBufferCache.set(audioBufferId, cache);
807
+ return audioBuffer;
808
+ }
809
+ }
715
810
  async createNote(channel, voice, noteNumber, velocity, startTime, isSF3) {
716
811
  const state = channel.state;
717
- const voiceParams = voice.getAllParams(state.array);
812
+ const controllerState = this.getControllerState(channel, noteNumber, velocity);
813
+ const voiceParams = voice.getAllParams(controllerState);
718
814
  const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
719
- note.bufferSource = await this.createNoteBufferNode(voiceParams, isSF3);
815
+ const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
816
+ note.bufferSource = this.createNoteBufferNode(audioBuffer, voiceParams);
720
817
  note.volumeEnvelopeNode = new GainNode(this.audioContext);
721
818
  note.filterNode = new BiquadFilterNode(this.audioContext, {
722
819
  type: "lowpass",
@@ -740,10 +837,10 @@ class MidyGM1 {
740
837
  if (soundFontIndex === undefined)
741
838
  return;
742
839
  const soundFont = this.soundFonts[soundFontIndex];
743
- const isSF3 = soundFont.parsed.info.version.major === 3;
744
840
  const voice = soundFont.getVoice(bankNumber, channel.program, noteNumber, velocity);
745
841
  if (!voice)
746
842
  return;
843
+ const isSF3 = soundFont.parsed.info.version.major === 3;
747
844
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
748
845
  note.volumeEnvelopeNode.connect(channel.gainL);
749
846
  note.volumeEnvelopeNode.connect(channel.gainR);
@@ -877,7 +974,7 @@ class MidyGM1 {
877
974
  const next = (value - 8192) / 8192;
878
975
  state.pitchWheel = value / 16383;
879
976
  channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
880
- this.updateDetune(channel);
977
+ this.updateChannelDetune(channel);
881
978
  this.applyVoiceParams(channel, 14);
882
979
  }
883
980
  setModLfoToPitch(channel, note) {
@@ -975,7 +1072,7 @@ class MidyGM1 {
975
1072
  const freqVibLFO = note.voiceParams.freqVibLFO;
976
1073
  note.vibratoLFO.frequency
977
1074
  .cancelScheduledValues(now)
978
- .setValueAtTime(freqVibLFO * channel.state.vibratoRate, now);
1075
+ .setValueAtTime(freqVibLFO * channel.state.vibratoRate * 2, now);
979
1076
  }
980
1077
  },
981
1078
  };
@@ -1015,7 +1112,7 @@ class MidyGM1 {
1015
1112
  if (key in voiceParams)
1016
1113
  noteVoiceParams[key] = voiceParams[key];
1017
1114
  }
1018
- this.setFilterEnvelope(channel, note);
1115
+ this.setFilterEnvelope(note);
1019
1116
  this.setPitchEnvelope(note);
1020
1117
  }
1021
1118
  else if (volumeEnvelopeKeySet.has(key)) {
@@ -1055,7 +1152,7 @@ class MidyGM1 {
1055
1152
  if (handler) {
1056
1153
  handler.call(this, channelNumber, value);
1057
1154
  const channel = this.channels[channelNumber];
1058
- this.applyVoiceParams(channel, controller + 128);
1155
+ this.applyVoiceParams(channel, controllerType + 128);
1059
1156
  }
1060
1157
  else {
1061
1158
  console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
@@ -1194,7 +1291,7 @@ class MidyGM1 {
1194
1291
  const next = value / 128;
1195
1292
  state.pitchWheelSensitivity = next;
1196
1293
  channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
1197
- this.updateDetune(channel);
1294
+ this.updateChannelDetune(channel);
1198
1295
  this.applyVoiceParams(channel, 16);
1199
1296
  }
1200
1297
  handleFineTuningRPN(channelNumber) {
@@ -1209,7 +1306,7 @@ class MidyGM1 {
1209
1306
  const next = (value - 8192) / 8.192; // cent
1210
1307
  channel.fineTuning = next;
1211
1308
  channel.detune += next - prev;
1212
- this.updateDetune(channel);
1309
+ this.updateChannelDetune(channel);
1213
1310
  }
1214
1311
  handleCoarseTuningRPN(channelNumber) {
1215
1312
  const channel = this.channels[channelNumber];
@@ -1223,7 +1320,7 @@ class MidyGM1 {
1223
1320
  const next = (value - 64) * 100; // cent
1224
1321
  channel.coarseTuning = next;
1225
1322
  channel.detune += next - prev;
1226
- this.updateDetune(channel);
1323
+ this.updateChannelDetune(channel);
1227
1324
  }
1228
1325
  allSoundOff(channelNumber) {
1229
1326
  return this.stopChannelNotes(channelNumber, 0, true);
@@ -1239,7 +1336,7 @@ class MidyGM1 {
1239
1336
  const state = channel.state;
1240
1337
  for (let i = 0; i < stateTypes.length; i++) {
1241
1338
  const type = stateTypes[i];
1242
- state[type] = defaultControllerState[type];
1339
+ state[type] = defaultControllerState[type].defaultValue;
1243
1340
  }
1244
1341
  const settingTypes = [
1245
1342
  "rpnMSB",
@@ -2,8 +2,8 @@ export class MidyGM2 {
2
2
  static channelSettings: {
3
3
  currentBufferSource: null;
4
4
  detune: number;
5
- scaleOctaveTuningTable: any[];
6
- pressureTable: Uint8Array<ArrayBuffer>;
5
+ scaleOctaveTuningTable: Int8Array<ArrayBuffer>;
6
+ channelPressureTable: Uint8Array<ArrayBuffer>;
7
7
  keyBasedInstrumentControlTable: Int8Array<ArrayBuffer>;
8
8
  program: number;
9
9
  bank: number;
@@ -17,14 +17,6 @@ export class MidyGM2 {
17
17
  coarseTuning: number;
18
18
  modulationDepthRange: number;
19
19
  };
20
- static controllerDestinationSettings: {
21
- pitchControl: number;
22
- filterCutoffControl: number;
23
- amplitudeControl: number;
24
- lfoPitchDepth: number;
25
- lfoFilterDepth: number;
26
- lfoAmplitudeDepth: number;
27
- };
28
20
  constructor(audioContext: any, options?: {
29
21
  reverbAlgorithm: (audioContext: any) => {
30
22
  input: any;
@@ -55,6 +47,8 @@ export class MidyGM2 {
55
47
  resumeTime: number;
56
48
  soundFonts: any[];
57
49
  soundFontTable: any[];
50
+ audioBufferCounter: Map<any, any>;
51
+ audioBufferCache: Map<any, any>;
58
52
  isPlaying: boolean;
59
53
  isPausing: boolean;
60
54
  isPaused: boolean;
@@ -63,7 +57,7 @@ export class MidyGM2 {
63
57
  timeline: any[];
64
58
  instruments: any[];
65
59
  notePromises: any[];
66
- exclusiveClassMap: Map<any, any>;
60
+ exclusiveClassMap: SparseMap;
67
61
  defaultOptions: {
68
62
  reverbAlgorithm: (audioContext: any) => {
69
63
  input: any;
@@ -141,13 +135,14 @@ export class MidyGM2 {
141
135
  };
142
136
  createChannels(audioContext: any): any[];
143
137
  createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
144
- createNoteBufferNode(voiceParams: any, isSF3: any): Promise<any>;
138
+ createNoteBufferNode(audioBuffer: any, voiceParams: any): any;
145
139
  findPortamentoTarget(queueIndex: any): any;
146
140
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
147
141
  getQueueIndex(second: any): number;
148
142
  playNotes(): Promise<any>;
149
143
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
150
144
  secondToTicks(second: any, secondsPerBeat: any): number;
145
+ getAudioBufferId(programNumber: any, noteNumber: any, velocity: any): string;
151
146
  extractMidiData(midi: any): {
152
147
  instruments: Set<any>;
153
148
  timeline: any[];
@@ -161,7 +156,7 @@ export class MidyGM2 {
161
156
  seekTo(second: any): void;
162
157
  calcTotalTime(): number;
163
158
  currentTime(): number;
164
- getActiveNotes(channel: any, time: any): Map<any, any>;
159
+ getActiveNotes(channel: any, time: any): SparseMap;
165
160
  getActiveNote(noteList: any, time: any): any;
166
161
  createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
167
162
  createConvolutionReverb(audioContext: any, impulse: any): {
@@ -191,16 +186,18 @@ export class MidyGM2 {
191
186
  centToHz(cent: any): number;
192
187
  calcChannelDetune(channel: any): any;
193
188
  calcNoteDetune(channel: any, note: any): any;
194
- updateDetune(channel: any): void;
189
+ updateChannelDetune(channel: any): void;
190
+ updateDetune(channel: any, note: any, pressure: any): void;
195
191
  getPortamentoTime(channel: any): number;
196
192
  setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
197
- setVolumeEnvelope(channel: any, note: any): void;
193
+ setVolumeEnvelope(note: any, pressure: any): void;
198
194
  setPitchEnvelope(note: any): void;
199
195
  clampCutoffFrequency(frequency: any): number;
200
196
  setPortamentoStartFilterEnvelope(channel: any, note: any): void;
201
- setFilterEnvelope(channel: any, note: any): void;
197
+ setFilterEnvelope(channel: any, note: any, pressure: any): void;
202
198
  startModulation(channel: any, note: any, startTime: any): void;
203
199
  startVibrato(channel: any, note: any, startTime: any): void;
200
+ getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
204
201
  createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
205
202
  calcBank(channel: any, channelNumber: any): any;
206
203
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
@@ -213,17 +210,17 @@ export class MidyGM2 {
213
210
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
214
211
  handleProgramChange(channelNumber: any, program: any): void;
215
212
  handleChannelPressure(channelNumber: any, value: any): void;
216
- setChannelPressure(channel: any, note: any): void;
217
213
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
218
214
  setPitchBend(channelNumber: any, value: any): void;
219
- setModLfoToPitch(channel: any, note: any): void;
215
+ setModLfoToPitch(channel: any, note: any, pressure: any): void;
220
216
  setVibLfoToPitch(channel: any, note: any): void;
221
- setModLfoToFilterFc(channel: any, note: any): void;
222
- setModLfoToVolume(channel: any, note: any): void;
217
+ setModLfoToFilterFc(note: any, pressure: any): void;
218
+ setModLfoToVolume(note: any, pressure: any): void;
223
219
  setReverbEffectsSend(channel: any, note: any, prevValue: any): void;
224
220
  setChorusEffectsSend(channel: any, note: any, prevValue: any): void;
225
221
  setDelayModLFO(note: any): void;
226
222
  setFreqModLFO(note: any): void;
223
+ setFreqVibLFO(channel: any, note: any): void;
227
224
  createVoiceParamsHandlers(): {
228
225
  modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
229
226
  vibLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
@@ -311,7 +308,7 @@ export class MidyGM2 {
311
308
  handleUniversalNonRealTimeExclusiveMessage(data: any): void;
312
309
  GM1SystemOn(): void;
313
310
  GM2SystemOn(): void;
314
- handleUniversalRealTimeExclusiveMessage(data: any): void;
311
+ handleUniversalRealTimeExclusiveMessage(data: any): any;
315
312
  handleMasterVolumeSysEx(data: any): void;
316
313
  setMasterVolume(volume: any): void;
317
314
  handleMasterFineTuningSysEx(data: any): void;
@@ -337,18 +334,31 @@ export class MidyGM2 {
337
334
  setChorusSendToReverb(value: any): void;
338
335
  getChorusSendToReverb(value: any): number;
339
336
  getChannelBitmap(data: any): any[];
340
- handleScaleOctaveTuning1ByteFormatSysEx(data: any): void;
337
+ handleScaleOctaveTuning1ByteFormatSysEx(data: any, realtime: any): void;
341
338
  applyDestinationSettings(channel: any, note: any, table: any): void;
342
- handleChannelPressureSysEx(data: any): void;
339
+ handleChannelPressureSysEx(data: any, tableName: any): void;
343
340
  initControlTable(): Uint8Array<ArrayBuffer>;
344
341
  applyControlTable(channel: any, controllerType: any): void;
345
342
  handleControlChangeSysEx(data: any): void;
346
343
  getKeyBasedInstrumentControlValue(channel: any, keyNumber: any, controllerType: any): number;
347
344
  handleKeyBasedInstrumentControlSysEx(data: any): void;
348
345
  handleExclusiveMessage(data: any): void;
349
- handleSysEx(data: any): void;
346
+ handleSysEx(data: any): any;
350
347
  scheduleTask(callback: any, startTime: any): Promise<any>;
351
348
  }
349
+ declare class SparseMap {
350
+ constructor(size: any);
351
+ data: any[];
352
+ activeIndices: any[];
353
+ set(key: any, value: any): void;
354
+ get(key: any): any;
355
+ delete(key: any): boolean;
356
+ has(key: any): boolean;
357
+ get size(): number;
358
+ clear(): void;
359
+ forEach(callback: any): void;
360
+ [Symbol.iterator](): Generator<any[], void, unknown>;
361
+ }
352
362
  declare class Note {
353
363
  constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
354
364
  bufferSource: 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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"}