@marmooo/midy 0.1.4 → 0.1.6

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.
Files changed (35) hide show
  1. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.4 → soundfont-parser@0.0.6}/+esm.d.ts +16 -20
  2. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +1 -0
  3. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +180 -0
  4. package/esm/midy-GM1.d.ts +36 -8
  5. package/esm/midy-GM1.d.ts.map +1 -1
  6. package/esm/midy-GM1.js +87 -89
  7. package/esm/midy-GM2.d.ts +65 -10
  8. package/esm/midy-GM2.d.ts.map +1 -1
  9. package/esm/midy-GM2.js +233 -154
  10. package/esm/midy-GMLite.d.ts +36 -8
  11. package/esm/midy-GMLite.d.ts.map +1 -1
  12. package/esm/midy-GMLite.js +87 -89
  13. package/esm/midy.d.ts +85 -10
  14. package/esm/midy.d.ts.map +1 -1
  15. package/esm/midy.js +254 -174
  16. package/package.json +1 -1
  17. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.4 → soundfont-parser@0.0.6}/+esm.d.ts +16 -20
  18. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +1 -0
  19. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +190 -0
  20. package/script/midy-GM1.d.ts +36 -8
  21. package/script/midy-GM1.d.ts.map +1 -1
  22. package/script/midy-GM1.js +87 -89
  23. package/script/midy-GM2.d.ts +65 -10
  24. package/script/midy-GM2.d.ts.map +1 -1
  25. package/script/midy-GM2.js +233 -154
  26. package/script/midy-GMLite.d.ts +36 -8
  27. package/script/midy-GMLite.d.ts.map +1 -1
  28. package/script/midy-GMLite.js +87 -89
  29. package/script/midy.d.ts +85 -10
  30. package/script/midy.d.ts.map +1 -1
  31. package/script/midy.js +254 -174
  32. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +0 -1
  33. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js +0 -162
  34. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +0 -1
  35. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js +0 -169
@@ -37,6 +37,20 @@ export class MidyGMLite {
37
37
  notePromises: any[];
38
38
  audioContext: any;
39
39
  masterGain: any;
40
+ controlChangeHandlers: {
41
+ 1: (channelNumber: any, modulation: any) => void;
42
+ 6: (channelNumber: any, value: any) => void;
43
+ 7: (channelNumber: any, volume: any) => void;
44
+ 10: (channelNumber: any, pan: any) => void;
45
+ 11: (channelNumber: any, expression: any) => void;
46
+ 38: (channelNumber: any, value: any) => void;
47
+ 64: (channelNumber: any, value: any) => void;
48
+ 100: (channelNumber: any, value: any) => void;
49
+ 101: (channelNumber: any, value: any) => void;
50
+ 120: (channelNumber: any) => Promise<void>;
51
+ 121: (channelNumber: any) => void;
52
+ 123: (channelNumber: any) => Promise<void>;
53
+ };
40
54
  channels: any[];
41
55
  initSoundFontTable(): any[];
42
56
  addSoundFont(soundFont: any): void;
@@ -50,7 +64,6 @@ export class MidyGMLite {
50
64
  createChannels(audioContext: any): any[];
51
65
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
52
66
  createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
53
- convertToFloat32Array(uint8Array: any): Float32Array;
54
67
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
55
68
  getQueueIndex(second: any): number;
56
69
  playNotes(): Promise<any>;
@@ -60,8 +73,8 @@ export class MidyGMLite {
60
73
  instruments: Set<any>;
61
74
  timeline: any[];
62
75
  };
63
- stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
64
- stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
76
+ stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
77
+ stopNotes(velocity: any, force: any): Promise<any[]>;
65
78
  start(): Promise<void>;
66
79
  stop(): void;
67
80
  pause(): void;
@@ -83,14 +96,29 @@ export class MidyGMLite {
83
96
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
84
97
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
85
98
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
86
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
87
- releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
99
+ stopNote(stopTime: any, endTime: any, scheduledNotes: any, index: any): Promise<any>;
100
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, force: any): void;
101
+ releaseNote(channelNumber: any, noteNumber: any, velocity: any): void;
88
102
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
89
- handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
103
+ handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<void>;
90
104
  handleProgramChange(channelNumber: any, program: any): void;
91
105
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
92
106
  setPitchBend(channelNumber: any, pitchBend: any): void;
93
- handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
107
+ createControlChangeHandlers(): {
108
+ 1: (channelNumber: any, modulation: any) => void;
109
+ 6: (channelNumber: any, value: any) => void;
110
+ 7: (channelNumber: any, volume: any) => void;
111
+ 10: (channelNumber: any, pan: any) => void;
112
+ 11: (channelNumber: any, expression: any) => void;
113
+ 38: (channelNumber: any, value: any) => void;
114
+ 64: (channelNumber: any, value: any) => void;
115
+ 100: (channelNumber: any, value: any) => void;
116
+ 101: (channelNumber: any, value: any) => void;
117
+ 120: (channelNumber: any) => Promise<void>;
118
+ 121: (channelNumber: any) => void;
119
+ 123: (channelNumber: any) => Promise<void>;
120
+ };
121
+ handleControlChange(channelNumber: any, controller: any, value: any): void;
94
122
  updateModulation(channel: any): void;
95
123
  setModulationDepth(channelNumber: any, modulation: any): void;
96
124
  setVolume(channelNumber: any, volume: any): void;
@@ -101,7 +129,7 @@ export class MidyGMLite {
101
129
  setPan(channelNumber: any, pan: any): void;
102
130
  setExpression(channelNumber: any, expression: any): void;
103
131
  dataEntryLSB(channelNumber: any, value: any): void;
104
- updateChannelGain(channel: any): void;
132
+ updateChannelVolume(channel: any): void;
105
133
  setSustainPedal(channelNumber: any, value: any): void;
106
134
  handleRPN(channelNumber: any): void;
107
135
  setRPNMSB(channelNumber: any, value: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,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;IAuBhB,kBAAgC;IAChC,gBAA4C;IAC5C,gBAAiD;IAKnD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,mFAmBC;IAED,yDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAmCC;IAED,kGA6BC;IAED,0EAGC;IAED,uIAyCC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED,2FA+BC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAl/BD;IAQE,gFAKC;IAZD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA7CD,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;IAuBhB,kBAAgC;IAChC,gBAA4C;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAuBC;IAED,mEAWC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;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,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAgCC;IAED,kGA8BC;IAED,0EAGC;IAED,qFA4BC;IAED,0GAsBC;IAED,sEAGC;IAED,kEAeC;IAED,iFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED;;;;;;;;;;;;;MAeC;IAED,2EASC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBASC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAj/BD;IAQE,gFAKC;IAZD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
@@ -1,5 +1,5 @@
1
1
  import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
2
- import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js";
2
+ import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js";
3
3
  class Note {
4
4
  constructor(noteNumber, velocity, startTime, instrumentKey) {
5
5
  Object.defineProperty(this, "bufferSource", {
@@ -150,6 +150,7 @@ export class MidyGMLite {
150
150
  });
151
151
  this.audioContext = audioContext;
152
152
  this.masterGain = new GainNode(audioContext);
153
+ this.controlChangeHandlers = this.createControlChangeHandlers();
153
154
  this.channels = this.createChannels(audioContext);
154
155
  this.masterGain.connect(audioContext.destination);
155
156
  this.GM1SystemOn();
@@ -164,12 +165,14 @@ export class MidyGMLite {
164
165
  addSoundFont(soundFont) {
165
166
  const index = this.soundFonts.length;
166
167
  this.soundFonts.push(soundFont);
167
- soundFont.parsed.presetHeaders.forEach((presetHeader) => {
168
+ const presetHeaders = soundFont.parsed.presetHeaders;
169
+ for (let i = 0; i < presetHeaders.length; i++) {
170
+ const presetHeader = presetHeaders[i];
168
171
  if (!presetHeader.presetName.startsWith("\u0000")) { // TODO: Only SF3 generated by PolyPone?
169
172
  const banks = this.soundFontTable[presetHeader.preset];
170
173
  banks.set(presetHeader.bank, index);
171
174
  }
172
- });
175
+ }
173
176
  }
174
177
  async loadSoundFont(soundFontUrl) {
175
178
  const response = await fetch(soundFontUrl);
@@ -214,27 +217,25 @@ export class MidyGMLite {
214
217
  return channels;
215
218
  }
216
219
  async createNoteBuffer(instrumentKey, isSF3) {
220
+ const sampleStart = instrumentKey.start;
217
221
  const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
218
222
  if (isSF3) {
219
- const sample = new Uint8Array(instrumentKey.sample.length);
220
- sample.set(instrumentKey.sample);
223
+ const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
221
224
  const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
222
- for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
223
- const channelData = audioBuffer.getChannelData(channel);
224
- channelData.set(channelData.subarray(0, sampleEnd));
225
- }
226
225
  return audioBuffer;
227
226
  }
228
227
  else {
229
- const sample = instrumentKey.sample.subarray(0, sampleEnd);
230
- const floatSample = this.convertToFloat32Array(sample);
228
+ const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
231
229
  const audioBuffer = new AudioBuffer({
232
230
  numberOfChannels: 1,
233
231
  length: sample.length,
234
232
  sampleRate: instrumentKey.sampleRate,
235
233
  });
236
234
  const channelData = audioBuffer.getChannelData(0);
237
- channelData.set(floatSample);
235
+ const int16Array = new Int16Array(sample.buffer);
236
+ for (let i = 0; i < int16Array.length; i++) {
237
+ channelData[i] = int16Array[i] / 32768;
238
+ }
238
239
  return audioBuffer;
239
240
  }
240
241
  }
@@ -250,14 +251,6 @@ export class MidyGMLite {
250
251
  }
251
252
  return bufferSource;
252
253
  }
253
- convertToFloat32Array(uint8Array) {
254
- const int16Array = new Int16Array(uint8Array.buffer);
255
- const float32Array = new Float32Array(int16Array.length);
256
- for (let i = 0; i < int16Array.length; i++) {
257
- float32Array[i] = int16Array[i] / 32768;
258
- }
259
- return float32Array;
260
- }
261
254
  async scheduleTimelineEvents(t, offset, queueIndex) {
262
255
  while (queueIndex < this.timeline.length) {
263
256
  const event = this.timeline[queueIndex];
@@ -368,9 +361,11 @@ export class MidyGMLite {
368
361
  bank: this.channels[i].bank,
369
362
  };
370
363
  }
371
- midi.tracks.forEach((track) => {
364
+ for (let i = 0; i < midi.tracks.length; i++) {
365
+ const track = midi.tracks[i];
372
366
  let currentTicks = 0;
373
- track.forEach((event) => {
367
+ for (let j = 0; j < track.length; j++) {
368
+ const event = track[j];
374
369
  currentTicks += event.deltaTime;
375
370
  event.ticks = currentTicks;
376
371
  switch (event.type) {
@@ -390,8 +385,8 @@ export class MidyGMLite {
390
385
  }
391
386
  delete event.deltaTime;
392
387
  timeline.push(event);
393
- });
394
- });
388
+ }
389
+ }
395
390
  const priority = {
396
391
  controller: 0,
397
392
  sysEx: 1,
@@ -416,7 +411,7 @@ export class MidyGMLite {
416
411
  }
417
412
  return { instruments, timeline };
418
413
  }
419
- async stopChannelNotes(channelNumber, velocity, stopPedal) {
414
+ async stopChannelNotes(channelNumber, velocity, force) {
420
415
  const now = this.audioContext.currentTime;
421
416
  const channel = this.channels[channelNumber];
422
417
  channel.scheduledNotes.forEach((noteList) => {
@@ -424,16 +419,16 @@ export class MidyGMLite {
424
419
  const note = noteList[i];
425
420
  if (!note)
426
421
  continue;
427
- const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
422
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, force);
428
423
  this.notePromises.push(promise);
429
424
  }
430
425
  });
431
426
  channel.scheduledNotes.clear();
432
427
  await Promise.all(this.notePromises);
433
428
  }
434
- stopNotes(velocity, stopPedal) {
429
+ stopNotes(velocity, force) {
435
430
  for (let i = 0; i < this.channels.length; i++) {
436
- this.stopChannelNotes(i, velocity, stopPedal);
431
+ this.stopChannelNotes(i, velocity, force);
437
432
  }
438
433
  return Promise.all(this.notePromises);
439
434
  }
@@ -609,7 +604,7 @@ export class MidyGMLite {
609
604
  note.volumeNode = new GainNode(this.audioContext);
610
605
  note.filterNode = new BiquadFilterNode(this.audioContext, {
611
606
  type: "lowpass",
612
- Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
607
+ Q: instrumentKey.initialFilterQ / 10, // dB
613
608
  });
614
609
  this.setVolumeEnvelope(note);
615
610
  this.setFilterEnvelope(note);
@@ -622,7 +617,7 @@ export class MidyGMLite {
622
617
  }
623
618
  note.bufferSource.connect(note.filterNode);
624
619
  note.filterNode.connect(note.volumeNode);
625
- note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
620
+ note.bufferSource.start(startTime);
626
621
  return note;
627
622
  }
628
623
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
@@ -633,7 +628,7 @@ export class MidyGMLite {
633
628
  return;
634
629
  const soundFont = this.soundFonts[soundFontIndex];
635
630
  const isSF3 = soundFont.parsed.info.version.major === 3;
636
- const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
631
+ const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber, velocity);
637
632
  if (!instrumentKey)
638
633
  return;
639
634
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
@@ -651,9 +646,38 @@ export class MidyGMLite {
651
646
  const now = this.audioContext.currentTime;
652
647
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
653
648
  }
654
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
649
+ stopNote(stopTime, endTime, scheduledNotes, index) {
650
+ const note = scheduledNotes[index];
651
+ note.volumeNode.gain
652
+ .cancelScheduledValues(stopTime)
653
+ .linearRampToValueAtTime(0, endTime);
654
+ note.ending = true;
655
+ this.scheduleTask(() => {
656
+ note.bufferSource.loop = false;
657
+ }, endTime);
658
+ return new Promise((resolve) => {
659
+ note.bufferSource.onended = () => {
660
+ scheduledNotes[index] = null;
661
+ note.bufferSource.disconnect();
662
+ note.volumeNode.disconnect();
663
+ note.filterNode.disconnect();
664
+ if (note.modulationDepth) {
665
+ note.volumeDepth.disconnect();
666
+ note.modulationDepth.disconnect();
667
+ note.modulationLFO.stop();
668
+ }
669
+ if (note.vibratoDepth) {
670
+ note.vibratoDepth.disconnect();
671
+ note.vibratoLFO.stop();
672
+ }
673
+ resolve();
674
+ };
675
+ note.bufferSource.stop(endTime);
676
+ });
677
+ }
678
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, force) {
655
679
  const channel = this.channels[channelNumber];
656
- if (stopPedal && channel.sustainPedal)
680
+ if (!force && channel.sustainPedal)
657
681
  return;
658
682
  if (!channel.scheduledNotes.has(noteNumber))
659
683
  return;
@@ -665,33 +689,11 @@ export class MidyGMLite {
665
689
  if (note.ending)
666
690
  continue;
667
691
  const volEndTime = stopTime + note.instrumentKey.volRelease;
668
- note.volumeNode.gain
669
- .cancelScheduledValues(stopTime)
670
- .linearRampToValueAtTime(0, volEndTime);
671
692
  const modRelease = stopTime + note.instrumentKey.modRelease;
672
693
  note.filterNode.frequency
673
694
  .cancelScheduledValues(stopTime)
674
695
  .linearRampToValueAtTime(0, modRelease);
675
- note.ending = true;
676
- this.scheduleTask(() => {
677
- note.bufferSource.loop = false;
678
- }, stopTime);
679
- return new Promise((resolve) => {
680
- note.bufferSource.onended = () => {
681
- scheduledNotes[i] = null;
682
- note.bufferSource.disconnect();
683
- note.volumeNode.disconnect();
684
- note.filterNode.disconnect();
685
- if (note.volumeDepth)
686
- note.volumeDepth.disconnect();
687
- if (note.modulationDepth)
688
- note.modulationDepth.disconnect();
689
- if (note.modulationLFO)
690
- note.modulationLFO.stop();
691
- resolve();
692
- };
693
- note.bufferSource.stop(volEndTime);
694
- });
696
+ this.stopNote(stopTime, volEndTime, scheduledNotes, i);
695
697
  }
696
698
  }
697
699
  releaseNote(channelNumber, noteNumber, velocity) {
@@ -749,34 +751,29 @@ export class MidyGMLite {
749
751
  channel.pitchBendRange * 100;
750
752
  this.updateDetune(channel, detuneChange);
751
753
  }
754
+ createControlChangeHandlers() {
755
+ return {
756
+ 1: this.setModulationDepth,
757
+ 6: this.dataEntryMSB,
758
+ 7: this.setVolume,
759
+ 10: this.setPan,
760
+ 11: this.setExpression,
761
+ 38: this.dataEntryLSB,
762
+ 64: this.setSustainPedal,
763
+ 100: this.setRPNLSB,
764
+ 101: this.setRPNMSB,
765
+ 120: this.allSoundOff,
766
+ 121: this.resetAllControllers,
767
+ 123: this.allNotesOff,
768
+ };
769
+ }
752
770
  handleControlChange(channelNumber, controller, value) {
753
- switch (controller) {
754
- case 1:
755
- return this.setModulationDepth(channelNumber, value);
756
- case 6:
757
- return this.dataEntryMSB(channelNumber, value);
758
- case 7:
759
- return this.setVolume(channelNumber, value);
760
- case 10:
761
- return this.setPan(channelNumber, value);
762
- case 11:
763
- return this.setExpression(channelNumber, value);
764
- case 38:
765
- return this.dataEntryLSB(channelNumber, value);
766
- case 64:
767
- return this.setSustainPedal(channelNumber, value);
768
- case 100:
769
- return this.setRPNLSB(channelNumber, value);
770
- case 101:
771
- return this.setRPNMSB(channelNumber, value);
772
- case 120:
773
- return this.allSoundOff(channelNumber);
774
- case 121:
775
- return this.resetAllControllers(channelNumber);
776
- case 123:
777
- return this.allNotesOff(channelNumber);
778
- default:
779
- console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
771
+ const handler = this.controlChangeHandlers[controller];
772
+ if (handler) {
773
+ handler.call(this, channelNumber, value);
774
+ }
775
+ else {
776
+ console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
780
777
  }
781
778
  }
782
779
  updateModulation(channel) {
@@ -805,7 +802,7 @@ export class MidyGMLite {
805
802
  setVolume(channelNumber, volume) {
806
803
  const channel = this.channels[channelNumber];
807
804
  channel.volume = volume / 127;
808
- this.updateChannelGain(channel);
805
+ this.updateChannelVolume(channel);
809
806
  }
810
807
  panToGain(pan) {
811
808
  const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
@@ -817,18 +814,18 @@ export class MidyGMLite {
817
814
  setPan(channelNumber, pan) {
818
815
  const channel = this.channels[channelNumber];
819
816
  channel.pan = pan;
820
- this.updateChannelGain(channel);
817
+ this.updateChannelVolume(channel);
821
818
  }
822
819
  setExpression(channelNumber, expression) {
823
820
  const channel = this.channels[channelNumber];
824
821
  channel.expression = expression / 127;
825
- this.updateChannelGain(channel);
822
+ this.updateChannelVolume(channel);
826
823
  }
827
824
  dataEntryLSB(channelNumber, value) {
828
825
  this.channels[channelNumber].dataLSB = value;
829
826
  this.handleRPN(channelNumber);
830
827
  }
831
- updateChannelGain(channel) {
828
+ updateChannelVolume(channel) {
832
829
  const now = this.audioContext.currentTime;
833
830
  const volume = channel.volume * channel.expression;
834
831
  const { gainLeft, gainRight } = this.panToGain(channel.pan);
@@ -923,11 +920,12 @@ export class MidyGMLite {
923
920
  }
924
921
  }
925
922
  GM1SystemOn() {
926
- this.channels.forEach((channel) => {
923
+ for (let i = 0; i < this.channels.length; i++) {
924
+ const channel = this.channels[i];
927
925
  channel.bankMSB = 0;
928
926
  channel.bankLSB = 0;
929
927
  channel.bank = 0;
930
- });
928
+ }
931
929
  this.channels[9].bankMSB = 1;
932
930
  this.channels[9].bank = 128;
933
931
  }
package/esm/midy.d.ts CHANGED
@@ -97,6 +97,42 @@ export class Midy {
97
97
  };
98
98
  };
99
99
  masterGain: any;
100
+ controlChangeHandlers: {
101
+ 0: (channelNumber: any, msb: any) => void;
102
+ 1: (channelNumber: any, modulation: any) => void;
103
+ 5: (channelNumber: any, portamentoTime: any) => void;
104
+ 6: (channelNumber: any, value: any) => void;
105
+ 7: (channelNumber: any, volume: any) => void;
106
+ 10: (channelNumber: any, pan: any) => void;
107
+ 11: (channelNumber: any, expression: any) => void;
108
+ 32: (channelNumber: any, lsb: any) => void;
109
+ 38: (channelNumber: any, value: any) => void;
110
+ 64: (channelNumber: any, value: any) => void;
111
+ 65: (channelNumber: any, value: any) => void;
112
+ 66: (channelNumber: any, value: any) => void;
113
+ 67: (channelNumber: any, softPedal: any) => void;
114
+ 71: (channelNumber: any, filterResonance: any) => void;
115
+ 72: (channelNumber: any, releaseTime: any) => void;
116
+ 73: (channelNumber: any, attackTime: any) => void;
117
+ 74: (channelNumber: any, brightness: any) => void;
118
+ 75: (channelNumber: any, dacayTime: any) => void;
119
+ 76: (channelNumber: any, vibratoRate: any) => void;
120
+ 77: (channelNumber: any, vibratoDepth: any) => void;
121
+ 78: (channelNumber: any, vibratoDelay: any) => void;
122
+ 91: (channelNumber: any, reverbSendLevel: any) => void;
123
+ 93: (channelNumber: any, chorusSendLevel: any) => void;
124
+ 96: (channelNumber: any) => void;
125
+ 97: (channelNumber: any) => void;
126
+ 100: (channelNumber: any, value: any) => void;
127
+ 101: (channelNumber: any, value: any) => void;
128
+ 120: (channelNumber: any) => Promise<void>;
129
+ 121: (channelNumber: any) => void;
130
+ 123: (channelNumber: any) => Promise<void>;
131
+ 124: () => void;
132
+ 125: () => void;
133
+ 126: () => void;
134
+ 127: () => void;
135
+ };
100
136
  channels: any[];
101
137
  reverbEffect: {
102
138
  input: any;
@@ -123,7 +159,7 @@ export class Midy {
123
159
  createChannels(audioContext: any): any[];
124
160
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
125
161
  createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
126
- convertToFloat32Array(uint8Array: any): Float32Array;
162
+ findPortamentoTarget(queueIndex: any): any;
127
163
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
128
164
  getQueueIndex(second: any): number;
129
165
  playNotes(): Promise<any>;
@@ -133,8 +169,8 @@ export class Midy {
133
169
  instruments: Set<any>;
134
170
  timeline: any[];
135
171
  };
136
- stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
137
- stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
172
+ stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
173
+ stopNotes(velocity: any, force: any): Promise<any[]>;
138
174
  start(): Promise<void>;
139
175
  stop(): void;
140
176
  pause(): void;
@@ -170,18 +206,21 @@ export class Midy {
170
206
  centToHz(cent: any): number;
171
207
  calcSemitoneOffset(channel: any): any;
172
208
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
209
+ setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
173
210
  setVolumeEnvelope(channel: any, note: any): void;
174
211
  setPitch(note: any, semitoneOffset: any): void;
175
212
  clampCutoffFrequency(frequency: any): number;
213
+ setPortamentoStartFilterEnvelope(channel: any, note: any): void;
176
214
  setFilterEnvelope(channel: any, note: any): void;
177
215
  startModulation(channel: any, note: any, startTime: any): void;
178
216
  startVibrato(channel: any, note: any, startTime: any): void;
179
- createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
217
+ createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
180
218
  calcBank(channel: any, channelNumber: any): any;
181
- scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
182
- noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
183
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
184
- releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
219
+ scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
220
+ noteOn(channelNumber: any, noteNumber: any, velocity: any, portamento: any): Promise<void>;
221
+ stopNote(stopTime: any, endTime: any, scheduledNotes: any, index: any): Promise<any>;
222
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, portamentoNoteNumber: any, force: any): Promise<any> | undefined;
223
+ releaseNote(channelNumber: any, noteNumber: any, velocity: any, portamentoNoteNumber: any): Promise<any> | undefined;
185
224
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
186
225
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
187
226
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
@@ -190,7 +229,43 @@ export class Midy {
190
229
  handleChannelPressure(channelNumber: any, pressure: any): void;
191
230
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
192
231
  setPitchBend(channelNumber: any, pitchBend: any): void;
193
- handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
232
+ createControlChangeHandlers(): {
233
+ 0: (channelNumber: any, msb: any) => void;
234
+ 1: (channelNumber: any, modulation: any) => void;
235
+ 5: (channelNumber: any, portamentoTime: any) => void;
236
+ 6: (channelNumber: any, value: any) => void;
237
+ 7: (channelNumber: any, volume: any) => void;
238
+ 10: (channelNumber: any, pan: any) => void;
239
+ 11: (channelNumber: any, expression: any) => void;
240
+ 32: (channelNumber: any, lsb: any) => void;
241
+ 38: (channelNumber: any, value: any) => void;
242
+ 64: (channelNumber: any, value: any) => void;
243
+ 65: (channelNumber: any, value: any) => void;
244
+ 66: (channelNumber: any, value: any) => void;
245
+ 67: (channelNumber: any, softPedal: any) => void;
246
+ 71: (channelNumber: any, filterResonance: any) => void;
247
+ 72: (channelNumber: any, releaseTime: any) => void;
248
+ 73: (channelNumber: any, attackTime: any) => void;
249
+ 74: (channelNumber: any, brightness: any) => void;
250
+ 75: (channelNumber: any, dacayTime: any) => void;
251
+ 76: (channelNumber: any, vibratoRate: any) => void;
252
+ 77: (channelNumber: any, vibratoDepth: any) => void;
253
+ 78: (channelNumber: any, vibratoDelay: any) => void;
254
+ 91: (channelNumber: any, reverbSendLevel: any) => void;
255
+ 93: (channelNumber: any, chorusSendLevel: any) => void;
256
+ 96: (channelNumber: any) => void;
257
+ 97: (channelNumber: any) => void;
258
+ 100: (channelNumber: any, value: any) => void;
259
+ 101: (channelNumber: any, value: any) => void;
260
+ 120: (channelNumber: any) => Promise<void>;
261
+ 121: (channelNumber: any) => void;
262
+ 123: (channelNumber: any) => Promise<void>;
263
+ 124: () => void;
264
+ 125: () => void;
265
+ 126: () => void;
266
+ 127: () => void;
267
+ };
268
+ handleControlChange(channelNumber: any, controller: any, value: any): void;
194
269
  setBankMSB(channelNumber: any, msb: any): void;
195
270
  updateModulation(channel: any): void;
196
271
  setModulationDepth(channelNumber: any, modulation: any): void;
@@ -204,7 +279,7 @@ export class Midy {
204
279
  setExpression(channelNumber: any, expression: any): void;
205
280
  setBankLSB(channelNumber: any, lsb: any): void;
206
281
  dataEntryLSB(channelNumber: any, value: any): void;
207
- updateChannelGain(channel: any): void;
282
+ updateChannelVolume(channel: any): void;
208
283
  setSustainPedal(channelNumber: any, value: any): void;
209
284
  setPortamento(channelNumber: any, value: any): void;
210
285
  setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
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":"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"}