@marmooo/midy 0.3.8 → 0.4.1

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
@@ -22,6 +22,7 @@ This library provides several files depending on the implementation level.
22
22
 
23
23
  - [@marmooo/midi-player](https://marmooo.github.io/midi-player/) - GUI library
24
24
  - [Humidy](https://marmooo.github.io/humidy/) - GM2 MIDI mixer app
25
+ - [Timidy](https://marmooo.github.io/timidy/) - Timidity++ style MIDI player
25
26
 
26
27
  ## Support Status
27
28
 
@@ -54,7 +55,7 @@ All implementations follow the specification.
54
55
  import { Midy } from "midy.js";
55
56
 
56
57
  const audioContext = new AudioContext();
57
- await audioContext.suspend();
58
+ if (audioContext.state === "running") await audioContext.suspend();
58
59
  const midy = new Midy(audioContext);
59
60
  await midy.loadMIDI("test.mid");
60
61
  await midy.loadSoundFont("test.sf3");
package/esm/midy-GM1.d.ts CHANGED
@@ -25,6 +25,7 @@ export class MidyGM1 {
25
25
  soundFontTable: never[][];
26
26
  voiceCounter: Map<any, any>;
27
27
  voiceCache: Map<any, any>;
28
+ realtimeVoiceCache: Map<any, any>;
28
29
  isPlaying: boolean;
29
30
  isPausing: boolean;
30
31
  isPaused: boolean;
@@ -104,21 +105,20 @@ export class MidyGM1 {
104
105
  clampCutoffFrequency(frequency: any): number;
105
106
  setFilterEnvelope(note: any, scheduleTime: any): void;
106
107
  startModulation(channel: any, note: any, scheduleTime: any): void;
107
- getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
108
- createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any): Promise<Note>;
108
+ getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
109
+ setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
109
110
  handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
110
- scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
111
- noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
111
+ setNoteRouting(channelNumber: any, note: any, startTime: any): void;
112
+ noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
112
113
  disconnectNote(note: any): void;
113
114
  releaseNote(channel: any, note: any, endTime: any): Promise<any>;
114
- scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): void;
115
+ noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
115
116
  setNoteIndex(channel: any, index: any): void;
116
117
  findNoteOffIndex(channel: any, noteNumber: any): any;
117
- noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
118
- releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
118
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
119
119
  createMessageHandlers(): any[];
120
120
  handleMessage(data: any, scheduleTime: any): void;
121
- handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
121
+ handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
122
122
  setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
123
123
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
124
124
  setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
@@ -179,22 +179,4 @@ export class MidyGM1 {
179
179
  handleSysEx(data: any, scheduleTime: any): void;
180
180
  scheduleTask(callback: any, scheduleTime: any): Promise<any>;
181
181
  }
182
- declare class Note {
183
- constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
184
- index: number;
185
- ending: boolean;
186
- bufferSource: any;
187
- filterNode: any;
188
- filterDepth: any;
189
- volumeEnvelopeNode: any;
190
- volumeDepth: any;
191
- modulationLFO: any;
192
- modulationDepth: any;
193
- noteNumber: any;
194
- velocity: any;
195
- startTime: any;
196
- voice: any;
197
- voiceParams: any;
198
- }
199
- export {};
200
182
  //# sourceMappingURL=midy-GM1.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AA4FA;IAyBE;;;;;;;;;;;MAWE;IAEF,+BAeC;IApDD,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,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,kDAUC;IAED,4DASC;IAED,yEAqDC;IAED,mCAOC;IAED,uBAQC;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,sBAGC;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,6FAyBC;IAED,oGAuCC;IAED,0EAiBC;IAED,kGAgCC;IAED,6FASC;IAED,gCASC;IAED,iEAoBC;IAED,qGAeC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;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,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;AAtiDD;IAWE,0FAMC;IAhBD,cAAW;IACX,gBAAe;IACf,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
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"}
package/esm/midy-GM1.js CHANGED
@@ -1,7 +1,19 @@
1
1
  import { parseMidi } from "midi-file";
2
2
  import { parse, SoundFont } from "@marmooo/soundfont-parser";
3
3
  class Note {
4
- constructor(noteNumber, velocity, startTime, voice, voiceParams) {
4
+ constructor(noteNumber, velocity, startTime) {
5
+ Object.defineProperty(this, "voice", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "voiceParams", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
5
17
  Object.defineProperty(this, "index", {
6
18
  enumerable: true,
7
19
  configurable: true,
@@ -14,6 +26,12 @@ class Note {
14
26
  writable: true,
15
27
  value: false
16
28
  });
29
+ Object.defineProperty(this, "pending", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: true
34
+ });
17
35
  Object.defineProperty(this, "bufferSource", {
18
36
  enumerable: true,
19
37
  configurable: true,
@@ -59,8 +77,6 @@ class Note {
59
77
  this.noteNumber = noteNumber;
60
78
  this.velocity = velocity;
61
79
  this.startTime = startTime;
62
- this.voice = voice;
63
- this.voiceParams = voiceParams;
64
80
  }
65
81
  }
66
82
  // normalized to 0-1 for use with the SF2 modulator model
@@ -70,11 +86,11 @@ const defaultControllerState = {
70
86
  pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
71
87
  pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
72
88
  link: { type: 127, defaultValue: 0 },
73
- modulationDepth: { type: 128 + 1, defaultValue: 0 },
89
+ modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
74
90
  // dataMSB: { type: 128 + 6, defaultValue: 0, },
75
- volume: { type: 128 + 7, defaultValue: 100 / 127 },
76
- pan: { type: 128 + 10, defaultValue: 64 / 127 },
77
- expression: { type: 128 + 11, defaultValue: 1 },
91
+ volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
92
+ panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
93
+ expressionMSB: { type: 128 + 11, defaultValue: 1 },
78
94
  // dataLSB: { type: 128 + 38, defaultValue: 0, },
79
95
  sustainPedal: { type: 128 + 64, defaultValue: 0 },
80
96
  // rpnLSB: { type: 128 + 100, defaultValue: 127 },
@@ -214,6 +230,12 @@ export class MidyGM1 {
214
230
  writable: true,
215
231
  value: new Map()
216
232
  });
233
+ Object.defineProperty(this, "realtimeVoiceCache", {
234
+ enumerable: true,
235
+ configurable: true,
236
+ writable: true,
237
+ value: new Map()
238
+ });
217
239
  Object.defineProperty(this, "isPlaying", {
218
240
  enumerable: true,
219
241
  configurable: true,
@@ -388,7 +410,7 @@ export class MidyGM1 {
388
410
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
389
411
  }
390
412
  createChannelAudioNodes(audioContext) {
391
- const { gainLeft, gainRight } = this.panToGain(defaultControllerState.pan.defaultValue);
413
+ const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
392
414
  const gainL = new GainNode(audioContext, { gain: gainLeft });
393
415
  const gainR = new GainNode(audioContext, { gain: gainRight });
394
416
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
@@ -416,10 +438,9 @@ export class MidyGM1 {
416
438
  return channels;
417
439
  }
418
440
  async createAudioBuffer(voiceParams) {
419
- const sample = voiceParams.sample;
420
- const sampleStart = voiceParams.start;
421
- const sampleEnd = sample.data.length + voiceParams.end;
422
- const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
441
+ const { sample, start, end } = voiceParams;
442
+ const sampleEnd = sample.data.length + end;
443
+ const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
423
444
  return audioBuffer;
424
445
  }
425
446
  createBufferSource(voiceParams, audioBuffer) {
@@ -444,12 +465,10 @@ export class MidyGM1 {
444
465
  const startTime = event.startTime + schedulingOffset;
445
466
  switch (event.type) {
446
467
  case "noteOn":
447
- await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
468
+ await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
448
469
  break;
449
470
  case "noteOff": {
450
- const notePromise = this.scheduleNoteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
451
- if (notePromise)
452
- this.notePromises.push(notePromise);
471
+ this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
453
472
  break;
454
473
  }
455
474
  case "controller":
@@ -480,6 +499,7 @@ export class MidyGM1 {
480
499
  this.exclusiveClassNotes.fill(undefined);
481
500
  this.drumExclusiveClassNotes.fill(undefined);
482
501
  this.voiceCache.clear();
502
+ this.realtimeVoiceCache.clear();
483
503
  for (let i = 0; i < this.channels.length; i++) {
484
504
  this.channels[i].scheduledNotes = [];
485
505
  this.resetChannelStates(i);
@@ -517,7 +537,6 @@ export class MidyGM1 {
517
537
  this.notePromises = [];
518
538
  while (queueIndex < this.timeline.length) {
519
539
  const now = this.audioContext.currentTime;
520
- queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
521
540
  if (this.isPausing) {
522
541
  await this.stopNotes(0, true, now);
523
542
  await this.audioContext.suspend();
@@ -539,9 +558,16 @@ export class MidyGM1 {
539
558
  this.isSeeking = false;
540
559
  continue;
541
560
  }
561
+ queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
542
562
  const waitTime = now + this.noteCheckInterval;
543
563
  await this.scheduleTask(() => { }, waitTime);
544
564
  }
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
+ }
545
571
  if (finished) {
546
572
  this.notePromises = [];
547
573
  this.resetAllStates();
@@ -616,7 +642,7 @@ export class MidyGM1 {
616
642
  const channel = this.channels[channelNumber];
617
643
  const promises = [];
618
644
  this.processActiveNotes(channel, scheduleTime, (note) => {
619
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
645
+ const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
620
646
  this.notePromises.push(promise);
621
647
  promises.push(promise);
622
648
  });
@@ -626,7 +652,7 @@ export class MidyGM1 {
626
652
  const channel = this.channels[channelNumber];
627
653
  const promises = [];
628
654
  this.processScheduledNotes(channel, (note) => {
629
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
655
+ const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
630
656
  this.notePromises.push(promise);
631
657
  promises.push(promise);
632
658
  });
@@ -659,7 +685,7 @@ export class MidyGM1 {
659
685
  if (!this.isPlaying || this.isPaused)
660
686
  return;
661
687
  const now = this.audioContext.currentTime;
662
- this.resumeTime += now - this.startTime - this.startDelay;
688
+ this.resumeTime = now - this.startTime - this.startDelay;
663
689
  this.isPausing = true;
664
690
  await this.playPromise;
665
691
  this.isPausing = false;
@@ -685,11 +711,13 @@ export class MidyGM1 {
685
711
  if (totalTime < event.startTime)
686
712
  totalTime = event.startTime;
687
713
  }
688
- return totalTime;
714
+ return totalTime + this.startDelay;
689
715
  }
690
716
  currentTime() {
717
+ if (!this.isPlaying)
718
+ return this.resumeTime;
691
719
  const now = this.audioContext.currentTime;
692
- return this.resumeTime + now - this.startTime - this.startDelay;
720
+ return now + this.resumeTime - this.startTime;
693
721
  }
694
722
  processScheduledNotes(channel, callback) {
695
723
  const scheduledNotes = channel.scheduledNotes;
@@ -828,31 +856,42 @@ export class MidyGM1 {
828
856
  note.modulationLFO.connect(note.volumeDepth);
829
857
  note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
830
858
  }
831
- async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
859
+ async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
832
860
  const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
833
- const cache = this.voiceCache.get(audioBufferId);
834
- if (cache) {
835
- cache.counter += 1;
836
- if (cache.maxCount <= cache.counter) {
837
- this.voiceCache.delete(audioBufferId);
838
- }
839
- return cache.audioBuffer;
840
- }
841
- else {
842
- const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
861
+ if (realtime) {
862
+ const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
863
+ if (cachedAudioBuffer)
864
+ return cachedAudioBuffer;
843
865
  const audioBuffer = await this.createAudioBuffer(voiceParams);
844
- const cache = { audioBuffer, maxCount, counter: 1 };
845
- this.voiceCache.set(audioBufferId, cache);
866
+ this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
846
867
  return audioBuffer;
847
868
  }
869
+ else {
870
+ const cache = this.voiceCache.get(audioBufferId);
871
+ if (cache) {
872
+ cache.counter += 1;
873
+ if (cache.maxCount <= cache.counter) {
874
+ this.voiceCache.delete(audioBufferId);
875
+ }
876
+ return cache.audioBuffer;
877
+ }
878
+ else {
879
+ const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
880
+ const audioBuffer = await this.createAudioBuffer(voiceParams);
881
+ const cache = { audioBuffer, maxCount, counter: 1 };
882
+ this.voiceCache.set(audioBufferId, cache);
883
+ return audioBuffer;
884
+ }
885
+ }
848
886
  }
849
- async createNote(channel, voice, noteNumber, velocity, startTime) {
887
+ async setNoteAudioNode(channel, note, realtime) {
850
888
  const now = this.audioContext.currentTime;
889
+ const { noteNumber, velocity, startTime } = note;
851
890
  const state = channel.state;
852
891
  const controllerState = this.getControllerState(channel, noteNumber, velocity);
853
- const voiceParams = voice.getAllParams(controllerState);
854
- const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
855
- const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
892
+ const voiceParams = note.voice.getAllParams(controllerState);
893
+ note.voiceParams = voiceParams;
894
+ const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
856
895
  note.bufferSource = this.createBufferSource(voiceParams, audioBuffer);
857
896
  note.volumeEnvelopeNode = new GainNode(this.audioContext);
858
897
  note.filterNode = new BiquadFilterNode(this.audioContext, {
@@ -868,7 +907,13 @@ export class MidyGM1 {
868
907
  }
869
908
  note.bufferSource.connect(note.filterNode);
870
909
  note.filterNode.connect(note.volumeEnvelopeNode);
871
- note.bufferSource.start(startTime);
910
+ if (voiceParams.sample.type === "compressed") {
911
+ const offset = voiceParams.start / audioBuffer.sampleRate;
912
+ note.bufferSource.start(startTime, offset);
913
+ }
914
+ else {
915
+ note.bufferSource.start(startTime);
916
+ }
872
917
  return note;
873
918
  }
874
919
  handleExclusiveClass(note, channelNumber, startTime) {
@@ -879,14 +924,31 @@ export class MidyGM1 {
879
924
  if (prev) {
880
925
  const [prevNote, prevChannelNumber] = prev;
881
926
  if (prevNote && !prevNote.ending) {
882
- this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
927
+ this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
883
928
  startTime, true);
884
929
  }
885
930
  }
886
931
  this.exclusiveClassNotes[exclusiveClass] = [note, channelNumber];
887
932
  }
888
- async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
933
+ setNoteRouting(channelNumber, note, startTime) {
934
+ const channel = this.channels[channelNumber];
935
+ const volumeEnvelopeNode = note.volumeEnvelopeNode;
936
+ volumeEnvelopeNode.connect(channel.gainL);
937
+ volumeEnvelopeNode.connect(channel.gainR);
938
+ if (0.5 <= channel.state.sustainPedal) {
939
+ channel.sustainNotes.push(note);
940
+ }
941
+ this.handleExclusiveClass(note, channelNumber, startTime);
942
+ }
943
+ async noteOn(channelNumber, noteNumber, velocity, startTime) {
889
944
  const channel = this.channels[channelNumber];
945
+ const realtime = startTime === undefined;
946
+ if (realtime)
947
+ startTime = this.audioContext.currentTime;
948
+ const note = new Note(noteNumber, velocity, startTime);
949
+ const scheduledNotes = channel.scheduledNotes;
950
+ note.index = scheduledNotes.length;
951
+ scheduledNotes.push(note);
890
952
  const programNumber = channel.programNumber;
891
953
  const bankTable = this.soundFontTable[programNumber];
892
954
  if (!bankTable)
@@ -896,23 +958,16 @@ export class MidyGM1 {
896
958
  if (soundFontIndex === undefined)
897
959
  return;
898
960
  const soundFont = this.soundFonts[soundFontIndex];
899
- const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
900
- if (!voice)
961
+ note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
962
+ if (!note.voice)
901
963
  return;
902
- const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
903
- note.volumeEnvelopeNode.connect(channel.gainL);
904
- note.volumeEnvelopeNode.connect(channel.gainR);
905
- if (0.5 <= channel.state.sustainPedal) {
906
- channel.sustainNotes.push(note);
964
+ await this.setNoteAudioNode(channel, note, realtime);
965
+ 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);
907
970
  }
908
- this.handleExclusiveClass(note, channelNumber, startTime);
909
- const scheduledNotes = channel.scheduledNotes;
910
- note.index = scheduledNotes.length;
911
- scheduledNotes.push(note);
912
- }
913
- noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
914
- scheduleTime ??= this.audioContext.currentTime;
915
- return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
916
971
  }
917
972
  disconnectNote(note) {
918
973
  note.bufferSource.disconnect();
@@ -925,6 +980,7 @@ export class MidyGM1 {
925
980
  }
926
981
  }
927
982
  releaseNote(channel, note, endTime) {
983
+ endTime ??= this.audioContext.currentTime;
928
984
  const volRelease = endTime + note.voiceParams.volRelease;
929
985
  const modRelease = endTime + note.voiceParams.modRelease;
930
986
  const stopTime = Math.min(volRelease, modRelease);
@@ -945,7 +1001,7 @@ export class MidyGM1 {
945
1001
  }, stopTime);
946
1002
  });
947
1003
  }
948
- scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
1004
+ noteOff(channelNumber, noteNumber, velocity, endTime, force) {
949
1005
  const channel = this.channels[channelNumber];
950
1006
  if (!force && 0.5 <= channel.state.sustainPedal)
951
1007
  return;
@@ -953,9 +1009,15 @@ export class MidyGM1 {
953
1009
  if (index < 0)
954
1010
  return;
955
1011
  const note = channel.scheduledNotes[index];
1012
+ if (note.pending) {
1013
+ note.offEvent = { velocity, startTime: endTime };
1014
+ return;
1015
+ }
956
1016
  note.ending = true;
957
1017
  this.setNoteIndex(channel, index);
958
- this.releaseNote(channel, note, endTime);
1018
+ const promise = this.releaseNote(channel, note, endTime);
1019
+ this.notePromises.push(promise);
1020
+ return promise;
959
1021
  }
960
1022
  setNoteIndex(channel, index) {
961
1023
  let allEnds = true;
@@ -983,16 +1045,12 @@ export class MidyGM1 {
983
1045
  }
984
1046
  return -1;
985
1047
  }
986
- noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
987
- scheduleTime ??= this.audioContext.currentTime;
988
- return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
989
- }
990
1048
  releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
991
1049
  const velocity = halfVelocity * 2;
992
1050
  const channel = this.channels[channelNumber];
993
1051
  const promises = [];
994
1052
  for (let i = 0; i < channel.sustainNotes.length; i++) {
995
- const promise = this.scheduleNoteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
1053
+ const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
996
1054
  promises.push(promise);
997
1055
  }
998
1056
  channel.sustainNotes = [];
@@ -1057,11 +1115,12 @@ export class MidyGM1 {
1057
1115
  setModLfoToPitch(channel, note, scheduleTime) {
1058
1116
  if (note.modulationDepth) {
1059
1117
  const modLfoToPitch = note.voiceParams.modLfoToPitch;
1060
- const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
1061
- const modulationDepth = baseDepth * Math.sign(modLfoToPitch);
1118
+ const baseDepth = Math.abs(modLfoToPitch) +
1119
+ channel.state.modulationDepthMSB;
1120
+ const depth = baseDepth * Math.sign(modLfoToPitch);
1062
1121
  note.modulationDepth.gain
1063
1122
  .cancelScheduledValues(scheduleTime)
1064
- .setValueAtTime(modulationDepth, scheduleTime);
1123
+ .setValueAtTime(depth, scheduleTime);
1065
1124
  }
1066
1125
  else {
1067
1126
  this.startModulation(channel, note, scheduleTime);
@@ -1098,18 +1157,18 @@ export class MidyGM1 {
1098
1157
  createVoiceParamsHandlers() {
1099
1158
  return {
1100
1159
  modLfoToPitch: (channel, note, scheduleTime) => {
1101
- if (0 < channel.state.modulationDepth) {
1160
+ if (0 < channel.state.modulationDepthMSB) {
1102
1161
  this.setModLfoToPitch(channel, note, scheduleTime);
1103
1162
  }
1104
1163
  },
1105
1164
  vibLfoToPitch: (_channel, _note, _scheduleTime) => { },
1106
1165
  modLfoToFilterFc: (channel, note, scheduleTime) => {
1107
- if (0 < channel.state.modulationDepth) {
1166
+ if (0 < channel.state.modulationDepthMSB) {
1108
1167
  this.setModLfoToFilterFc(note, scheduleTime);
1109
1168
  }
1110
1169
  },
1111
1170
  modLfoToVolume: (channel, note, scheduleTime) => {
1112
- if (0 < channel.state.modulationDepth) {
1171
+ if (0 < channel.state.modulationDepthMSB) {
1113
1172
  this.setModLfoToVolume(note, scheduleTime);
1114
1173
  }
1115
1174
  },
@@ -1121,7 +1180,7 @@ export class MidyGM1 {
1121
1180
  }
1122
1181
  },
1123
1182
  freqModLFO: (_channel, note, scheduleTime) => {
1124
- if (0 < channel.state.modulationDepth) {
1183
+ if (0 < channel.state.modulationDepthMSB) {
1125
1184
  this.setFreqModLFO(note, scheduleTime);
1126
1185
  }
1127
1186
  },
@@ -1196,7 +1255,8 @@ export class MidyGM1 {
1196
1255
  }
1197
1256
  }
1198
1257
  updateModulation(channel, scheduleTime) {
1199
- const depth = channel.state.modulationDepth * channel.modulationDepthRange;
1258
+ const depth = channel.state.modulationDepthMSB *
1259
+ channel.modulationDepthRange;
1200
1260
  this.processScheduledNotes(channel, (note) => {
1201
1261
  if (note.modulationDepth) {
1202
1262
  note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
@@ -1209,13 +1269,13 @@ export class MidyGM1 {
1209
1269
  setModulationDepth(channelNumber, modulation, scheduleTime) {
1210
1270
  const channel = this.channels[channelNumber];
1211
1271
  scheduleTime ??= this.audioContext.currentTime;
1212
- channel.state.modulationDepth = modulation / 127;
1272
+ channel.state.modulationDepthMSB = modulation / 127;
1213
1273
  this.updateModulation(channel, scheduleTime);
1214
1274
  }
1215
1275
  setVolume(channelNumber, volume, scheduleTime) {
1216
1276
  scheduleTime ??= this.audioContext.currentTime;
1217
1277
  const channel = this.channels[channelNumber];
1218
- channel.state.volume = volume / 127;
1278
+ channel.state.volumeMSB = volume / 127;
1219
1279
  this.updateChannelVolume(channel, scheduleTime);
1220
1280
  }
1221
1281
  panToGain(pan) {
@@ -1228,13 +1288,13 @@ export class MidyGM1 {
1228
1288
  setPan(channelNumber, pan, scheduleTime) {
1229
1289
  scheduleTime ??= this.audioContext.currentTime;
1230
1290
  const channel = this.channels[channelNumber];
1231
- channel.state.pan = pan / 127;
1291
+ channel.state.panMSB = pan / 127;
1232
1292
  this.updateChannelVolume(channel, scheduleTime);
1233
1293
  }
1234
1294
  setExpression(channelNumber, expression, scheduleTime) {
1235
1295
  scheduleTime ??= this.audioContext.currentTime;
1236
1296
  const channel = this.channels[channelNumber];
1237
- channel.state.expression = expression / 127;
1297
+ channel.state.expressionMSB = expression / 127;
1238
1298
  this.updateChannelVolume(channel, scheduleTime);
1239
1299
  }
1240
1300
  dataEntryLSB(channelNumber, value, scheduleTime) {
@@ -1243,8 +1303,8 @@ export class MidyGM1 {
1243
1303
  }
1244
1304
  updateChannelVolume(channel, scheduleTime) {
1245
1305
  const state = channel.state;
1246
- const volume = state.volume * state.expression;
1247
- const { gainLeft, gainRight } = this.panToGain(state.pan);
1306
+ const volume = state.volumeMSB * state.expressionMSB;
1307
+ const { gainLeft, gainRight } = this.panToGain(state.panMSB);
1248
1308
  channel.gainL.gain
1249
1309
  .cancelScheduledValues(scheduleTime)
1250
1310
  .setValueAtTime(volume * gainLeft, scheduleTime);
@@ -1392,8 +1452,8 @@ export class MidyGM1 {
1392
1452
  resetAllControllers(channelNumber, _value, scheduleTime) {
1393
1453
  const keys = [
1394
1454
  "pitchWheel",
1395
- "expression",
1396
- "modulationDepth",
1455
+ "expressionMSB",
1456
+ "modulationDepthMSB",
1397
1457
  "sustainPedal",
1398
1458
  ];
1399
1459
  const channel = this.channels[channelNumber];
package/esm/midy-GM2.d.ts CHANGED
@@ -44,6 +44,7 @@ export class MidyGM2 {
44
44
  soundFontTable: never[][];
45
45
  voiceCounter: Map<any, any>;
46
46
  voiceCache: Map<any, any>;
47
+ realtimeVoiceCache: Map<any, any>;
47
48
  isPlaying: boolean;
48
49
  isPausing: boolean;
49
50
  isPaused: boolean;
@@ -173,20 +174,19 @@ export class MidyGM2 {
173
174
  setFilterEnvelope(channel: any, note: any, scheduleTime: any): void;
174
175
  startModulation(channel: any, note: any, scheduleTime: any): void;
175
176
  startVibrato(channel: any, note: any, scheduleTime: any): void;
176
- getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
177
- createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any): Promise<Note>;
177
+ getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
178
+ setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
178
179
  handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
179
180
  handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
180
- scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
181
- noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
181
+ setNoteRouting(channelNumber: any, note: any, startTime: any): void;
182
+ noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
182
183
  disconnectNote(note: any): void;
183
184
  releaseNote(channel: any, note: any, endTime: any): Promise<any>;
184
- scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): void;
185
+ noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
185
186
  setNoteIndex(channel: any, index: any): void;
186
187
  findNoteOffIndex(channel: any, noteNumber: any): any;
187
- noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
188
- releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
189
- releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
188
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
189
+ releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
190
190
  createMessageHandlers(): any[];
191
191
  handleMessage(data: any, scheduleTime: any): void;
192
192
  activeSensing(): void;
@@ -312,27 +312,4 @@ export class MidyGM2 {
312
312
  handleSysEx(data: any, scheduleTime: any): void;
313
313
  scheduleTask(callback: any, scheduleTime: any): Promise<any>;
314
314
  }
315
- declare class Note {
316
- constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
317
- index: number;
318
- ending: boolean;
319
- bufferSource: any;
320
- filterNode: any;
321
- filterDepth: any;
322
- volumeEnvelopeNode: any;
323
- volumeDepth: any;
324
- modulationLFO: any;
325
- modulationDepth: any;
326
- vibratoLFO: any;
327
- vibratoDepth: any;
328
- reverbSend: any;
329
- chorusSend: any;
330
- portamentoNoteNumber: number;
331
- noteNumber: any;
332
- velocity: any;
333
- startTime: any;
334
- voice: any;
335
- voiceParams: any;
336
- }
337
- export {};
338
315
  //# sourceMappingURL=midy-GM2.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAkJA;IA4CE;;;;;;;;;;;;;;MAcE;IAEF,+BAoBC;IA/ED,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,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,sCAKC;IAED,yCAqBC;IAED,kDAUC;IAED,mDAIC;IAED,2FAWC;IAED,yEAwDC;IAED,mCAOC;IAED,uBAQC;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,sBAGC;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,+DAgBC;IAED,mDAIC;IAED,2CAoDC;IAED,8EAWC;IAED,oEAgBC;IAED,+DAKC;IAED,qDAoBC;IAED,6CAIC;IAED,8EAoBC;IAED,oEAwBC;IAED,kEAoBC;IAED,+DAeC;IAED,6FAyBC;IAED,oGAiEC;IAED,0EAiBC;IAED,8EAoBC;IAED,kGA+CC;IAED,6FASC;IAED,gCAmBC;IAED,iEAoBC;IAED,qGAuBC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;IAED,sFAeC;IAED,wFAkBC;IAED,+BAuBC;IAED,kDAOC;IAED,sBAEC;IAED,mFAcC;IAED,4EAgBC;IAED,wFAGC;IAED,sEAWC;IAED,mEAYC;IAED,mEAYC;IAED,sEAMC;IAED,oEAQC;IAED,gEAyBC;IAED,gEAyBC;IAED,gCAKC;IAED,kDAKC;IAED,gEAMC;IAED,8CAOC;IAED;;;;;;;;;;;MAiDC;IAED,oFAOC;IAED,6EA+BC;IAED,qCA2BC;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,sFAQC;IAED,sFAQC;IAED,kFAeC;IAED,2DAMC;IAED,uDAqBC;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,8EAoCC;IAED,gFAGC;IAED,iEAEC;IAED,gEAEC;IAED,gEAIC;IAED,gEAIC;IAED,+EAgCC;IAED,qCAYC;IAED,qCAYC;IAED,4EA4CC;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,6CAMC;IAED,0CAMC;IAED,uCAMC;IAED,wCAMC;IAED,2CAMC;IAED,yEAgBC;IAED,wEAaC;IAED,2CAIC;IAED,oFAOC;IAED,6DAcC;IAED,yEAIC;IAED,0CAmBC;IAED,yEAcC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA34FD;IAgBE,0FAMC;IArBD,cAAW;IACX,gBAAe;IACf,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,6BAA0B;IAGxB,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}