@marmooo/midy 0.4.0 → 0.4.2

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.
@@ -1,4 +1,4 @@
1
- export class MidyGMLite {
1
+ export class MidyGMLite extends EventTarget {
2
2
  static channelSettings: {
3
3
  scheduleIndex: number;
4
4
  detune: number;
@@ -29,6 +29,7 @@ export class MidyGMLite {
29
29
  isPaused: boolean;
30
30
  isStopping: boolean;
31
31
  isSeeking: boolean;
32
+ loop: boolean;
32
33
  playPromise: any;
33
34
  timeline: any[];
34
35
  notePromises: any[];
@@ -68,7 +69,7 @@ export class MidyGMLite {
68
69
  createChannels(audioContext: any): any[];
69
70
  createAudioBuffer(voiceParams: any): Promise<any>;
70
71
  createBufferSource(channel: any, voiceParams: any, audioBuffer: any): any;
71
- scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
72
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): any;
72
73
  getQueueIndex(second: any): number;
73
74
  resetAllStates(): void;
74
75
  updateStates(queueIndex: any, nextQueueIndex: any): void;
@@ -90,8 +91,8 @@ export class MidyGMLite {
90
91
  seekTo(second: any): void;
91
92
  calcTotalTime(): number;
92
93
  currentTime(): number;
93
- processScheduledNotes(channel: any, callback: any): void;
94
- processActiveNotes(channel: any, scheduleTime: any, callback: any): void;
94
+ processScheduledNotes(channel: any, callback: any): Promise<void>;
95
+ processActiveNotes(channel: any, scheduleTime: any, callback: any): Promise<void>;
95
96
  cbToRatio(cb: any): number;
96
97
  rateToCent(rate: any): number;
97
98
  centToRate(cent: any): number;
@@ -112,13 +113,13 @@ export class MidyGMLite {
112
113
  noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
113
114
  disconnectNote(note: any): void;
114
115
  releaseNote(channel: any, note: any, endTime: any): Promise<any>;
115
- noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): void;
116
+ noteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any>;
116
117
  setNoteIndex(channel: any, index: any): void;
117
118
  findNoteOffIndex(channel: any, noteNumber: any): any;
118
- releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
119
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): Promise<any>[];
119
120
  createMessageHandlers(): any[];
120
121
  handleMessage(data: any, scheduleTime: any): void;
121
- handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
122
+ handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
122
123
  setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
123
124
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
124
125
  setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA2GA;IA6BE;;;;;;;;;MASE;IAEF,+BAeC;IAtDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,kCAA+B;IAC/B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IACrC,+BAEE;IAcA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAWC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDAUC;IAED,0EAUC;IAED,yEAqDC;IAED,mCAOC;IAED,uBASC;IAED,yDA2BC;IAED,2BAwCC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAIC;IAED,yDAQC;IAED,yEASC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,4GAkCC;IAED,uEAuCC;IAED,0EAiBC;IAED,8EAiBC;IAED,oEAUC;IAED,0FAwBC;IAED,gCASC;IAED,iEAqBC;IAED,4FAsBC;IAED,6CAUC;IAED,qDAUC;IAED,sFAeC;IAED,+BAmBC;IAED,kDAOC;IAED,uGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAWC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA6GA;IA8BE;;;;;;;;;MASE;IAEF,+BAgBC;IAxDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,kCAA+B;IAC/B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,cAAa;IACb,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IACrC,+BAEE;IAeA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAWC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDASC;IAED,0EAUC;IAED,gEAoDC;IAED,mCAOC;IAED,uBASC;IAED,yDAgCC;IAED,2BAyEC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAIC;IAED,uBAMC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAIC;IAED,kEAWC;IAED,kFAYC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,4GAkCC;IAED,uEA4CC;IAED,0EAiBC;IAED,8EAiBC;IAED,oEAUC;IAED,0FAoBC;IAED,gCASC;IAED,iEAqBC;IAED,qGAsBC;IAED,6CAUC;IAED,qDAUC;IAED,8FAeC;IAED,+BAmBC;IAED,kDAOC;IAED,sGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAYC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF"}
@@ -26,12 +26,6 @@ class Note {
26
26
  writable: true,
27
27
  value: false
28
28
  });
29
- Object.defineProperty(this, "pending", {
30
- enumerable: true,
31
- configurable: true,
32
- writable: true,
33
- value: true
34
- });
35
29
  Object.defineProperty(this, "bufferSource", {
36
30
  enumerable: true,
37
31
  configurable: true,
@@ -77,6 +71,9 @@ class Note {
77
71
  this.noteNumber = noteNumber;
78
72
  this.velocity = velocity;
79
73
  this.startTime = startTime;
74
+ this.ready = new Promise((resolve) => {
75
+ this.resolveReady = resolve;
76
+ });
80
77
  }
81
78
  }
82
79
  const drumExclusiveClasses = new Uint8Array(128);
@@ -99,11 +96,11 @@ const defaultControllerState = {
99
96
  pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
100
97
  pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
101
98
  link: { type: 127, defaultValue: 0 },
102
- modulationDepth: { type: 128 + 1, defaultValue: 0 },
99
+ modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
103
100
  // dataMSB: { type: 128 + 6, defaultValue: 0, },
104
- volume: { type: 128 + 7, defaultValue: 100 / 127 },
105
- pan: { type: 128 + 10, defaultValue: 64 / 127 },
106
- expression: { type: 128 + 11, defaultValue: 1 },
101
+ volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
102
+ panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
103
+ expressionMSB: { type: 128 + 11, defaultValue: 1 },
107
104
  // dataLSB: { type: 128 + 38, defaultValue: 0, },
108
105
  sustainPedal: { type: 128 + 64, defaultValue: 0 },
109
106
  // rpnLSB: { type: 128 + 100, defaultValue: 127 },
@@ -163,8 +160,9 @@ const pitchEnvelopeKeys = [
163
160
  "playbackRate",
164
161
  ];
165
162
  const pitchEnvelopeKeySet = new Set(pitchEnvelopeKeys);
166
- export class MidyGMLite {
163
+ export class MidyGMLite extends EventTarget {
167
164
  constructor(audioContext) {
165
+ super();
168
166
  Object.defineProperty(this, "mode", {
169
167
  enumerable: true,
170
168
  configurable: true,
@@ -279,6 +277,12 @@ export class MidyGMLite {
279
277
  writable: true,
280
278
  value: false
281
279
  });
280
+ Object.defineProperty(this, "loop", {
281
+ enumerable: true,
282
+ configurable: true,
283
+ writable: true,
284
+ value: false
285
+ });
282
286
  Object.defineProperty(this, "playPromise", {
283
287
  enumerable: true,
284
288
  configurable: true,
@@ -429,7 +433,7 @@ export class MidyGMLite {
429
433
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
430
434
  }
431
435
  createChannelAudioNodes(audioContext) {
432
- const { gainLeft, gainRight } = this.panToGain(defaultControllerState.pan.defaultValue);
436
+ const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
433
437
  const gainL = new GainNode(audioContext, { gain: gainLeft });
434
438
  const gainR = new GainNode(audioContext, { gain: gainRight });
435
439
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
@@ -457,10 +461,9 @@ export class MidyGMLite {
457
461
  return channels;
458
462
  }
459
463
  async createAudioBuffer(voiceParams) {
460
- const sample = voiceParams.sample;
461
- const sampleStart = voiceParams.start;
462
- const sampleEnd = sample.data.length + voiceParams.end;
463
- const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
464
+ const { sample, start, end } = voiceParams;
465
+ const sampleEnd = sample.data.length + end;
466
+ const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
464
467
  return audioBuffer;
465
468
  }
466
469
  createBufferSource(channel, voiceParams, audioBuffer) {
@@ -475,7 +478,7 @@ export class MidyGMLite {
475
478
  }
476
479
  return bufferSource;
477
480
  }
478
- async scheduleTimelineEvents(scheduleTime, queueIndex) {
481
+ scheduleTimelineEvents(scheduleTime, queueIndex) {
479
482
  const timeOffset = this.resumeTime - this.startTime;
480
483
  const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
481
484
  const schedulingOffset = this.startDelay - timeOffset;
@@ -487,12 +490,10 @@ export class MidyGMLite {
487
490
  const startTime = event.startTime + schedulingOffset;
488
491
  switch (event.type) {
489
492
  case "noteOn":
490
- await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
493
+ this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
491
494
  break;
492
495
  case "noteOff": {
493
- const notePromise = this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
494
- if (notePromise)
495
- this.notePromises.push(notePromise);
496
+ this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
496
497
  break;
497
498
  }
498
499
  case "controller":
@@ -530,22 +531,23 @@ export class MidyGMLite {
530
531
  }
531
532
  }
532
533
  updateStates(queueIndex, nextQueueIndex) {
534
+ const now = this.audioContext.currentTime;
533
535
  if (nextQueueIndex < queueIndex)
534
536
  queueIndex = 0;
535
537
  for (let i = queueIndex; i < nextQueueIndex; i++) {
536
538
  const event = this.timeline[i];
537
539
  switch (event.type) {
538
540
  case "controller":
539
- this.setControlChange(event.channel, event.controllerType, event.value, 0);
541
+ this.setControlChange(event.channel, event.controllerType, event.value, now - this.resumeTime + event.startTime);
540
542
  break;
541
543
  case "programChange":
542
- this.setProgramChange(event.channel, event.programNumber, 0);
544
+ this.setProgramChange(event.channel, event.programNumber, now - this.resumeTime + event.startTime);
543
545
  break;
544
546
  case "pitchBend":
545
- this.setPitchBend(event.channel, event.value + 8192, 0);
547
+ this.setPitchBend(event.channel, event.value + 8192, now - this.resumeTime + event.startTime);
546
548
  break;
547
549
  case "sysEx":
548
- this.handleSysEx(event.data, 0);
550
+ this.handleSysEx(event.data, now - this.resumeTime + event.startTime);
549
551
  }
550
552
  }
551
553
  }
@@ -553,44 +555,80 @@ export class MidyGMLite {
553
555
  if (this.audioContext.state === "suspended") {
554
556
  await this.audioContext.resume();
555
557
  }
558
+ const paused = this.isPaused;
556
559
  this.isPlaying = true;
557
560
  this.isPaused = false;
558
561
  this.startTime = this.audioContext.currentTime;
562
+ if (paused) {
563
+ this.dispatchEvent(new Event("resumed"));
564
+ }
565
+ else {
566
+ this.dispatchEvent(new Event("started"));
567
+ }
559
568
  let queueIndex = this.getQueueIndex(this.resumeTime);
560
- let finished = false;
569
+ let exitReason;
561
570
  this.notePromises = [];
562
- while (queueIndex < this.timeline.length) {
571
+ while (true) {
563
572
  const now = this.audioContext.currentTime;
573
+ if (this.timeline.length <= queueIndex) {
574
+ await this.stopNotes(0, true, now);
575
+ if (this.loop) {
576
+ this.notePromises = [];
577
+ this.resetAllStates();
578
+ this.startTime = this.audioContext.currentTime;
579
+ this.resumeTime = 0;
580
+ queueIndex = 0;
581
+ this.dispatchEvent(new Event("looped"));
582
+ continue;
583
+ }
584
+ else {
585
+ await this.audioContext.suspend();
586
+ exitReason = "ended";
587
+ break;
588
+ }
589
+ }
564
590
  if (this.isPausing) {
565
591
  await this.stopNotes(0, true, now);
566
592
  await this.audioContext.suspend();
567
593
  this.notePromises = [];
594
+ this.isPausing = false;
595
+ exitReason = "paused";
568
596
  break;
569
597
  }
570
598
  else if (this.isStopping) {
571
599
  await this.stopNotes(0, true, now);
572
600
  await this.audioContext.suspend();
573
- finished = true;
601
+ this.isStopping = false;
602
+ exitReason = "stopped";
574
603
  break;
575
604
  }
576
605
  else if (this.isSeeking) {
577
- await this.stopNotes(0, true, now);
606
+ this.stopNotes(0, true, now);
578
607
  this.startTime = this.audioContext.currentTime;
579
608
  const nextQueueIndex = this.getQueueIndex(this.resumeTime);
580
609
  this.updateStates(queueIndex, nextQueueIndex);
581
610
  queueIndex = nextQueueIndex;
582
611
  this.isSeeking = false;
612
+ this.dispatchEvent(new Event("seeked"));
583
613
  continue;
584
614
  }
585
- queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
615
+ queueIndex = this.scheduleTimelineEvents(now, queueIndex);
586
616
  const waitTime = now + this.noteCheckInterval;
587
617
  await this.scheduleTask(() => { }, waitTime);
588
618
  }
589
- if (finished) {
619
+ if (exitReason !== "paused") {
590
620
  this.notePromises = [];
591
621
  this.resetAllStates();
592
622
  }
593
623
  this.isPlaying = false;
624
+ if (exitReason === "paused") {
625
+ this.isPaused = true;
626
+ this.dispatchEvent(new Event("paused"));
627
+ }
628
+ else {
629
+ this.isPaused = false;
630
+ this.dispatchEvent(new Event(exitReason));
631
+ }
594
632
  }
595
633
  ticksToSecond(ticks, secondsPerBeat) {
596
634
  return ticks * secondsPerBeat / this.ticksPerBeat;
@@ -697,24 +735,20 @@ export class MidyGMLite {
697
735
  return;
698
736
  this.isStopping = true;
699
737
  await this.playPromise;
700
- this.isStopping = false;
701
738
  }
702
739
  async pause() {
703
740
  if (!this.isPlaying || this.isPaused)
704
741
  return;
705
742
  const now = this.audioContext.currentTime;
706
- this.resumeTime = now - this.startTime - this.startDelay;
743
+ this.resumeTime = now + this.resumeTime - this.startTime;
707
744
  this.isPausing = true;
708
745
  await this.playPromise;
709
- this.isPausing = false;
710
- this.isPaused = true;
711
746
  }
712
747
  async resume() {
713
748
  if (!this.isPaused)
714
749
  return;
715
750
  this.playPromise = this.playNotes();
716
751
  await this.playPromise;
717
- this.isPaused = false;
718
752
  }
719
753
  seekTo(second) {
720
754
  this.resumeTime = second;
@@ -737,19 +771,23 @@ export class MidyGMLite {
737
771
  const now = this.audioContext.currentTime;
738
772
  return now + this.resumeTime - this.startTime;
739
773
  }
740
- processScheduledNotes(channel, callback) {
774
+ async processScheduledNotes(channel, callback) {
741
775
  const scheduledNotes = channel.scheduledNotes;
776
+ const tasks = [];
742
777
  for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
743
778
  const note = scheduledNotes[i];
744
779
  if (!note)
745
780
  continue;
746
781
  if (note.ending)
747
782
  continue;
748
- callback(note);
783
+ const task = note.ready.then(() => callback(note));
784
+ tasks.push(task);
749
785
  }
786
+ await Promise.all(tasks);
750
787
  }
751
- processActiveNotes(channel, scheduleTime, callback) {
788
+ async processActiveNotes(channel, scheduleTime, callback) {
752
789
  const scheduledNotes = channel.scheduledNotes;
790
+ const tasks = [];
753
791
  for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
754
792
  const note = scheduledNotes[i];
755
793
  if (!note)
@@ -758,8 +796,10 @@ export class MidyGMLite {
758
796
  continue;
759
797
  if (scheduleTime < note.startTime)
760
798
  break;
761
- callback(note);
799
+ const task = note.ready.then(() => callback(note));
800
+ tasks.push(task);
762
801
  }
802
+ await Promise.all(tasks);
763
803
  }
764
804
  cbToRatio(cb) {
765
805
  return Math.pow(10, cb / 200);
@@ -918,12 +958,18 @@ export class MidyGMLite {
918
958
  this.setFilterEnvelope(note, now);
919
959
  this.setPitchEnvelope(note, now);
920
960
  this.updateDetune(channel, note, now);
921
- if (0 < state.modulationDepth) {
961
+ if (0 < state.modulationDepthMSB) {
922
962
  this.startModulation(channel, note, now);
923
963
  }
924
964
  note.bufferSource.connect(note.filterNode);
925
965
  note.filterNode.connect(note.volumeEnvelopeNode);
926
- note.bufferSource.start(startTime);
966
+ if (voiceParams.sample.type === "compressed") {
967
+ const offset = voiceParams.start / audioBuffer.sampleRate;
968
+ note.bufferSource.start(startTime, offset);
969
+ }
970
+ else {
971
+ note.bufferSource.start(startTime);
972
+ }
927
973
  return note;
928
974
  }
929
975
  handleExclusiveClass(note, channelNumber, startTime) {
@@ -989,11 +1035,7 @@ export class MidyGMLite {
989
1035
  return;
990
1036
  await this.setNoteAudioNode(channel, note, realtime);
991
1037
  this.setNoteRouting(channelNumber, note, startTime);
992
- note.pending = false;
993
- const off = note.offEvent;
994
- if (off) {
995
- this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
996
- }
1038
+ note.resolveReady();
997
1039
  }
998
1040
  disconnectNote(note) {
999
1041
  note.bufferSource.disconnect();
@@ -1027,7 +1069,7 @@ export class MidyGMLite {
1027
1069
  }, stopTime);
1028
1070
  });
1029
1071
  }
1030
- noteOff(channelNumber, noteNumber, velocity, endTime, force) {
1072
+ async noteOff(channelNumber, noteNumber, _velocity, endTime, force) {
1031
1073
  const channel = this.channels[channelNumber];
1032
1074
  if (!force) {
1033
1075
  if (channel.isDrum)
@@ -1039,13 +1081,13 @@ export class MidyGMLite {
1039
1081
  if (index < 0)
1040
1082
  return;
1041
1083
  const note = channel.scheduledNotes[index];
1042
- if (note.pending) {
1043
- note.offEvent = { velocity, startTime: endTime };
1044
- return;
1045
- }
1046
1084
  note.ending = true;
1047
1085
  this.setNoteIndex(channel, index);
1048
- this.releaseNote(channel, note, endTime);
1086
+ const promise = note.ready.then(() => {
1087
+ return this.releaseNote(channel, note, endTime);
1088
+ });
1089
+ this.notePromises.push(promise);
1090
+ return promise;
1049
1091
  }
1050
1092
  setNoteIndex(channel, index) {
1051
1093
  let allEnds = true;
@@ -1131,7 +1173,8 @@ export class MidyGMLite {
1131
1173
  }
1132
1174
  setPitchBend(channelNumber, value, scheduleTime) {
1133
1175
  const channel = this.channels[channelNumber];
1134
- scheduleTime ??= this.audioContext.currentTime;
1176
+ if (!(0 <= scheduleTime))
1177
+ scheduleTime = this.audioContext.currentTime;
1135
1178
  const state = channel.state;
1136
1179
  const prev = state.pitchWheel * 2 - 1;
1137
1180
  const next = (value - 8192) / 8192;
@@ -1143,11 +1186,12 @@ export class MidyGMLite {
1143
1186
  setModLfoToPitch(channel, note, scheduleTime) {
1144
1187
  if (note.modulationDepth) {
1145
1188
  const modLfoToPitch = note.voiceParams.modLfoToPitch;
1146
- const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
1147
- const modulationDepth = baseDepth * Math.sign(modLfoToPitch);
1189
+ const baseDepth = Math.abs(modLfoToPitch) +
1190
+ channel.state.modulationDepthMSB;
1191
+ const depth = baseDepth * Math.sign(modLfoToPitch);
1148
1192
  note.modulationDepth.gain
1149
1193
  .cancelScheduledValues(scheduleTime)
1150
- .setValueAtTime(modulationDepth, scheduleTime);
1194
+ .setValueAtTime(depth, scheduleTime);
1151
1195
  }
1152
1196
  else {
1153
1197
  this.startModulation(channel, note, scheduleTime);
@@ -1184,18 +1228,18 @@ export class MidyGMLite {
1184
1228
  createVoiceParamsHandlers() {
1185
1229
  return {
1186
1230
  modLfoToPitch: (channel, note, scheduleTime) => {
1187
- if (0 < channel.state.modulationDepth) {
1231
+ if (0 < channel.state.modulationDepthMSB) {
1188
1232
  this.setModLfoToPitch(channel, note, scheduleTime);
1189
1233
  }
1190
1234
  },
1191
1235
  vibLfoToPitch: (_channel, _note, _scheduleTime) => { },
1192
1236
  modLfoToFilterFc: (channel, note, scheduleTime) => {
1193
- if (0 < channel.state.modulationDepth) {
1237
+ if (0 < channel.state.modulationDepthMSB) {
1194
1238
  this.setModLfoToFilterFc(note, scheduleTime);
1195
1239
  }
1196
1240
  },
1197
1241
  modLfoToVolume: (channel, note, scheduleTime) => {
1198
- if (0 < channel.state.modulationDepth) {
1242
+ if (0 < channel.state.modulationDepthMSB) {
1199
1243
  this.setModLfoToVolume(note, scheduleTime);
1200
1244
  }
1201
1245
  },
@@ -1294,12 +1338,14 @@ export class MidyGMLite {
1294
1338
  }
1295
1339
  setModulationDepth(channelNumber, modulation, scheduleTime) {
1296
1340
  const channel = this.channels[channelNumber];
1297
- scheduleTime ??= this.audioContext.currentTime;
1341
+ if (!(0 <= scheduleTime))
1342
+ scheduleTime = this.audioContext.currentTime;
1298
1343
  channel.state.modulationDepth = modulation / 127;
1299
1344
  this.updateModulation(channel, scheduleTime);
1300
1345
  }
1301
1346
  setVolume(channelNumber, volume, scheduleTime) {
1302
- scheduleTime ??= this.audioContext.currentTime;
1347
+ if (!(0 <= scheduleTime))
1348
+ scheduleTime = this.audioContext.currentTime;
1303
1349
  const channel = this.channels[channelNumber];
1304
1350
  channel.state.volume = volume / 127;
1305
1351
  this.updateChannelVolume(channel, scheduleTime);
@@ -1312,13 +1358,15 @@ export class MidyGMLite {
1312
1358
  };
1313
1359
  }
1314
1360
  setPan(channelNumber, pan, scheduleTime) {
1315
- scheduleTime ??= this.audioContext.currentTime;
1361
+ if (!(0 <= scheduleTime))
1362
+ scheduleTime = this.audioContext.currentTime;
1316
1363
  const channel = this.channels[channelNumber];
1317
1364
  channel.state.pan = pan / 127;
1318
1365
  this.updateChannelVolume(channel, scheduleTime);
1319
1366
  }
1320
1367
  setExpression(channelNumber, expression, scheduleTime) {
1321
- scheduleTime ??= this.audioContext.currentTime;
1368
+ if (!(0 <= scheduleTime))
1369
+ scheduleTime = this.audioContext.currentTime;
1322
1370
  const channel = this.channels[channelNumber];
1323
1371
  channel.state.expression = expression / 127;
1324
1372
  this.updateChannelVolume(channel, scheduleTime);
@@ -1340,7 +1388,8 @@ export class MidyGMLite {
1340
1388
  }
1341
1389
  setSustainPedal(channelNumber, value, scheduleTime) {
1342
1390
  const channel = this.channels[channelNumber];
1343
- scheduleTime ??= this.audioContext.currentTime;
1391
+ if (!(0 <= scheduleTime))
1392
+ scheduleTime = this.audioContext.currentTime;
1344
1393
  channel.state.sustainPedal = value / 127;
1345
1394
  if (64 <= value) {
1346
1395
  this.processScheduledNotes(channel, (note) => {
@@ -1398,7 +1447,8 @@ export class MidyGMLite {
1398
1447
  }
1399
1448
  setPitchBendRange(channelNumber, value, scheduleTime) {
1400
1449
  const channel = this.channels[channelNumber];
1401
- scheduleTime ??= this.audioContext.currentTime;
1450
+ if (!(0 <= scheduleTime))
1451
+ scheduleTime = this.audioContext.currentTime;
1402
1452
  const state = channel.state;
1403
1453
  const prev = state.pitchWheelSensitivity;
1404
1454
  const next = value / 12800;
@@ -1408,7 +1458,8 @@ export class MidyGMLite {
1408
1458
  this.applyVoiceParams(channel, 16, scheduleTime);
1409
1459
  }
1410
1460
  allSoundOff(channelNumber, _value, scheduleTime) {
1411
- scheduleTime ??= this.audioContext.currentTime;
1461
+ if (!(0 <= scheduleTime))
1462
+ scheduleTime = this.audioContext.currentTime;
1412
1463
  return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
1413
1464
  }
1414
1465
  resetChannelStates(channelNumber) {
@@ -1433,8 +1484,8 @@ export class MidyGMLite {
1433
1484
  resetAllControllers(channelNumber, _value, scheduleTime) {
1434
1485
  const keys = [
1435
1486
  "pitchWheel",
1436
- "expression",
1437
- "modulationDepth",
1487
+ "expressionMSB",
1488
+ "modulationDepthMSB",
1438
1489
  "sustainPedal",
1439
1490
  ];
1440
1491
  const channel = this.channels[channelNumber];
@@ -1460,7 +1511,8 @@ export class MidyGMLite {
1460
1511
  }
1461
1512
  }
1462
1513
  allNotesOff(channelNumber, _value, scheduleTime) {
1463
- scheduleTime ??= this.audioContext.currentTime;
1514
+ if (!(0 <= scheduleTime))
1515
+ scheduleTime = this.audioContext.currentTime;
1464
1516
  return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
1465
1517
  }
1466
1518
  handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
@@ -1481,7 +1533,8 @@ export class MidyGMLite {
1481
1533
  }
1482
1534
  }
1483
1535
  GM1SystemOn(scheduleTime) {
1484
- scheduleTime ??= this.audioContext.currentTime;
1536
+ if (!(0 <= scheduleTime))
1537
+ scheduleTime = this.audioContext.currentTime;
1485
1538
  this.mode = "GM1";
1486
1539
  for (let i = 0; i < this.channels.length; i++) {
1487
1540
  this.allSoundOff(i, 0, scheduleTime);
@@ -1509,7 +1562,8 @@ export class MidyGMLite {
1509
1562
  this.setMasterVolume(volume, scheduleTime);
1510
1563
  }
1511
1564
  setMasterVolume(value, scheduleTime) {
1512
- scheduleTime ??= this.audioContext.currentTime;
1565
+ if (!(0 <= scheduleTime))
1566
+ scheduleTime = this.audioContext.currentTime;
1513
1567
  this.masterVolume.gain
1514
1568
  .cancelScheduledValues(scheduleTime)
1515
1569
  .setValueAtTime(value * value, scheduleTime);
package/esm/midy.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export class Midy {
1
+ export class Midy extends EventTarget {
2
2
  static channelSettings: {
3
3
  scheduleIndex: number;
4
4
  detune: number;
@@ -13,6 +13,7 @@ export class Midy {
13
13
  modulationDepthRange: number;
14
14
  fineTuning: number;
15
15
  coarseTuning: number;
16
+ portamentoControl: boolean;
16
17
  };
17
18
  constructor(audioContext: any);
18
19
  mode: string;
@@ -50,6 +51,8 @@ export class Midy {
50
51
  isPaused: boolean;
51
52
  isStopping: boolean;
52
53
  isSeeking: boolean;
54
+ loop: boolean;
55
+ loopStart: number;
53
56
  playPromise: any;
54
57
  timeline: any[];
55
58
  notePromises: any[];
@@ -105,7 +108,7 @@ export class Midy {
105
108
  createAudioBuffer(voiceParams: any): Promise<any>;
106
109
  isLoopDrum(channel: any, noteNumber: any): boolean;
107
110
  createBufferSource(channel: any, noteNumber: any, voiceParams: any, audioBuffer: any): any;
108
- scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
111
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): any;
109
112
  getQueueIndex(second: any): number;
110
113
  resetAllStates(): void;
111
114
  updateStates(queueIndex: any, nextQueueIndex: any): void;
@@ -127,8 +130,8 @@ export class Midy {
127
130
  seekTo(second: any): void;
128
131
  calcTotalTime(): number;
129
132
  currentTime(): number;
130
- processScheduledNotes(channel: any, callback: any): void;
131
- processActiveNotes(channel: any, scheduleTime: any, callback: any): void;
133
+ processScheduledNotes(channel: any, callback: any): Promise<void>;
134
+ processActiveNotes(channel: any, scheduleTime: any, callback: any): Promise<void>;
132
135
  createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
133
136
  createConvolutionReverb(audioContext: any, impulse: any): {
134
137
  input: any;
@@ -182,11 +185,11 @@ export class Midy {
182
185
  noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
183
186
  disconnectNote(note: any): void;
184
187
  releaseNote(channel: any, note: any, endTime: any): Promise<any>;
185
- noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): void;
188
+ noteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): any;
186
189
  setNoteIndex(channel: any, index: any): void;
187
190
  findNoteOffIndex(channel: any, noteNumber: any): any;
188
- releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
189
- releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
191
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): any[];
192
+ releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): any[];
190
193
  createMessageHandlers(): any[];
191
194
  handleMessage(data: any, scheduleTime: any): void;
192
195
  activeSensing(): void;
@@ -223,16 +226,16 @@ export class Midy {
223
226
  setControlChange(channelNumber: any, controllerType: any, value: any, scheduleTime: any): void;
224
227
  setBankMSB(channelNumber: any, msb: any): void;
225
228
  updateModulation(channel: any, scheduleTime: any): void;
226
- setModulationDepth(channelNumber: any, modulation: any, scheduleTime: any): void;
229
+ setModulationDepth(channelNumber: any, value: any, scheduleTime: any): void;
227
230
  updatePortamento(channel: any, scheduleTime: any): void;
228
- setPortamentoTime(channelNumber: any, portamentoTime: any, scheduleTime: any): void;
229
- setVolume(channelNumber: any, volume: any, scheduleTime: any): void;
231
+ setPortamentoTime(channelNumber: any, value: any, scheduleTime: any): void;
232
+ setVolume(channelNumber: any, value: any, scheduleTime: any): void;
230
233
  panToGain(pan: any): {
231
234
  gainLeft: number;
232
235
  gainRight: number;
233
236
  };
234
- setPan(channelNumber: any, pan: any, scheduleTime: any): void;
235
- setExpression(channelNumber: any, expression: any, scheduleTime: any): void;
237
+ setPan(channelNumber: any, value: any, scheduleTime: any): void;
238
+ setExpression(channelNumber: any, value: any, scheduleTime: any): void;
236
239
  setBankLSB(channelNumber: any, lsb: any): void;
237
240
  dataEntryLSB(channelNumber: any, value: any, scheduleTime: any): void;
238
241
  updateChannelVolume(channel: any, scheduleTime: any): void;
@@ -252,6 +255,7 @@ export class Midy {
252
255
  setVibratoRate(channelNumber: any, vibratoRate: any, scheduleTime: any): void;
253
256
  setVibratoDepth(channelNumber: any, vibratoDepth: any, scheduleTime: any): void;
254
257
  setVibratoDelay(channelNumber: any, vibratoDelay: any, scheduleTime: any): void;
258
+ setPortamentoNoteNumber(channelNumber: any, value: any, scheduleTime: any): void;
255
259
  setReverbSendLevel(channelNumber: any, reverbSendLevel: any, scheduleTime: any): void;
256
260
  setChorusSendLevel(channelNumber: any, chorusSendLevel: any, scheduleTime: any): void;
257
261
  limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
@@ -270,6 +274,7 @@ export class Midy {
270
274
  setCoarseTuning(channelNumber: any, value: any, scheduleTime: any): void;
271
275
  handleModulationDepthRangeRPN(channelNumber: any, scheduleTime: any): void;
272
276
  setModulationDepthRange(channelNumber: any, value: any, scheduleTime: any): void;
277
+ setRPGMakerLoop(_channelNumber: any, _value: any, scheduleTime: any): void;
273
278
  allSoundOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
274
279
  resetChannelStates(channelNumber: any): void;
275
280
  resetAllControllers(channelNumber: any, _value: any, scheduleTime: 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":"AA6JA;IA6CE;;;;;;;;;;;;;;MAcE;IAEF,+BAoBC;IAhFD,aAAa;IACb,yBAAqB;IACrB,2BAAuB;IACvB;;;;MAIE;IACF;;;;;;MAME;IACF,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAsB;IACtB,+BAA6B;IAC7B,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,kCAA+B;IAC/B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IACrC,+BAEE;IAmBA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,kCAAyE;IACzE,gBAAiD;IACjD;;;kBAAyD;IACzD;;;;;;;;MAAyD;IAQ3D,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAYC;IAED;;;;MAeC;IAED,sCAMC;IAED,yCAqBC;IAED,kDAUC;IAED,mDAIC;IAED,2FAWC;IAED,yEAgEC;IAED,mCAOC;IAED,uBASC;IAED,yDA2BC;IAED,2BAkDC;IAED,uDAEC;IAED,wDAEC;IAED,qCAMC;IAED;;;MAqFC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAIC;IAED,yDAQC;IAED,yEASC;IAED,kFAuBC;IAED;;;;MASC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA8BC;IAED;;;kBA6BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAkBC;IAED,6CAEC;IAED,2DAIC;IAED,+DAiBC;IAED,mDAIC;IAED,2CAoDC;IAED,8EAYC;IAED,oEAkBC;IAED,+DAKC;IAED,qDAoBC;IAED,6CAIC;IAED,8EAqBC;IAED,oEAyBC;IAED,kEAoBC;IAED,+DAcC;IAED,4GAkCC;IAED,uEA6DC;IAED,0EAiBC;IAED,8EAoBC;IAED,oEAuBC;IAED,0FAyBC;IAED,gCAmBC;IAED,iEAsBC;IAED,4FA2BC;IAED,6CAUC;IAED,qDAUC;IAED,sFAeC;IAED,wFAkBC;IAED,+BAyCC;IAED,kDAOC;IAED,sBAEC;IAED,sGAeC;IAED,mFAcC;IAED,4EAgBC;IAED,wFAGC;IAED,sEAWC;IAED,mEAYC;IAED,mEAaC;IAED,sEAMC;IAED,oEAQC;IAED,gEAyBC;IAED,gEAyBC;IAED,gCAKC;IAED,kDAKC;IAED,gEAMC;IAED,8CAOC;IAED;;;;;;;;;;;MAiDC;IAED,gHAQC;IAED,6EAgCC;IAED,qCAqCC;IAED,+FAYC;IAED,+CAEC;IAED,wDASC;IAED,iFAMC;IAED,wDAeC;IAED,oFAMC;IAED,oEAWC;IAED;;;MAMC;IAED,8DAWC;IAED,4EAKC;IAED,+CAEC;IAED,sEAGC;IAED,2DAUC;IAED,4EAoBC;IAED,yEAYC;IAED,+CAEC;IAED,uEAMC;IAED,2EAcC;IAED,oDAEC;IAED,0EAeC;IAED,8EAWC;IAED,4EAUC;IAED,8EAKC;IAED,4EAUC;IAED,4EAaC;IAED,0EAQC;IAED,8EASC;IAED,gFAeC;IAED,gFAUC;IAED,sFAQC;IAED,sFAQC;IAED,kFAeC;IAED,2DAMC;IAED,mEAyBC;IAGD,2DAGC;IAGD,2DAGC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAWC;IAED,iEAMC;IAED,uEASC;IAED,mEAKC;IAED,yEASC;IAED,2EAKC;IAED,iFAMC;IAED,gFAGC;IAED,6CAwBC;IAGD,8EAqCC;IAED,gFAGC;IAED,iEAEC;IAED,gEAEC;IAED,gEAIC;IAED,gEAIC;IAED,+EAuCC;IAED,qCAYC;IAED,qCAYC;IAED,4EAqEC;IAED,4DAGC;IAED,qDAKC;IAED,gEAIC;IAED,yDAWC;IAED,kEAGC;IAED,2DAWC;IAED,sEAeC;IAED,4CAOC;IAED,+BAIC;IAED,qDAiBC;IAED,gCAGC;IAED,kCAEC;IA6BD,4CAEC;IAED,+DAaC;IAED,kDAiBC;IAED,2GAKC;IAED,sDAIC;IAED,qCAEC;IAED,uDAMC;IAED,sCAEC;IAED,uDASC;IAED,sCAEC;IAED,2DAqBC;IAED,0CAEC;IAED,mCAeC;IAED,2FAgBC;IAED,2FAoBC;IAED,iDAMC;IAED,wDAUC;IAED,qDAUC;IAED,kDAUC;IAED,mDAUC;IAED,sDAUC;IAED,yEAgBC;IAED,wEAaC;IAED,2CAIC;IAED,oFAOC;IAED,6DAcC;IAED,yEAIC;IAED,0CAuEC;IAED,yEAcC;IAED,gDAYC;IAGD,6DAgBC;CACF"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}