@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"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGMLite = void 0;
4
4
  const _esm_js_1 = require("./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js");
5
- const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js");
5
+ const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js");
6
6
  class Note {
7
7
  constructor(noteNumber, velocity, startTime, instrumentKey) {
8
8
  Object.defineProperty(this, "bufferSource", {
@@ -153,6 +153,7 @@ class MidyGMLite {
153
153
  });
154
154
  this.audioContext = audioContext;
155
155
  this.masterGain = new GainNode(audioContext);
156
+ this.controlChangeHandlers = this.createControlChangeHandlers();
156
157
  this.channels = this.createChannels(audioContext);
157
158
  this.masterGain.connect(audioContext.destination);
158
159
  this.GM1SystemOn();
@@ -167,12 +168,14 @@ class MidyGMLite {
167
168
  addSoundFont(soundFont) {
168
169
  const index = this.soundFonts.length;
169
170
  this.soundFonts.push(soundFont);
170
- soundFont.parsed.presetHeaders.forEach((presetHeader) => {
171
+ const presetHeaders = soundFont.parsed.presetHeaders;
172
+ for (let i = 0; i < presetHeaders.length; i++) {
173
+ const presetHeader = presetHeaders[i];
171
174
  if (!presetHeader.presetName.startsWith("\u0000")) { // TODO: Only SF3 generated by PolyPone?
172
175
  const banks = this.soundFontTable[presetHeader.preset];
173
176
  banks.set(presetHeader.bank, index);
174
177
  }
175
- });
178
+ }
176
179
  }
177
180
  async loadSoundFont(soundFontUrl) {
178
181
  const response = await fetch(soundFontUrl);
@@ -217,27 +220,25 @@ class MidyGMLite {
217
220
  return channels;
218
221
  }
219
222
  async createNoteBuffer(instrumentKey, isSF3) {
223
+ const sampleStart = instrumentKey.start;
220
224
  const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
221
225
  if (isSF3) {
222
- const sample = new Uint8Array(instrumentKey.sample.length);
223
- sample.set(instrumentKey.sample);
226
+ const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
224
227
  const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
225
- for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
226
- const channelData = audioBuffer.getChannelData(channel);
227
- channelData.set(channelData.subarray(0, sampleEnd));
228
- }
229
228
  return audioBuffer;
230
229
  }
231
230
  else {
232
- const sample = instrumentKey.sample.subarray(0, sampleEnd);
233
- const floatSample = this.convertToFloat32Array(sample);
231
+ const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
234
232
  const audioBuffer = new AudioBuffer({
235
233
  numberOfChannels: 1,
236
234
  length: sample.length,
237
235
  sampleRate: instrumentKey.sampleRate,
238
236
  });
239
237
  const channelData = audioBuffer.getChannelData(0);
240
- channelData.set(floatSample);
238
+ const int16Array = new Int16Array(sample.buffer);
239
+ for (let i = 0; i < int16Array.length; i++) {
240
+ channelData[i] = int16Array[i] / 32768;
241
+ }
241
242
  return audioBuffer;
242
243
  }
243
244
  }
@@ -253,14 +254,6 @@ class MidyGMLite {
253
254
  }
254
255
  return bufferSource;
255
256
  }
256
- convertToFloat32Array(uint8Array) {
257
- const int16Array = new Int16Array(uint8Array.buffer);
258
- const float32Array = new Float32Array(int16Array.length);
259
- for (let i = 0; i < int16Array.length; i++) {
260
- float32Array[i] = int16Array[i] / 32768;
261
- }
262
- return float32Array;
263
- }
264
257
  async scheduleTimelineEvents(t, offset, queueIndex) {
265
258
  while (queueIndex < this.timeline.length) {
266
259
  const event = this.timeline[queueIndex];
@@ -371,9 +364,11 @@ class MidyGMLite {
371
364
  bank: this.channels[i].bank,
372
365
  };
373
366
  }
374
- midi.tracks.forEach((track) => {
367
+ for (let i = 0; i < midi.tracks.length; i++) {
368
+ const track = midi.tracks[i];
375
369
  let currentTicks = 0;
376
- track.forEach((event) => {
370
+ for (let j = 0; j < track.length; j++) {
371
+ const event = track[j];
377
372
  currentTicks += event.deltaTime;
378
373
  event.ticks = currentTicks;
379
374
  switch (event.type) {
@@ -393,8 +388,8 @@ class MidyGMLite {
393
388
  }
394
389
  delete event.deltaTime;
395
390
  timeline.push(event);
396
- });
397
- });
391
+ }
392
+ }
398
393
  const priority = {
399
394
  controller: 0,
400
395
  sysEx: 1,
@@ -419,7 +414,7 @@ class MidyGMLite {
419
414
  }
420
415
  return { instruments, timeline };
421
416
  }
422
- async stopChannelNotes(channelNumber, velocity, stopPedal) {
417
+ async stopChannelNotes(channelNumber, velocity, force) {
423
418
  const now = this.audioContext.currentTime;
424
419
  const channel = this.channels[channelNumber];
425
420
  channel.scheduledNotes.forEach((noteList) => {
@@ -427,16 +422,16 @@ class MidyGMLite {
427
422
  const note = noteList[i];
428
423
  if (!note)
429
424
  continue;
430
- const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
425
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, force);
431
426
  this.notePromises.push(promise);
432
427
  }
433
428
  });
434
429
  channel.scheduledNotes.clear();
435
430
  await Promise.all(this.notePromises);
436
431
  }
437
- stopNotes(velocity, stopPedal) {
432
+ stopNotes(velocity, force) {
438
433
  for (let i = 0; i < this.channels.length; i++) {
439
- this.stopChannelNotes(i, velocity, stopPedal);
434
+ this.stopChannelNotes(i, velocity, force);
440
435
  }
441
436
  return Promise.all(this.notePromises);
442
437
  }
@@ -612,7 +607,7 @@ class MidyGMLite {
612
607
  note.volumeNode = new GainNode(this.audioContext);
613
608
  note.filterNode = new BiquadFilterNode(this.audioContext, {
614
609
  type: "lowpass",
615
- Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
610
+ Q: instrumentKey.initialFilterQ / 10, // dB
616
611
  });
617
612
  this.setVolumeEnvelope(note);
618
613
  this.setFilterEnvelope(note);
@@ -625,7 +620,7 @@ class MidyGMLite {
625
620
  }
626
621
  note.bufferSource.connect(note.filterNode);
627
622
  note.filterNode.connect(note.volumeNode);
628
- note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
623
+ note.bufferSource.start(startTime);
629
624
  return note;
630
625
  }
631
626
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
@@ -636,7 +631,7 @@ class MidyGMLite {
636
631
  return;
637
632
  const soundFont = this.soundFonts[soundFontIndex];
638
633
  const isSF3 = soundFont.parsed.info.version.major === 3;
639
- const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
634
+ const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber, velocity);
640
635
  if (!instrumentKey)
641
636
  return;
642
637
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
@@ -654,9 +649,38 @@ class MidyGMLite {
654
649
  const now = this.audioContext.currentTime;
655
650
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
656
651
  }
657
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
652
+ stopNote(stopTime, endTime, scheduledNotes, index) {
653
+ const note = scheduledNotes[index];
654
+ note.volumeNode.gain
655
+ .cancelScheduledValues(stopTime)
656
+ .linearRampToValueAtTime(0, endTime);
657
+ note.ending = true;
658
+ this.scheduleTask(() => {
659
+ note.bufferSource.loop = false;
660
+ }, endTime);
661
+ return new Promise((resolve) => {
662
+ note.bufferSource.onended = () => {
663
+ scheduledNotes[index] = null;
664
+ note.bufferSource.disconnect();
665
+ note.volumeNode.disconnect();
666
+ note.filterNode.disconnect();
667
+ if (note.modulationDepth) {
668
+ note.volumeDepth.disconnect();
669
+ note.modulationDepth.disconnect();
670
+ note.modulationLFO.stop();
671
+ }
672
+ if (note.vibratoDepth) {
673
+ note.vibratoDepth.disconnect();
674
+ note.vibratoLFO.stop();
675
+ }
676
+ resolve();
677
+ };
678
+ note.bufferSource.stop(endTime);
679
+ });
680
+ }
681
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, force) {
658
682
  const channel = this.channels[channelNumber];
659
- if (stopPedal && channel.sustainPedal)
683
+ if (!force && channel.sustainPedal)
660
684
  return;
661
685
  if (!channel.scheduledNotes.has(noteNumber))
662
686
  return;
@@ -668,33 +692,11 @@ class MidyGMLite {
668
692
  if (note.ending)
669
693
  continue;
670
694
  const volEndTime = stopTime + note.instrumentKey.volRelease;
671
- note.volumeNode.gain
672
- .cancelScheduledValues(stopTime)
673
- .linearRampToValueAtTime(0, volEndTime);
674
695
  const modRelease = stopTime + note.instrumentKey.modRelease;
675
696
  note.filterNode.frequency
676
697
  .cancelScheduledValues(stopTime)
677
698
  .linearRampToValueAtTime(0, modRelease);
678
- note.ending = true;
679
- this.scheduleTask(() => {
680
- note.bufferSource.loop = false;
681
- }, stopTime);
682
- return new Promise((resolve) => {
683
- note.bufferSource.onended = () => {
684
- scheduledNotes[i] = null;
685
- note.bufferSource.disconnect();
686
- note.volumeNode.disconnect();
687
- note.filterNode.disconnect();
688
- if (note.volumeDepth)
689
- note.volumeDepth.disconnect();
690
- if (note.modulationDepth)
691
- note.modulationDepth.disconnect();
692
- if (note.modulationLFO)
693
- note.modulationLFO.stop();
694
- resolve();
695
- };
696
- note.bufferSource.stop(volEndTime);
697
- });
699
+ this.stopNote(stopTime, volEndTime, scheduledNotes, i);
698
700
  }
699
701
  }
700
702
  releaseNote(channelNumber, noteNumber, velocity) {
@@ -752,34 +754,29 @@ class MidyGMLite {
752
754
  channel.pitchBendRange * 100;
753
755
  this.updateDetune(channel, detuneChange);
754
756
  }
757
+ createControlChangeHandlers() {
758
+ return {
759
+ 1: this.setModulationDepth,
760
+ 6: this.dataEntryMSB,
761
+ 7: this.setVolume,
762
+ 10: this.setPan,
763
+ 11: this.setExpression,
764
+ 38: this.dataEntryLSB,
765
+ 64: this.setSustainPedal,
766
+ 100: this.setRPNLSB,
767
+ 101: this.setRPNMSB,
768
+ 120: this.allSoundOff,
769
+ 121: this.resetAllControllers,
770
+ 123: this.allNotesOff,
771
+ };
772
+ }
755
773
  handleControlChange(channelNumber, controller, value) {
756
- switch (controller) {
757
- case 1:
758
- return this.setModulationDepth(channelNumber, value);
759
- case 6:
760
- return this.dataEntryMSB(channelNumber, value);
761
- case 7:
762
- return this.setVolume(channelNumber, value);
763
- case 10:
764
- return this.setPan(channelNumber, value);
765
- case 11:
766
- return this.setExpression(channelNumber, value);
767
- case 38:
768
- return this.dataEntryLSB(channelNumber, value);
769
- case 64:
770
- return this.setSustainPedal(channelNumber, value);
771
- case 100:
772
- return this.setRPNLSB(channelNumber, value);
773
- case 101:
774
- return this.setRPNMSB(channelNumber, value);
775
- case 120:
776
- return this.allSoundOff(channelNumber);
777
- case 121:
778
- return this.resetAllControllers(channelNumber);
779
- case 123:
780
- return this.allNotesOff(channelNumber);
781
- default:
782
- console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
774
+ const handler = this.controlChangeHandlers[controller];
775
+ if (handler) {
776
+ handler.call(this, channelNumber, value);
777
+ }
778
+ else {
779
+ console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
783
780
  }
784
781
  }
785
782
  updateModulation(channel) {
@@ -808,7 +805,7 @@ class MidyGMLite {
808
805
  setVolume(channelNumber, volume) {
809
806
  const channel = this.channels[channelNumber];
810
807
  channel.volume = volume / 127;
811
- this.updateChannelGain(channel);
808
+ this.updateChannelVolume(channel);
812
809
  }
813
810
  panToGain(pan) {
814
811
  const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
@@ -820,18 +817,18 @@ class MidyGMLite {
820
817
  setPan(channelNumber, pan) {
821
818
  const channel = this.channels[channelNumber];
822
819
  channel.pan = pan;
823
- this.updateChannelGain(channel);
820
+ this.updateChannelVolume(channel);
824
821
  }
825
822
  setExpression(channelNumber, expression) {
826
823
  const channel = this.channels[channelNumber];
827
824
  channel.expression = expression / 127;
828
- this.updateChannelGain(channel);
825
+ this.updateChannelVolume(channel);
829
826
  }
830
827
  dataEntryLSB(channelNumber, value) {
831
828
  this.channels[channelNumber].dataLSB = value;
832
829
  this.handleRPN(channelNumber);
833
830
  }
834
- updateChannelGain(channel) {
831
+ updateChannelVolume(channel) {
835
832
  const now = this.audioContext.currentTime;
836
833
  const volume = channel.volume * channel.expression;
837
834
  const { gainLeft, gainRight } = this.panToGain(channel.pan);
@@ -926,11 +923,12 @@ class MidyGMLite {
926
923
  }
927
924
  }
928
925
  GM1SystemOn() {
929
- this.channels.forEach((channel) => {
926
+ for (let i = 0; i < this.channels.length; i++) {
927
+ const channel = this.channels[i];
930
928
  channel.bankMSB = 0;
931
929
  channel.bankLSB = 0;
932
930
  channel.bank = 0;
933
- });
931
+ }
934
932
  this.channels[9].bankMSB = 1;
935
933
  this.channels[9].bank = 128;
936
934
  }
package/script/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;
@@ -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":"AAwBA;IAkCE;;;;;;;;;;;;;;;;;;;;;;;;;MAyBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAYC;IA5HD,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,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAmDlB;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,gBAA4C;IAC5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAO3D,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAiBC;IAED,+DAuBC;IAED,mEAWC;IAED,2CAcC;IAED,2EA8DC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAoGC;IAED,+EAoBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA+BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,gEAUC;IAED,iDAeC;IAED,+CAwBC;IAED,6CAIC;IAED,gEAoBC;IAED,iDAyBC;IAED,+DA0BC;IAED,4DAiBC;IAED,yIA6CC;IAED,gDAQC;IAED,mHAwCC;IAED,2FASC;IAED,qFA4BC;IAED,yJAqCC;IAED,qHAUC;IAED,kEAeC;IAED,oEAYC;IAED,gFAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqCC;IAED,2EASC;IAED,+CAEC;IAED,qCAkBC;IAED,8DAIC;IAED,iEAIC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,wCAUC;IAED,sDAMC;IAED,oDAEC;IAED,mEAqBC;IAED,mEAqBC;IAED,wDAWC;IAED,uDAGC;IAED,mEAaC;IAED,2DAGC;IAED,yDAYC;IAED,yDAUC;IAED,uDAUC;IAED,2DAWC;IAED,6DAGC;IAED,6DAGC;IAED,kFAeC;IAED,2DAMC;IAED,gDAyBC;IAGD,wCAEC;IAGD,wCAEC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,wDAKC;IAED,6EAKC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBASC;IAED,oBASC;IAED,yDAiDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,mDAeC;IAED,4CAOC;IAED,+BAKC;IAED,qDAiBC;IAED,gCAMC;IAED,kCAEC;IA6BD,4CAEC;IAED,4CAaC;IAED,+BAiBC;IAED,wFAKC;IAED,mCAQC;IAED,qCAEC;IAED,oCAUC;IAED,sCAEC;IAED,oCAaC;IAED,sCAEC;IAED,wCAWC;IAED,0CAEC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAnhED;IAUE,gFAKC;IAdD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}