@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.
@@ -19,6 +19,8 @@ export class MidyGMLite {
19
19
  resumeTime: number;
20
20
  soundFonts: any[];
21
21
  soundFontTable: any[];
22
+ audioBufferCounter: Map<any, any>;
23
+ audioBufferCache: Map<any, any>;
22
24
  isPlaying: boolean;
23
25
  isPausing: boolean;
24
26
  isPaused: boolean;
@@ -27,7 +29,7 @@ export class MidyGMLite {
27
29
  timeline: any[];
28
30
  instruments: any[];
29
31
  notePromises: any[];
30
- exclusiveClassMap: Map<any, any>;
32
+ exclusiveClassMap: SparseMap;
31
33
  audioContext: any;
32
34
  masterVolume: any;
33
35
  voiceParamsHandlers: {
@@ -68,12 +70,13 @@ export class MidyGMLite {
68
70
  };
69
71
  createChannels(audioContext: any): any[];
70
72
  createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
71
- createNoteBufferNode(voiceParams: any, isSF3: any): Promise<any>;
73
+ createNoteBufferNode(audioBuffer: any, voiceParams: any): any;
72
74
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
73
75
  getQueueIndex(second: any): number;
74
76
  playNotes(): Promise<any>;
75
77
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
76
78
  secondToTicks(second: any, secondsPerBeat: any): number;
79
+ getAudioBufferId(programNumber: any, noteNumber: any, velocity: any): string;
77
80
  extractMidiData(midi: any): {
78
81
  instruments: Set<any>;
79
82
  timeline: any[];
@@ -87,19 +90,21 @@ export class MidyGMLite {
87
90
  seekTo(second: any): void;
88
91
  calcTotalTime(): number;
89
92
  currentTime(): number;
90
- getActiveNotes(channel: any, time: any): Map<any, any>;
93
+ getActiveNotes(channel: any, time: any): SparseMap;
91
94
  getActiveNote(noteList: any, time: any): any;
92
95
  cbToRatio(cb: any): number;
93
96
  rateToCent(rate: any): number;
94
97
  centToRate(cent: any): number;
95
98
  centToHz(cent: any): number;
96
99
  calcChannelDetune(channel: any): number;
97
- updateDetune(channel: any): void;
100
+ updateChannelDetune(channel: any): void;
101
+ updateDetune(channel: any, note: any): void;
98
102
  setVolumeEnvelope(note: any): void;
99
103
  setPitchEnvelope(note: any): void;
100
104
  clampCutoffFrequency(frequency: any): number;
101
105
  setFilterEnvelope(note: any): void;
102
106
  startModulation(channel: any, note: any, startTime: any): void;
107
+ getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
103
108
  createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
104
109
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
105
110
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
@@ -163,7 +168,7 @@ export class MidyGMLite {
163
168
  setRPNLSB(channelNumber: any, value: any): void;
164
169
  dataEntryMSB(channelNumber: any, value: any): void;
165
170
  handlePitchBendRangeRPN(channelNumber: any): void;
166
- setPitchBendRange(channelNumber: any, pitchWheelSensitivity: any): void;
171
+ setPitchBendRange(channelNumber: any, value: any): void;
167
172
  allSoundOff(channelNumber: any): Promise<void>;
168
173
  resetAllControllers(channelNumber: any): void;
169
174
  allNotesOff(channelNumber: any): Promise<void>;
@@ -176,6 +181,19 @@ export class MidyGMLite {
176
181
  handleSysEx(data: any): void;
177
182
  scheduleTask(callback: any, startTime: any): Promise<any>;
178
183
  }
184
+ declare class SparseMap {
185
+ constructor(size: any);
186
+ data: any[];
187
+ activeIndices: any[];
188
+ set(key: any, value: any): void;
189
+ get(key: any): any;
190
+ delete(key: any): boolean;
191
+ has(key: any): boolean;
192
+ get size(): number;
193
+ clear(): void;
194
+ forEach(callback: any): void;
195
+ [Symbol.iterator](): Generator<any[], void, unknown>;
196
+ }
179
197
  declare class Note {
180
198
  constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
181
199
  bufferSource: any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAmFA;IAoBE;;;;;;;;;MASE;IAEF,+BAQC;IAtCD,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;IAc5B,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,wCAIC;IAED,iCAWC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,gHA2BC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;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,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wEAOC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAptCD;IAQE,0FAMC;IAbD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAgJA;IAsBE;;;;;;;;;MASE;IAEF,+BAQC;IAxCD,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;IAcrC,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,wCAIC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,yGAgBC;IAED,gHAuCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;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,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAv0CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAQE,0FAMC;IAbD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
@@ -3,6 +3,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGMLite = 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", {
@@ -169,6 +221,18 @@ class MidyGMLite {
169
221
  writable: true,
170
222
  value: this.initSoundFontTable()
171
223
  });
224
+ Object.defineProperty(this, "audioBufferCounter", {
225
+ enumerable: true,
226
+ configurable: true,
227
+ writable: true,
228
+ value: new Map()
229
+ });
230
+ Object.defineProperty(this, "audioBufferCache", {
231
+ enumerable: true,
232
+ configurable: true,
233
+ writable: true,
234
+ value: new Map()
235
+ });
172
236
  Object.defineProperty(this, "isPlaying", {
173
237
  enumerable: true,
174
238
  configurable: true,
@@ -221,7 +285,7 @@ class MidyGMLite {
221
285
  enumerable: true,
222
286
  configurable: true,
223
287
  writable: true,
224
- value: new Map()
288
+ value: new SparseMap(128)
225
289
  });
226
290
  this.audioContext = audioContext;
227
291
  this.masterVolume = new GainNode(audioContext);
@@ -234,7 +298,7 @@ class MidyGMLite {
234
298
  initSoundFontTable() {
235
299
  const table = new Array(128);
236
300
  for (let i = 0; i < 128; i++) {
237
- table[i] = new Map();
301
+ table[i] = new SparseMap(128);
238
302
  }
239
303
  return table;
240
304
  }
@@ -287,7 +351,7 @@ class MidyGMLite {
287
351
  ...this.constructor.channelSettings,
288
352
  state: new ControllerState(),
289
353
  ...this.setChannelAudioNodes(audioContext),
290
- scheduledNotes: new Map(),
354
+ scheduledNotes: new SparseMap(128),
291
355
  };
292
356
  });
293
357
  return channels;
@@ -321,9 +385,8 @@ class MidyGMLite {
321
385
  return audioBuffer;
322
386
  }
323
387
  }
324
- async createNoteBufferNode(voiceParams, isSF3) {
388
+ createNoteBufferNode(audioBuffer, voiceParams) {
325
389
  const bufferSource = new AudioBufferSourceNode(this.audioContext);
326
- const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
327
390
  bufferSource.buffer = audioBuffer;
328
391
  bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
329
392
  if (bufferSource.loop) {
@@ -388,6 +451,7 @@ class MidyGMLite {
388
451
  await Promise.all(this.notePromises);
389
452
  this.notePromises = [];
390
453
  this.exclusiveClassMap.clear();
454
+ this.audioBufferCache.clear();
391
455
  resolve();
392
456
  return;
393
457
  }
@@ -403,8 +467,9 @@ class MidyGMLite {
403
467
  }
404
468
  else if (this.isStopping) {
405
469
  await this.stopNotes(0, true);
406
- this.exclusiveClassMap.clear();
407
470
  this.notePromises = [];
471
+ this.exclusiveClassMap.clear();
472
+ this.audioBufferCache.clear();
408
473
  resolve();
409
474
  this.isStopping = false;
410
475
  this.isPaused = false;
@@ -435,6 +500,9 @@ class MidyGMLite {
435
500
  secondToTicks(second, secondsPerBeat) {
436
501
  return second * this.ticksPerBeat / secondsPerBeat;
437
502
  }
503
+ getAudioBufferId(programNumber, noteNumber, velocity) {
504
+ return `${programNumber}:${noteNumber}:${velocity}`;
505
+ }
438
506
  extractMidiData(midi) {
439
507
  const instruments = new Set();
440
508
  const timeline = [];
@@ -455,6 +523,8 @@ class MidyGMLite {
455
523
  switch (event.type) {
456
524
  case "noteOn": {
457
525
  const channel = tmpChannels[event.channel];
526
+ const audioBufferId = this.getAudioBufferId(channel.programNumber, event.noteNumber, event.velocity);
527
+ this.audioBufferCounter.set(audioBufferId, (this.audioBufferCounter.get(audioBufferId) ?? 0) + 1);
458
528
  if (channel.programNumber < 0) {
459
529
  instruments.add(`${channel.bank}:0`);
460
530
  channel.programNumber = 0;
@@ -471,6 +541,10 @@ class MidyGMLite {
471
541
  timeline.push(event);
472
542
  }
473
543
  }
544
+ for (const [audioBufferId, count] of this.audioBufferCounter) {
545
+ if (count === 1)
546
+ this.audioBufferCounter.delete(audioBufferId);
547
+ }
474
548
  const priority = {
475
549
  controller: 0,
476
550
  sysEx: 1,
@@ -561,7 +635,7 @@ class MidyGMLite {
561
635
  return this.resumeTime + now - this.startTime - this.startDelay;
562
636
  }
563
637
  getActiveNotes(channel, time) {
564
- const activeNotes = new Map();
638
+ const activeNotes = new SparseMap(128);
565
639
  channel.scheduledNotes.forEach((noteList) => {
566
640
  const activeNote = this.getActiveNote(noteList, time);
567
641
  if (activeNote) {
@@ -598,19 +672,22 @@ class MidyGMLite {
598
672
  const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
599
673
  return pitchWheel * pitchWheelSensitivity;
600
674
  }
601
- updateDetune(channel) {
602
- const now = this.audioContext.currentTime;
675
+ updateChannelDetune(channel) {
603
676
  channel.scheduledNotes.forEach((noteList) => {
604
677
  for (let i = 0; i < noteList.length; i++) {
605
678
  const note = noteList[i];
606
679
  if (!note)
607
680
  continue;
608
- note.bufferSource.detune
609
- .cancelScheduledValues(now)
610
- .setValueAtTime(channel.detune, now);
681
+ this.updateDetune(channel, note);
611
682
  }
612
683
  });
613
684
  }
685
+ updateDetune(channel, note) {
686
+ const now = this.audioContext.currentTime;
687
+ note.bufferSource.detune
688
+ .cancelScheduledValues(now)
689
+ .setValueAtTime(channel.detune, now);
690
+ }
614
691
  setVolumeEnvelope(note) {
615
692
  const now = this.audioContext.currentTime;
616
693
  const { voiceParams, startTime } = note;
@@ -698,11 +775,31 @@ class MidyGMLite {
698
775
  note.modulationLFO.connect(note.volumeDepth);
699
776
  note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
700
777
  }
778
+ async getAudioBuffer(program, noteNumber, velocity, voiceParams, isSF3) {
779
+ const audioBufferId = this.getAudioBufferId(program, noteNumber, velocity);
780
+ const cache = this.audioBufferCache.get(audioBufferId);
781
+ if (cache) {
782
+ cache.counter += 1;
783
+ if (cache.maxCount <= cache.counter) {
784
+ this.audioBufferCache.delete(audioBufferId);
785
+ }
786
+ return cache.audioBuffer;
787
+ }
788
+ else {
789
+ const maxCount = this.audioBufferCounter.get(audioBufferId) ?? 0;
790
+ const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
791
+ const cache = { audioBuffer, maxCount, counter: 1 };
792
+ this.audioBufferCache.set(audioBufferId, cache);
793
+ return audioBuffer;
794
+ }
795
+ }
701
796
  async createNote(channel, voice, noteNumber, velocity, startTime, isSF3) {
702
797
  const state = channel.state;
703
- const voiceParams = voice.getAllParams(state.array);
798
+ const controllerState = this.getControllerState(channel, noteNumber, velocity);
799
+ const voiceParams = voice.getAllParams(controllerState);
704
800
  const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
705
- note.bufferSource = await this.createNoteBufferNode(voiceParams, isSF3);
801
+ const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
802
+ note.bufferSource = this.createNoteBufferNode(audioBuffer, voiceParams);
706
803
  note.volumeEnvelopeNode = new GainNode(this.audioContext);
707
804
  note.filterNode = new BiquadFilterNode(this.audioContext, {
708
805
  type: "lowpass",
@@ -726,10 +823,10 @@ class MidyGMLite {
726
823
  if (soundFontIndex === undefined)
727
824
  return;
728
825
  const soundFont = this.soundFonts[soundFontIndex];
729
- const isSF3 = soundFont.parsed.info.version.major === 3;
730
826
  const voice = soundFont.getVoice(bankNumber, channel.program, noteNumber, velocity);
731
827
  if (!voice)
732
828
  return;
829
+ const isSF3 = soundFont.parsed.info.version.major === 3;
733
830
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
734
831
  note.volumeEnvelopeNode.connect(channel.gainL);
735
832
  note.volumeEnvelopeNode.connect(channel.gainR);
@@ -859,7 +956,7 @@ class MidyGMLite {
859
956
  const next = (value - 8192) / 8192;
860
957
  state.pitchWheel = value / 16383;
861
958
  channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
862
- this.updateDetune(channel);
959
+ this.updateChannelDetune(channel);
863
960
  this.applyVoiceParams(channel, 14);
864
961
  }
865
962
  setModLfoToPitch(channel, note) {
@@ -963,7 +1060,7 @@ class MidyGMLite {
963
1060
  if (key in voiceParams)
964
1061
  noteVoiceParams[key] = voiceParams[key];
965
1062
  }
966
- this.setFilterEnvelope(channel, note);
1063
+ this.setFilterEnvelope(note);
967
1064
  this.setPitchEnvelope(note);
968
1065
  }
969
1066
  else if (volumeEnvelopeKeySet.has(key)) {
@@ -1003,7 +1100,7 @@ class MidyGMLite {
1003
1100
  if (handler) {
1004
1101
  handler.call(this, channelNumber, value);
1005
1102
  const channel = this.channels[channelNumber];
1006
- this.applyVoiceParams(channel, controller + 128);
1103
+ this.applyVoiceParams(channel, controllerType + 128);
1007
1104
  }
1008
1105
  else {
1009
1106
  console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
@@ -1121,12 +1218,14 @@ class MidyGMLite {
1121
1218
  const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
1122
1219
  this.setPitchBendRange(channelNumber, pitchBendRange);
1123
1220
  }
1124
- setPitchBendRange(channelNumber, pitchWheelSensitivity) {
1221
+ setPitchBendRange(channelNumber, value) {
1125
1222
  const channel = this.channels[channelNumber];
1126
1223
  const state = channel.state;
1127
- state.pitchWheelSensitivity = pitchWheelSensitivity / 128;
1128
- const detune = (state.pitchWheel * 2 - 1) * pitchWheelSensitivity * 100;
1129
- this.updateDetune(channel, detune);
1224
+ const prev = state.pitchWheelSensitivity;
1225
+ const next = value / 128;
1226
+ state.pitchWheelSensitivity = next;
1227
+ channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
1228
+ this.updateChannelDetune(channel);
1130
1229
  this.applyVoiceParams(channel, 16);
1131
1230
  }
1132
1231
  allSoundOff(channelNumber) {
@@ -1143,7 +1242,7 @@ class MidyGMLite {
1143
1242
  const state = channel.state;
1144
1243
  for (let i = 0; i < stateTypes.length; i++) {
1145
1244
  const type = stateTypes[i];
1146
- state[type] = defaultControllerState[type];
1245
+ state[type] = defaultControllerState[type].defaultValue;
1147
1246
  }
1148
1247
  const settingTypes = [
1149
1248
  "rpnMSB",
package/script/midy.d.ts CHANGED
@@ -2,8 +2,9 @@ export class Midy {
2
2
  static channelSettings: {
3
3
  currentBufferSource: null;
4
4
  detune: number;
5
- scaleOctaveTuningTable: any[];
6
- pressureTable: Uint8Array<ArrayBuffer>;
5
+ scaleOctaveTuningTable: Float32Array<ArrayBuffer>;
6
+ channelPressureTable: Uint8Array<ArrayBuffer>;
7
+ polyphonicKeyPressureTable: Uint8Array<ArrayBuffer>;
7
8
  keyBasedInstrumentControlTable: Int8Array<ArrayBuffer>;
8
9
  program: number;
9
10
  bank: number;
@@ -17,14 +18,6 @@ export class Midy {
17
18
  coarseTuning: number;
18
19
  modulationDepthRange: number;
19
20
  };
20
- static controllerDestinationSettings: {
21
- pitchControl: number;
22
- filterCutoffControl: number;
23
- amplitudeControl: number;
24
- lfoPitchDepth: number;
25
- lfoFilterDepth: number;
26
- lfoAmplitudeDepth: number;
27
- };
28
21
  constructor(audioContext: any, options?: {
29
22
  reverbAlgorithm: (audioContext: any) => {
30
23
  input: any;
@@ -55,6 +48,8 @@ export class Midy {
55
48
  resumeTime: number;
56
49
  soundFonts: any[];
57
50
  soundFontTable: any[];
51
+ audioBufferCounter: Map<any, any>;
52
+ audioBufferCache: Map<any, any>;
58
53
  isPlaying: boolean;
59
54
  isPausing: boolean;
60
55
  isPaused: boolean;
@@ -63,7 +58,7 @@ export class Midy {
63
58
  timeline: any[];
64
59
  instruments: any[];
65
60
  notePromises: any[];
66
- exclusiveClassMap: Map<any, any>;
61
+ exclusiveClassMap: SparseMap;
67
62
  defaultOptions: {
68
63
  reverbAlgorithm: (audioContext: any) => {
69
64
  input: any;
@@ -151,13 +146,14 @@ export class Midy {
151
146
  };
152
147
  createChannels(audioContext: any): any[];
153
148
  createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
154
- createNoteBufferNode(voiceParams: any, isSF3: any): Promise<any>;
149
+ createNoteBufferNode(audioBuffer: any, voiceParams: any): any;
155
150
  findPortamentoTarget(queueIndex: any): any;
156
151
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
157
152
  getQueueIndex(second: any): number;
158
153
  playNotes(): Promise<any>;
159
154
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
160
155
  secondToTicks(second: any, secondsPerBeat: any): number;
156
+ getAudioBufferId(programNumber: any, noteNumber: any, velocity: any): string;
161
157
  extractMidiData(midi: any): {
162
158
  instruments: Set<any>;
163
159
  timeline: any[];
@@ -171,7 +167,7 @@ export class Midy {
171
167
  seekTo(second: any): void;
172
168
  calcTotalTime(): number;
173
169
  currentTime(): number;
174
- getActiveNotes(channel: any, time: any): Map<any, any>;
170
+ getActiveNotes(channel: any, time: any): SparseMap;
175
171
  getActiveNote(noteList: any, time: any): any;
176
172
  createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
177
173
  createConvolutionReverb(audioContext: any, impulse: any): {
@@ -201,16 +197,18 @@ export class Midy {
201
197
  centToHz(cent: any): number;
202
198
  calcChannelDetune(channel: any): any;
203
199
  calcNoteDetune(channel: any, note: any): any;
204
- updateDetune(channel: any): void;
200
+ updateChannelDetune(channel: any): void;
201
+ updateDetune(channel: any, note: any, pressure: any): void;
205
202
  getPortamentoTime(channel: any): number;
206
203
  setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
207
- setVolumeEnvelope(channel: any, note: any): void;
204
+ setVolumeEnvelope(channel: any, note: any, pressure: any): void;
208
205
  setPitchEnvelope(note: any): void;
209
206
  clampCutoffFrequency(frequency: any): number;
210
207
  setPortamentoStartFilterEnvelope(channel: any, note: any): void;
211
- setFilterEnvelope(channel: any, note: any): void;
208
+ setFilterEnvelope(channel: any, note: any, pressure: any): void;
212
209
  startModulation(channel: any, note: any, startTime: any): void;
213
210
  startVibrato(channel: any, note: any, startTime: any): void;
211
+ getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
214
212
  createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
215
213
  calcBank(channel: any, channelNumber: any): any;
216
214
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
@@ -226,14 +224,15 @@ export class Midy {
226
224
  handleChannelPressure(channelNumber: any, value: any): void;
227
225
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
228
226
  setPitchBend(channelNumber: any, value: any): void;
229
- setModLfoToPitch(channel: any, note: any): void;
227
+ setModLfoToPitch(channel: any, note: any, pressure: any): void;
230
228
  setVibLfoToPitch(channel: any, note: any): void;
231
- setModLfoToFilterFc(channel: any, note: any): void;
232
- setModLfoToVolume(channel: any, note: any): void;
229
+ setModLfoToFilterFc(note: any, pressure: any): void;
230
+ setModLfoToVolume(note: any, pressure: any): void;
233
231
  setReverbEffectsSend(channel: any, note: any, prevValue: any): void;
234
232
  setChorusEffectsSend(channel: any, note: any, prevValue: any): void;
235
233
  setDelayModLFO(note: any): void;
236
234
  setFreqModLFO(note: any): void;
235
+ setFreqVibLFO(channel: any, note: any): void;
237
236
  createVoiceParamsHandlers(): {
238
237
  modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
239
238
  vibLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
@@ -341,7 +340,7 @@ export class Midy {
341
340
  handleUniversalNonRealTimeExclusiveMessage(data: any): void;
342
341
  GM1SystemOn(): void;
343
342
  GM2SystemOn(): void;
344
- handleUniversalRealTimeExclusiveMessage(data: any): void;
343
+ handleUniversalRealTimeExclusiveMessage(data: any): any;
345
344
  handleMasterVolumeSysEx(data: any): void;
346
345
  setMasterVolume(volume: any): void;
347
346
  handleMasterFineTuningSysEx(data: any): void;
@@ -367,18 +366,32 @@ export class Midy {
367
366
  setChorusSendToReverb(value: any): void;
368
367
  getChorusSendToReverb(value: any): number;
369
368
  getChannelBitmap(data: any): any[];
370
- handleScaleOctaveTuning1ByteFormatSysEx(data: any): void;
369
+ handleScaleOctaveTuning1ByteFormatSysEx(data: any, realtime: any): void;
370
+ handleScaleOctaveTuning2ByteFormatSysEx(data: any, realtime: any): void;
371
371
  applyDestinationSettings(channel: any, note: any, table: any): void;
372
- handleChannelPressureSysEx(data: any): void;
372
+ handleChannelPressureSysEx(data: any, tableName: any): void;
373
373
  initControlTable(): Uint8Array<ArrayBuffer>;
374
374
  applyControlTable(channel: any, controllerType: any): void;
375
375
  handleControlChangeSysEx(data: any): void;
376
376
  getKeyBasedInstrumentControlValue(channel: any, keyNumber: any, controllerType: any): number;
377
377
  handleKeyBasedInstrumentControlSysEx(data: any): void;
378
378
  handleExclusiveMessage(data: any): void;
379
- handleSysEx(data: any): void;
379
+ handleSysEx(data: any): any;
380
380
  scheduleTask(callback: any, startTime: any): Promise<any>;
381
381
  }
382
+ declare class SparseMap {
383
+ constructor(size: any);
384
+ data: any[];
385
+ activeIndices: any[];
386
+ set(key: any, value: any): void;
387
+ get(key: any): any;
388
+ delete(key: any): boolean;
389
+ has(key: any): boolean;
390
+ get size(): number;
391
+ clear(): void;
392
+ forEach(callback: any): void;
393
+ [Symbol.iterator](): Generator<any[], void, unknown>;
394
+ }
382
395
  declare class Note {
383
396
  constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
384
397
  bufferSource: any;
@@ -395,6 +408,7 @@ declare class Note {
395
408
  reverbEffectsSend: any;
396
409
  chorusEffectsSend: any;
397
410
  portamento: any;
411
+ pressure: number;
398
412
  noteNumber: any;
399
413
  velocity: any;
400
414
  startTime: any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AA+KA;IAqCE;;;;;;;;;;;;;;;;;;MAkBE;IAgCF;;;;;OAaC;IAnGD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,cAAa;IACb,cAAa;IACb,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;IAsBvC;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAO3D,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAYC;IAED,6DA2BC;IAED,8DASC;IAED,2CAcC;IAED,2EA8DC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MAgHC;IAED,+EAoBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,mDASC;IAED,6CAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA8BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAUC;IAED,6CAEC;IAED,wCAQC;IAED,2DAOC;IAED,wCAIC;IAED,gEAWC;IAED,gEAkBC;IAED,kCAqBC;IAED,6CAIC;IAED,gEAuBC;IAED,gEA2BC;IAED,+DAoBC;IAED,4DAaC;IAED,yGAgBC;IAED,iIAoEC;IAED,gDAQC;IAED,mHA0DC;IAED,2FASC;IAED,qFAqCC;IAED,wJAwCC;IAED,qHAUC;IAED,kEAeC;IAED,oEAYC;IAED,gFAqBC;IAED,sFAWC;IAED,4DAIC;IAED,4DAeC;IAED,qEAGC;IAED,mDASC;IAED,+DAQC;IAED,gDASC;IAED,oDAMC;IAED,kDAQC;IAED,oEA2BC;IAED,oEA2BC;IAED,gCAOC;IAED,+BAMC;IAED,6CAMC;IAED;;;;;;;;;;;MAgDC;IAED,oFAMC;IAED,0DAiDC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqCC;IAED,+EAYC;IAED,+CAEC;IAED,qCAeC;IAED,8DAIC;IAED,iEAIC;IAED,sCAiBC;IAED,iDAKC;IAED;;;MAMC;IAED,mCAqBC;IAED,2CAKC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,oDAEC;IAED,wDASC;IAED,uDAGC;IAED,mEAaC;IAED,2DAGC;IAED,yDAYC;IAED,yDAcC;IAED,uDAUC;IAED,2DAWC;IAED,6DAqBC;IAED,6DAYC;IAED,mEAmCC;IAED,mEAmCC;IAED,kFAeC;IAED,2DAMC;IAED,gDAyBC;IAGD,wCAEC;IAGD,wCAEC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,8CAKC;IAED,oDAOC;IAED,gDAKC;IAED,sDAOC;IAED,wDAKC;IAED,6EAIC;IAED,+CAEC;IAED,8CAyBC;IAED,+CAEC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DA+BC;IAED,oBASC;IAED,oBASC;IAED,wDAkDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,sCAMC;IAED,+CAGC;IAED,wCAMC;IAED,mDAeC;IAED,4CAOC;IAED,+BAKC;IAED,qDAiBC;IAED,gCAIC;IAED,kCAEC;IA6BD,4CAEC;IAED,4CAaC;IAED,+BAiBC;IAED,wFAKC;IAED,mCAKC;IAED,qCAEC;IAED,oCAOC;IAED,sCAEC;IAED,oCAUC;IAED,sCAEC;IAED,wCAuBC;IAED,0CAEC;IAED,mCAeC;IAED,wEAeC;IAED,wEAmBC;IAED,oEAuDC;IAED,4DAQC;IAED,4CAUC;IAED,2DAWC;IAED,0CASC;IAED,6FAIC;IAED,sDAcC;IAED,wCAEC;IAED,4BASC;IAED,0DAUC;CACF;AAryFD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAiBE,0FAMC;IAtBD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,gBAAW;IACX,WAAM;IACN,WAAM;IACN,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IACb,uBAAkB;IAClB,uBAAkB;IAClB,gBAAW;IACX,iBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}