@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
package/esm/midy-GM1.d.ts CHANGED
@@ -37,6 +37,7 @@ export class MidyGM1 {
37
37
  timeline: any[];
38
38
  instruments: any[];
39
39
  notePromises: any[];
40
+ exclusiveClassMap: Map<any, any>;
40
41
  audioContext: any;
41
42
  masterGain: any;
42
43
  controlChangeHandlers: {
@@ -66,7 +67,6 @@ export class MidyGM1 {
66
67
  createChannels(audioContext: any): any[];
67
68
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
68
69
  createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
69
- convertToFloat32Array(uint8Array: any): Float32Array;
70
70
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
71
71
  getQueueIndex(second: any): number;
72
72
  playNotes(): Promise<any>;
@@ -76,8 +76,8 @@ export class MidyGM1 {
76
76
  instruments: Set<any>;
77
77
  timeline: any[];
78
78
  };
79
- stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
80
- stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
79
+ stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
80
+ stopNotes(velocity: any, force: any): Promise<any[]>;
81
81
  start(): Promise<void>;
82
82
  stop(): void;
83
83
  pause(): void;
@@ -99,7 +99,8 @@ export class MidyGM1 {
99
99
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
100
100
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
101
101
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
102
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
102
+ stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
103
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
103
104
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
104
105
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
105
106
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
@@ -131,7 +132,7 @@ export class MidyGM1 {
131
132
  setPan(channelNumber: any, pan: any): void;
132
133
  setExpression(channelNumber: any, expression: any): void;
133
134
  dataEntryLSB(channelNumber: any, value: any): void;
134
- updateChannelGain(channel: any): void;
135
+ updateChannelVolume(channel: any): void;
135
136
  setSustainPedal(channelNumber: any, value: any): void;
136
137
  limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
137
138
  limitDataMSB(channel: any, minMSB: any, maxMSB: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAwBA;IAmBE;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA/CD,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;IAyBhB,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,sCAGC;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,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAnjCD;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"}
1
+ {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAqBA;IAoBE;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IAhDD,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;IAyB5B,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,sCAGC;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,kFAeC;IAED,2DAMC;IAED,oCAkBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBASC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA9kCD;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"}
package/esm/midy-GM1.js CHANGED
@@ -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", {
@@ -160,6 +160,12 @@ export class MidyGM1 {
160
160
  writable: true,
161
161
  value: []
162
162
  });
163
+ Object.defineProperty(this, "exclusiveClassMap", {
164
+ enumerable: true,
165
+ configurable: true,
166
+ writable: true,
167
+ value: new Map()
168
+ });
163
169
  this.audioContext = audioContext;
164
170
  this.masterGain = new GainNode(audioContext);
165
171
  this.controlChangeHandlers = this.createControlChangeHandlers();
@@ -177,12 +183,14 @@ export class MidyGM1 {
177
183
  addSoundFont(soundFont) {
178
184
  const index = this.soundFonts.length;
179
185
  this.soundFonts.push(soundFont);
180
- soundFont.parsed.presetHeaders.forEach((presetHeader) => {
186
+ const presetHeaders = soundFont.parsed.presetHeaders;
187
+ for (let i = 0; i < presetHeaders.length; i++) {
188
+ const presetHeader = presetHeaders[i];
181
189
  if (!presetHeader.presetName.startsWith("\u0000")) { // TODO: Only SF3 generated by PolyPone?
182
190
  const banks = this.soundFontTable[presetHeader.preset];
183
191
  banks.set(presetHeader.bank, index);
184
192
  }
185
- });
193
+ }
186
194
  }
187
195
  async loadSoundFont(soundFontUrl) {
188
196
  const response = await fetch(soundFontUrl);
@@ -227,27 +235,31 @@ export class MidyGM1 {
227
235
  return channels;
228
236
  }
229
237
  async createNoteBuffer(instrumentKey, isSF3) {
238
+ const sampleStart = instrumentKey.start;
230
239
  const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
231
240
  if (isSF3) {
232
- const sample = new Uint8Array(instrumentKey.sample.length);
233
- sample.set(instrumentKey.sample);
234
- const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
235
- for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
236
- const channelData = audioBuffer.getChannelData(channel);
237
- channelData.set(channelData.subarray(0, sampleEnd));
238
- }
241
+ const sample = instrumentKey.sample;
242
+ const start = sample.byteOffset + sampleStart;
243
+ const end = sample.byteOffset + sampleEnd;
244
+ const buffer = sample.buffer.slice(start, end);
245
+ const audioBuffer = await this.audioContext.decodeAudioData(buffer);
239
246
  return audioBuffer;
240
247
  }
241
248
  else {
242
- const sample = instrumentKey.sample.subarray(0, sampleEnd);
243
- const floatSample = this.convertToFloat32Array(sample);
249
+ const sample = instrumentKey.sample;
250
+ const start = sample.byteOffset + sampleStart;
251
+ const end = sample.byteOffset + sampleEnd;
252
+ const buffer = sample.buffer.slice(start, end);
244
253
  const audioBuffer = new AudioBuffer({
245
254
  numberOfChannels: 1,
246
255
  length: sample.length,
247
256
  sampleRate: instrumentKey.sampleRate,
248
257
  });
249
258
  const channelData = audioBuffer.getChannelData(0);
250
- channelData.set(floatSample);
259
+ const int16Array = new Int16Array(buffer);
260
+ for (let i = 0; i < int16Array.length; i++) {
261
+ channelData[i] = int16Array[i] / 32768;
262
+ }
251
263
  return audioBuffer;
252
264
  }
253
265
  }
@@ -263,14 +275,6 @@ export class MidyGM1 {
263
275
  }
264
276
  return bufferSource;
265
277
  }
266
- convertToFloat32Array(uint8Array) {
267
- const int16Array = new Int16Array(uint8Array.buffer);
268
- const float32Array = new Float32Array(int16Array.length);
269
- for (let i = 0; i < int16Array.length; i++) {
270
- float32Array[i] = int16Array[i] / 32768;
271
- }
272
- return float32Array;
273
- }
274
278
  async scheduleTimelineEvents(t, offset, queueIndex) {
275
279
  while (queueIndex < this.timeline.length) {
276
280
  const event = this.timeline[queueIndex];
@@ -326,6 +330,7 @@ export class MidyGM1 {
326
330
  if (queueIndex >= this.timeline.length) {
327
331
  await Promise.all(this.notePromises);
328
332
  this.notePromises = [];
333
+ this.exclusiveClassMap.clear();
329
334
  resolve();
330
335
  return;
331
336
  }
@@ -341,6 +346,7 @@ export class MidyGM1 {
341
346
  }
342
347
  else if (this.isStopping) {
343
348
  await this.stopNotes(0, true);
349
+ this.exclusiveClassMap.clear();
344
350
  this.notePromises = [];
345
351
  resolve();
346
352
  this.isStopping = false;
@@ -349,6 +355,7 @@ export class MidyGM1 {
349
355
  }
350
356
  else if (this.isSeeking) {
351
357
  this.stopNotes(0, true);
358
+ this.exclusiveClassMap.clear();
352
359
  this.startTime = this.audioContext.currentTime;
353
360
  queueIndex = this.getQueueIndex(this.resumeTime);
354
361
  offset = this.resumeTime - this.startTime;
@@ -381,9 +388,11 @@ export class MidyGM1 {
381
388
  bank: this.channels[i].bank,
382
389
  };
383
390
  }
384
- midi.tracks.forEach((track) => {
391
+ for (let i = 0; i < midi.tracks.length; i++) {
392
+ const track = midi.tracks[i];
385
393
  let currentTicks = 0;
386
- track.forEach((event) => {
394
+ for (let j = 0; j < track.length; j++) {
395
+ const event = track[j];
387
396
  currentTicks += event.deltaTime;
388
397
  event.ticks = currentTicks;
389
398
  switch (event.type) {
@@ -403,8 +412,8 @@ export class MidyGM1 {
403
412
  }
404
413
  delete event.deltaTime;
405
414
  timeline.push(event);
406
- });
407
- });
415
+ }
416
+ }
408
417
  const priority = {
409
418
  controller: 0,
410
419
  sysEx: 1,
@@ -429,7 +438,7 @@ export class MidyGM1 {
429
438
  }
430
439
  return { instruments, timeline };
431
440
  }
432
- async stopChannelNotes(channelNumber, velocity, stopPedal) {
441
+ async stopChannelNotes(channelNumber, velocity, force) {
433
442
  const now = this.audioContext.currentTime;
434
443
  const channel = this.channels[channelNumber];
435
444
  channel.scheduledNotes.forEach((noteList) => {
@@ -437,16 +446,16 @@ export class MidyGM1 {
437
446
  const note = noteList[i];
438
447
  if (!note)
439
448
  continue;
440
- const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
449
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, force);
441
450
  this.notePromises.push(promise);
442
451
  }
443
452
  });
444
453
  channel.scheduledNotes.clear();
445
454
  await Promise.all(this.notePromises);
446
455
  }
447
- stopNotes(velocity, stopPedal) {
456
+ stopNotes(velocity, force) {
448
457
  for (let i = 0; i < this.channels.length; i++) {
449
- this.stopChannelNotes(i, velocity, stopPedal);
458
+ this.stopChannelNotes(i, velocity, force);
450
459
  }
451
460
  return Promise.all(this.notePromises);
452
461
  }
@@ -623,7 +632,7 @@ export class MidyGM1 {
623
632
  note.volumeNode = new GainNode(this.audioContext);
624
633
  note.filterNode = new BiquadFilterNode(this.audioContext, {
625
634
  type: "lowpass",
626
- Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
635
+ Q: instrumentKey.initialFilterQ / 10, // dB
627
636
  });
628
637
  this.setVolumeEnvelope(note);
629
638
  this.setFilterEnvelope(note);
@@ -636,7 +645,7 @@ export class MidyGM1 {
636
645
  }
637
646
  note.bufferSource.connect(note.filterNode);
638
647
  note.filterNode.connect(note.volumeNode);
639
- note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
648
+ note.bufferSource.start(startTime);
640
649
  return note;
641
650
  }
642
651
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
@@ -653,6 +662,19 @@ export class MidyGM1 {
653
662
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
654
663
  note.volumeNode.connect(channel.gainL);
655
664
  note.volumeNode.connect(channel.gainR);
665
+ const exclusiveClass = instrumentKey.exclusiveClass;
666
+ if (exclusiveClass !== 0) {
667
+ if (this.exclusiveClassMap.has(exclusiveClass)) {
668
+ const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
669
+ const [prevNote, prevChannelNumber] = prevEntry;
670
+ if (!prevNote.ending) {
671
+ this.scheduleNoteRelease(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
672
+ startTime, undefined, // portamentoNoteNumber
673
+ true);
674
+ }
675
+ }
676
+ this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
677
+ }
656
678
  const scheduledNotes = channel.scheduledNotes;
657
679
  if (scheduledNotes.has(noteNumber)) {
658
680
  scheduledNotes.get(noteNumber).push(note);
@@ -665,9 +687,38 @@ export class MidyGM1 {
665
687
  const now = this.audioContext.currentTime;
666
688
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
667
689
  }
668
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
690
+ stopNote(endTime, stopTime, scheduledNotes, index) {
691
+ const note = scheduledNotes[index];
692
+ note.volumeNode.gain
693
+ .cancelScheduledValues(endTime)
694
+ .linearRampToValueAtTime(0, stopTime);
695
+ note.ending = true;
696
+ this.scheduleTask(() => {
697
+ note.bufferSource.loop = false;
698
+ }, stopTime);
699
+ return new Promise((resolve) => {
700
+ note.bufferSource.onended = () => {
701
+ scheduledNotes[index] = null;
702
+ note.bufferSource.disconnect();
703
+ note.volumeNode.disconnect();
704
+ note.filterNode.disconnect();
705
+ if (note.modulationDepth) {
706
+ note.volumeDepth.disconnect();
707
+ note.modulationDepth.disconnect();
708
+ note.modulationLFO.stop();
709
+ }
710
+ if (note.vibratoDepth) {
711
+ note.vibratoDepth.disconnect();
712
+ note.vibratoLFO.stop();
713
+ }
714
+ resolve();
715
+ };
716
+ note.bufferSource.stop(stopTime);
717
+ });
718
+ }
719
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, endTime, force) {
669
720
  const channel = this.channels[channelNumber];
670
- if (stopPedal && channel.sustainPedal)
721
+ if (!force && channel.sustainPedal)
671
722
  return;
672
723
  if (!channel.scheduledNotes.has(noteNumber))
673
724
  return;
@@ -678,33 +729,13 @@ export class MidyGM1 {
678
729
  continue;
679
730
  if (note.ending)
680
731
  continue;
681
- const volEndTime = stopTime + note.instrumentKey.volRelease;
682
- note.volumeNode.gain
683
- .cancelScheduledValues(stopTime)
684
- .linearRampToValueAtTime(0, volEndTime);
685
- const modRelease = stopTime + note.instrumentKey.modRelease;
732
+ const volRelease = endTime + note.instrumentKey.volRelease;
733
+ const modRelease = endTime + note.instrumentKey.modRelease;
686
734
  note.filterNode.frequency
687
- .cancelScheduledValues(stopTime)
735
+ .cancelScheduledValues(endTime)
688
736
  .linearRampToValueAtTime(0, modRelease);
689
- note.ending = true;
690
- this.scheduleTask(() => {
691
- note.bufferSource.loop = false;
692
- }, stopTime);
693
- return new Promise((resolve) => {
694
- note.bufferSource.onended = () => {
695
- scheduledNotes[i] = null;
696
- note.bufferSource.disconnect();
697
- note.volumeNode.disconnect();
698
- note.filterNode.disconnect();
699
- if (note.modulationDepth) {
700
- note.volumeDepth.disconnect();
701
- note.modulationDepth.disconnect();
702
- note.modulationLFO.stop();
703
- }
704
- resolve();
705
- };
706
- note.bufferSource.stop(volEndTime);
707
- });
737
+ const stopTime = Math.min(volRelease, modRelease);
738
+ return this.stopNote(endTime, stopTime, scheduledNotes, i);
708
739
  }
709
740
  }
710
741
  releaseNote(channelNumber, noteNumber, velocity) {
@@ -813,7 +844,7 @@ export class MidyGM1 {
813
844
  setVolume(channelNumber, volume) {
814
845
  const channel = this.channels[channelNumber];
815
846
  channel.volume = volume / 127;
816
- this.updateChannelGain(channel);
847
+ this.updateChannelVolume(channel);
817
848
  }
818
849
  panToGain(pan) {
819
850
  const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
@@ -825,18 +856,18 @@ export class MidyGM1 {
825
856
  setPan(channelNumber, pan) {
826
857
  const channel = this.channels[channelNumber];
827
858
  channel.pan = pan;
828
- this.updateChannelGain(channel);
859
+ this.updateChannelVolume(channel);
829
860
  }
830
861
  setExpression(channelNumber, expression) {
831
862
  const channel = this.channels[channelNumber];
832
863
  channel.expression = expression / 127;
833
- this.updateChannelGain(channel);
864
+ this.updateChannelVolume(channel);
834
865
  }
835
866
  dataEntryLSB(channelNumber, value) {
836
867
  this.channels[channelNumber].dataLSB = value;
837
868
  this.handleRPN(channelNumber, 0);
838
869
  }
839
- updateChannelGain(channel) {
870
+ updateChannelVolume(channel) {
840
871
  const now = this.audioContext.currentTime;
841
872
  const volume = channel.volume * channel.expression;
842
873
  const { gainLeft, gainRight } = this.panToGain(channel.pan);
@@ -989,11 +1020,12 @@ export class MidyGM1 {
989
1020
  }
990
1021
  }
991
1022
  GM1SystemOn() {
992
- this.channels.forEach((channel) => {
1023
+ for (let i = 0; i < this.channels.length; i++) {
1024
+ const channel = this.channels[i];
993
1025
  channel.bankMSB = 0;
994
1026
  channel.bankLSB = 0;
995
1027
  channel.bank = 0;
996
- });
1028
+ }
997
1029
  this.channels[9].bankMSB = 1;
998
1030
  this.channels[9].bank = 128;
999
1031
  }
package/esm/midy-GM2.d.ts CHANGED
@@ -78,6 +78,7 @@ export class MidyGM2 {
78
78
  timeline: any[];
79
79
  instruments: any[];
80
80
  notePromises: any[];
81
+ exclusiveClassMap: Map<any, any>;
81
82
  defaultOptions: {
82
83
  reverbAlgorithm: (audioContext: any) => {
83
84
  input: any;
@@ -144,7 +145,7 @@ export class MidyGM2 {
144
145
  createChannels(audioContext: any): any[];
145
146
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
146
147
  createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
147
- convertToFloat32Array(uint8Array: any): Float32Array;
148
+ findPortamentoTarget(queueIndex: any): any;
148
149
  scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
149
150
  getQueueIndex(second: any): number;
150
151
  playNotes(): Promise<any>;
@@ -154,8 +155,8 @@ export class MidyGM2 {
154
155
  instruments: Set<any>;
155
156
  timeline: any[];
156
157
  };
157
- stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
158
- stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
158
+ stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
159
+ stopNotes(velocity: any, force: any): Promise<any[]>;
159
160
  start(): Promise<void>;
160
161
  stop(): void;
161
162
  pause(): void;
@@ -191,18 +192,21 @@ export class MidyGM2 {
191
192
  centToHz(cent: any): number;
192
193
  calcSemitoneOffset(channel: any): any;
193
194
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
195
+ setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
194
196
  setVolumeEnvelope(note: any): void;
195
197
  setPitch(note: any, semitoneOffset: any): void;
196
198
  clampCutoffFrequency(frequency: any): number;
199
+ setPortamentoStartFilterEnvelope(channel: any, note: any): void;
197
200
  setFilterEnvelope(channel: any, note: any): void;
198
201
  startModulation(channel: any, note: any, startTime: any): void;
199
202
  startVibrato(channel: any, note: any, startTime: any): void;
200
- createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
203
+ createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
201
204
  calcBank(channel: any, channelNumber: any): any;
202
- scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
203
- noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
204
- scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
205
- releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
205
+ scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
206
+ noteOn(channelNumber: any, noteNumber: any, velocity: any, portamento: any): Promise<void>;
207
+ stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
208
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, portamentoNoteNumber: any, force: any): Promise<any> | undefined;
209
+ releaseNote(channelNumber: any, noteNumber: any, velocity: any, portamentoNoteNumber: any): Promise<any> | undefined;
206
210
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
207
211
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
208
212
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
@@ -250,7 +254,7 @@ export class MidyGM2 {
250
254
  setExpression(channelNumber: any, expression: any): void;
251
255
  setBankLSB(channelNumber: any, lsb: any): void;
252
256
  dataEntryLSB(channelNumber: any, value: any): void;
253
- updateChannelGain(channel: any): void;
257
+ updateChannelVolume(channel: any): void;
254
258
  setSustainPedal(channelNumber: any, value: any): void;
255
259
  setPortamento(channelNumber: any, value: any): void;
256
260
  setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
@@ -321,6 +325,8 @@ declare class Note {
321
325
  modulationDepth: any;
322
326
  vibratoLFO: any;
323
327
  vibratoDepth: any;
328
+ reverbEffectsSend: any;
329
+ chorusEffectsSend: any;
324
330
  noteNumber: any;
325
331
  velocity: any;
326
332
  startTime: 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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"}