@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"}
@@ -1,5 +1,57 @@
1
1
  import { parseMidi } from "midi-file";
2
2
  import { parse, SoundFont } from "@marmooo/soundfont-parser";
3
+ // 2-3 times faster than Map
4
+ class SparseMap {
5
+ constructor(size) {
6
+ this.data = new Array(size);
7
+ this.activeIndices = [];
8
+ }
9
+ set(key, value) {
10
+ if (this.data[key] === undefined) {
11
+ this.activeIndices.push(key);
12
+ }
13
+ this.data[key] = value;
14
+ }
15
+ get(key) {
16
+ return this.data[key];
17
+ }
18
+ delete(key) {
19
+ if (this.data[key] !== undefined) {
20
+ this.data[key] = undefined;
21
+ const index = this.activeIndices.indexOf(key);
22
+ if (index !== -1) {
23
+ this.activeIndices.splice(index, 1);
24
+ }
25
+ return true;
26
+ }
27
+ return false;
28
+ }
29
+ has(key) {
30
+ return this.data[key] !== undefined;
31
+ }
32
+ get size() {
33
+ return this.activeIndices.length;
34
+ }
35
+ clear() {
36
+ for (let i = 0; i < this.activeIndices.length; i++) {
37
+ const key = this.activeIndices[i];
38
+ this.data[key] = undefined;
39
+ }
40
+ this.activeIndices = [];
41
+ }
42
+ *[Symbol.iterator]() {
43
+ for (let i = 0; i < this.activeIndices.length; i++) {
44
+ const key = this.activeIndices[i];
45
+ yield [key, this.data[key]];
46
+ }
47
+ }
48
+ forEach(callback) {
49
+ for (let i = 0; i < this.activeIndices.length; i++) {
50
+ const key = this.activeIndices[i];
51
+ callback(this.data[key], key, this);
52
+ }
53
+ }
54
+ }
3
55
  class Note {
4
56
  constructor(noteNumber, velocity, startTime, voice, voiceParams) {
5
57
  Object.defineProperty(this, "bufferSource", {
@@ -166,6 +218,18 @@ export class MidyGMLite {
166
218
  writable: true,
167
219
  value: this.initSoundFontTable()
168
220
  });
221
+ Object.defineProperty(this, "audioBufferCounter", {
222
+ enumerable: true,
223
+ configurable: true,
224
+ writable: true,
225
+ value: new Map()
226
+ });
227
+ Object.defineProperty(this, "audioBufferCache", {
228
+ enumerable: true,
229
+ configurable: true,
230
+ writable: true,
231
+ value: new Map()
232
+ });
169
233
  Object.defineProperty(this, "isPlaying", {
170
234
  enumerable: true,
171
235
  configurable: true,
@@ -218,7 +282,7 @@ export class MidyGMLite {
218
282
  enumerable: true,
219
283
  configurable: true,
220
284
  writable: true,
221
- value: new Map()
285
+ value: new SparseMap(128)
222
286
  });
223
287
  this.audioContext = audioContext;
224
288
  this.masterVolume = new GainNode(audioContext);
@@ -231,7 +295,7 @@ export class MidyGMLite {
231
295
  initSoundFontTable() {
232
296
  const table = new Array(128);
233
297
  for (let i = 0; i < 128; i++) {
234
- table[i] = new Map();
298
+ table[i] = new SparseMap(128);
235
299
  }
236
300
  return table;
237
301
  }
@@ -284,7 +348,7 @@ export class MidyGMLite {
284
348
  ...this.constructor.channelSettings,
285
349
  state: new ControllerState(),
286
350
  ...this.setChannelAudioNodes(audioContext),
287
- scheduledNotes: new Map(),
351
+ scheduledNotes: new SparseMap(128),
288
352
  };
289
353
  });
290
354
  return channels;
@@ -318,9 +382,8 @@ export class MidyGMLite {
318
382
  return audioBuffer;
319
383
  }
320
384
  }
321
- async createNoteBufferNode(voiceParams, isSF3) {
385
+ createNoteBufferNode(audioBuffer, voiceParams) {
322
386
  const bufferSource = new AudioBufferSourceNode(this.audioContext);
323
- const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
324
387
  bufferSource.buffer = audioBuffer;
325
388
  bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
326
389
  if (bufferSource.loop) {
@@ -385,6 +448,7 @@ export class MidyGMLite {
385
448
  await Promise.all(this.notePromises);
386
449
  this.notePromises = [];
387
450
  this.exclusiveClassMap.clear();
451
+ this.audioBufferCache.clear();
388
452
  resolve();
389
453
  return;
390
454
  }
@@ -400,8 +464,9 @@ export class MidyGMLite {
400
464
  }
401
465
  else if (this.isStopping) {
402
466
  await this.stopNotes(0, true);
403
- this.exclusiveClassMap.clear();
404
467
  this.notePromises = [];
468
+ this.exclusiveClassMap.clear();
469
+ this.audioBufferCache.clear();
405
470
  resolve();
406
471
  this.isStopping = false;
407
472
  this.isPaused = false;
@@ -432,6 +497,9 @@ export class MidyGMLite {
432
497
  secondToTicks(second, secondsPerBeat) {
433
498
  return second * this.ticksPerBeat / secondsPerBeat;
434
499
  }
500
+ getAudioBufferId(programNumber, noteNumber, velocity) {
501
+ return `${programNumber}:${noteNumber}:${velocity}`;
502
+ }
435
503
  extractMidiData(midi) {
436
504
  const instruments = new Set();
437
505
  const timeline = [];
@@ -452,6 +520,8 @@ export class MidyGMLite {
452
520
  switch (event.type) {
453
521
  case "noteOn": {
454
522
  const channel = tmpChannels[event.channel];
523
+ const audioBufferId = this.getAudioBufferId(channel.programNumber, event.noteNumber, event.velocity);
524
+ this.audioBufferCounter.set(audioBufferId, (this.audioBufferCounter.get(audioBufferId) ?? 0) + 1);
455
525
  if (channel.programNumber < 0) {
456
526
  instruments.add(`${channel.bank}:0`);
457
527
  channel.programNumber = 0;
@@ -468,6 +538,10 @@ export class MidyGMLite {
468
538
  timeline.push(event);
469
539
  }
470
540
  }
541
+ for (const [audioBufferId, count] of this.audioBufferCounter) {
542
+ if (count === 1)
543
+ this.audioBufferCounter.delete(audioBufferId);
544
+ }
471
545
  const priority = {
472
546
  controller: 0,
473
547
  sysEx: 1,
@@ -558,7 +632,7 @@ export class MidyGMLite {
558
632
  return this.resumeTime + now - this.startTime - this.startDelay;
559
633
  }
560
634
  getActiveNotes(channel, time) {
561
- const activeNotes = new Map();
635
+ const activeNotes = new SparseMap(128);
562
636
  channel.scheduledNotes.forEach((noteList) => {
563
637
  const activeNote = this.getActiveNote(noteList, time);
564
638
  if (activeNote) {
@@ -595,19 +669,22 @@ export class MidyGMLite {
595
669
  const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
596
670
  return pitchWheel * pitchWheelSensitivity;
597
671
  }
598
- updateDetune(channel) {
599
- const now = this.audioContext.currentTime;
672
+ updateChannelDetune(channel) {
600
673
  channel.scheduledNotes.forEach((noteList) => {
601
674
  for (let i = 0; i < noteList.length; i++) {
602
675
  const note = noteList[i];
603
676
  if (!note)
604
677
  continue;
605
- note.bufferSource.detune
606
- .cancelScheduledValues(now)
607
- .setValueAtTime(channel.detune, now);
678
+ this.updateDetune(channel, note);
608
679
  }
609
680
  });
610
681
  }
682
+ updateDetune(channel, note) {
683
+ const now = this.audioContext.currentTime;
684
+ note.bufferSource.detune
685
+ .cancelScheduledValues(now)
686
+ .setValueAtTime(channel.detune, now);
687
+ }
611
688
  setVolumeEnvelope(note) {
612
689
  const now = this.audioContext.currentTime;
613
690
  const { voiceParams, startTime } = note;
@@ -695,11 +772,31 @@ export class MidyGMLite {
695
772
  note.modulationLFO.connect(note.volumeDepth);
696
773
  note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
697
774
  }
775
+ async getAudioBuffer(program, noteNumber, velocity, voiceParams, isSF3) {
776
+ const audioBufferId = this.getAudioBufferId(program, noteNumber, velocity);
777
+ const cache = this.audioBufferCache.get(audioBufferId);
778
+ if (cache) {
779
+ cache.counter += 1;
780
+ if (cache.maxCount <= cache.counter) {
781
+ this.audioBufferCache.delete(audioBufferId);
782
+ }
783
+ return cache.audioBuffer;
784
+ }
785
+ else {
786
+ const maxCount = this.audioBufferCounter.get(audioBufferId) ?? 0;
787
+ const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
788
+ const cache = { audioBuffer, maxCount, counter: 1 };
789
+ this.audioBufferCache.set(audioBufferId, cache);
790
+ return audioBuffer;
791
+ }
792
+ }
698
793
  async createNote(channel, voice, noteNumber, velocity, startTime, isSF3) {
699
794
  const state = channel.state;
700
- const voiceParams = voice.getAllParams(state.array);
795
+ const controllerState = this.getControllerState(channel, noteNumber, velocity);
796
+ const voiceParams = voice.getAllParams(controllerState);
701
797
  const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
702
- note.bufferSource = await this.createNoteBufferNode(voiceParams, isSF3);
798
+ const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
799
+ note.bufferSource = this.createNoteBufferNode(audioBuffer, voiceParams);
703
800
  note.volumeEnvelopeNode = new GainNode(this.audioContext);
704
801
  note.filterNode = new BiquadFilterNode(this.audioContext, {
705
802
  type: "lowpass",
@@ -723,10 +820,10 @@ export class MidyGMLite {
723
820
  if (soundFontIndex === undefined)
724
821
  return;
725
822
  const soundFont = this.soundFonts[soundFontIndex];
726
- const isSF3 = soundFont.parsed.info.version.major === 3;
727
823
  const voice = soundFont.getVoice(bankNumber, channel.program, noteNumber, velocity);
728
824
  if (!voice)
729
825
  return;
826
+ const isSF3 = soundFont.parsed.info.version.major === 3;
730
827
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
731
828
  note.volumeEnvelopeNode.connect(channel.gainL);
732
829
  note.volumeEnvelopeNode.connect(channel.gainR);
@@ -856,7 +953,7 @@ export class MidyGMLite {
856
953
  const next = (value - 8192) / 8192;
857
954
  state.pitchWheel = value / 16383;
858
955
  channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
859
- this.updateDetune(channel);
956
+ this.updateChannelDetune(channel);
860
957
  this.applyVoiceParams(channel, 14);
861
958
  }
862
959
  setModLfoToPitch(channel, note) {
@@ -960,7 +1057,7 @@ export class MidyGMLite {
960
1057
  if (key in voiceParams)
961
1058
  noteVoiceParams[key] = voiceParams[key];
962
1059
  }
963
- this.setFilterEnvelope(channel, note);
1060
+ this.setFilterEnvelope(note);
964
1061
  this.setPitchEnvelope(note);
965
1062
  }
966
1063
  else if (volumeEnvelopeKeySet.has(key)) {
@@ -1000,7 +1097,7 @@ export class MidyGMLite {
1000
1097
  if (handler) {
1001
1098
  handler.call(this, channelNumber, value);
1002
1099
  const channel = this.channels[channelNumber];
1003
- this.applyVoiceParams(channel, controller + 128);
1100
+ this.applyVoiceParams(channel, controllerType + 128);
1004
1101
  }
1005
1102
  else {
1006
1103
  console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
@@ -1118,12 +1215,14 @@ export class MidyGMLite {
1118
1215
  const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
1119
1216
  this.setPitchBendRange(channelNumber, pitchBendRange);
1120
1217
  }
1121
- setPitchBendRange(channelNumber, pitchWheelSensitivity) {
1218
+ setPitchBendRange(channelNumber, value) {
1122
1219
  const channel = this.channels[channelNumber];
1123
1220
  const state = channel.state;
1124
- state.pitchWheelSensitivity = pitchWheelSensitivity / 128;
1125
- const detune = (state.pitchWheel * 2 - 1) * pitchWheelSensitivity * 100;
1126
- this.updateDetune(channel, detune);
1221
+ const prev = state.pitchWheelSensitivity;
1222
+ const next = value / 128;
1223
+ state.pitchWheelSensitivity = next;
1224
+ channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
1225
+ this.updateChannelDetune(channel);
1127
1226
  this.applyVoiceParams(channel, 16);
1128
1227
  }
1129
1228
  allSoundOff(channelNumber) {
@@ -1140,7 +1239,7 @@ export class MidyGMLite {
1140
1239
  const state = channel.state;
1141
1240
  for (let i = 0; i < stateTypes.length; i++) {
1142
1241
  const type = stateTypes[i];
1143
- state[type] = defaultControllerState[type];
1242
+ state[type] = defaultControllerState[type].defaultValue;
1144
1243
  }
1145
1244
  const settingTypes = [
1146
1245
  "rpnMSB",
package/esm/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;
package/esm/midy.d.ts.map CHANGED
@@ -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"}