@marmooo/midy 0.4.1 → 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.
package/README.md CHANGED
@@ -65,6 +65,7 @@ await midy.start();
65
65
  ### Playback
66
66
 
67
67
  ```js
68
+ midy.loop = true;
68
69
  await midy.start();
69
70
  await midy.stop();
70
71
  await midy.pause();
@@ -72,6 +73,17 @@ await midy.resume();
72
73
  midy.seekTo(second);
73
74
  ```
74
75
 
76
+ ### Events
77
+
78
+ ```js
79
+ midy.addEventListener("looped", func);
80
+ midy.addEventListener("started", func);
81
+ midy.addEventListener("stopped", func);
82
+ midy.addEventListener("paused", func);
83
+ midy.addEventListener("resumed", func);
84
+ midy.addEventListener("seeked", func);
85
+ ```
86
+
75
87
  ### MIDI Message
76
88
 
77
89
  There are functions that handle MIDI messages as they are, as well as simplified
package/esm/midy-GM1.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export class MidyGM1 {
1
+ export class MidyGM1 extends EventTarget {
2
2
  static channelSettings: {
3
3
  scheduleIndex: number;
4
4
  detune: number;
@@ -31,6 +31,7 @@ export class MidyGM1 {
31
31
  isPaused: boolean;
32
32
  isStopping: boolean;
33
33
  isSeeking: boolean;
34
+ loop: boolean;
34
35
  playPromise: any;
35
36
  timeline: any[];
36
37
  notePromises: any[];
@@ -69,7 +70,7 @@ export class MidyGM1 {
69
70
  createChannels(audioContext: any): any[];
70
71
  createAudioBuffer(voiceParams: any): Promise<any>;
71
72
  createBufferSource(voiceParams: any, audioBuffer: any): any;
72
- scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
73
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): any;
73
74
  getQueueIndex(second: any): number;
74
75
  resetAllStates(): void;
75
76
  updateStates(queueIndex: any, nextQueueIndex: any): void;
@@ -91,8 +92,8 @@ export class MidyGM1 {
91
92
  seekTo(second: any): void;
92
93
  calcTotalTime(): number;
93
94
  currentTime(): number;
94
- processScheduledNotes(channel: any, callback: any): void;
95
- processActiveNotes(channel: any, scheduleTime: any, callback: any): void;
95
+ processScheduledNotes(channel: any, callback: any): Promise<void>;
96
+ processActiveNotes(channel: any, scheduleTime: any, callback: any): Promise<void>;
96
97
  cbToRatio(cb: any): number;
97
98
  rateToCent(rate: any): number;
98
99
  centToRate(cent: any): number;
@@ -112,13 +113,13 @@ export class MidyGM1 {
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): Promise<any> | undefined;
116
+ noteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): 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): (Promise<any> | undefined)[];
119
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): 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<any>;
122
+ handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): 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-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AA6FA;IA0BE;;;;;;;;;;;MAWE;IAEF,+BAeC;IArDD,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;IAgBnC,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,4DASC;IAED,yEAoDC;IAED,mCAOC;IAED,uBASC;IAED,yDA2BC;IAED,2BA8CC;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,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,4GAkCC;IAED,uEAwCC;IAED,0EAiBC;IAED,oEASC;IAED,0FAwBC;IAED,gCASC;IAED,iEAqBC;IAED,gHAqBC;IAED,6CAUC;IAED,qDAUC;IAED,4GAeC;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,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAMC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;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-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AA+FA;IA2BE;;;;;;;;;;;MAWE;IAEF,+BAgBC;IAvDD,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;IAiBnC,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,4DASC;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,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,4GAkCC;IAED,uEAwCC;IAED,0EAiBC;IAED,oEASC;IAED,0FAoBC;IAED,gCASC;IAED,iEAqBC;IAED,4FAmBC;IAED,6CAUC;IAED,qDAUC;IAED,qFAeC;IAED,+BAmBC;IAED,kDAOC;IAED,sFA2BC;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,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAMC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF"}
package/esm/midy-GM1.js CHANGED
@@ -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
  // normalized to 0-1 for use with the SF2 modulator model
@@ -150,8 +147,9 @@ const pitchEnvelopeKeys = [
150
147
  "playbackRate",
151
148
  ];
152
149
  const pitchEnvelopeKeySet = new Set(pitchEnvelopeKeys);
153
- export class MidyGM1 {
150
+ export class MidyGM1 extends EventTarget {
154
151
  constructor(audioContext) {
152
+ super();
155
153
  Object.defineProperty(this, "mode", {
156
154
  enumerable: true,
157
155
  configurable: true,
@@ -266,6 +264,12 @@ export class MidyGM1 {
266
264
  writable: true,
267
265
  value: false
268
266
  });
267
+ Object.defineProperty(this, "loop", {
268
+ enumerable: true,
269
+ configurable: true,
270
+ writable: true,
271
+ value: false
272
+ });
269
273
  Object.defineProperty(this, "playPromise", {
270
274
  enumerable: true,
271
275
  configurable: true,
@@ -453,7 +457,7 @@ export class MidyGM1 {
453
457
  }
454
458
  return bufferSource;
455
459
  }
456
- async scheduleTimelineEvents(scheduleTime, queueIndex) {
460
+ scheduleTimelineEvents(scheduleTime, queueIndex) {
457
461
  const timeOffset = this.resumeTime - this.startTime;
458
462
  const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
459
463
  const schedulingOffset = this.startDelay - timeOffset;
@@ -465,7 +469,7 @@ export class MidyGM1 {
465
469
  const startTime = event.startTime + schedulingOffset;
466
470
  switch (event.type) {
467
471
  case "noteOn":
468
- await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
472
+ this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
469
473
  break;
470
474
  case "noteOff": {
471
475
  this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
@@ -506,22 +510,23 @@ export class MidyGM1 {
506
510
  }
507
511
  }
508
512
  updateStates(queueIndex, nextQueueIndex) {
513
+ const now = this.audioContext.currentTime;
509
514
  if (nextQueueIndex < queueIndex)
510
515
  queueIndex = 0;
511
516
  for (let i = queueIndex; i < nextQueueIndex; i++) {
512
517
  const event = this.timeline[i];
513
518
  switch (event.type) {
514
519
  case "controller":
515
- this.setControlChange(event.channel, event.controllerType, event.value, 0);
520
+ this.setControlChange(event.channel, event.controllerType, event.value, now - this.resumeTime + event.startTime);
516
521
  break;
517
522
  case "programChange":
518
- this.setProgramChange(event.channel, event.programNumber, 0);
523
+ this.setProgramChange(event.channel, event.programNumber, now - this.resumeTime + event.startTime);
519
524
  break;
520
525
  case "pitchBend":
521
- this.setPitchBend(event.channel, event.value + 8192, 0);
526
+ this.setPitchBend(event.channel, event.value + 8192, now - this.resumeTime + event.startTime);
522
527
  break;
523
528
  case "sysEx":
524
- this.handleSysEx(event.data, 0);
529
+ this.handleSysEx(event.data, now - this.resumeTime + event.startTime);
525
530
  }
526
531
  }
527
532
  }
@@ -529,50 +534,80 @@ export class MidyGM1 {
529
534
  if (this.audioContext.state === "suspended") {
530
535
  await this.audioContext.resume();
531
536
  }
537
+ const paused = this.isPaused;
532
538
  this.isPlaying = true;
533
539
  this.isPaused = false;
534
540
  this.startTime = this.audioContext.currentTime;
541
+ if (paused) {
542
+ this.dispatchEvent(new Event("resumed"));
543
+ }
544
+ else {
545
+ this.dispatchEvent(new Event("started"));
546
+ }
535
547
  let queueIndex = this.getQueueIndex(this.resumeTime);
536
- let finished = false;
548
+ let exitReason;
537
549
  this.notePromises = [];
538
- while (queueIndex < this.timeline.length) {
550
+ while (true) {
539
551
  const now = this.audioContext.currentTime;
552
+ if (this.timeline.length <= queueIndex) {
553
+ await this.stopNotes(0, true, now);
554
+ if (this.loop) {
555
+ this.notePromises = [];
556
+ this.resetAllStates();
557
+ this.startTime = this.audioContext.currentTime;
558
+ this.resumeTime = 0;
559
+ queueIndex = 0;
560
+ this.dispatchEvent(new Event("looped"));
561
+ continue;
562
+ }
563
+ else {
564
+ await this.audioContext.suspend();
565
+ exitReason = "ended";
566
+ break;
567
+ }
568
+ }
540
569
  if (this.isPausing) {
541
570
  await this.stopNotes(0, true, now);
542
571
  await this.audioContext.suspend();
543
572
  this.notePromises = [];
573
+ this.isPausing = false;
574
+ exitReason = "paused";
544
575
  break;
545
576
  }
546
577
  else if (this.isStopping) {
547
578
  await this.stopNotes(0, true, now);
548
579
  await this.audioContext.suspend();
549
- finished = true;
580
+ this.isStopping = false;
581
+ exitReason = "stopped";
550
582
  break;
551
583
  }
552
584
  else if (this.isSeeking) {
553
- await this.stopNotes(0, true, now);
585
+ this.stopNotes(0, true, now);
554
586
  this.startTime = this.audioContext.currentTime;
555
587
  const nextQueueIndex = this.getQueueIndex(this.resumeTime);
556
588
  this.updateStates(queueIndex, nextQueueIndex);
557
589
  queueIndex = nextQueueIndex;
558
590
  this.isSeeking = false;
591
+ this.dispatchEvent(new Event("seeked"));
559
592
  continue;
560
593
  }
561
- queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
594
+ queueIndex = this.scheduleTimelineEvents(now, queueIndex);
562
595
  const waitTime = now + this.noteCheckInterval;
563
596
  await this.scheduleTask(() => { }, waitTime);
564
597
  }
565
- if (this.timeline.length <= queueIndex) {
566
- const now = this.audioContext.currentTime;
567
- await this.stopNotes(0, true, now);
568
- await this.audioContext.suspend();
569
- finished = true;
570
- }
571
- if (finished) {
598
+ if (exitReason !== "paused") {
572
599
  this.notePromises = [];
573
600
  this.resetAllStates();
574
601
  }
575
602
  this.isPlaying = false;
603
+ if (exitReason === "paused") {
604
+ this.isPaused = true;
605
+ this.dispatchEvent(new Event("paused"));
606
+ }
607
+ else {
608
+ this.isPaused = false;
609
+ this.dispatchEvent(new Event(exitReason));
610
+ }
576
611
  }
577
612
  ticksToSecond(ticks, secondsPerBeat) {
578
613
  return ticks * secondsPerBeat / this.ticksPerBeat;
@@ -679,24 +714,20 @@ export class MidyGM1 {
679
714
  return;
680
715
  this.isStopping = true;
681
716
  await this.playPromise;
682
- this.isStopping = false;
683
717
  }
684
718
  async pause() {
685
719
  if (!this.isPlaying || this.isPaused)
686
720
  return;
687
721
  const now = this.audioContext.currentTime;
688
- this.resumeTime = now - this.startTime - this.startDelay;
722
+ this.resumeTime = now + this.resumeTime - this.startTime;
689
723
  this.isPausing = true;
690
724
  await this.playPromise;
691
- this.isPausing = false;
692
- this.isPaused = true;
693
725
  }
694
726
  async resume() {
695
727
  if (!this.isPaused)
696
728
  return;
697
729
  this.playPromise = this.playNotes();
698
730
  await this.playPromise;
699
- this.isPaused = false;
700
731
  }
701
732
  seekTo(second) {
702
733
  this.resumeTime = second;
@@ -719,19 +750,23 @@ export class MidyGM1 {
719
750
  const now = this.audioContext.currentTime;
720
751
  return now + this.resumeTime - this.startTime;
721
752
  }
722
- processScheduledNotes(channel, callback) {
753
+ async processScheduledNotes(channel, callback) {
723
754
  const scheduledNotes = channel.scheduledNotes;
755
+ const tasks = [];
724
756
  for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
725
757
  const note = scheduledNotes[i];
726
758
  if (!note)
727
759
  continue;
728
760
  if (note.ending)
729
761
  continue;
730
- callback(note);
762
+ const task = note.ready.then(() => callback(note));
763
+ tasks.push(task);
731
764
  }
765
+ await Promise.all(tasks);
732
766
  }
733
- processActiveNotes(channel, scheduleTime, callback) {
767
+ async processActiveNotes(channel, scheduleTime, callback) {
734
768
  const scheduledNotes = channel.scheduledNotes;
769
+ const tasks = [];
735
770
  for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
736
771
  const note = scheduledNotes[i];
737
772
  if (!note)
@@ -740,8 +775,10 @@ export class MidyGM1 {
740
775
  continue;
741
776
  if (scheduleTime < note.startTime)
742
777
  break;
743
- callback(note);
778
+ const task = note.ready.then(() => callback(note));
779
+ tasks.push(task);
744
780
  }
781
+ await Promise.all(tasks);
745
782
  }
746
783
  cbToRatio(cb) {
747
784
  return Math.pow(10, cb / 200);
@@ -963,11 +1000,7 @@ export class MidyGM1 {
963
1000
  return;
964
1001
  await this.setNoteAudioNode(channel, note, realtime);
965
1002
  this.setNoteRouting(channelNumber, note, startTime);
966
- note.pending = false;
967
- const off = note.offEvent;
968
- if (off) {
969
- this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
970
- }
1003
+ note.resolveReady();
971
1004
  }
972
1005
  disconnectNote(note) {
973
1006
  note.bufferSource.disconnect();
@@ -1001,7 +1034,7 @@ export class MidyGM1 {
1001
1034
  }, stopTime);
1002
1035
  });
1003
1036
  }
1004
- noteOff(channelNumber, noteNumber, velocity, endTime, force) {
1037
+ noteOff(channelNumber, noteNumber, _velocity, endTime, force) {
1005
1038
  const channel = this.channels[channelNumber];
1006
1039
  if (!force && 0.5 <= channel.state.sustainPedal)
1007
1040
  return;
@@ -1009,13 +1042,11 @@ export class MidyGM1 {
1009
1042
  if (index < 0)
1010
1043
  return;
1011
1044
  const note = channel.scheduledNotes[index];
1012
- if (note.pending) {
1013
- note.offEvent = { velocity, startTime: endTime };
1014
- return;
1015
- }
1016
1045
  note.ending = true;
1017
1046
  this.setNoteIndex(channel, index);
1018
- const promise = this.releaseNote(channel, note, endTime);
1047
+ const promise = note.ready.then(() => {
1048
+ return this.releaseNote(channel, note, endTime);
1049
+ });
1019
1050
  this.notePromises.push(promise);
1020
1051
  return promise;
1021
1052
  }
@@ -1103,7 +1134,8 @@ export class MidyGM1 {
1103
1134
  }
1104
1135
  setPitchBend(channelNumber, value, scheduleTime) {
1105
1136
  const channel = this.channels[channelNumber];
1106
- scheduleTime ??= this.audioContext.currentTime;
1137
+ if (!(0 <= scheduleTime))
1138
+ scheduleTime = this.audioContext.currentTime;
1107
1139
  const state = channel.state;
1108
1140
  const prev = state.pitchWheel * 2 - 1;
1109
1141
  const next = (value - 8192) / 8192;
@@ -1268,12 +1300,14 @@ export class MidyGM1 {
1268
1300
  }
1269
1301
  setModulationDepth(channelNumber, modulation, scheduleTime) {
1270
1302
  const channel = this.channels[channelNumber];
1271
- scheduleTime ??= this.audioContext.currentTime;
1303
+ if (!(0 <= scheduleTime))
1304
+ scheduleTime = this.audioContext.currentTime;
1272
1305
  channel.state.modulationDepthMSB = modulation / 127;
1273
1306
  this.updateModulation(channel, scheduleTime);
1274
1307
  }
1275
1308
  setVolume(channelNumber, volume, scheduleTime) {
1276
- scheduleTime ??= this.audioContext.currentTime;
1309
+ if (!(0 <= scheduleTime))
1310
+ scheduleTime = this.audioContext.currentTime;
1277
1311
  const channel = this.channels[channelNumber];
1278
1312
  channel.state.volumeMSB = volume / 127;
1279
1313
  this.updateChannelVolume(channel, scheduleTime);
@@ -1286,13 +1320,15 @@ export class MidyGM1 {
1286
1320
  };
1287
1321
  }
1288
1322
  setPan(channelNumber, pan, scheduleTime) {
1289
- scheduleTime ??= this.audioContext.currentTime;
1323
+ if (!(0 <= scheduleTime))
1324
+ scheduleTime = this.audioContext.currentTime;
1290
1325
  const channel = this.channels[channelNumber];
1291
1326
  channel.state.panMSB = pan / 127;
1292
1327
  this.updateChannelVolume(channel, scheduleTime);
1293
1328
  }
1294
1329
  setExpression(channelNumber, expression, scheduleTime) {
1295
- scheduleTime ??= this.audioContext.currentTime;
1330
+ if (!(0 <= scheduleTime))
1331
+ scheduleTime = this.audioContext.currentTime;
1296
1332
  const channel = this.channels[channelNumber];
1297
1333
  channel.state.expressionMSB = expression / 127;
1298
1334
  this.updateChannelVolume(channel, scheduleTime);
@@ -1314,7 +1350,8 @@ export class MidyGM1 {
1314
1350
  }
1315
1351
  setSustainPedal(channelNumber, value, scheduleTime) {
1316
1352
  const channel = this.channels[channelNumber];
1317
- scheduleTime ??= this.audioContext.currentTime;
1353
+ if (!(0 <= scheduleTime))
1354
+ scheduleTime = this.audioContext.currentTime;
1318
1355
  channel.state.sustainPedal = value / 127;
1319
1356
  if (64 <= value) {
1320
1357
  this.processScheduledNotes(channel, (note) => {
@@ -1386,7 +1423,8 @@ export class MidyGM1 {
1386
1423
  }
1387
1424
  setPitchBendRange(channelNumber, value, scheduleTime) {
1388
1425
  const channel = this.channels[channelNumber];
1389
- scheduleTime ??= this.audioContext.currentTime;
1426
+ if (!(0 <= scheduleTime))
1427
+ scheduleTime = this.audioContext.currentTime;
1390
1428
  const state = channel.state;
1391
1429
  const prev = state.pitchWheelSensitivity;
1392
1430
  const next = value / 12800;
@@ -1404,7 +1442,8 @@ export class MidyGM1 {
1404
1442
  }
1405
1443
  setFineTuning(channelNumber, value, scheduleTime) {
1406
1444
  const channel = this.channels[channelNumber];
1407
- scheduleTime ??= this.audioContext.currentTime;
1445
+ if (!(0 <= scheduleTime))
1446
+ scheduleTime = this.audioContext.currentTime;
1408
1447
  const prev = channel.fineTuning;
1409
1448
  const next = value;
1410
1449
  channel.fineTuning = next;
@@ -1419,7 +1458,8 @@ export class MidyGM1 {
1419
1458
  }
1420
1459
  setCoarseTuning(channelNumber, value, scheduleTime) {
1421
1460
  const channel = this.channels[channelNumber];
1422
- scheduleTime ??= this.audioContext.currentTime;
1461
+ if (!(0 <= scheduleTime))
1462
+ scheduleTime = this.audioContext.currentTime;
1423
1463
  const prev = channel.coarseTuning;
1424
1464
  const next = value;
1425
1465
  channel.coarseTuning = next;
@@ -1427,7 +1467,8 @@ export class MidyGM1 {
1427
1467
  this.updateChannelDetune(channel, scheduleTime);
1428
1468
  }
1429
1469
  allSoundOff(channelNumber, _value, scheduleTime) {
1430
- scheduleTime ??= this.audioContext.currentTime;
1470
+ if (!(0 <= scheduleTime))
1471
+ scheduleTime = this.audioContext.currentTime;
1431
1472
  return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
1432
1473
  }
1433
1474
  resetChannelStates(channelNumber) {
@@ -1479,7 +1520,8 @@ export class MidyGM1 {
1479
1520
  }
1480
1521
  }
1481
1522
  allNotesOff(channelNumber, _value, scheduleTime) {
1482
- scheduleTime ??= this.audioContext.currentTime;
1523
+ if (!(0 <= scheduleTime))
1524
+ scheduleTime = this.audioContext.currentTime;
1483
1525
  return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
1484
1526
  }
1485
1527
  handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
@@ -1500,7 +1542,8 @@ export class MidyGM1 {
1500
1542
  }
1501
1543
  }
1502
1544
  GM1SystemOn(scheduleTime) {
1503
- scheduleTime ??= this.audioContext.currentTime;
1545
+ if (!(0 <= scheduleTime))
1546
+ scheduleTime = this.audioContext.currentTime;
1504
1547
  this.mode = "GM1";
1505
1548
  for (let i = 0; i < this.channels.length; i++) {
1506
1549
  this.allSoundOff(i, 0, scheduleTime);
@@ -1528,7 +1571,8 @@ export class MidyGM1 {
1528
1571
  this.setMasterVolume(volume, scheduleTime);
1529
1572
  }
1530
1573
  setMasterVolume(value, scheduleTime) {
1531
- scheduleTime ??= this.audioContext.currentTime;
1574
+ if (!(0 <= scheduleTime))
1575
+ scheduleTime = this.audioContext.currentTime;
1532
1576
  this.masterVolume.gain
1533
1577
  .cancelScheduledValues(scheduleTime)
1534
1578
  .setValueAtTime(value * value, scheduleTime);
package/esm/midy-GM2.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export class MidyGM2 {
1
+ export class MidyGM2 extends EventTarget {
2
2
  static channelSettings: {
3
3
  scheduleIndex: number;
4
4
  detune: number;
@@ -50,6 +50,7 @@ export class MidyGM2 {
50
50
  isPaused: boolean;
51
51
  isStopping: boolean;
52
52
  isSeeking: boolean;
53
+ loop: boolean;
53
54
  playPromise: any;
54
55
  timeline: any[];
55
56
  notePromises: any[];
@@ -105,7 +106,7 @@ export class MidyGM2 {
105
106
  createAudioBuffer(voiceParams: any): Promise<any>;
106
107
  isLoopDrum(channel: any, noteNumber: any): boolean;
107
108
  createBufferSource(channel: any, noteNumber: any, voiceParams: any, audioBuffer: any): any;
108
- scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
109
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): any;
109
110
  getQueueIndex(second: any): number;
110
111
  resetAllStates(): void;
111
112
  updateStates(queueIndex: any, nextQueueIndex: any): void;
@@ -127,8 +128,8 @@ export class MidyGM2 {
127
128
  seekTo(second: any): void;
128
129
  calcTotalTime(): number;
129
130
  currentTime(): number;
130
- processScheduledNotes(channel: any, callback: any): void;
131
- processActiveNotes(channel: any, scheduleTime: any, callback: any): void;
131
+ processScheduledNotes(channel: any, callback: any): Promise<void>;
132
+ processActiveNotes(channel: any, scheduleTime: any, callback: any): Promise<void>;
132
133
  createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
133
134
  createConvolutionReverb(audioContext: any, impulse: any): {
134
135
  input: any;
@@ -182,11 +183,11 @@ export class MidyGM2 {
182
183
  noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
183
184
  disconnectNote(note: any): void;
184
185
  releaseNote(channel: any, note: any, endTime: any): Promise<any>;
185
- noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
186
+ noteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): any;
186
187
  setNoteIndex(channel: any, index: any): void;
187
188
  findNoteOffIndex(channel: any, noteNumber: any): any;
188
- releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
189
- releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
189
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): any[];
190
+ releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): any[];
190
191
  createMessageHandlers(): any[];
191
192
  handleMessage(data: any, scheduleTime: any): void;
192
193
  activeSensing(): void;
@@ -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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"}