@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"}
@@ -29,12 +29,6 @@ class Note {
29
29
  writable: true,
30
30
  value: false
31
31
  });
32
- Object.defineProperty(this, "pending", {
33
- enumerable: true,
34
- configurable: true,
35
- writable: true,
36
- value: true
37
- });
38
32
  Object.defineProperty(this, "bufferSource", {
39
33
  enumerable: true,
40
34
  configurable: true,
@@ -80,6 +74,9 @@ class Note {
80
74
  this.noteNumber = noteNumber;
81
75
  this.velocity = velocity;
82
76
  this.startTime = startTime;
77
+ this.ready = new Promise((resolve) => {
78
+ this.resolveReady = resolve;
79
+ });
83
80
  }
84
81
  }
85
82
  const drumExclusiveClasses = new Uint8Array(128);
@@ -102,11 +99,11 @@ const defaultControllerState = {
102
99
  pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
103
100
  pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
104
101
  link: { type: 127, defaultValue: 0 },
105
- modulationDepth: { type: 128 + 1, defaultValue: 0 },
102
+ modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
106
103
  // dataMSB: { type: 128 + 6, defaultValue: 0, },
107
- volume: { type: 128 + 7, defaultValue: 100 / 127 },
108
- pan: { type: 128 + 10, defaultValue: 64 / 127 },
109
- expression: { type: 128 + 11, defaultValue: 1 },
104
+ volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
105
+ panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
106
+ expressionMSB: { type: 128 + 11, defaultValue: 1 },
110
107
  // dataLSB: { type: 128 + 38, defaultValue: 0, },
111
108
  sustainPedal: { type: 128 + 64, defaultValue: 0 },
112
109
  // rpnLSB: { type: 128 + 100, defaultValue: 127 },
@@ -166,8 +163,9 @@ const pitchEnvelopeKeys = [
166
163
  "playbackRate",
167
164
  ];
168
165
  const pitchEnvelopeKeySet = new Set(pitchEnvelopeKeys);
169
- class MidyGMLite {
166
+ class MidyGMLite extends EventTarget {
170
167
  constructor(audioContext) {
168
+ super();
171
169
  Object.defineProperty(this, "mode", {
172
170
  enumerable: true,
173
171
  configurable: true,
@@ -282,6 +280,12 @@ class MidyGMLite {
282
280
  writable: true,
283
281
  value: false
284
282
  });
283
+ Object.defineProperty(this, "loop", {
284
+ enumerable: true,
285
+ configurable: true,
286
+ writable: true,
287
+ value: false
288
+ });
285
289
  Object.defineProperty(this, "playPromise", {
286
290
  enumerable: true,
287
291
  configurable: true,
@@ -432,7 +436,7 @@ class MidyGMLite {
432
436
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
433
437
  }
434
438
  createChannelAudioNodes(audioContext) {
435
- const { gainLeft, gainRight } = this.panToGain(defaultControllerState.pan.defaultValue);
439
+ const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
436
440
  const gainL = new GainNode(audioContext, { gain: gainLeft });
437
441
  const gainR = new GainNode(audioContext, { gain: gainRight });
438
442
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
@@ -460,10 +464,9 @@ class MidyGMLite {
460
464
  return channels;
461
465
  }
462
466
  async createAudioBuffer(voiceParams) {
463
- const sample = voiceParams.sample;
464
- const sampleStart = voiceParams.start;
465
- const sampleEnd = sample.data.length + voiceParams.end;
466
- const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
467
+ const { sample, start, end } = voiceParams;
468
+ const sampleEnd = sample.data.length + end;
469
+ const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
467
470
  return audioBuffer;
468
471
  }
469
472
  createBufferSource(channel, voiceParams, audioBuffer) {
@@ -478,7 +481,7 @@ class MidyGMLite {
478
481
  }
479
482
  return bufferSource;
480
483
  }
481
- async scheduleTimelineEvents(scheduleTime, queueIndex) {
484
+ scheduleTimelineEvents(scheduleTime, queueIndex) {
482
485
  const timeOffset = this.resumeTime - this.startTime;
483
486
  const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
484
487
  const schedulingOffset = this.startDelay - timeOffset;
@@ -490,12 +493,10 @@ class MidyGMLite {
490
493
  const startTime = event.startTime + schedulingOffset;
491
494
  switch (event.type) {
492
495
  case "noteOn":
493
- await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
496
+ this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
494
497
  break;
495
498
  case "noteOff": {
496
- const notePromise = this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
497
- if (notePromise)
498
- this.notePromises.push(notePromise);
499
+ this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
499
500
  break;
500
501
  }
501
502
  case "controller":
@@ -533,22 +534,23 @@ class MidyGMLite {
533
534
  }
534
535
  }
535
536
  updateStates(queueIndex, nextQueueIndex) {
537
+ const now = this.audioContext.currentTime;
536
538
  if (nextQueueIndex < queueIndex)
537
539
  queueIndex = 0;
538
540
  for (let i = queueIndex; i < nextQueueIndex; i++) {
539
541
  const event = this.timeline[i];
540
542
  switch (event.type) {
541
543
  case "controller":
542
- this.setControlChange(event.channel, event.controllerType, event.value, 0);
544
+ this.setControlChange(event.channel, event.controllerType, event.value, now - this.resumeTime + event.startTime);
543
545
  break;
544
546
  case "programChange":
545
- this.setProgramChange(event.channel, event.programNumber, 0);
547
+ this.setProgramChange(event.channel, event.programNumber, now - this.resumeTime + event.startTime);
546
548
  break;
547
549
  case "pitchBend":
548
- this.setPitchBend(event.channel, event.value + 8192, 0);
550
+ this.setPitchBend(event.channel, event.value + 8192, now - this.resumeTime + event.startTime);
549
551
  break;
550
552
  case "sysEx":
551
- this.handleSysEx(event.data, 0);
553
+ this.handleSysEx(event.data, now - this.resumeTime + event.startTime);
552
554
  }
553
555
  }
554
556
  }
@@ -556,44 +558,80 @@ class MidyGMLite {
556
558
  if (this.audioContext.state === "suspended") {
557
559
  await this.audioContext.resume();
558
560
  }
561
+ const paused = this.isPaused;
559
562
  this.isPlaying = true;
560
563
  this.isPaused = false;
561
564
  this.startTime = this.audioContext.currentTime;
565
+ if (paused) {
566
+ this.dispatchEvent(new Event("resumed"));
567
+ }
568
+ else {
569
+ this.dispatchEvent(new Event("started"));
570
+ }
562
571
  let queueIndex = this.getQueueIndex(this.resumeTime);
563
- let finished = false;
572
+ let exitReason;
564
573
  this.notePromises = [];
565
- while (queueIndex < this.timeline.length) {
574
+ while (true) {
566
575
  const now = this.audioContext.currentTime;
576
+ if (this.timeline.length <= queueIndex) {
577
+ await this.stopNotes(0, true, now);
578
+ if (this.loop) {
579
+ this.notePromises = [];
580
+ this.resetAllStates();
581
+ this.startTime = this.audioContext.currentTime;
582
+ this.resumeTime = 0;
583
+ queueIndex = 0;
584
+ this.dispatchEvent(new Event("looped"));
585
+ continue;
586
+ }
587
+ else {
588
+ await this.audioContext.suspend();
589
+ exitReason = "ended";
590
+ break;
591
+ }
592
+ }
567
593
  if (this.isPausing) {
568
594
  await this.stopNotes(0, true, now);
569
595
  await this.audioContext.suspend();
570
596
  this.notePromises = [];
597
+ this.isPausing = false;
598
+ exitReason = "paused";
571
599
  break;
572
600
  }
573
601
  else if (this.isStopping) {
574
602
  await this.stopNotes(0, true, now);
575
603
  await this.audioContext.suspend();
576
- finished = true;
604
+ this.isStopping = false;
605
+ exitReason = "stopped";
577
606
  break;
578
607
  }
579
608
  else if (this.isSeeking) {
580
- await this.stopNotes(0, true, now);
609
+ this.stopNotes(0, true, now);
581
610
  this.startTime = this.audioContext.currentTime;
582
611
  const nextQueueIndex = this.getQueueIndex(this.resumeTime);
583
612
  this.updateStates(queueIndex, nextQueueIndex);
584
613
  queueIndex = nextQueueIndex;
585
614
  this.isSeeking = false;
615
+ this.dispatchEvent(new Event("seeked"));
586
616
  continue;
587
617
  }
588
- queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
618
+ queueIndex = this.scheduleTimelineEvents(now, queueIndex);
589
619
  const waitTime = now + this.noteCheckInterval;
590
620
  await this.scheduleTask(() => { }, waitTime);
591
621
  }
592
- if (finished) {
622
+ if (exitReason !== "paused") {
593
623
  this.notePromises = [];
594
624
  this.resetAllStates();
595
625
  }
596
626
  this.isPlaying = false;
627
+ if (exitReason === "paused") {
628
+ this.isPaused = true;
629
+ this.dispatchEvent(new Event("paused"));
630
+ }
631
+ else {
632
+ this.isPaused = false;
633
+ this.dispatchEvent(new Event(exitReason));
634
+ }
597
635
  }
598
636
  ticksToSecond(ticks, secondsPerBeat) {
599
637
  return ticks * secondsPerBeat / this.ticksPerBeat;
@@ -700,24 +738,20 @@ class MidyGMLite {
700
738
  return;
701
739
  this.isStopping = true;
702
740
  await this.playPromise;
703
- this.isStopping = false;
704
741
  }
705
742
  async pause() {
706
743
  if (!this.isPlaying || this.isPaused)
707
744
  return;
708
745
  const now = this.audioContext.currentTime;
709
- this.resumeTime = now - this.startTime - this.startDelay;
746
+ this.resumeTime = now + this.resumeTime - this.startTime;
710
747
  this.isPausing = true;
711
748
  await this.playPromise;
712
- this.isPausing = false;
713
- this.isPaused = true;
714
749
  }
715
750
  async resume() {
716
751
  if (!this.isPaused)
717
752
  return;
718
753
  this.playPromise = this.playNotes();
719
754
  await this.playPromise;
720
- this.isPaused = false;
721
755
  }
722
756
  seekTo(second) {
723
757
  this.resumeTime = second;
@@ -740,19 +774,23 @@ class MidyGMLite {
740
774
  const now = this.audioContext.currentTime;
741
775
  return now + this.resumeTime - this.startTime;
742
776
  }
743
- processScheduledNotes(channel, callback) {
777
+ async processScheduledNotes(channel, callback) {
744
778
  const scheduledNotes = channel.scheduledNotes;
779
+ const tasks = [];
745
780
  for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
746
781
  const note = scheduledNotes[i];
747
782
  if (!note)
748
783
  continue;
749
784
  if (note.ending)
750
785
  continue;
751
- callback(note);
786
+ const task = note.ready.then(() => callback(note));
787
+ tasks.push(task);
752
788
  }
789
+ await Promise.all(tasks);
753
790
  }
754
- processActiveNotes(channel, scheduleTime, callback) {
791
+ async processActiveNotes(channel, scheduleTime, callback) {
755
792
  const scheduledNotes = channel.scheduledNotes;
793
+ const tasks = [];
756
794
  for (let i = channel.scheduleIndex; i < scheduledNotes.length; i++) {
757
795
  const note = scheduledNotes[i];
758
796
  if (!note)
@@ -761,8 +799,10 @@ class MidyGMLite {
761
799
  continue;
762
800
  if (scheduleTime < note.startTime)
763
801
  break;
764
- callback(note);
802
+ const task = note.ready.then(() => callback(note));
803
+ tasks.push(task);
765
804
  }
805
+ await Promise.all(tasks);
766
806
  }
767
807
  cbToRatio(cb) {
768
808
  return Math.pow(10, cb / 200);
@@ -921,12 +961,18 @@ class MidyGMLite {
921
961
  this.setFilterEnvelope(note, now);
922
962
  this.setPitchEnvelope(note, now);
923
963
  this.updateDetune(channel, note, now);
924
- if (0 < state.modulationDepth) {
964
+ if (0 < state.modulationDepthMSB) {
925
965
  this.startModulation(channel, note, now);
926
966
  }
927
967
  note.bufferSource.connect(note.filterNode);
928
968
  note.filterNode.connect(note.volumeEnvelopeNode);
929
- note.bufferSource.start(startTime);
969
+ if (voiceParams.sample.type === "compressed") {
970
+ const offset = voiceParams.start / audioBuffer.sampleRate;
971
+ note.bufferSource.start(startTime, offset);
972
+ }
973
+ else {
974
+ note.bufferSource.start(startTime);
975
+ }
930
976
  return note;
931
977
  }
932
978
  handleExclusiveClass(note, channelNumber, startTime) {
@@ -992,11 +1038,7 @@ class MidyGMLite {
992
1038
  return;
993
1039
  await this.setNoteAudioNode(channel, note, realtime);
994
1040
  this.setNoteRouting(channelNumber, note, startTime);
995
- note.pending = false;
996
- const off = note.offEvent;
997
- if (off) {
998
- this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
999
- }
1041
+ note.resolveReady();
1000
1042
  }
1001
1043
  disconnectNote(note) {
1002
1044
  note.bufferSource.disconnect();
@@ -1030,7 +1072,7 @@ class MidyGMLite {
1030
1072
  }, stopTime);
1031
1073
  });
1032
1074
  }
1033
- noteOff(channelNumber, noteNumber, velocity, endTime, force) {
1075
+ async noteOff(channelNumber, noteNumber, _velocity, endTime, force) {
1034
1076
  const channel = this.channels[channelNumber];
1035
1077
  if (!force) {
1036
1078
  if (channel.isDrum)
@@ -1042,13 +1084,13 @@ class MidyGMLite {
1042
1084
  if (index < 0)
1043
1085
  return;
1044
1086
  const note = channel.scheduledNotes[index];
1045
- if (note.pending) {
1046
- note.offEvent = { velocity, startTime: endTime };
1047
- return;
1048
- }
1049
1087
  note.ending = true;
1050
1088
  this.setNoteIndex(channel, index);
1051
- this.releaseNote(channel, note, endTime);
1089
+ const promise = note.ready.then(() => {
1090
+ return this.releaseNote(channel, note, endTime);
1091
+ });
1092
+ this.notePromises.push(promise);
1093
+ return promise;
1052
1094
  }
1053
1095
  setNoteIndex(channel, index) {
1054
1096
  let allEnds = true;
@@ -1134,7 +1176,8 @@ class MidyGMLite {
1134
1176
  }
1135
1177
  setPitchBend(channelNumber, value, scheduleTime) {
1136
1178
  const channel = this.channels[channelNumber];
1137
- scheduleTime ??= this.audioContext.currentTime;
1179
+ if (!(0 <= scheduleTime))
1180
+ scheduleTime = this.audioContext.currentTime;
1138
1181
  const state = channel.state;
1139
1182
  const prev = state.pitchWheel * 2 - 1;
1140
1183
  const next = (value - 8192) / 8192;
@@ -1146,11 +1189,12 @@ class MidyGMLite {
1146
1189
  setModLfoToPitch(channel, note, scheduleTime) {
1147
1190
  if (note.modulationDepth) {
1148
1191
  const modLfoToPitch = note.voiceParams.modLfoToPitch;
1149
- const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
1150
- const modulationDepth = baseDepth * Math.sign(modLfoToPitch);
1192
+ const baseDepth = Math.abs(modLfoToPitch) +
1193
+ channel.state.modulationDepthMSB;
1194
+ const depth = baseDepth * Math.sign(modLfoToPitch);
1151
1195
  note.modulationDepth.gain
1152
1196
  .cancelScheduledValues(scheduleTime)
1153
- .setValueAtTime(modulationDepth, scheduleTime);
1197
+ .setValueAtTime(depth, scheduleTime);
1154
1198
  }
1155
1199
  else {
1156
1200
  this.startModulation(channel, note, scheduleTime);
@@ -1187,18 +1231,18 @@ class MidyGMLite {
1187
1231
  createVoiceParamsHandlers() {
1188
1232
  return {
1189
1233
  modLfoToPitch: (channel, note, scheduleTime) => {
1190
- if (0 < channel.state.modulationDepth) {
1234
+ if (0 < channel.state.modulationDepthMSB) {
1191
1235
  this.setModLfoToPitch(channel, note, scheduleTime);
1192
1236
  }
1193
1237
  },
1194
1238
  vibLfoToPitch: (_channel, _note, _scheduleTime) => { },
1195
1239
  modLfoToFilterFc: (channel, note, scheduleTime) => {
1196
- if (0 < channel.state.modulationDepth) {
1240
+ if (0 < channel.state.modulationDepthMSB) {
1197
1241
  this.setModLfoToFilterFc(note, scheduleTime);
1198
1242
  }
1199
1243
  },
1200
1244
  modLfoToVolume: (channel, note, scheduleTime) => {
1201
- if (0 < channel.state.modulationDepth) {
1245
+ if (0 < channel.state.modulationDepthMSB) {
1202
1246
  this.setModLfoToVolume(note, scheduleTime);
1203
1247
  }
1204
1248
  },
@@ -1297,12 +1341,14 @@ class MidyGMLite {
1297
1341
  }
1298
1342
  setModulationDepth(channelNumber, modulation, scheduleTime) {
1299
1343
  const channel = this.channels[channelNumber];
1300
- scheduleTime ??= this.audioContext.currentTime;
1344
+ if (!(0 <= scheduleTime))
1345
+ scheduleTime = this.audioContext.currentTime;
1301
1346
  channel.state.modulationDepth = modulation / 127;
1302
1347
  this.updateModulation(channel, scheduleTime);
1303
1348
  }
1304
1349
  setVolume(channelNumber, volume, scheduleTime) {
1305
- scheduleTime ??= this.audioContext.currentTime;
1350
+ if (!(0 <= scheduleTime))
1351
+ scheduleTime = this.audioContext.currentTime;
1306
1352
  const channel = this.channels[channelNumber];
1307
1353
  channel.state.volume = volume / 127;
1308
1354
  this.updateChannelVolume(channel, scheduleTime);
@@ -1315,13 +1361,15 @@ class MidyGMLite {
1315
1361
  };
1316
1362
  }
1317
1363
  setPan(channelNumber, pan, scheduleTime) {
1318
- scheduleTime ??= this.audioContext.currentTime;
1364
+ if (!(0 <= scheduleTime))
1365
+ scheduleTime = this.audioContext.currentTime;
1319
1366
  const channel = this.channels[channelNumber];
1320
1367
  channel.state.pan = pan / 127;
1321
1368
  this.updateChannelVolume(channel, scheduleTime);
1322
1369
  }
1323
1370
  setExpression(channelNumber, expression, scheduleTime) {
1324
- scheduleTime ??= this.audioContext.currentTime;
1371
+ if (!(0 <= scheduleTime))
1372
+ scheduleTime = this.audioContext.currentTime;
1325
1373
  const channel = this.channels[channelNumber];
1326
1374
  channel.state.expression = expression / 127;
1327
1375
  this.updateChannelVolume(channel, scheduleTime);
@@ -1343,7 +1391,8 @@ class MidyGMLite {
1343
1391
  }
1344
1392
  setSustainPedal(channelNumber, value, scheduleTime) {
1345
1393
  const channel = this.channels[channelNumber];
1346
- scheduleTime ??= this.audioContext.currentTime;
1394
+ if (!(0 <= scheduleTime))
1395
+ scheduleTime = this.audioContext.currentTime;
1347
1396
  channel.state.sustainPedal = value / 127;
1348
1397
  if (64 <= value) {
1349
1398
  this.processScheduledNotes(channel, (note) => {
@@ -1401,7 +1450,8 @@ class MidyGMLite {
1401
1450
  }
1402
1451
  setPitchBendRange(channelNumber, value, scheduleTime) {
1403
1452
  const channel = this.channels[channelNumber];
1404
- scheduleTime ??= this.audioContext.currentTime;
1453
+ if (!(0 <= scheduleTime))
1454
+ scheduleTime = this.audioContext.currentTime;
1405
1455
  const state = channel.state;
1406
1456
  const prev = state.pitchWheelSensitivity;
1407
1457
  const next = value / 12800;
@@ -1411,7 +1461,8 @@ class MidyGMLite {
1411
1461
  this.applyVoiceParams(channel, 16, scheduleTime);
1412
1462
  }
1413
1463
  allSoundOff(channelNumber, _value, scheduleTime) {
1414
- scheduleTime ??= this.audioContext.currentTime;
1464
+ if (!(0 <= scheduleTime))
1465
+ scheduleTime = this.audioContext.currentTime;
1415
1466
  return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
1416
1467
  }
1417
1468
  resetChannelStates(channelNumber) {
@@ -1436,8 +1487,8 @@ class MidyGMLite {
1436
1487
  resetAllControllers(channelNumber, _value, scheduleTime) {
1437
1488
  const keys = [
1438
1489
  "pitchWheel",
1439
- "expression",
1440
- "modulationDepth",
1490
+ "expressionMSB",
1491
+ "modulationDepthMSB",
1441
1492
  "sustainPedal",
1442
1493
  ];
1443
1494
  const channel = this.channels[channelNumber];
@@ -1463,7 +1514,8 @@ class MidyGMLite {
1463
1514
  }
1464
1515
  }
1465
1516
  allNotesOff(channelNumber, _value, scheduleTime) {
1466
- scheduleTime ??= this.audioContext.currentTime;
1517
+ if (!(0 <= scheduleTime))
1518
+ scheduleTime = this.audioContext.currentTime;
1467
1519
  return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
1468
1520
  }
1469
1521
  handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
@@ -1484,7 +1536,8 @@ class MidyGMLite {
1484
1536
  }
1485
1537
  }
1486
1538
  GM1SystemOn(scheduleTime) {
1487
- scheduleTime ??= this.audioContext.currentTime;
1539
+ if (!(0 <= scheduleTime))
1540
+ scheduleTime = this.audioContext.currentTime;
1488
1541
  this.mode = "GM1";
1489
1542
  for (let i = 0; i < this.channels.length; i++) {
1490
1543
  this.allSoundOff(i, 0, scheduleTime);
@@ -1512,7 +1565,8 @@ class MidyGMLite {
1512
1565
  this.setMasterVolume(volume, scheduleTime);
1513
1566
  }
1514
1567
  setMasterVolume(value, scheduleTime) {
1515
- scheduleTime ??= this.audioContext.currentTime;
1568
+ if (!(0 <= scheduleTime))
1569
+ scheduleTime = this.audioContext.currentTime;
1516
1570
  this.masterVolume.gain
1517
1571
  .cancelScheduledValues(scheduleTime)
1518
1572
  .setValueAtTime(value * value, scheduleTime);
package/script/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;
@@ -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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"}