@marmooo/midy 0.3.7 → 0.3.8

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/README.md CHANGED
@@ -23,6 +23,26 @@ This library provides several files depending on the implementation level.
23
23
  - [@marmooo/midi-player](https://marmooo.github.io/midi-player/) - GUI library
24
24
  - [Humidy](https://marmooo.github.io/humidy/) - GM2 MIDI mixer app
25
25
 
26
+ ## Support Status
27
+
28
+ All implementations follow the specification.
29
+
30
+ | Message | Support | Notes |
31
+ | :----------------------- | :-----: | :------- |
32
+ | Note Off | ✔️ | |
33
+ | Note On | ✔️ | |
34
+ | Polyphonic Key Pressure | ✔️ | full GM2 |
35
+ | Controller Change | ✔️ | full GM2 |
36
+ | Program Change | ✔️ | full GM2 |
37
+ | Channel Pressure | ✔️ | full GM2 |
38
+ | Pitch Bend | ✔️ | |
39
+ | System Exclusive Message | ✔️ | full GM2 |
40
+ | System Common Message | ❌ | |
41
+ | System Real Time Message | ✔️ | full GM2 |
42
+ | MIDI Time Code | ❌ | |
43
+ | MIDI Show Control | ❌ | |
44
+ | MIDI Machine Control | ❌ | |
45
+
26
46
  ## Usage
27
47
 
28
48
  ### Initialization
@@ -34,6 +54,7 @@ This library provides several files depending on the implementation level.
34
54
  import { Midy } from "midy.js";
35
55
 
36
56
  const audioContext = new AudioContext();
57
+ await audioContext.suspend();
37
58
  const midy = new Midy(audioContext);
38
59
  await midy.loadMIDI("test.mid");
39
60
  await midy.loadSoundFont("test.sf3");
@@ -56,9 +77,9 @@ There are functions that handle MIDI messages as they are, as well as simplified
56
77
  functions.
57
78
 
58
79
  ```js
59
- midy.handleMIDIMessage(statusByte, data1, data2, scheduleTime);
80
+ midy.handleMessage(data, scheduleTime);
60
81
  midy.noteOn(channelNumber, noteNumber, velocity);
61
- midy.setProgramChange(channelNumber, program);
82
+ midy.setProgramChange(channelNumber, programNumber);
62
83
  ```
63
84
 
64
85
  ### Control Change
@@ -101,19 +122,18 @@ const soundFontURL = "https://soundfonts.pages.dev/GeneralUser_GS_v1.471";
101
122
  function getSoundFontPaths() {
102
123
  const paths = [];
103
124
  for (const instrument of midy.instruments) {
104
- const [bankNumber, programNumber] = instrument.split(":").map(Number);
105
- const table = midy.soundFontTable[programNumber];
106
- if (table.has(bankNumber)) continue;
107
- const program = programNumber.toString().padStart(3, "0");
108
- const path = bankNumber === 128
109
- ? `${soundFontURL}/128.sf3`
110
- : `${soundFontURL}/${program}.sf3`;
111
- paths.push(path);
125
+ const [bank, program] = instrument.split(":");
126
+ const bankNumber = Number(bank);
127
+ const programNumber = Number(program);
128
+ const index = midy.soundFontTable[programNumber][bankNumber];
129
+ if (index !== undefined) continue;
130
+ const baseName = bankNumber === 128 ? "128" : program;
131
+ paths.push(`${soundFontURL}/${baseName}.sf3`);
112
132
  }
113
133
  return paths;
114
134
  }
115
135
 
116
- const paths = this.getSoundFontPaths();
136
+ const paths = getSoundFontPaths();
117
137
  await midy.loadSoundFont(paths);
118
138
  ```
119
139
 
package/esm/midy-GM1.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export class MidyGM1 {
2
2
  static channelSettings: {
3
+ scheduleIndex: number;
3
4
  detune: number;
4
5
  programNumber: number;
5
- bank: number;
6
6
  dataMSB: number;
7
7
  dataLSB: number;
8
8
  rpnMSB: number;
@@ -22,7 +22,7 @@ export class MidyGM1 {
22
22
  startTime: number;
23
23
  resumeTime: number;
24
24
  soundFonts: any[];
25
- soundFontTable: any[];
25
+ soundFontTable: never[][];
26
26
  voiceCounter: Map<any, any>;
27
27
  voiceCache: Map<any, any>;
28
28
  isPlaying: boolean;
@@ -39,6 +39,7 @@ export class MidyGM1 {
39
39
  masterVolume: any;
40
40
  scheduler: any;
41
41
  schedulerBuffer: any;
42
+ messageHandlers: any[];
42
43
  voiceParamsHandlers: {
43
44
  modLfoToPitch: (channel: any, note: any, scheduleTime: any) => void;
44
45
  vibLfoToPitch: (_channel: any, _note: any, _scheduleTime: any) => void;
@@ -53,7 +54,6 @@ export class MidyGM1 {
53
54
  };
54
55
  controlChangeHandlers: any[];
55
56
  channels: any[];
56
- initSoundFontTable(): any[];
57
57
  addSoundFont(soundFont: any): void;
58
58
  toUint8Array(input: any): Promise<Uint8Array<ArrayBuffer>>;
59
59
  loadSoundFont(input: any): Promise<void>;
@@ -68,13 +68,14 @@ export class MidyGM1 {
68
68
  createChannels(audioContext: any): any[];
69
69
  createAudioBuffer(voiceParams: any): Promise<any>;
70
70
  createBufferSource(voiceParams: any, audioBuffer: any): any;
71
- scheduleTimelineEvents(t: any, resumeTime: any, queueIndex: any): Promise<any>;
71
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
72
72
  getQueueIndex(second: any): number;
73
73
  resetAllStates(): void;
74
74
  updateStates(queueIndex: any, nextQueueIndex: any): void;
75
75
  playNotes(): Promise<void>;
76
76
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
77
77
  secondToTicks(second: any, secondsPerBeat: any): number;
78
+ getSoundFontId(channel: any): string;
78
79
  extractMidiData(midi: any): {
79
80
  instruments: Set<any>;
80
81
  timeline: any[];
@@ -115,7 +116,9 @@ export class MidyGM1 {
115
116
  findNoteOffIndex(channel: any, noteNumber: any): any;
116
117
  noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
117
118
  releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
118
- handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
119
+ createMessageHandlers(): any[];
120
+ handleMessage(data: any, scheduleTime: any): void;
121
+ handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
119
122
  setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
120
123
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
121
124
  setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
@@ -172,7 +175,7 @@ export class MidyGM1 {
172
175
  GM1SystemOn(scheduleTime: any): void;
173
176
  handleUniversalRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
174
177
  handleMasterVolumeSysEx(data: any, scheduleTime: any): void;
175
- setMasterVolume(volume: any, scheduleTime: any): void;
178
+ setMasterVolume(value: any, scheduleTime: any): void;
176
179
  handleSysEx(data: any, scheduleTime: any): void;
177
180
  scheduleTask(callback: any, scheduleTime: any): Promise<any>;
178
181
  }
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AA4FA;IAyBE;;;;;;;;;;;MAWE;IAEF,+BAcC;IAnDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,4BAAyB;IACzB,0BAAuB;IACvB,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IAgBnC,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAcC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDAUC;IAED,4DASC;IAED,+EAkDC;IAED,mCAOC;IAED,uBAQC;IAED,yDA2BC;IAED,2BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgEC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,yEASC;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,6FAyBC;IAED,oGAuCC;IAED,0EAiBC;IAED,kGAmCC;IAED,6FASC;IAED,gCASC;IAED,iEAoBC;IAED,qGAeC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;IAED,sFAeC;IAED,oGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAWC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;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,iEAMC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AAhiDD;IAWE,0FAMC;IAhBD,cAAW;IACX,gBAAe;IACf,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":"AA4FA;IAyBE;;;;;;;;;;;MAWE;IAEF,+BAeC;IApDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IAgBnC,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAWC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDAUC;IAED,4DASC;IAED,yEAqDC;IAED,mCAOC;IAED,uBAQC;IAED,yDA2BC;IAED,2BAwCC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,yEASC;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,6FAyBC;IAED,oGAuCC;IAED,0EAiBC;IAED,kGAgCC;IAED,6FASC;IAED,gCASC;IAED,iEAoBC;IAED,qGAeC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;IAED,sFAeC;IAED,+BAmBC;IAED,kDAOC;IAED,uGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAWC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;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,iEAMC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF;AAtiDD;IAWE,0FAMC;IAhBD,cAAW;IACX,gBAAe;IACf,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
package/esm/midy-GM1.js CHANGED
@@ -200,7 +200,7 @@ export class MidyGM1 {
200
200
  enumerable: true,
201
201
  configurable: true,
202
202
  writable: true,
203
- value: this.initSoundFontTable()
203
+ value: Array.from({ length: 128 }, () => [])
204
204
  });
205
205
  Object.defineProperty(this, "voiceCounter", {
206
206
  enumerable: true,
@@ -281,6 +281,7 @@ export class MidyGM1 {
281
281
  length: 1,
282
282
  sampleRate: audioContext.sampleRate,
283
283
  });
284
+ this.messageHandlers = this.createMessageHandlers();
284
285
  this.voiceParamsHandlers = this.createVoiceParamsHandlers();
285
286
  this.controlChangeHandlers = this.createControlChangeHandlers();
286
287
  this.channels = this.createChannels(audioContext);
@@ -288,21 +289,14 @@ export class MidyGM1 {
288
289
  this.scheduler.connect(audioContext.destination);
289
290
  this.GM1SystemOn();
290
291
  }
291
- initSoundFontTable() {
292
- const table = new Array(128);
293
- for (let i = 0; i < 128; i++) {
294
- table[i] = new Map();
295
- }
296
- return table;
297
- }
298
292
  addSoundFont(soundFont) {
299
293
  const index = this.soundFonts.length;
300
294
  this.soundFonts.push(soundFont);
301
295
  const presetHeaders = soundFont.parsed.presetHeaders;
296
+ const soundFontTable = this.soundFontTable;
302
297
  for (let i = 0; i < presetHeaders.length; i++) {
303
- const presetHeader = presetHeaders[i];
304
- const banks = this.soundFontTable[presetHeader.preset];
305
- banks.set(presetHeader.bank, index);
298
+ const { preset, bank } = presetHeaders[i];
299
+ soundFontTable[preset][bank] = index;
306
300
  }
307
301
  }
308
302
  async toUint8Array(input) {
@@ -380,13 +374,16 @@ export class MidyGM1 {
380
374
  this.GM1SystemOn();
381
375
  }
382
376
  getVoiceId(channel, noteNumber, velocity) {
383
- const bankNumber = this.calcBank(channel);
384
- const soundFontIndex = this.soundFontTable[channel.programNumber]
385
- .get(bankNumber);
377
+ const programNumber = channel.programNumber;
378
+ const bankTable = this.soundFontTable[programNumber];
379
+ if (!bankTable)
380
+ return;
381
+ const bank = channel.isDrum ? 128 : 0;
382
+ const soundFontIndex = bankTable[bank];
386
383
  if (soundFontIndex === undefined)
387
384
  return;
388
385
  const soundFont = this.soundFonts[soundFontIndex];
389
- const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
386
+ const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
390
387
  const { instrument, sampleID } = voice.generators;
391
388
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
392
389
  }
@@ -435,13 +432,16 @@ export class MidyGM1 {
435
432
  }
436
433
  return bufferSource;
437
434
  }
438
- async scheduleTimelineEvents(t, resumeTime, queueIndex) {
439
- while (queueIndex < this.timeline.length) {
440
- const event = this.timeline[queueIndex];
441
- if (event.startTime > t + this.lookAhead)
435
+ async scheduleTimelineEvents(scheduleTime, queueIndex) {
436
+ const timeOffset = this.resumeTime - this.startTime;
437
+ const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
438
+ const schedulingOffset = this.startDelay - timeOffset;
439
+ const timeline = this.timeline;
440
+ while (queueIndex < timeline.length) {
441
+ const event = timeline[queueIndex];
442
+ if (lookAheadCheckTime < event.startTime)
442
443
  break;
443
- const delay = this.startDelay - resumeTime;
444
- const startTime = event.startTime + delay;
444
+ const startTime = event.startTime + schedulingOffset;
445
445
  switch (event.type) {
446
446
  case "noteOn":
447
447
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
@@ -513,13 +513,11 @@ export class MidyGM1 {
513
513
  this.isPaused = false;
514
514
  this.startTime = this.audioContext.currentTime;
515
515
  let queueIndex = this.getQueueIndex(this.resumeTime);
516
- let resumeTime = this.resumeTime - this.startTime;
517
516
  let finished = false;
518
517
  this.notePromises = [];
519
518
  while (queueIndex < this.timeline.length) {
520
519
  const now = this.audioContext.currentTime;
521
- const t = now + resumeTime;
522
- queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
520
+ queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
523
521
  if (this.isPausing) {
524
522
  await this.stopNotes(0, true, now);
525
523
  await this.audioContext.suspend();
@@ -538,7 +536,6 @@ export class MidyGM1 {
538
536
  const nextQueueIndex = this.getQueueIndex(this.resumeTime);
539
537
  this.updateStates(queueIndex, nextQueueIndex);
540
538
  queueIndex = nextQueueIndex;
541
- resumeTime = this.resumeTime - this.startTime;
542
539
  this.isSeeking = false;
543
540
  continue;
544
541
  }
@@ -557,16 +554,16 @@ export class MidyGM1 {
557
554
  secondToTicks(second, secondsPerBeat) {
558
555
  return second * this.ticksPerBeat / secondsPerBeat;
559
556
  }
557
+ getSoundFontId(channel) {
558
+ const programNumber = channel.programNumber;
559
+ const bank = channel.isDrum ? "128" : "000";
560
+ const program = programNumber.toString().padStart(3, "0");
561
+ return `${bank}:${program}`;
562
+ }
560
563
  extractMidiData(midi) {
561
564
  const instruments = new Set();
562
565
  const timeline = [];
563
- const tmpChannels = new Array(this.channels.length);
564
- for (let i = 0; i < tmpChannels.length; i++) {
565
- tmpChannels[i] = {
566
- programNumber: -1,
567
- bank: this.channels[i].bank,
568
- };
569
- }
566
+ const channels = this.channels;
570
567
  for (let i = 0; i < midi.tracks.length; i++) {
571
568
  const track = midi.tracks[i];
572
569
  let currentTicks = 0;
@@ -576,17 +573,15 @@ export class MidyGM1 {
576
573
  event.ticks = currentTicks;
577
574
  switch (event.type) {
578
575
  case "noteOn": {
579
- const channel = tmpChannels[event.channel];
580
- if (channel.programNumber < 0) {
581
- instruments.add(`${channel.bank}:0`);
582
- channel.programNumber = 0;
583
- }
576
+ const channel = channels[event.channel];
577
+ instruments.add(this.getSoundFontId(channel));
584
578
  break;
585
579
  }
586
580
  case "programChange": {
587
- const channel = tmpChannels[event.channel];
588
- channel.programNumber = event.programNumber;
589
- instruments.add(`${channel.bankNumber}:${channel.programNumber}`);
581
+ const channel = channels[event.channel];
582
+ this.setProgramChange(event.channel, event.programNumber);
583
+ instruments.add(this.getSoundFontId(channel));
584
+ break;
590
585
  }
591
586
  }
592
587
  delete event.deltaTime;
@@ -892,13 +887,16 @@ export class MidyGM1 {
892
887
  }
893
888
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
894
889
  const channel = this.channels[channelNumber];
895
- const bankNumber = channel.bank;
896
- const soundFontIndex = this.soundFontTable[channel.programNumber]
897
- .get(bankNumber);
890
+ const programNumber = channel.programNumber;
891
+ const bankTable = this.soundFontTable[programNumber];
892
+ if (!bankTable)
893
+ return;
894
+ const bank = channel.isDrum ? 128 : 0;
895
+ const soundFontIndex = bankTable[bank];
898
896
  if (soundFontIndex === undefined)
899
897
  return;
900
898
  const soundFont = this.soundFonts[soundFontIndex];
901
- const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
899
+ const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
902
900
  if (!voice)
903
901
  return;
904
902
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
@@ -1000,7 +998,26 @@ export class MidyGM1 {
1000
998
  channel.sustainNotes = [];
1001
999
  return promises;
1002
1000
  }
1003
- handleMIDIMessage(statusByte, data1, data2, scheduleTime) {
1001
+ createMessageHandlers() {
1002
+ const handlers = new Array(256);
1003
+ // Channel Message
1004
+ handlers[0x80] = (data, scheduleTime) => this.noteOff(data[0] & 0x0F, data[1], data[2], scheduleTime);
1005
+ handlers[0x90] = (data, scheduleTime) => this.noteOn(data[0] & 0x0F, data[1], data[2], scheduleTime);
1006
+ handlers[0xB0] = (data, scheduleTime) => this.setControlChange(data[0] & 0x0F, data[1], data[2], scheduleTime);
1007
+ handlers[0xC0] = (data, scheduleTime) => this.setProgramChange(data[0] & 0x0F, data[1], scheduleTime);
1008
+ handlers[0xE0] = (data, scheduleTime) => this.handlePitchBendMessage(data[0] & 0x0F, data[1], data[2], scheduleTime);
1009
+ return handlers;
1010
+ }
1011
+ handleMessage(data, scheduleTime) {
1012
+ const status = data[0];
1013
+ if (status === 0xF0) {
1014
+ return this.handleSysEx(data.subarray(1), scheduleTime);
1015
+ }
1016
+ const handler = this.messageHandlers[status];
1017
+ if (handler)
1018
+ handler(data, scheduleTime);
1019
+ }
1020
+ handleChannelMessage(statusByte, data1, data2, scheduleTime) {
1004
1021
  const channelNumber = statusByte & 0x0F;
1005
1022
  const messageType = statusByte & 0xF0;
1006
1023
  switch (messageType) {
@@ -1428,10 +1445,8 @@ export class MidyGM1 {
1428
1445
  for (let i = 0; i < this.channels.length; i++) {
1429
1446
  this.allSoundOff(i, 0, scheduleTime);
1430
1447
  const channel = this.channels[i];
1431
- channel.bank = 0;
1432
1448
  channel.isDrum = false;
1433
1449
  }
1434
- this.channels[9].bank = 128;
1435
1450
  this.channels[9].isDrum = true;
1436
1451
  }
1437
1452
  handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
@@ -1452,16 +1467,11 @@ export class MidyGM1 {
1452
1467
  const volume = (data[5] * 128 + data[4]) / 16383;
1453
1468
  this.setMasterVolume(volume, scheduleTime);
1454
1469
  }
1455
- setMasterVolume(volume, scheduleTime) {
1470
+ setMasterVolume(value, scheduleTime) {
1456
1471
  scheduleTime ??= this.audioContext.currentTime;
1457
- if (volume < 0 && 1 < volume) {
1458
- console.error("Master Volume is out of range");
1459
- }
1460
- else {
1461
- this.masterVolume.gain
1462
- .cancelScheduledValues(scheduleTime)
1463
- .setValueAtTime(volume * volume, scheduleTime);
1464
- }
1472
+ this.masterVolume.gain
1473
+ .cancelScheduledValues(scheduleTime)
1474
+ .setValueAtTime(value * value, scheduleTime);
1465
1475
  }
1466
1476
  handleSysEx(data, scheduleTime) {
1467
1477
  switch (data[0]) {
@@ -1498,9 +1508,9 @@ Object.defineProperty(MidyGM1, "channelSettings", {
1498
1508
  configurable: true,
1499
1509
  writable: true,
1500
1510
  value: {
1511
+ scheduleIndex: 0,
1501
1512
  detune: 0,
1502
1513
  programNumber: 0,
1503
- bank: 0,
1504
1514
  dataMSB: 0,
1505
1515
  dataLSB: 0,
1506
1516
  rpnMSB: 127,
package/esm/midy-GM2.d.ts CHANGED
@@ -3,7 +3,6 @@ export class MidyGM2 {
3
3
  scheduleIndex: number;
4
4
  detune: number;
5
5
  programNumber: number;
6
- bank: number;
7
6
  bankMSB: number;
8
7
  bankLSB: number;
9
8
  dataMSB: number;
@@ -34,13 +33,15 @@ export class MidyGM2 {
34
33
  numChannels: number;
35
34
  ticksPerBeat: number;
36
35
  totalTime: number;
36
+ lastActiveSensing: number;
37
+ activeSensingThreshold: number;
37
38
  noteCheckInterval: number;
38
39
  lookAhead: number;
39
40
  startDelay: number;
40
41
  startTime: number;
41
42
  resumeTime: number;
42
43
  soundFonts: any[];
43
- soundFontTable: any[];
44
+ soundFontTable: never[][];
44
45
  voiceCounter: Map<any, any>;
45
46
  voiceCache: Map<any, any>;
46
47
  isPlaying: boolean;
@@ -58,6 +59,7 @@ export class MidyGM2 {
58
59
  masterVolume: any;
59
60
  scheduler: any;
60
61
  schedulerBuffer: any;
62
+ messageHandlers: any[];
61
63
  voiceParamsHandlers: {
62
64
  modLfoToPitch: (channel: any, note: any, scheduleTime: any) => void;
63
65
  vibLfoToPitch: (channel: any, note: any, scheduleTime: any) => void;
@@ -71,6 +73,7 @@ export class MidyGM2 {
71
73
  freqVibLFO: (channel: any, note: any, scheduleTime: any) => void;
72
74
  };
73
75
  controlChangeHandlers: any[];
76
+ keyBasedControllerHandlers: any[];
74
77
  channels: any[];
75
78
  reverbEffect: {
76
79
  input: any;
@@ -85,7 +88,6 @@ export class MidyGM2 {
85
88
  delayNodes: any[];
86
89
  feedbackGains: any[];
87
90
  };
88
- initSoundFontTable(): any[];
89
91
  addSoundFont(soundFont: any): void;
90
92
  toUint8Array(input: any): Promise<Uint8Array<ArrayBuffer>>;
91
93
  loadSoundFont(input: any): Promise<void>;
@@ -102,13 +104,14 @@ export class MidyGM2 {
102
104
  createAudioBuffer(voiceParams: any): Promise<any>;
103
105
  isLoopDrum(channel: any, noteNumber: any): boolean;
104
106
  createBufferSource(channel: any, noteNumber: any, voiceParams: any, audioBuffer: any): any;
105
- scheduleTimelineEvents(t: any, resumeTime: any, queueIndex: any): Promise<any>;
107
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
106
108
  getQueueIndex(second: any): number;
107
109
  resetAllStates(): void;
108
110
  updateStates(queueIndex: any, nextQueueIndex: any): void;
109
111
  playNotes(): Promise<void>;
110
112
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
111
113
  secondToTicks(second: any, secondsPerBeat: any): number;
114
+ getSoundFontId(channel: any): string;
112
115
  extractMidiData(midi: any): {
113
116
  instruments: Set<any>;
114
117
  timeline: any[];
@@ -172,7 +175,6 @@ export class MidyGM2 {
172
175
  startVibrato(channel: any, note: any, scheduleTime: any): void;
173
176
  getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
174
177
  createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any): Promise<Note>;
175
- calcBank(channel: any): any;
176
178
  handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
177
179
  handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
178
180
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
@@ -185,7 +187,9 @@ export class MidyGM2 {
185
187
  noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
186
188
  releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
187
189
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
188
- handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
190
+ createMessageHandlers(): any[];
191
+ handleMessage(data: any, scheduleTime: any): void;
192
+ activeSensing(): void;
189
193
  setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
190
194
  setChannelPressure(channelNumber: any, value: any, scheduleTime: any): void;
191
195
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
@@ -233,6 +237,7 @@ export class MidyGM2 {
233
237
  updateChannelVolume(channel: any, scheduleTime: any): void;
234
238
  updateKeyBasedVolume(channel: any, keyNumber: any, scheduleTime: any): void;
235
239
  setSustainPedal(channelNumber: any, value: any, scheduleTime: any): void;
240
+ isPortamento(channel: any, note: any): boolean;
236
241
  setPortamento(channelNumber: any, value: any, scheduleTime: any): void;
237
242
  setSostenutoPedal(channelNumber: any, value: any, scheduleTime: any): void;
238
243
  getSoftPedalFactor(channel: any, note: any): number;
@@ -266,7 +271,7 @@ export class MidyGM2 {
266
271
  GM2SystemOn(scheduleTime: any): void;
267
272
  handleUniversalRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
268
273
  handleMasterVolumeSysEx(data: any, scheduleTime: any): void;
269
- setMasterVolume(volume: any, scheduleTime: any): void;
274
+ setMasterVolume(value: any, scheduleTime: any): void;
270
275
  handleMasterFineTuningSysEx(data: any, scheduleTime: any): void;
271
276
  setMasterFineTuning(value: any, scheduleTime: any): void;
272
277
  handleMasterCoarseTuningSysEx(data: any, scheduleTime: any): void;
@@ -302,6 +307,7 @@ export class MidyGM2 {
302
307
  setControlChangeEffects(channel: any, controllerType: any, scheduleTime: any): void;
303
308
  handleControlChangeSysEx(data: any, scheduleTime: any): void;
304
309
  getKeyBasedValue(channel: any, keyNumber: any, controllerType: any): any;
310
+ createKeyBasedControllerHandlers(): any[];
305
311
  handleKeyBasedInstrumentControlSysEx(data: any, scheduleTime: any): void;
306
312
  handleSysEx(data: any, scheduleTime: any): void;
307
313
  scheduleTask(callback: any, scheduleTime: any): Promise<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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"}