@marmooo/midy 0.1.5 → 0.1.7

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 (37) hide show
  1. package/esm/midy-GM1.d.ts +6 -5
  2. package/esm/midy-GM1.d.ts.map +1 -1
  3. package/esm/midy-GM1.js +97 -65
  4. package/esm/midy-GM2.d.ts +15 -9
  5. package/esm/midy-GM2.d.ts.map +1 -1
  6. package/esm/midy-GM2.js +316 -129
  7. package/esm/midy-GMLite.d.ts +6 -5
  8. package/esm/midy-GMLite.d.ts.map +1 -1
  9. package/esm/midy-GMLite.js +97 -65
  10. package/esm/midy.d.ts +15 -9
  11. package/esm/midy.d.ts.map +1 -1
  12. package/esm/midy.js +317 -134
  13. package/package.json +5 -1
  14. package/script/midy-GM1.d.ts +6 -5
  15. package/script/midy-GM1.d.ts.map +1 -1
  16. package/script/midy-GM1.js +100 -68
  17. package/script/midy-GM2.d.ts +15 -9
  18. package/script/midy-GM2.d.ts.map +1 -1
  19. package/script/midy-GM2.js +319 -132
  20. package/script/midy-GMLite.d.ts +6 -5
  21. package/script/midy-GMLite.d.ts.map +1 -1
  22. package/script/midy-GMLite.js +100 -68
  23. package/script/midy.d.ts +15 -9
  24. package/script/midy.d.ts.map +1 -1
  25. package/script/midy.js +320 -137
  26. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts +0 -149
  27. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +0 -1
  28. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +0 -180
  29. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts +0 -84
  30. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts.map +0 -1
  31. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js +0 -216
  32. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts +0 -149
  33. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +0 -1
  34. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +0 -190
  35. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts +0 -84
  36. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts.map +0 -1
  37. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js +0 -221
@@ -35,6 +35,7 @@ export class MidyGMLite {
35
35
  timeline: any[];
36
36
  instruments: any[];
37
37
  notePromises: any[];
38
+ exclusiveClassMap: Map<any, any>;
38
39
  audioContext: any;
39
40
  masterGain: any;
40
41
  controlChangeHandlers: {
@@ -64,7 +65,6 @@ export class MidyGMLite {
64
65
  createChannels(audioContext: any): any[];
65
66
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
66
67
  createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
67
- convertToFloat32Array(uint8Array: any): Float32Array;
68
68
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
69
69
  getQueueIndex(second: any): number;
70
70
  playNotes(): Promise<any>;
@@ -74,8 +74,8 @@ export class MidyGMLite {
74
74
  instruments: Set<any>;
75
75
  timeline: any[];
76
76
  };
77
- stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
78
- stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
77
+ stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
78
+ stopNotes(velocity: any, force: any): Promise<any[]>;
79
79
  start(): Promise<void>;
80
80
  stop(): void;
81
81
  pause(): void;
@@ -97,7 +97,8 @@ export class MidyGMLite {
97
97
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
98
98
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
99
99
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
100
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
100
+ stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
101
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
101
102
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
102
103
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
103
104
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
@@ -129,7 +130,7 @@ export class MidyGMLite {
129
130
  setPan(channelNumber: any, pan: any): void;
130
131
  setExpression(channelNumber: any, expression: any): void;
131
132
  dataEntryLSB(channelNumber: any, value: any): void;
132
- updateChannelGain(channel: any): void;
133
+ updateChannelVolume(channel: any): void;
133
134
  setSustainPedal(channelNumber: any, value: any): void;
134
135
  handleRPN(channelNumber: any): void;
135
136
  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,+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,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,kGA8BC;IAED,0EAGC;IAED,uIA2CC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;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,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;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
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAmBA;IAoBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA9CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,iCAA8B;IAuB5B,kBAAgC;IAChC,gBAA4C;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DA2BC;IAED,mEAWC;IAED,2EA+CC;IAED,mCAOC;IAED,0BAkDC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgEC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAgCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFA4BC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;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;AA5gCD;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
- 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.6/+esm.js";
1
+ import { parseMidi } from "midi-file";
2
+ import { parse, SoundFont } from "@marmooo/soundfont-parser";
3
3
  class Note {
4
4
  constructor(noteNumber, velocity, startTime, instrumentKey) {
5
5
  Object.defineProperty(this, "bufferSource", {
@@ -148,6 +148,12 @@ export class MidyGMLite {
148
148
  writable: true,
149
149
  value: []
150
150
  });
151
+ Object.defineProperty(this, "exclusiveClassMap", {
152
+ enumerable: true,
153
+ configurable: true,
154
+ writable: true,
155
+ value: new Map()
156
+ });
151
157
  this.audioContext = audioContext;
152
158
  this.masterGain = new GainNode(audioContext);
153
159
  this.controlChangeHandlers = this.createControlChangeHandlers();
@@ -165,12 +171,14 @@ export class MidyGMLite {
165
171
  addSoundFont(soundFont) {
166
172
  const index = this.soundFonts.length;
167
173
  this.soundFonts.push(soundFont);
168
- soundFont.parsed.presetHeaders.forEach((presetHeader) => {
174
+ const presetHeaders = soundFont.parsed.presetHeaders;
175
+ for (let i = 0; i < presetHeaders.length; i++) {
176
+ const presetHeader = presetHeaders[i];
169
177
  if (!presetHeader.presetName.startsWith("\u0000")) { // TODO: Only SF3 generated by PolyPone?
170
178
  const banks = this.soundFontTable[presetHeader.preset];
171
179
  banks.set(presetHeader.bank, index);
172
180
  }
173
- });
181
+ }
174
182
  }
175
183
  async loadSoundFont(soundFontUrl) {
176
184
  const response = await fetch(soundFontUrl);
@@ -215,27 +223,31 @@ export class MidyGMLite {
215
223
  return channels;
216
224
  }
217
225
  async createNoteBuffer(instrumentKey, isSF3) {
226
+ const sampleStart = instrumentKey.start;
218
227
  const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
219
228
  if (isSF3) {
220
- const sample = new Uint8Array(instrumentKey.sample.length);
221
- sample.set(instrumentKey.sample);
222
- const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
223
- for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
224
- const channelData = audioBuffer.getChannelData(channel);
225
- channelData.set(channelData.subarray(0, sampleEnd));
226
- }
229
+ const sample = instrumentKey.sample;
230
+ const start = sample.byteOffset + sampleStart;
231
+ const end = sample.byteOffset + sampleEnd;
232
+ const buffer = sample.buffer.slice(start, end);
233
+ const audioBuffer = await this.audioContext.decodeAudioData(buffer);
227
234
  return audioBuffer;
228
235
  }
229
236
  else {
230
- const sample = instrumentKey.sample.subarray(0, sampleEnd);
231
- const floatSample = this.convertToFloat32Array(sample);
237
+ const sample = instrumentKey.sample;
238
+ const start = sample.byteOffset + sampleStart;
239
+ const end = sample.byteOffset + sampleEnd;
240
+ const buffer = sample.buffer.slice(start, end);
232
241
  const audioBuffer = new AudioBuffer({
233
242
  numberOfChannels: 1,
234
243
  length: sample.length,
235
244
  sampleRate: instrumentKey.sampleRate,
236
245
  });
237
246
  const channelData = audioBuffer.getChannelData(0);
238
- channelData.set(floatSample);
247
+ const int16Array = new Int16Array(buffer);
248
+ for (let i = 0; i < int16Array.length; i++) {
249
+ channelData[i] = int16Array[i] / 32768;
250
+ }
239
251
  return audioBuffer;
240
252
  }
241
253
  }
@@ -251,14 +263,6 @@ export class MidyGMLite {
251
263
  }
252
264
  return bufferSource;
253
265
  }
254
- convertToFloat32Array(uint8Array) {
255
- const int16Array = new Int16Array(uint8Array.buffer);
256
- const float32Array = new Float32Array(int16Array.length);
257
- for (let i = 0; i < int16Array.length; i++) {
258
- float32Array[i] = int16Array[i] / 32768;
259
- }
260
- return float32Array;
261
- }
262
266
  async scheduleTimelineEvents(t, offset, queueIndex) {
263
267
  while (queueIndex < this.timeline.length) {
264
268
  const event = this.timeline[queueIndex];
@@ -314,6 +318,7 @@ export class MidyGMLite {
314
318
  if (queueIndex >= this.timeline.length) {
315
319
  await Promise.all(this.notePromises);
316
320
  this.notePromises = [];
321
+ this.exclusiveClassMap.clear();
317
322
  resolve();
318
323
  return;
319
324
  }
@@ -329,6 +334,7 @@ export class MidyGMLite {
329
334
  }
330
335
  else if (this.isStopping) {
331
336
  await this.stopNotes(0, true);
337
+ this.exclusiveClassMap.clear();
332
338
  this.notePromises = [];
333
339
  resolve();
334
340
  this.isStopping = false;
@@ -337,6 +343,7 @@ export class MidyGMLite {
337
343
  }
338
344
  else if (this.isSeeking) {
339
345
  this.stopNotes(0, true);
346
+ this.exclusiveClassMap.clear();
340
347
  this.startTime = this.audioContext.currentTime;
341
348
  queueIndex = this.getQueueIndex(this.resumeTime);
342
349
  offset = this.resumeTime - this.startTime;
@@ -369,9 +376,11 @@ export class MidyGMLite {
369
376
  bank: this.channels[i].bank,
370
377
  };
371
378
  }
372
- midi.tracks.forEach((track) => {
379
+ for (let i = 0; i < midi.tracks.length; i++) {
380
+ const track = midi.tracks[i];
373
381
  let currentTicks = 0;
374
- track.forEach((event) => {
382
+ for (let j = 0; j < track.length; j++) {
383
+ const event = track[j];
375
384
  currentTicks += event.deltaTime;
376
385
  event.ticks = currentTicks;
377
386
  switch (event.type) {
@@ -391,8 +400,8 @@ export class MidyGMLite {
391
400
  }
392
401
  delete event.deltaTime;
393
402
  timeline.push(event);
394
- });
395
- });
403
+ }
404
+ }
396
405
  const priority = {
397
406
  controller: 0,
398
407
  sysEx: 1,
@@ -417,7 +426,7 @@ export class MidyGMLite {
417
426
  }
418
427
  return { instruments, timeline };
419
428
  }
420
- async stopChannelNotes(channelNumber, velocity, stopPedal) {
429
+ async stopChannelNotes(channelNumber, velocity, force) {
421
430
  const now = this.audioContext.currentTime;
422
431
  const channel = this.channels[channelNumber];
423
432
  channel.scheduledNotes.forEach((noteList) => {
@@ -425,16 +434,16 @@ export class MidyGMLite {
425
434
  const note = noteList[i];
426
435
  if (!note)
427
436
  continue;
428
- const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
437
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, force);
429
438
  this.notePromises.push(promise);
430
439
  }
431
440
  });
432
441
  channel.scheduledNotes.clear();
433
442
  await Promise.all(this.notePromises);
434
443
  }
435
- stopNotes(velocity, stopPedal) {
444
+ stopNotes(velocity, force) {
436
445
  for (let i = 0; i < this.channels.length; i++) {
437
- this.stopChannelNotes(i, velocity, stopPedal);
446
+ this.stopChannelNotes(i, velocity, force);
438
447
  }
439
448
  return Promise.all(this.notePromises);
440
449
  }
@@ -610,7 +619,7 @@ export class MidyGMLite {
610
619
  note.volumeNode = new GainNode(this.audioContext);
611
620
  note.filterNode = new BiquadFilterNode(this.audioContext, {
612
621
  type: "lowpass",
613
- Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
622
+ Q: instrumentKey.initialFilterQ / 10, // dB
614
623
  });
615
624
  this.setVolumeEnvelope(note);
616
625
  this.setFilterEnvelope(note);
@@ -623,7 +632,7 @@ export class MidyGMLite {
623
632
  }
624
633
  note.bufferSource.connect(note.filterNode);
625
634
  note.filterNode.connect(note.volumeNode);
626
- note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
635
+ note.bufferSource.start(startTime);
627
636
  return note;
628
637
  }
629
638
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
@@ -640,6 +649,19 @@ export class MidyGMLite {
640
649
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
641
650
  note.volumeNode.connect(channel.gainL);
642
651
  note.volumeNode.connect(channel.gainR);
652
+ const exclusiveClass = instrumentKey.exclusiveClass;
653
+ if (exclusiveClass !== 0) {
654
+ if (this.exclusiveClassMap.has(exclusiveClass)) {
655
+ const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
656
+ const [prevNote, prevChannelNumber] = prevEntry;
657
+ if (!prevNote.ending) {
658
+ this.scheduleNoteRelease(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
659
+ startTime, undefined, // portamentoNoteNumber
660
+ true);
661
+ }
662
+ }
663
+ this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
664
+ }
643
665
  const scheduledNotes = channel.scheduledNotes;
644
666
  if (scheduledNotes.has(noteNumber)) {
645
667
  scheduledNotes.get(noteNumber).push(note);
@@ -652,9 +674,38 @@ export class MidyGMLite {
652
674
  const now = this.audioContext.currentTime;
653
675
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
654
676
  }
655
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
677
+ stopNote(endTime, stopTime, scheduledNotes, index) {
678
+ const note = scheduledNotes[index];
679
+ note.volumeNode.gain
680
+ .cancelScheduledValues(endTime)
681
+ .linearRampToValueAtTime(0, stopTime);
682
+ note.ending = true;
683
+ this.scheduleTask(() => {
684
+ note.bufferSource.loop = false;
685
+ }, stopTime);
686
+ return new Promise((resolve) => {
687
+ note.bufferSource.onended = () => {
688
+ scheduledNotes[index] = null;
689
+ note.bufferSource.disconnect();
690
+ note.volumeNode.disconnect();
691
+ note.filterNode.disconnect();
692
+ if (note.modulationDepth) {
693
+ note.volumeDepth.disconnect();
694
+ note.modulationDepth.disconnect();
695
+ note.modulationLFO.stop();
696
+ }
697
+ if (note.vibratoDepth) {
698
+ note.vibratoDepth.disconnect();
699
+ note.vibratoLFO.stop();
700
+ }
701
+ resolve();
702
+ };
703
+ note.bufferSource.stop(stopTime);
704
+ });
705
+ }
706
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, endTime, force) {
656
707
  const channel = this.channels[channelNumber];
657
- if (stopPedal && channel.sustainPedal)
708
+ if (!force && channel.sustainPedal)
658
709
  return;
659
710
  if (!channel.scheduledNotes.has(noteNumber))
660
711
  return;
@@ -665,33 +716,13 @@ export class MidyGMLite {
665
716
  continue;
666
717
  if (note.ending)
667
718
  continue;
668
- const volEndTime = stopTime + note.instrumentKey.volRelease;
669
- note.volumeNode.gain
670
- .cancelScheduledValues(stopTime)
671
- .linearRampToValueAtTime(0, volEndTime);
672
- const modRelease = stopTime + note.instrumentKey.modRelease;
719
+ const volRelease = endTime + note.instrumentKey.volRelease;
720
+ const modRelease = endTime + note.instrumentKey.modRelease;
673
721
  note.filterNode.frequency
674
- .cancelScheduledValues(stopTime)
722
+ .cancelScheduledValues(endTime)
675
723
  .linearRampToValueAtTime(0, modRelease);
676
- note.ending = true;
677
- this.scheduleTask(() => {
678
- note.bufferSource.loop = false;
679
- }, stopTime);
680
- return new Promise((resolve) => {
681
- note.bufferSource.onended = () => {
682
- scheduledNotes[i] = null;
683
- note.bufferSource.disconnect();
684
- note.volumeNode.disconnect();
685
- note.filterNode.disconnect();
686
- if (note.modulationDepth) {
687
- note.volumeDepth.disconnect();
688
- note.modulationDepth.disconnect();
689
- note.modulationLFO.stop();
690
- }
691
- resolve();
692
- };
693
- note.bufferSource.stop(volEndTime);
694
- });
724
+ const stopTime = Math.min(volRelease, modRelease);
725
+ return this.stopNote(endTime, stopTime, scheduledNotes, i);
695
726
  }
696
727
  }
697
728
  releaseNote(channelNumber, noteNumber, velocity) {
@@ -800,7 +831,7 @@ export class MidyGMLite {
800
831
  setVolume(channelNumber, volume) {
801
832
  const channel = this.channels[channelNumber];
802
833
  channel.volume = volume / 127;
803
- this.updateChannelGain(channel);
834
+ this.updateChannelVolume(channel);
804
835
  }
805
836
  panToGain(pan) {
806
837
  const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
@@ -812,18 +843,18 @@ export class MidyGMLite {
812
843
  setPan(channelNumber, pan) {
813
844
  const channel = this.channels[channelNumber];
814
845
  channel.pan = pan;
815
- this.updateChannelGain(channel);
846
+ this.updateChannelVolume(channel);
816
847
  }
817
848
  setExpression(channelNumber, expression) {
818
849
  const channel = this.channels[channelNumber];
819
850
  channel.expression = expression / 127;
820
- this.updateChannelGain(channel);
851
+ this.updateChannelVolume(channel);
821
852
  }
822
853
  dataEntryLSB(channelNumber, value) {
823
854
  this.channels[channelNumber].dataLSB = value;
824
855
  this.handleRPN(channelNumber);
825
856
  }
826
- updateChannelGain(channel) {
857
+ updateChannelVolume(channel) {
827
858
  const now = this.audioContext.currentTime;
828
859
  const volume = channel.volume * channel.expression;
829
860
  const { gainLeft, gainRight } = this.panToGain(channel.pan);
@@ -918,11 +949,12 @@ export class MidyGMLite {
918
949
  }
919
950
  }
920
951
  GM1SystemOn() {
921
- this.channels.forEach((channel) => {
952
+ for (let i = 0; i < this.channels.length; i++) {
953
+ const channel = this.channels[i];
922
954
  channel.bankMSB = 0;
923
955
  channel.bankLSB = 0;
924
956
  channel.bank = 0;
925
- });
957
+ }
926
958
  this.channels[9].bankMSB = 1;
927
959
  this.channels[9].bank = 128;
928
960
  }
package/esm/midy.d.ts CHANGED
@@ -83,6 +83,7 @@ export class Midy {
83
83
  timeline: any[];
84
84
  instruments: any[];
85
85
  notePromises: any[];
86
+ exclusiveClassMap: Map<any, any>;
86
87
  defaultOptions: {
87
88
  reverbAlgorithm: (audioContext: any) => {
88
89
  input: any;
@@ -159,7 +160,7 @@ export class Midy {
159
160
  createChannels(audioContext: any): any[];
160
161
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
161
162
  createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
162
- convertToFloat32Array(uint8Array: any): Float32Array;
163
+ findPortamentoTarget(queueIndex: any): any;
163
164
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
164
165
  getQueueIndex(second: any): number;
165
166
  playNotes(): Promise<any>;
@@ -169,8 +170,8 @@ export class Midy {
169
170
  instruments: Set<any>;
170
171
  timeline: any[];
171
172
  };
172
- stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
173
- stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
173
+ stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
174
+ stopNotes(velocity: any, force: any): Promise<any[]>;
174
175
  start(): Promise<void>;
175
176
  stop(): void;
176
177
  pause(): void;
@@ -206,18 +207,21 @@ export class Midy {
206
207
  centToHz(cent: any): number;
207
208
  calcSemitoneOffset(channel: any): any;
208
209
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
210
+ setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
209
211
  setVolumeEnvelope(channel: any, note: any): void;
210
212
  setPitch(note: any, semitoneOffset: any): void;
211
213
  clampCutoffFrequency(frequency: any): number;
214
+ setPortamentoStartFilterEnvelope(channel: any, note: any): void;
212
215
  setFilterEnvelope(channel: any, note: any): void;
213
216
  startModulation(channel: any, note: any, startTime: any): void;
214
217
  startVibrato(channel: any, note: any, startTime: any): void;
215
- createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
218
+ createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
216
219
  calcBank(channel: any, channelNumber: any): any;
217
- scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
218
- noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
219
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
220
- releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
220
+ scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
221
+ noteOn(channelNumber: any, noteNumber: any, velocity: any, portamento: any): Promise<void>;
222
+ stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
223
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, portamentoNoteNumber: any, force: any): Promise<any> | undefined;
224
+ releaseNote(channelNumber: any, noteNumber: any, velocity: any, portamentoNoteNumber: any): Promise<any> | undefined;
221
225
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
222
226
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
223
227
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
@@ -276,7 +280,7 @@ export class Midy {
276
280
  setExpression(channelNumber: any, expression: any): void;
277
281
  setBankLSB(channelNumber: any, lsb: any): void;
278
282
  dataEntryLSB(channelNumber: any, value: any): void;
279
- updateChannelGain(channel: any): void;
283
+ updateChannelVolume(channel: any): void;
280
284
  setSustainPedal(channelNumber: any, value: any): void;
281
285
  setPortamento(channelNumber: any, value: any): void;
282
286
  setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
@@ -357,6 +361,8 @@ declare class Note {
357
361
  modulationDepth: any;
358
362
  vibratoLFO: any;
359
363
  vibratoDepth: any;
364
+ reverbEffectsSend: any;
365
+ chorusEffectsSend: any;
360
366
  noteNumber: any;
361
367
  velocity: any;
362
368
  startTime: any;
package/esm/midy.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}