@marmooo/midy 0.4.6 → 0.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midy",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "A MIDI player/synthesizer written in JavaScript that supports GM-Lite/GM1 and SF2/SF3.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,7 +22,8 @@
22
22
  "test": "node test_runner.js"
23
23
  },
24
24
  "dependencies": {
25
- "@marmooo/soundfont-parser": "^0.1.7",
25
+ "@marmooo/soundfont-parser": "^0.1.8",
26
+ "@wasm-audio-decoders/ogg-vorbis": "^0.1.20",
26
27
  "midi-file": "^1.2.4"
27
28
  },
28
29
  "devDependencies": {
@@ -27,6 +27,8 @@ export class MidyGM1 extends EventTarget {
27
27
  voiceCounter: Map<any, any>;
28
28
  voiceCache: Map<any, any>;
29
29
  realtimeVoiceCache: Map<any, any>;
30
+ decodeMethod: string;
31
+ decoderQueue: Promise<void>;
30
32
  isPlaying: boolean;
31
33
  isPausing: boolean;
32
34
  isPaused: boolean;
@@ -72,6 +74,7 @@ export class MidyGM1 extends EventTarget {
72
74
  merger: any;
73
75
  };
74
76
  createChannels(audioContext: any): any[];
77
+ decodeOggVorbis(sample: any): Promise<any>;
75
78
  createAudioBuffer(voiceParams: any): Promise<any>;
76
79
  createBufferSource(voiceParams: any, audioBuffer: any): any;
77
80
  scheduleTimelineEvents(scheduleTime: any, queueIndex: any): any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAuGA;IAoCE;;;;;;;;;;;MAWE;IAEF,+BAgBC;IA5DD,gCAAgC;IAChC,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,iCAEG;IACH,cAAU;IACV,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,8DAeC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDASC;IAED,4DASC;IAED,gEAsDC;IAED,mCASC;IAED,uBAUC;IAED,yDAqCC;IAED,2BA0EC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAQC;IAED,uBAMC;IAED,sBAIC;IAED,uBAMC;IAED,wBAIC;IAED,0BAKC;IAED,8BAMC;IAED,wBAYC;IAED,sBAIC;IAED,kEAWC;IAED,kFAYC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,2DAIC;IAED,6CAEC;IAED,sDAeC;IAED,4DASC;IAED,qDAkBC;IAED,6CAIC;IAED,sDA6BC;IAED,kEAqBC;IAED,4GAkCC;IAED,uEAyCC;IAED,0EAiBC;IAED,oEASC;IAED,0FAwBC;IAED,gCASC;IAED,iEAwBC;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;;;;;;;;;;;;MAoCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDAUC;IAED,4EAKC;IAED,mEAKC;IAED;;;MAMC;IAED,gEAKC;IAED,uEAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAoBC;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,qCAUC;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":"AAmHA;IAsCE;;;;;;;;;;;MAWE;IAEF,+BAgBC;IA9DD,gCAAgC;IAChC,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,qBAAqC;IACrC,4BAAiC;IACjC,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iCAEG;IACH,cAAU;IACV,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,sBA6BC;IAED,8DAeC;IAED;;;;MAeC;IAED,yCAaC;IAED,2CAsBC;IAED,kDA6BC;IAED,4DASC;IAED,gEAsDC;IAED,mCASC;IAED,uBAUC;IAED,yDAqCC;IAED,2BA0EC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAQC;IAED,uBAMC;IAED,sBAIC;IAED,uBAMC;IAED,wBAIC;IAED,0BAKC;IAED,8BAMC;IAED,wBAYC;IAED,sBAIC;IAED,kEAWC;IAED,kFAYC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,2DAIC;IAED,6CAEC;IAED,sDAeC;IAED,4DASC;IAED,qDAkBC;IAED,6CAIC;IAED,sDA6BC;IAED,kEAqBC;IAED,4GAkCC;IAED,uEAyCC;IAED,0EAiBC;IAED,oEASC;IAED,0FAwBC;IAED,gCASC;IAED,iEAwBC;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;;;;;;;;;;;;MAoCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAYC;IAED,wDAUC;IAED,4EAKC;IAED,mEAKC;IAED;;;MAMC;IAED,gEAKC;IAED,uEAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAoBC;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,qCAUC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF"}
@@ -3,6 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGM1 = void 0;
4
4
  const midi_file_1 = require("midi-file");
5
5
  const soundfont_parser_1 = require("@marmooo/soundfont-parser");
6
+ const ogg_vorbis_1 = require("@wasm-audio-decoders/ogg-vorbis");
7
+ let decoderPromise = null;
8
+ let decoderQueue = Promise.resolve();
9
+ function initDecoder() {
10
+ if (!decoderPromise) {
11
+ const instance = new ogg_vorbis_1.OggVorbisDecoderWebWorker();
12
+ decoderPromise = instance.ready.then(() => instance);
13
+ }
14
+ return decoderPromise;
15
+ }
6
16
  class Note {
7
17
  constructor(noteNumber, velocity, startTime) {
8
18
  Object.defineProperty(this, "voice", {
@@ -41,37 +51,37 @@ class Note {
41
51
  writable: true,
42
52
  value: void 0
43
53
  });
44
- Object.defineProperty(this, "filterNode", {
54
+ Object.defineProperty(this, "filterEnvelopeNode", {
45
55
  enumerable: true,
46
56
  configurable: true,
47
57
  writable: true,
48
58
  value: void 0
49
59
  });
50
- Object.defineProperty(this, "filterDepth", {
60
+ Object.defineProperty(this, "volumeEnvelopeNode", {
51
61
  enumerable: true,
52
62
  configurable: true,
53
63
  writable: true,
54
64
  value: void 0
55
65
  });
56
- Object.defineProperty(this, "volumeEnvelopeNode", {
66
+ Object.defineProperty(this, "modLfo", {
57
67
  enumerable: true,
58
68
  configurable: true,
59
69
  writable: true,
60
70
  value: void 0
61
- });
62
- Object.defineProperty(this, "volumeDepth", {
71
+ }); // CC#1 modulation LFO
72
+ Object.defineProperty(this, "modLfoToPitch", {
63
73
  enumerable: true,
64
74
  configurable: true,
65
75
  writable: true,
66
76
  value: void 0
67
77
  });
68
- Object.defineProperty(this, "modulationLFO", {
78
+ Object.defineProperty(this, "modLfoToFilterFc", {
69
79
  enumerable: true,
70
80
  configurable: true,
71
81
  writable: true,
72
82
  value: void 0
73
83
  });
74
- Object.defineProperty(this, "modulationDepth", {
84
+ Object.defineProperty(this, "modLfoToVolume", {
75
85
  enumerable: true,
76
86
  configurable: true,
77
87
  writable: true,
@@ -258,6 +268,18 @@ class MidyGM1 extends EventTarget {
258
268
  writable: true,
259
269
  value: new Map()
260
270
  });
271
+ Object.defineProperty(this, "decodeMethod", {
272
+ enumerable: true,
273
+ configurable: true,
274
+ writable: true,
275
+ value: "wasm-audio-decoders"
276
+ });
277
+ Object.defineProperty(this, "decoderQueue", {
278
+ enumerable: true,
279
+ configurable: true,
280
+ writable: true,
281
+ value: Promise.resolve()
282
+ });
261
283
  Object.defineProperty(this, "isPlaying", {
262
284
  enumerable: true,
263
285
  configurable: true,
@@ -419,14 +441,6 @@ class MidyGM1 extends EventTarget {
419
441
  voiceCounter.set(audioBufferId, (voiceCounter.get(audioBufferId) ?? 0) + 1);
420
442
  break;
421
443
  }
422
- case "controller":
423
- if (event.controllerType === 0) {
424
- this.setBankMSB(event.channel, event.value);
425
- }
426
- else if (event.controllerType === 32) {
427
- this.setBankLSB(event.channel, event.value);
428
- }
429
- break;
430
444
  case "programChange":
431
445
  this.setProgramChange(event.channel, event.programNumber, event.startTime);
432
446
  }
@@ -484,11 +498,57 @@ class MidyGM1 extends EventTarget {
484
498
  });
485
499
  return channels;
486
500
  }
501
+ decodeOggVorbis(sample) {
502
+ const task = decoderQueue.then(async () => {
503
+ const decoder = await initDecoder();
504
+ const slice = sample.data.slice();
505
+ const { channelData, sampleRate, errors } = await decoder.decodeFile(slice);
506
+ if (0 < errors.length) {
507
+ throw new Error(errors.join(", "));
508
+ }
509
+ const audioBuffer = new AudioBuffer({
510
+ numberOfChannels: channelData.length,
511
+ length: channelData[0].length,
512
+ sampleRate,
513
+ });
514
+ for (let ch = 0; ch < channelData.length; ch++) {
515
+ audioBuffer.getChannelData(ch).set(channelData[ch]);
516
+ }
517
+ return audioBuffer;
518
+ });
519
+ decoderQueue = task.catch(() => { });
520
+ return task;
521
+ }
487
522
  async createAudioBuffer(voiceParams) {
488
- const { sample, start, end } = voiceParams;
489
- const sampleEnd = sample.data.length + end;
490
- const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
491
- return audioBuffer;
523
+ const sample = voiceParams.sample;
524
+ if (sample.type === "compressed") {
525
+ switch (this.decodeMethod) {
526
+ case "decodeAudioData": {
527
+ // https://jakearchibald.com/2016/sounds-fun/
528
+ // https://github.com/WebAudio/web-audio-api/issues/1091
529
+ // decodeAudioData() has priming issues on Safari
530
+ const arrayBuffer = sample.data.slice().buffer;
531
+ return await this.audioContext.decodeAudioData(arrayBuffer);
532
+ }
533
+ case "wasm-audio-decoders":
534
+ return await this.decodeOggVorbis(sample);
535
+ default:
536
+ throw new Error(`Unknown decodeMethod: ${this.decodeMethod}`);
537
+ }
538
+ }
539
+ else {
540
+ const data = sample.data;
541
+ const end = data.length + voiceParams.end;
542
+ const subarray = data.subarray(voiceParams.start, end);
543
+ const pcm = sample.decodePCM(subarray);
544
+ const audioBuffer = new AudioBuffer({
545
+ numberOfChannels: 1,
546
+ length: pcm.length,
547
+ sampleRate: sample.sampleHeader.sampleRate,
548
+ });
549
+ audioBuffer.getChannelData(0).set(pcm);
550
+ return audioBuffer;
551
+ }
492
552
  }
493
553
  createBufferSource(voiceParams, audioBuffer) {
494
554
  const bufferSource = new AudioBufferSourceNode(this.audioContext);
@@ -554,7 +614,7 @@ class MidyGM1 extends EventTarget {
554
614
  const channels = this.channels;
555
615
  for (let ch = 0; ch < channels.length; ch++) {
556
616
  channels[ch].scheduledNotes = [];
557
- this.resetChannelStates(i);
617
+ this.resetChannelStates(ch);
558
618
  }
559
619
  }
560
620
  updateStates(queueIndex, nextQueueIndex) {
@@ -937,7 +997,7 @@ class MidyGM1 extends EventTarget {
937
997
  const modHold = modAttack + voiceParams.modHold;
938
998
  const decayDuration = voiceParams.modDecay;
939
999
  note.adjustedBaseFreq = adjustedBaseFreq;
940
- note.filterNode.frequency
1000
+ note.filterEnvelopeNode.frequency
941
1001
  .cancelScheduledValues(scheduleTime)
942
1002
  .setValueAtTime(adjustedBaseFreq, startTime)
943
1003
  .setValueAtTime(adjustedBaseFreq, modDelay)
@@ -948,23 +1008,23 @@ class MidyGM1 extends EventTarget {
948
1008
  startModulation(channel, note, scheduleTime) {
949
1009
  const audioContext = this.audioContext;
950
1010
  const { voiceParams } = note;
951
- note.modulationLFO = new OscillatorNode(audioContext, {
1011
+ note.modLfo = new OscillatorNode(audioContext, {
952
1012
  frequency: this.centToHz(voiceParams.freqModLFO),
953
1013
  });
954
- note.filterDepth = new GainNode(audioContext, {
1014
+ note.modLfoToFilterFc = new GainNode(audioContext, {
955
1015
  gain: voiceParams.modLfoToFilterFc,
956
1016
  });
957
- note.modulationDepth = new GainNode(audioContext);
1017
+ note.modLfoToPitch = new GainNode(audioContext);
958
1018
  this.setModLfoToPitch(channel, note, scheduleTime);
959
- note.volumeDepth = new GainNode(audioContext);
1019
+ note.modLfoToVolume = new GainNode(audioContext);
960
1020
  this.setModLfoToVolume(note, scheduleTime);
961
- note.modulationLFO.start(note.startTime + voiceParams.delayModLFO);
962
- note.modulationLFO.connect(note.filterDepth);
963
- note.filterDepth.connect(note.filterNode.frequency);
964
- note.modulationLFO.connect(note.modulationDepth);
965
- note.modulationDepth.connect(note.bufferSource.detune);
966
- note.modulationLFO.connect(note.volumeDepth);
967
- note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
1021
+ note.modLfo.start(note.startTime + voiceParams.delayModLFO);
1022
+ note.modLfo.connect(note.modLfoToFilterFc);
1023
+ note.modLfoToFilterFc.connect(note.filterEnvelopeNode.frequency);
1024
+ note.modLfo.connect(note.modLfoToPitch);
1025
+ note.modLfoToPitch.connect(note.bufferSource.detune);
1026
+ note.modLfo.connect(note.modLfoToVolume);
1027
+ note.modLfoToVolume.connect(note.volumeEnvelopeNode.gain);
968
1028
  }
969
1029
  async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
970
1030
  const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
@@ -1005,7 +1065,7 @@ class MidyGM1 extends EventTarget {
1005
1065
  const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
1006
1066
  note.bufferSource = this.createBufferSource(voiceParams, audioBuffer);
1007
1067
  note.volumeEnvelopeNode = new GainNode(audioContext);
1008
- note.filterNode = new BiquadFilterNode(audioContext, {
1068
+ note.filterEnvelopeNode = new BiquadFilterNode(audioContext, {
1009
1069
  type: "lowpass",
1010
1070
  Q: voiceParams.initialFilterQ / 10, // dB
1011
1071
  });
@@ -1016,8 +1076,8 @@ class MidyGM1 extends EventTarget {
1016
1076
  if (0 < state.modulationDepthMSB) {
1017
1077
  this.startModulation(channel, note, now);
1018
1078
  }
1019
- note.bufferSource.connect(note.filterNode);
1020
- note.filterNode.connect(note.volumeEnvelopeNode);
1079
+ note.bufferSource.connect(note.filterEnvelopeNode);
1080
+ note.filterEnvelopeNode.connect(note.volumeEnvelopeNode);
1021
1081
  if (voiceParams.sample.type === "compressed") {
1022
1082
  const offset = voiceParams.start / audioBuffer.sampleRate;
1023
1083
  note.bufferSource.start(startTime, offset);
@@ -1083,19 +1143,19 @@ class MidyGM1 extends EventTarget {
1083
1143
  }
1084
1144
  disconnectNote(note) {
1085
1145
  note.bufferSource.disconnect();
1086
- note.filterNode.disconnect();
1146
+ note.filterEnvelopeNode.disconnect();
1087
1147
  note.volumeEnvelopeNode.disconnect();
1088
- if (note.modulationDepth) {
1089
- note.volumeDepth.disconnect();
1090
- note.modulationDepth.disconnect();
1091
- note.modulationLFO.stop();
1148
+ if (note.modLfoToPitch) {
1149
+ note.modLfoToVolume.disconnect();
1150
+ note.modLfoToPitch.disconnect();
1151
+ note.modLfo.stop();
1092
1152
  }
1093
1153
  }
1094
1154
  releaseNote(channel, note, endTime) {
1095
1155
  endTime ??= this.audioContext.currentTime;
1096
1156
  const volDuration = note.voiceParams.volRelease;
1097
1157
  const volRelease = endTime + volDuration;
1098
- note.filterNode.frequency
1158
+ note.filterEnvelopeNode.frequency
1099
1159
  .cancelScheduledValues(endTime)
1100
1160
  .setTargetAtTime(note.adjustedBaseFreq, endTime, note.voiceParams.modRelease * releaseCurve);
1101
1161
  note.volumeEnvelopeNode.gain
@@ -1223,12 +1283,12 @@ class MidyGM1 extends EventTarget {
1223
1283
  this.applyVoiceParams(channel, 14, scheduleTime);
1224
1284
  }
1225
1285
  setModLfoToPitch(channel, note, scheduleTime) {
1226
- if (note.modulationDepth) {
1286
+ if (note.modLfoToPitch) {
1227
1287
  const modLfoToPitch = note.voiceParams.modLfoToPitch;
1228
1288
  const baseDepth = Math.abs(modLfoToPitch) +
1229
1289
  channel.state.modulationDepthMSB;
1230
1290
  const depth = baseDepth * Math.sign(modLfoToPitch);
1231
- note.modulationDepth.gain
1291
+ note.modLfoToPitch.gain
1232
1292
  .cancelScheduledValues(scheduleTime)
1233
1293
  .setValueAtTime(depth, scheduleTime);
1234
1294
  }
@@ -1238,29 +1298,29 @@ class MidyGM1 extends EventTarget {
1238
1298
  }
1239
1299
  setModLfoToFilterFc(note, scheduleTime) {
1240
1300
  const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc;
1241
- note.filterDepth.gain
1301
+ note.modLfoToFilterFc.gain
1242
1302
  .cancelScheduledValues(scheduleTime)
1243
1303
  .setValueAtTime(modLfoToFilterFc, scheduleTime);
1244
1304
  }
1245
1305
  setModLfoToVolume(note, scheduleTime) {
1246
1306
  const modLfoToVolume = note.voiceParams.modLfoToVolume;
1247
1307
  const baseDepth = cbToRatio(Math.abs(modLfoToVolume)) - 1;
1248
- const volumeDepth = baseDepth * Math.sign(modLfoToVolume);
1249
- note.volumeDepth.gain
1308
+ const depth = baseDepth * Math.sign(modLfoToVolume);
1309
+ note.modLfoToVolume.gain
1250
1310
  .cancelScheduledValues(scheduleTime)
1251
- .setValueAtTime(volumeDepth, scheduleTime);
1311
+ .setValueAtTime(depth, scheduleTime);
1252
1312
  }
1253
1313
  setDelayModLFO(note, scheduleTime) {
1254
1314
  const startTime = note.startTime;
1255
1315
  if (startTime < scheduleTime)
1256
1316
  return;
1257
- note.modulationLFO.stop(scheduleTime);
1258
- note.modulationLFO.start(startTime + note.voiceParams.delayModLFO);
1259
- note.modulationLFO.connect(note.filterDepth);
1317
+ note.modLfo.stop(scheduleTime);
1318
+ note.modLfo.start(startTime + note.voiceParams.delayModLFO);
1319
+ note.modLfo.connect(note.modLfoToFilterFc);
1260
1320
  }
1261
1321
  setFreqModLFO(note, scheduleTime) {
1262
1322
  const freqModLFO = note.voiceParams.freqModLFO;
1263
- note.modulationLFO.frequency
1323
+ note.modLfo.frequency
1264
1324
  .cancelScheduledValues(scheduleTime)
1265
1325
  .setValueAtTime(freqModLFO, scheduleTime);
1266
1326
  }
@@ -1357,6 +1417,8 @@ class MidyGM1 extends EventTarget {
1357
1417
  return handlers;
1358
1418
  }
1359
1419
  setControlChange(channelNumber, controllerType, value, scheduleTime) {
1420
+ if (!(0 <= scheduleTime))
1421
+ scheduleTime = this.audioContext.currentTime;
1360
1422
  const handler = this.controlChangeHandlers[controllerType];
1361
1423
  if (handler) {
1362
1424
  handler.call(this, channelNumber, value, scheduleTime);
@@ -1371,8 +1433,8 @@ class MidyGM1 extends EventTarget {
1371
1433
  const depth = channel.state.modulationDepthMSB *
1372
1434
  channel.modulationDepthRange;
1373
1435
  this.processScheduledNotes(channel, (note) => {
1374
- if (note.modulationDepth) {
1375
- note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
1436
+ if (note.modLfoToPitch) {
1437
+ note.modLfoToPitch.gain.setValueAtTime(depth, scheduleTime);
1376
1438
  }
1377
1439
  else {
1378
1440
  this.startModulation(channel, note, scheduleTime);
@@ -46,6 +46,7 @@ export class MidyGM2 extends EventTarget {
46
46
  voiceCounter: Map<any, any>;
47
47
  voiceCache: Map<any, any>;
48
48
  realtimeVoiceCache: Map<any, any>;
49
+ decodeMethod: string;
49
50
  isPlaying: boolean;
50
51
  isPausing: boolean;
51
52
  isPaused: boolean;
@@ -80,6 +81,7 @@ export class MidyGM2 extends EventTarget {
80
81
  };
81
82
  controlChangeHandlers: any[];
82
83
  keyBasedControllerHandlers: any[];
84
+ effectHandlers: any[];
83
85
  channels: any[];
84
86
  reverbEffect: {
85
87
  input: any;
@@ -107,6 +109,7 @@ export class MidyGM2 extends EventTarget {
107
109
  };
108
110
  resetChannelTable(channel: any): void;
109
111
  createChannels(audioContext: any): any[];
112
+ decodeOggVorbis(sample: any): Promise<any>;
110
113
  createAudioBuffer(voiceParams: any): Promise<any>;
111
114
  isLoopDrum(channel: any, noteNumber: any): boolean;
112
115
  createBufferSource(channel: any, noteNumber: any, voiceParams: any, audioBuffer: any): any;
@@ -234,6 +237,7 @@ export class MidyGM2 extends EventTarget {
234
237
  updatePortamento(channel: any, scheduleTime: any): void;
235
238
  setPortamentoTime(channelNumber: any, value: any, scheduleTime: any): void;
236
239
  setVolume(channelNumber: any, value: any, scheduleTime: any): void;
240
+ applyVolume(channel: any, scheduleTime: any): void;
237
241
  panToGain(pan: any): {
238
242
  gainLeft: number;
239
243
  gainRight: number;
@@ -304,15 +308,23 @@ export class MidyGM2 extends EventTarget {
304
308
  getChorusSendToReverb(value: any): number;
305
309
  getChannelBitmap(data: any): any[];
306
310
  handleScaleOctaveTuning1ByteFormatSysEx(data: any, realtime: any, scheduleTime: any): void;
311
+ calcEffectValue(channel: any, destination: any): number;
312
+ calcChannelEffectValue(channel: any, destination: any): number;
313
+ calcControlChangeEffectValue(channel: any, destination: any): number;
314
+ calcChannelPressureEffectValue(channel: any, destination: any): number;
315
+ getChannelPitchControl(channel: any): number;
316
+ getPitchControl(channel: any, note: any): number;
307
317
  getFilterCutoffControl(channel: any): number;
308
- getAmplitudeControl(channel: any): number;
318
+ getChannelAmplitudeControl(channel: any): number;
309
319
  getLFOPitchDepth(channel: any): number;
310
320
  getLFOFilterDepth(channel: any): number;
311
321
  getLFOAmplitudeDepth(channel: any): number;
312
- setEffects(channel: any, note: any, table: any, scheduleTime: any): void;
322
+ createEffectHandlers(): any[];
323
+ setControlChangeEffects(channel: any, note: any, scheduleTime: any): void;
324
+ setChannelPressureEffects(channel: any, note: any, scheduleTime: any): void;
325
+ setPressureEffects(channel: any, note: any, tableName: any, scheduleTime: any): void;
326
+ handleChannelPressureSysEx(data: any, scheduleTime: any): void;
313
327
  handlePressureSysEx(data: any, tableName: any, scheduleTime: any): void;
314
- initControlTable(): Int8Array<ArrayBuffer>;
315
- setControlChangeEffects(channel: any, controllerType: any, scheduleTime: any): void;
316
328
  handleControlChangeSysEx(data: any, scheduleTime: any): void;
317
329
  getKeyBasedValue(channel: any, keyNumber: any, controllerType: any): any;
318
330
  createKeyBasedControllerHandlers(): any[];
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}