@marmooo/midy 0.1.2 → 0.1.4
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/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts +153 -0
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +1 -0
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.2 → soundfont-parser@0.0.4}/+esm.js +73 -66
- package/esm/midy-GM1.d.ts +19 -13
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +171 -131
- package/esm/midy-GM2.d.ts +22 -14
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +186 -133
- package/esm/midy-GMLite.d.ts +17 -13
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +159 -131
- package/esm/midy.d.ts +30 -16
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +266 -166
- package/package.json +1 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts +153 -0
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +1 -0
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.2 → soundfont-parser@0.0.4}/+esm.js +75 -68
- package/script/midy-GM1.d.ts +19 -13
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +171 -131
- package/script/midy-GM2.d.ts +22 -14
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +186 -133
- package/script/midy-GMLite.d.ts +17 -13
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +159 -131
- package/script/midy.d.ts +30 -16
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +266 -166
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts +0 -135
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +0 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts +0 -135
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +0 -1
package/esm/midy-GMLite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
|
|
2
|
-
import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.
|
|
2
|
+
import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js";
|
|
3
3
|
class Note {
|
|
4
4
|
constructor(noteNumber, velocity, startTime, instrumentKey) {
|
|
5
5
|
Object.defineProperty(this, "bufferSource", {
|
|
@@ -8,25 +8,31 @@ class Note {
|
|
|
8
8
|
writable: true,
|
|
9
9
|
value: void 0
|
|
10
10
|
});
|
|
11
|
-
Object.defineProperty(this, "
|
|
11
|
+
Object.defineProperty(this, "filterNode", {
|
|
12
12
|
enumerable: true,
|
|
13
13
|
configurable: true,
|
|
14
14
|
writable: true,
|
|
15
15
|
value: void 0
|
|
16
16
|
});
|
|
17
|
-
Object.defineProperty(this, "
|
|
17
|
+
Object.defineProperty(this, "volumeNode", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
value: void 0
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(this, "volumeDepth", {
|
|
18
24
|
enumerable: true,
|
|
19
25
|
configurable: true,
|
|
20
26
|
writable: true,
|
|
21
27
|
value: void 0
|
|
22
28
|
});
|
|
23
|
-
Object.defineProperty(this, "
|
|
29
|
+
Object.defineProperty(this, "modulationLFO", {
|
|
24
30
|
enumerable: true,
|
|
25
31
|
configurable: true,
|
|
26
32
|
writable: true,
|
|
27
33
|
value: void 0
|
|
28
34
|
});
|
|
29
|
-
Object.defineProperty(this, "
|
|
35
|
+
Object.defineProperty(this, "modulationDepth", {
|
|
30
36
|
enumerable: true,
|
|
31
37
|
configurable: true,
|
|
32
38
|
writable: true,
|
|
@@ -313,7 +319,7 @@ export class MidyGMLite {
|
|
|
313
319
|
const t = this.audioContext.currentTime + offset;
|
|
314
320
|
queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
|
|
315
321
|
if (this.isPausing) {
|
|
316
|
-
await this.stopNotes();
|
|
322
|
+
await this.stopNotes(0, true);
|
|
317
323
|
this.notePromises = [];
|
|
318
324
|
resolve();
|
|
319
325
|
this.isPausing = false;
|
|
@@ -321,7 +327,7 @@ export class MidyGMLite {
|
|
|
321
327
|
return;
|
|
322
328
|
}
|
|
323
329
|
else if (this.isStopping) {
|
|
324
|
-
await this.stopNotes();
|
|
330
|
+
await this.stopNotes(0, true);
|
|
325
331
|
this.notePromises = [];
|
|
326
332
|
resolve();
|
|
327
333
|
this.isStopping = false;
|
|
@@ -329,7 +335,7 @@ export class MidyGMLite {
|
|
|
329
335
|
return;
|
|
330
336
|
}
|
|
331
337
|
else if (this.isSeeking) {
|
|
332
|
-
this.stopNotes();
|
|
338
|
+
this.stopNotes(0, true);
|
|
333
339
|
this.startTime = this.audioContext.currentTime;
|
|
334
340
|
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
335
341
|
offset = this.resumeTime - this.startTime;
|
|
@@ -410,21 +416,25 @@ export class MidyGMLite {
|
|
|
410
416
|
}
|
|
411
417
|
return { instruments, timeline };
|
|
412
418
|
}
|
|
413
|
-
|
|
419
|
+
async stopChannelNotes(channelNumber, velocity, stopPedal) {
|
|
414
420
|
const now = this.audioContext.currentTime;
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
|
-
channel.scheduledNotes.clear();
|
|
421
|
+
const channel = this.channels[channelNumber];
|
|
422
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
423
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
424
|
+
const note = noteList[i];
|
|
425
|
+
if (!note)
|
|
426
|
+
continue;
|
|
427
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
|
|
428
|
+
this.notePromises.push(promise);
|
|
429
|
+
}
|
|
427
430
|
});
|
|
431
|
+
channel.scheduledNotes.clear();
|
|
432
|
+
await Promise.all(this.notePromises);
|
|
433
|
+
}
|
|
434
|
+
stopNotes(velocity, stopPedal) {
|
|
435
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
436
|
+
this.stopChannelNotes(i, velocity, stopPedal);
|
|
437
|
+
}
|
|
428
438
|
return Promise.all(this.notePromises);
|
|
429
439
|
}
|
|
430
440
|
async start() {
|
|
@@ -507,75 +517,111 @@ export class MidyGMLite {
|
|
|
507
517
|
}
|
|
508
518
|
setVolumeEnvelope(note) {
|
|
509
519
|
const { instrumentKey, startTime } = note;
|
|
510
|
-
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
511
520
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
512
521
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
513
522
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
514
523
|
const volAttack = volDelay + instrumentKey.volAttack;
|
|
515
524
|
const volHold = volAttack + instrumentKey.volHold;
|
|
516
525
|
const volDecay = volHold + instrumentKey.volDecay;
|
|
517
|
-
note.
|
|
526
|
+
note.volumeNode.gain
|
|
527
|
+
.cancelScheduledValues(startTime)
|
|
528
|
+
.setValueAtTime(0, startTime)
|
|
518
529
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
519
530
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
520
531
|
.setValueAtTime(attackVolume, volHold)
|
|
521
532
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
522
533
|
}
|
|
523
|
-
|
|
524
|
-
const { instrumentKey,
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const
|
|
531
|
-
const
|
|
532
|
-
|
|
534
|
+
setPitch(note, semitoneOffset) {
|
|
535
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
536
|
+
const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
|
|
537
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
538
|
+
if (modEnvToPitch === 0)
|
|
539
|
+
return;
|
|
540
|
+
const basePitch = note.bufferSource.playbackRate.value;
|
|
541
|
+
const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
|
|
542
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
543
|
+
const modAttack = modDelay + instrumentKey.modAttack;
|
|
544
|
+
const modHold = modAttack + instrumentKey.modHold;
|
|
545
|
+
const modDecay = modHold + instrumentKey.modDecay;
|
|
546
|
+
note.bufferSource.playbackRate.value
|
|
547
|
+
.setValueAtTime(basePitch, modDelay)
|
|
548
|
+
.exponentialRampToValueAtTime(peekPitch, modAttack)
|
|
549
|
+
.setValueAtTime(peekPitch, modHold)
|
|
550
|
+
.linearRampToValueAtTime(basePitch, modDecay);
|
|
551
|
+
}
|
|
552
|
+
clampCutoffFrequency(frequency) {
|
|
553
|
+
const minFrequency = 20; // min Hz of initialFilterFc
|
|
554
|
+
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
555
|
+
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
556
|
+
}
|
|
557
|
+
setFilterEnvelope(note) {
|
|
558
|
+
const { instrumentKey, startTime } = note;
|
|
559
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
560
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc);
|
|
561
|
+
const sustainFreq = baseFreq +
|
|
562
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
563
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
564
|
+
const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
|
|
565
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
533
566
|
const modDelay = startTime + instrumentKey.modDelay;
|
|
534
567
|
const modAttack = modDelay + instrumentKey.modAttack;
|
|
535
568
|
const modHold = modAttack + instrumentKey.modHold;
|
|
536
569
|
const modDecay = modHold + instrumentKey.modDecay;
|
|
537
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
538
|
-
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
539
|
-
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
540
|
-
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
541
|
-
type: "lowpass",
|
|
542
|
-
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
543
|
-
frequency: adjustedBaseFreq,
|
|
544
|
-
});
|
|
545
570
|
note.filterNode.frequency
|
|
571
|
+
.cancelScheduledValues(startTime)
|
|
572
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
546
573
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
547
574
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
548
575
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
549
576
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
550
|
-
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
|
|
551
577
|
}
|
|
552
|
-
startModulation(channel, note,
|
|
578
|
+
startModulation(channel, note, startTime) {
|
|
553
579
|
const { instrumentKey } = note;
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
});
|
|
557
|
-
note.modLFO = new OscillatorNode(this.audioContext, {
|
|
580
|
+
const { modLfoToPitch, modLfoToVolume } = instrumentKey;
|
|
581
|
+
note.modulationLFO = new OscillatorNode(this.audioContext, {
|
|
558
582
|
frequency: this.centToHz(instrumentKey.freqModLFO),
|
|
559
583
|
});
|
|
560
|
-
note.
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
584
|
+
note.filterDepth = new GainNode(this.audioContext, {
|
|
585
|
+
gain: instrumentKey.modLfoToFilterFc,
|
|
586
|
+
});
|
|
587
|
+
const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
|
|
588
|
+
const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
|
|
589
|
+
note.modulationDepth = new GainNode(this.audioContext, {
|
|
590
|
+
gain: modulationDepth * modulationDepthSign,
|
|
591
|
+
});
|
|
592
|
+
const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
|
|
593
|
+
const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
|
|
594
|
+
note.volumeDepth = new GainNode(this.audioContext, {
|
|
595
|
+
gain: volumeDepth * volumeDepthSign,
|
|
596
|
+
});
|
|
597
|
+
note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
|
|
598
|
+
note.modulationLFO.connect(note.filterDepth);
|
|
599
|
+
note.filterDepth.connect(note.filterNode.frequency);
|
|
600
|
+
note.modulationLFO.connect(note.modulationDepth);
|
|
601
|
+
note.modulationDepth.connect(note.bufferSource.detune);
|
|
602
|
+
note.modulationLFO.connect(note.volumeDepth);
|
|
603
|
+
note.volumeDepth.connect(note.volumeNode.gain);
|
|
565
604
|
}
|
|
566
605
|
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
567
606
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
568
607
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
569
608
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
570
|
-
note.
|
|
609
|
+
note.volumeNode = new GainNode(this.audioContext);
|
|
610
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
611
|
+
type: "lowpass",
|
|
612
|
+
Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
|
|
613
|
+
});
|
|
571
614
|
this.setVolumeEnvelope(note);
|
|
572
|
-
this.setFilterEnvelope(
|
|
573
|
-
if (channel.
|
|
574
|
-
|
|
575
|
-
this.startModulation(channel, note,
|
|
615
|
+
this.setFilterEnvelope(note);
|
|
616
|
+
if (0 < channel.modulationDepth) {
|
|
617
|
+
this.setPitch(note, semitoneOffset);
|
|
618
|
+
this.startModulation(channel, note, startTime);
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
576
622
|
}
|
|
577
623
|
note.bufferSource.connect(note.filterNode);
|
|
578
|
-
note.filterNode.connect(note.
|
|
624
|
+
note.filterNode.connect(note.volumeNode);
|
|
579
625
|
note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
|
|
580
626
|
return note;
|
|
581
627
|
}
|
|
@@ -591,8 +637,8 @@ export class MidyGMLite {
|
|
|
591
637
|
if (!instrumentKey)
|
|
592
638
|
return;
|
|
593
639
|
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
594
|
-
note.
|
|
595
|
-
note.
|
|
640
|
+
note.volumeNode.connect(channel.gainL);
|
|
641
|
+
note.volumeNode.connect(channel.gainR);
|
|
596
642
|
const scheduledNotes = channel.scheduledNotes;
|
|
597
643
|
if (scheduledNotes.has(noteNumber)) {
|
|
598
644
|
scheduledNotes.get(noteNumber).push(note);
|
|
@@ -605,7 +651,7 @@ export class MidyGMLite {
|
|
|
605
651
|
const now = this.audioContext.currentTime;
|
|
606
652
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
607
653
|
}
|
|
608
|
-
scheduleNoteRelease(channelNumber, noteNumber,
|
|
654
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
|
|
609
655
|
const channel = this.channels[channelNumber];
|
|
610
656
|
if (stopPedal && channel.sustainPedal)
|
|
611
657
|
return;
|
|
@@ -618,20 +664,14 @@ export class MidyGMLite {
|
|
|
618
664
|
continue;
|
|
619
665
|
if (note.ending)
|
|
620
666
|
continue;
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
note.instrumentKey.volRelease * velocityRate;
|
|
624
|
-
note.gainNode.gain
|
|
667
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
668
|
+
note.volumeNode.gain
|
|
625
669
|
.cancelScheduledValues(stopTime)
|
|
626
670
|
.linearRampToValueAtTime(0, volEndTime);
|
|
627
|
-
const
|
|
628
|
-
const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
|
|
629
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
630
|
-
const modEndTime = stopTime +
|
|
631
|
-
note.instrumentKey.modRelease * velocityRate;
|
|
671
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
632
672
|
note.filterNode.frequency
|
|
633
673
|
.cancelScheduledValues(stopTime)
|
|
634
|
-
.linearRampToValueAtTime(
|
|
674
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
635
675
|
note.ending = true;
|
|
636
676
|
this.scheduleTask(() => {
|
|
637
677
|
note.bufferSource.loop = false;
|
|
@@ -640,15 +680,17 @@ export class MidyGMLite {
|
|
|
640
680
|
note.bufferSource.onended = () => {
|
|
641
681
|
scheduledNotes[i] = null;
|
|
642
682
|
note.bufferSource.disconnect();
|
|
683
|
+
note.volumeNode.disconnect();
|
|
643
684
|
note.filterNode.disconnect();
|
|
644
|
-
note.
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
685
|
+
if (note.volumeDepth)
|
|
686
|
+
note.volumeDepth.disconnect();
|
|
687
|
+
if (note.modulationDepth)
|
|
688
|
+
note.modulationDepth.disconnect();
|
|
689
|
+
if (note.modulationLFO)
|
|
690
|
+
note.modulationLFO.stop();
|
|
649
691
|
resolve();
|
|
650
692
|
};
|
|
651
|
-
bufferSource.stop(volEndTime);
|
|
693
|
+
note.bufferSource.stop(volEndTime);
|
|
652
694
|
});
|
|
653
695
|
}
|
|
654
696
|
}
|
|
@@ -661,14 +703,15 @@ export class MidyGMLite {
|
|
|
661
703
|
const channel = this.channels[channelNumber];
|
|
662
704
|
const promises = [];
|
|
663
705
|
channel.sustainPedal = false;
|
|
664
|
-
channel.scheduledNotes.forEach((
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
706
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
707
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
708
|
+
const note = noteList[i];
|
|
709
|
+
if (!note)
|
|
710
|
+
continue;
|
|
711
|
+
const { noteNumber } = note;
|
|
712
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
713
|
+
promises.push(promise);
|
|
714
|
+
}
|
|
672
715
|
});
|
|
673
716
|
return promises;
|
|
674
717
|
}
|
|
@@ -709,7 +752,7 @@ export class MidyGMLite {
|
|
|
709
752
|
handleControlChange(channelNumber, controller, value) {
|
|
710
753
|
switch (controller) {
|
|
711
754
|
case 1:
|
|
712
|
-
return this.
|
|
755
|
+
return this.setModulationDepth(channelNumber, value);
|
|
713
756
|
case 6:
|
|
714
757
|
return this.dataEntryMSB(channelNumber, value);
|
|
715
758
|
case 7:
|
|
@@ -738,20 +781,25 @@ export class MidyGMLite {
|
|
|
738
781
|
}
|
|
739
782
|
updateModulation(channel) {
|
|
740
783
|
const now = this.audioContext.currentTime;
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
784
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
785
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
786
|
+
const note = noteList[i];
|
|
787
|
+
if (!note)
|
|
788
|
+
continue;
|
|
789
|
+
if (note.modulationDepth) {
|
|
790
|
+
note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
794
|
+
this.setPitch(note, semitoneOffset);
|
|
795
|
+
this.startModulation(channel, note, now);
|
|
796
|
+
}
|
|
749
797
|
}
|
|
750
798
|
});
|
|
751
799
|
}
|
|
752
|
-
|
|
800
|
+
setModulationDepth(channelNumber, modulation) {
|
|
753
801
|
const channel = this.channels[channelNumber];
|
|
754
|
-
channel.
|
|
802
|
+
channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
|
|
755
803
|
this.updateModulation(channel);
|
|
756
804
|
}
|
|
757
805
|
setVolume(channelNumber, volume) {
|
|
@@ -821,13 +869,17 @@ export class MidyGMLite {
|
|
|
821
869
|
}
|
|
822
870
|
updateDetune(channel, detuneChange) {
|
|
823
871
|
const now = this.audioContext.currentTime;
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
.
|
|
872
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
873
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
874
|
+
const note = noteList[i];
|
|
875
|
+
if (!note)
|
|
876
|
+
continue;
|
|
877
|
+
const { bufferSource } = note;
|
|
878
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
879
|
+
bufferSource.detune
|
|
880
|
+
.cancelScheduledValues(now)
|
|
881
|
+
.setValueAtTime(detune, now);
|
|
882
|
+
}
|
|
831
883
|
});
|
|
832
884
|
}
|
|
833
885
|
handlePitchBendRangeRPN(channelNumber) {
|
|
@@ -845,37 +897,13 @@ export class MidyGMLite {
|
|
|
845
897
|
this.updateDetune(channel, detuneChange);
|
|
846
898
|
}
|
|
847
899
|
allSoundOff(channelNumber) {
|
|
848
|
-
|
|
849
|
-
const channel = this.channels[channelNumber];
|
|
850
|
-
const velocity = 0;
|
|
851
|
-
const stopPedal = true;
|
|
852
|
-
const promises = [];
|
|
853
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
854
|
-
const activeNote = this.getActiveNote(noteList, now);
|
|
855
|
-
if (activeNote) {
|
|
856
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
857
|
-
promises.push(notePromise);
|
|
858
|
-
}
|
|
859
|
-
});
|
|
860
|
-
return promises;
|
|
900
|
+
return this.stopChannelNotes(channelNumber, 0, true);
|
|
861
901
|
}
|
|
862
902
|
resetAllControllers(channelNumber) {
|
|
863
903
|
Object.assign(this.channels[channelNumber], this.effectSettings);
|
|
864
904
|
}
|
|
865
905
|
allNotesOff(channelNumber) {
|
|
866
|
-
|
|
867
|
-
const channel = this.channels[channelNumber];
|
|
868
|
-
const velocity = 0;
|
|
869
|
-
const stopPedal = false;
|
|
870
|
-
const promises = [];
|
|
871
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
872
|
-
const activeNote = this.getActiveNote(noteList, now);
|
|
873
|
-
if (activeNote) {
|
|
874
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
|
|
875
|
-
promises.push(notePromise);
|
|
876
|
-
}
|
|
877
|
-
});
|
|
878
|
-
return promises;
|
|
906
|
+
return this.stopChannelNotes(channelNumber, 0, false);
|
|
879
907
|
}
|
|
880
908
|
handleUniversalNonRealTimeExclusiveMessage(data) {
|
|
881
909
|
switch (data[2]) {
|
|
@@ -968,7 +996,7 @@ Object.defineProperty(MidyGMLite, "channelSettings", {
|
|
|
968
996
|
dataLSB: 0,
|
|
969
997
|
program: 0,
|
|
970
998
|
pitchBend: 0,
|
|
971
|
-
modulationDepthRange:
|
|
999
|
+
modulationDepthRange: 50, // cent
|
|
972
1000
|
}
|
|
973
1001
|
});
|
|
974
1002
|
Object.defineProperty(MidyGMLite, "effectSettings", {
|
|
@@ -977,7 +1005,7 @@ Object.defineProperty(MidyGMLite, "effectSettings", {
|
|
|
977
1005
|
writable: true,
|
|
978
1006
|
value: {
|
|
979
1007
|
expression: 1,
|
|
980
|
-
|
|
1008
|
+
modulationDepth: 0,
|
|
981
1009
|
sustainPedal: false,
|
|
982
1010
|
rpnMSB: 127,
|
|
983
1011
|
rpnLSB: 127,
|
package/esm/midy.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ export class Midy {
|
|
|
4
4
|
volume: number;
|
|
5
5
|
pan: number;
|
|
6
6
|
portamentoTime: number;
|
|
7
|
+
filterResonance: number;
|
|
8
|
+
releaseTime: number;
|
|
9
|
+
attackTime: number;
|
|
10
|
+
brightness: number;
|
|
11
|
+
decayTime: number;
|
|
7
12
|
reverbSendLevel: number;
|
|
8
13
|
chorusSendLevel: number;
|
|
9
14
|
vibratoRate: number;
|
|
@@ -22,7 +27,7 @@ export class Midy {
|
|
|
22
27
|
};
|
|
23
28
|
static effectSettings: {
|
|
24
29
|
expression: number;
|
|
25
|
-
|
|
30
|
+
modulationDepth: number;
|
|
26
31
|
sustainPedal: boolean;
|
|
27
32
|
portamento: boolean;
|
|
28
33
|
sostenutoPedal: boolean;
|
|
@@ -128,7 +133,8 @@ export class Midy {
|
|
|
128
133
|
instruments: Set<any>;
|
|
129
134
|
timeline: any[];
|
|
130
135
|
};
|
|
131
|
-
|
|
136
|
+
stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
|
|
137
|
+
stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
|
|
132
138
|
start(): Promise<void>;
|
|
133
139
|
stop(): void;
|
|
134
140
|
pause(): void;
|
|
@@ -164,28 +170,30 @@ export class Midy {
|
|
|
164
170
|
centToHz(cent: any): number;
|
|
165
171
|
calcSemitoneOffset(channel: any): any;
|
|
166
172
|
calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
|
|
167
|
-
setVolumeEnvelope(note: any): void;
|
|
173
|
+
setVolumeEnvelope(channel: any, note: any): void;
|
|
174
|
+
setPitch(note: any, semitoneOffset: any): void;
|
|
175
|
+
clampCutoffFrequency(frequency: any): number;
|
|
168
176
|
setFilterEnvelope(channel: any, note: any): void;
|
|
169
|
-
startModulation(channel: any, note: any,
|
|
170
|
-
startVibrato(channel: any, note: any,
|
|
177
|
+
startModulation(channel: any, note: any, startTime: any): void;
|
|
178
|
+
startVibrato(channel: any, note: any, startTime: any): void;
|
|
171
179
|
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
172
180
|
calcBank(channel: any, channelNumber: any): any;
|
|
173
181
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
174
182
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
175
|
-
scheduleNoteRelease(channelNumber: any, noteNumber: any,
|
|
183
|
+
scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
176
184
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
177
185
|
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
178
186
|
releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
|
|
179
|
-
handleMIDIMessage(statusByte: any, data1: any, data2: any): void |
|
|
187
|
+
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
|
|
180
188
|
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
181
189
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
182
190
|
handleChannelPressure(channelNumber: any, pressure: any): void;
|
|
183
191
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
184
192
|
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
185
|
-
handleControlChange(channelNumber: any, controller: any, value: any): void |
|
|
193
|
+
handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
|
|
186
194
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
187
195
|
updateModulation(channel: any): void;
|
|
188
|
-
|
|
196
|
+
setModulationDepth(channelNumber: any, modulation: any): void;
|
|
189
197
|
setPortamentoTime(channelNumber: any, portamentoTime: any): void;
|
|
190
198
|
setVolume(channelNumber: any, volume: any): void;
|
|
191
199
|
panToGain(pan: any): {
|
|
@@ -203,6 +211,11 @@ export class Midy {
|
|
|
203
211
|
setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
|
|
204
212
|
setSostenutoPedal(channelNumber: any, value: any): void;
|
|
205
213
|
setSoftPedal(channelNumber: any, softPedal: any): void;
|
|
214
|
+
setFilterResonance(channelNumber: any, filterResonance: any): void;
|
|
215
|
+
setReleaseTime(channelNumber: any, releaseTime: any): void;
|
|
216
|
+
setAttackTime(channelNumber: any, attackTime: any): void;
|
|
217
|
+
setBrightness(channelNumber: any, brightness: any): void;
|
|
218
|
+
setDecayTime(channelNumber: any, dacayTime: any): void;
|
|
206
219
|
setVibratoRate(channelNumber: any, vibratoRate: any): void;
|
|
207
220
|
setVibratoDepth(channelNumber: any, vibratoDepth: any): void;
|
|
208
221
|
setVibratoDelay(channelNumber: any, vibratoDelay: any): void;
|
|
@@ -223,9 +236,9 @@ export class Midy {
|
|
|
223
236
|
setCoarseTuning(channelNumber: any, coarseTuning: any): void;
|
|
224
237
|
handleModulationDepthRangeRPN(channelNumber: any): void;
|
|
225
238
|
setModulationDepthRange(channelNumber: any, modulationDepthRange: any): void;
|
|
226
|
-
allSoundOff(channelNumber: any):
|
|
239
|
+
allSoundOff(channelNumber: any): Promise<void>;
|
|
227
240
|
resetAllControllers(channelNumber: any): void;
|
|
228
|
-
allNotesOff(channelNumber: any):
|
|
241
|
+
allNotesOff(channelNumber: any): Promise<void>;
|
|
229
242
|
omniOff(): void;
|
|
230
243
|
omniOn(): void;
|
|
231
244
|
monoOn(): void;
|
|
@@ -265,12 +278,13 @@ export class Midy {
|
|
|
265
278
|
declare class Note {
|
|
266
279
|
constructor(noteNumber: any, velocity: any, startTime: any, instrumentKey: any);
|
|
267
280
|
bufferSource: any;
|
|
268
|
-
gainNode: any;
|
|
269
281
|
filterNode: any;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
282
|
+
volumeNode: any;
|
|
283
|
+
volumeDepth: any;
|
|
284
|
+
modulationLFO: any;
|
|
285
|
+
modulationDepth: any;
|
|
286
|
+
vibratoLFO: any;
|
|
287
|
+
vibratoDepth: any;
|
|
274
288
|
noteNumber: any;
|
|
275
289
|
velocity: any;
|
|
276
290
|
startTime: any;
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|