@marmooo/midy 0.0.4 → 0.0.5
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.1 → soundfont-parser@0.0.2}/+esm.d.ts +13 -6
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +1 -0
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.js +5 -5
- package/esm/midy-GM1.d.ts +24 -34
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +167 -106
- package/esm/midy-GM2.d.ts +123 -21
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +170 -116
- package/esm/midy-GMLite.d.ts +23 -35
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +156 -107
- package/esm/midy.d.ts +25 -23
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +191 -120
- package/package.json +1 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.d.ts +13 -6
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +1 -0
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.js +5 -5
- package/script/midy-GM1.d.ts +24 -34
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +167 -106
- package/script/midy-GM2.d.ts +123 -21
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +170 -116
- package/script/midy-GMLite.d.ts +23 -35
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +156 -107
- package/script/midy.d.ts +25 -23
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +191 -120
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.1/+esm.d.ts.map +0 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.1/+esm.d.ts.map +0 -1
package/script/midy.js
CHANGED
|
@@ -2,7 +2,57 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Midy = void 0;
|
|
4
4
|
const _esm_js_1 = require("./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js");
|
|
5
|
-
const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.
|
|
5
|
+
const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.js");
|
|
6
|
+
class Note {
|
|
7
|
+
constructor(noteNumber, velocity, startTime, instrumentKey) {
|
|
8
|
+
Object.defineProperty(this, "bufferSource", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: void 0
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(this, "gainNode", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: void 0
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(this, "filterNode", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true,
|
|
24
|
+
value: void 0
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(this, "modLFO", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(this, "modLFOGain", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "vibLFO", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
writable: true,
|
|
42
|
+
value: void 0
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(this, "vibLFOGain", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: void 0
|
|
49
|
+
});
|
|
50
|
+
this.noteNumber = noteNumber;
|
|
51
|
+
this.velocity = velocity;
|
|
52
|
+
this.startTime = startTime;
|
|
53
|
+
this.instrumentKey = instrumentKey;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
6
56
|
class Midy {
|
|
7
57
|
constructor(audioContext) {
|
|
8
58
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
@@ -184,10 +234,8 @@ class Midy {
|
|
|
184
234
|
const pannerNode = new StereoPannerNode(audioContext, {
|
|
185
235
|
pan: Midy.channelSettings.pan,
|
|
186
236
|
});
|
|
187
|
-
const modulationEffect = this.createModulationEffect(audioContext);
|
|
188
237
|
const reverbEffect = this.createReverbEffect(audioContext);
|
|
189
238
|
const chorusEffect = this.createChorusEffect(audioContext);
|
|
190
|
-
modulationEffect.lfo.start();
|
|
191
239
|
chorusEffect.lfo.start();
|
|
192
240
|
reverbEffect.dryGain.connect(pannerNode);
|
|
193
241
|
reverbEffect.wetGain.connect(pannerNode);
|
|
@@ -196,7 +244,6 @@ class Midy {
|
|
|
196
244
|
return {
|
|
197
245
|
gainNode,
|
|
198
246
|
pannerNode,
|
|
199
|
-
modulationEffect,
|
|
200
247
|
reverbEffect,
|
|
201
248
|
chorusEffect,
|
|
202
249
|
};
|
|
@@ -219,11 +266,11 @@ class Midy {
|
|
|
219
266
|
});
|
|
220
267
|
return channels;
|
|
221
268
|
}
|
|
222
|
-
async createNoteBuffer(
|
|
223
|
-
const sampleEnd =
|
|
269
|
+
async createNoteBuffer(instrumentKey, isSF3) {
|
|
270
|
+
const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
|
|
224
271
|
if (isSF3) {
|
|
225
|
-
const sample = new Uint8Array(
|
|
226
|
-
sample.set(
|
|
272
|
+
const sample = new Uint8Array(instrumentKey.sample.length);
|
|
273
|
+
sample.set(instrumentKey.sample);
|
|
227
274
|
const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
|
|
228
275
|
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
|
|
229
276
|
const channelData = audioBuffer.getChannelData(channel);
|
|
@@ -232,26 +279,27 @@ class Midy {
|
|
|
232
279
|
return audioBuffer;
|
|
233
280
|
}
|
|
234
281
|
else {
|
|
235
|
-
const sample =
|
|
282
|
+
const sample = instrumentKey.sample.subarray(0, sampleEnd);
|
|
236
283
|
const floatSample = this.convertToFloat32Array(sample);
|
|
237
284
|
const audioBuffer = new AudioBuffer({
|
|
238
285
|
numberOfChannels: 1,
|
|
239
286
|
length: sample.length,
|
|
240
|
-
sampleRate:
|
|
287
|
+
sampleRate: instrumentKey.sampleRate,
|
|
241
288
|
});
|
|
242
289
|
const channelData = audioBuffer.getChannelData(0);
|
|
243
290
|
channelData.set(floatSample);
|
|
244
291
|
return audioBuffer;
|
|
245
292
|
}
|
|
246
293
|
}
|
|
247
|
-
async createNoteBufferNode(
|
|
294
|
+
async createNoteBufferNode(instrumentKey, isSF3) {
|
|
248
295
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
249
|
-
const audioBuffer = await this.createNoteBuffer(
|
|
296
|
+
const audioBuffer = await this.createNoteBuffer(instrumentKey, isSF3);
|
|
250
297
|
bufferSource.buffer = audioBuffer;
|
|
251
|
-
bufferSource.loop =
|
|
298
|
+
bufferSource.loop = instrumentKey.sampleModes % 2 !== 0;
|
|
252
299
|
if (bufferSource.loop) {
|
|
253
|
-
bufferSource.loopStart =
|
|
254
|
-
|
|
300
|
+
bufferSource.loopStart = instrumentKey.loopStart /
|
|
301
|
+
instrumentKey.sampleRate;
|
|
302
|
+
bufferSource.loopEnd = instrumentKey.loopEnd / instrumentKey.sampleRate;
|
|
255
303
|
}
|
|
256
304
|
return bufferSource;
|
|
257
305
|
}
|
|
@@ -533,30 +581,26 @@ class Midy {
|
|
|
533
581
|
const now = this.audioContext.currentTime;
|
|
534
582
|
return this.resumeTime + now - this.startTime - this.startDelay;
|
|
535
583
|
}
|
|
536
|
-
getActiveNotes(channel) {
|
|
584
|
+
getActiveNotes(channel, time) {
|
|
537
585
|
const activeNotes = new Map();
|
|
538
|
-
channel.scheduledNotes.forEach((
|
|
539
|
-
const activeNote = this.
|
|
586
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
587
|
+
const activeNote = this.getActiveNote(noteList, time);
|
|
540
588
|
if (activeNote) {
|
|
541
589
|
activeNotes.set(activeNote.noteNumber, activeNote);
|
|
542
590
|
}
|
|
543
591
|
});
|
|
544
592
|
return activeNotes;
|
|
545
593
|
}
|
|
546
|
-
|
|
547
|
-
for (let i =
|
|
548
|
-
const
|
|
549
|
-
if (
|
|
550
|
-
return
|
|
594
|
+
getActiveNote(noteList, time) {
|
|
595
|
+
for (let i = noteList.length - 1; i >= 0; i--) {
|
|
596
|
+
const note = noteList[i];
|
|
597
|
+
if (!note)
|
|
598
|
+
return;
|
|
599
|
+
if (time < note.startTime)
|
|
600
|
+
continue;
|
|
601
|
+
return (note.ending) ? null : note;
|
|
551
602
|
}
|
|
552
|
-
|
|
553
|
-
createModulationEffect(audioContext) {
|
|
554
|
-
const lfo = new OscillatorNode(audioContext, {
|
|
555
|
-
frequency: 5,
|
|
556
|
-
});
|
|
557
|
-
return {
|
|
558
|
-
lfo,
|
|
559
|
-
};
|
|
603
|
+
return noteList[0];
|
|
560
604
|
}
|
|
561
605
|
createReverbEffect(audioContext, options = {}) {
|
|
562
606
|
const { decay = 0.8, preDecay = 0, } = options;
|
|
@@ -666,77 +710,110 @@ class Midy {
|
|
|
666
710
|
const tuning = masterTuning + channelTuning;
|
|
667
711
|
return channel.pitchBend * channel.pitchBendRange + tuning;
|
|
668
712
|
}
|
|
669
|
-
calcPlaybackRate(
|
|
670
|
-
return
|
|
713
|
+
calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset) {
|
|
714
|
+
return instrumentKey.playbackRate(noteNumber) *
|
|
715
|
+
Math.pow(2, semitoneOffset / 12);
|
|
671
716
|
}
|
|
672
|
-
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
676
|
-
// volume envelope
|
|
677
|
-
const gainNode = new GainNode(this.audioContext, {
|
|
717
|
+
setVolumeEnvelope(channel, note) {
|
|
718
|
+
const { instrumentKey, startTime, velocity } = note;
|
|
719
|
+
note.gainNode = new GainNode(this.audioContext, {
|
|
678
720
|
gain: 0,
|
|
679
721
|
});
|
|
680
722
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
681
723
|
if (volume === 0)
|
|
682
724
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
683
|
-
const attackVolume = this.cbToRatio(-
|
|
684
|
-
|
|
685
|
-
const
|
|
686
|
-
const
|
|
687
|
-
const
|
|
688
|
-
const
|
|
689
|
-
|
|
725
|
+
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation) *
|
|
726
|
+
volume;
|
|
727
|
+
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
728
|
+
const volDelay = startTime + instrumentKey.volDelay;
|
|
729
|
+
const volAttack = volDelay + instrumentKey.volAttack;
|
|
730
|
+
const volHold = volAttack + instrumentKey.volHold;
|
|
731
|
+
const volDecay = volHold + instrumentKey.volDecay;
|
|
732
|
+
note.gainNode.gain
|
|
690
733
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
691
734
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
692
735
|
.setValueAtTime(attackVolume, volHold)
|
|
693
736
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
694
|
-
|
|
737
|
+
}
|
|
738
|
+
setFilterEnvelope(channel, note) {
|
|
739
|
+
const { instrumentKey, startTime, noteNumber } = note;
|
|
695
740
|
const softPedalFactor = 1 -
|
|
696
741
|
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
697
742
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
698
|
-
const baseFreq = this.centToHz(
|
|
699
|
-
|
|
743
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
744
|
+
softPedalFactor;
|
|
745
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
700
746
|
const sustainFreq = (baseFreq +
|
|
701
|
-
(peekFreq - baseFreq) * (1 -
|
|
747
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain)) * softPedalFactor;
|
|
748
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
749
|
+
const modAttack = modDelay + instrumentKey.modAttack;
|
|
750
|
+
const modHold = modAttack + instrumentKey.modHold;
|
|
751
|
+
const modDecay = modHold + instrumentKey.modDecay;
|
|
702
752
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
703
753
|
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
704
754
|
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
705
|
-
|
|
755
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
706
756
|
type: "lowpass",
|
|
707
|
-
Q:
|
|
757
|
+
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
708
758
|
frequency: adjustedBaseFreq,
|
|
709
759
|
});
|
|
710
|
-
|
|
711
|
-
const modAttack = modDelay + noteInfo.modAttack;
|
|
712
|
-
const modHold = modAttack + noteInfo.modHold;
|
|
713
|
-
const modDecay = modHold + noteInfo.modDecay;
|
|
714
|
-
filterNode.frequency
|
|
760
|
+
note.filterNode.frequency
|
|
715
761
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
716
762
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
717
763
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
718
764
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
719
|
-
|
|
765
|
+
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
|
|
766
|
+
}
|
|
767
|
+
startModulation(channel, note, time) {
|
|
768
|
+
const { instrumentKey } = note;
|
|
769
|
+
note.modLFOGain = new GainNode(this.audioContext, {
|
|
770
|
+
gain: this.cbToRatio(instrumentKey.modLfoToVolume) * channel.modulation,
|
|
771
|
+
});
|
|
772
|
+
note.modLFO = new OscillatorNode(this.audioContext, {
|
|
773
|
+
frequency: this.centToHz(instrumentKey.freqModLFO),
|
|
774
|
+
});
|
|
775
|
+
note.modLFO.start(time);
|
|
776
|
+
note.filterNode.frequency.setValueAtTime(note.filterNode.frequency.value + instrumentKey.modLfoToFilterFc, time);
|
|
777
|
+
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modLfoToPitch, time);
|
|
778
|
+
note.modLFO.connect(note.modLFOGain);
|
|
779
|
+
note.modLFOGain.connect(note.bufferSource.detune);
|
|
780
|
+
}
|
|
781
|
+
startVibrato(channel, note, time) {
|
|
782
|
+
const { instrumentKey } = note;
|
|
783
|
+
note.vibLFOGain = new GainNode(this.audioContext, {
|
|
784
|
+
gain: channel.vibratoDepth,
|
|
785
|
+
});
|
|
786
|
+
note.vibLFO = new OscillatorNode(this.audioContext, {
|
|
787
|
+
frequency: this.centToHz(instrumentKey.freqModLFO) +
|
|
788
|
+
channel.vibratoRate,
|
|
789
|
+
});
|
|
790
|
+
note.vibLFO.start(time + channel.vibratoDelay);
|
|
791
|
+
note.vibLFO.connect(note.vibLFOGain);
|
|
792
|
+
note.vibLFOGain.connect(note.bufferSource.detune);
|
|
793
|
+
}
|
|
794
|
+
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
795
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
796
|
+
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
797
|
+
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
798
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
799
|
+
this.setVolumeEnvelope(channel, note);
|
|
800
|
+
this.setFilterEnvelope(channel, note);
|
|
720
801
|
if (channel.modulation > 0) {
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
.setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
728
|
-
.exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
|
|
729
|
-
channel.modulationEffect.lfo.connect(lfoGain);
|
|
730
|
-
lfoGain.connect(bufferSource.detune);
|
|
802
|
+
const delayModLFO = startTime + instrumentKey.delayModLFO;
|
|
803
|
+
this.startModulation(channel, note, delayModLFO);
|
|
804
|
+
}
|
|
805
|
+
if (channel.vibratoDepth > 0) {
|
|
806
|
+
const delayVibLFO = startTime + instrumentKey.delayVibLFO;
|
|
807
|
+
this.startVibrato(channel, note, delayVibLFO);
|
|
731
808
|
}
|
|
732
|
-
bufferSource.connect(filterNode);
|
|
733
|
-
filterNode.connect(gainNode);
|
|
734
809
|
if (this.mono && channel.currentBufferSource) {
|
|
735
810
|
channel.currentBufferSource.stop(startTime);
|
|
736
|
-
channel.currentBufferSource = bufferSource;
|
|
811
|
+
channel.currentBufferSource = note.bufferSource;
|
|
737
812
|
}
|
|
738
|
-
bufferSource.
|
|
739
|
-
|
|
813
|
+
note.bufferSource.connect(note.filterNode);
|
|
814
|
+
note.filterNode.connect(note.gainNode);
|
|
815
|
+
note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
|
|
816
|
+
return note;
|
|
740
817
|
}
|
|
741
818
|
calcBank(channel, channelNumber) {
|
|
742
819
|
if (channel.bankMSB === 121) {
|
|
@@ -755,36 +832,20 @@ class Midy {
|
|
|
755
832
|
return;
|
|
756
833
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
757
834
|
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
758
|
-
const
|
|
759
|
-
if (!
|
|
835
|
+
const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
|
|
836
|
+
if (!instrumentKey)
|
|
760
837
|
return;
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
this.connectNoteEffects(channel, gainNode);
|
|
838
|
+
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
839
|
+
this.connectNoteEffects(channel, note.gainNode);
|
|
764
840
|
if (channel.sostenutoPedal) {
|
|
765
|
-
channel.sostenutoNotes.set(noteNumber,
|
|
766
|
-
gainNode,
|
|
767
|
-
filterNode,
|
|
768
|
-
bufferSource,
|
|
769
|
-
noteNumber,
|
|
770
|
-
noteInfo,
|
|
771
|
-
});
|
|
841
|
+
channel.sostenutoNotes.set(noteNumber, note);
|
|
772
842
|
}
|
|
773
843
|
const scheduledNotes = channel.scheduledNotes;
|
|
774
|
-
const scheduledNote = {
|
|
775
|
-
bufferSource,
|
|
776
|
-
filterNode,
|
|
777
|
-
gainNode,
|
|
778
|
-
lfoGain,
|
|
779
|
-
noteInfo,
|
|
780
|
-
noteNumber,
|
|
781
|
-
startTime,
|
|
782
|
-
};
|
|
783
844
|
if (scheduledNotes.has(noteNumber)) {
|
|
784
|
-
scheduledNotes.get(noteNumber).push(
|
|
845
|
+
scheduledNotes.get(noteNumber).push(note);
|
|
785
846
|
}
|
|
786
847
|
else {
|
|
787
|
-
scheduledNotes.set(noteNumber, [
|
|
848
|
+
scheduledNotes.set(noteNumber, [note]);
|
|
788
849
|
}
|
|
789
850
|
}
|
|
790
851
|
noteOn(channelNumber, noteNumber, velocity) {
|
|
@@ -806,15 +867,15 @@ class Midy {
|
|
|
806
867
|
continue;
|
|
807
868
|
if (targetNote.ending)
|
|
808
869
|
continue;
|
|
809
|
-
const { bufferSource, filterNode, gainNode,
|
|
870
|
+
const { bufferSource, filterNode, gainNode, modLFO, modLFOGain, vibLFO, vibLFOGain, instrumentKey, } = targetNote;
|
|
810
871
|
const velocityRate = (velocity + 127) / 127;
|
|
811
|
-
const volEndTime = stopTime +
|
|
872
|
+
const volEndTime = stopTime + instrumentKey.volRelease * velocityRate;
|
|
812
873
|
gainNode.gain.cancelScheduledValues(stopTime);
|
|
813
874
|
gainNode.gain.linearRampToValueAtTime(0, volEndTime);
|
|
814
875
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
815
|
-
const baseFreq = this.centToHz(
|
|
876
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
816
877
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
817
|
-
const modEndTime = stopTime +
|
|
878
|
+
const modEndTime = stopTime + instrumentKey.modRelease * velocityRate;
|
|
818
879
|
filterNode.frequency
|
|
819
880
|
.cancelScheduledValues(stopTime)
|
|
820
881
|
.linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
|
|
@@ -828,8 +889,14 @@ class Midy {
|
|
|
828
889
|
bufferSource.disconnect(0);
|
|
829
890
|
filterNode.disconnect(0);
|
|
830
891
|
gainNode.disconnect(0);
|
|
831
|
-
if (
|
|
832
|
-
|
|
892
|
+
if (modLFOGain)
|
|
893
|
+
modLFOGain.disconnect(0);
|
|
894
|
+
if (vibLFOGain)
|
|
895
|
+
vibLFOGain.disconnect(0);
|
|
896
|
+
if (modLFO)
|
|
897
|
+
modLFO.stop();
|
|
898
|
+
if (vibLFO)
|
|
899
|
+
vibLFO.stop();
|
|
833
900
|
resolve();
|
|
834
901
|
};
|
|
835
902
|
bufferSource.stop(volEndTime);
|
|
@@ -895,7 +962,7 @@ class Midy {
|
|
|
895
962
|
const now = this.audioContext.currentTime;
|
|
896
963
|
const channel = this.channels[channelNumber];
|
|
897
964
|
pressure /= 64;
|
|
898
|
-
const activeNotes = this.getActiveNotes(channel);
|
|
965
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
899
966
|
if (channel.polyphonicKeyPressure.amplitudeControl !== 1) {
|
|
900
967
|
if (activeNotes.has(noteNumber)) {
|
|
901
968
|
const activeNote = activeNotes.get(noteNumber);
|
|
@@ -916,7 +983,7 @@ class Midy {
|
|
|
916
983
|
const channel = this.channels[channelNumber];
|
|
917
984
|
pressure /= 64;
|
|
918
985
|
channel.channelPressure = pressure;
|
|
919
|
-
const activeNotes = this.getActiveNotes(channel);
|
|
986
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
920
987
|
if (channel.channelPressure.amplitudeControl !== 1) {
|
|
921
988
|
activeNotes.forEach((activeNote) => {
|
|
922
989
|
const gain = activeNote.gainNode.gain.value;
|
|
@@ -935,10 +1002,10 @@ class Midy {
|
|
|
935
1002
|
const channel = this.channels[channelNumber];
|
|
936
1003
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
937
1004
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
938
|
-
const activeNotes = this.getActiveNotes(channel);
|
|
1005
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
939
1006
|
activeNotes.forEach((activeNote) => {
|
|
940
|
-
const { bufferSource,
|
|
941
|
-
const playbackRate = calcPlaybackRate(
|
|
1007
|
+
const { bufferSource, instrumentKey, noteNumber } = activeNote;
|
|
1008
|
+
const playbackRate = calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
942
1009
|
bufferSource.playbackRate
|
|
943
1010
|
.cancelScheduledValues(now)
|
|
944
1011
|
.setValueAtTime(playbackRate * pressure, now);
|
|
@@ -1013,9 +1080,20 @@ class Midy {
|
|
|
1013
1080
|
this.channels[channelNumber].bankMSB = msb;
|
|
1014
1081
|
}
|
|
1015
1082
|
setModulation(channelNumber, modulation) {
|
|
1083
|
+
const now = this.audioContext.currentTime;
|
|
1016
1084
|
const channel = this.channels[channelNumber];
|
|
1017
1085
|
channel.modulation = (modulation / 127) *
|
|
1018
1086
|
(channel.modulationDepthRange * 100);
|
|
1087
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
1088
|
+
activeNotes.forEach((activeNote) => {
|
|
1089
|
+
if (activeNote.modLFO) {
|
|
1090
|
+
activeNote.gainNode.gain.setValueAtTime(this.cbToRatio(activeNote.instrumentKey.modLfoToVolume) *
|
|
1091
|
+
channel.modulation, now);
|
|
1092
|
+
}
|
|
1093
|
+
else {
|
|
1094
|
+
this.startModulation(channel, activeNote, now);
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1019
1097
|
}
|
|
1020
1098
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
1021
1099
|
this.channels[channelNumber].portamentoTime = portamentoTime / 127;
|
|
@@ -1076,7 +1154,8 @@ class Midy {
|
|
|
1076
1154
|
const channel = this.channels[channelNumber];
|
|
1077
1155
|
channel.sostenutoPedal = isOn;
|
|
1078
1156
|
if (isOn) {
|
|
1079
|
-
const
|
|
1157
|
+
const now = this.audioContext.currentTime;
|
|
1158
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
1080
1159
|
channel.sostenutoNotes = new Map(activeNotes);
|
|
1081
1160
|
}
|
|
1082
1161
|
else {
|
|
@@ -1088,20 +1167,12 @@ class Midy {
|
|
|
1088
1167
|
channel.softPedal = softPedal / 127;
|
|
1089
1168
|
}
|
|
1090
1169
|
setVibratoRate(channelNumber, vibratoRate) {
|
|
1091
|
-
const now = this.audioContext.currentTime;
|
|
1092
1170
|
const channel = this.channels[channelNumber];
|
|
1093
1171
|
channel.vibratoRate = vibratoRate / 127 * 4 + 3; // 3-7Hz
|
|
1094
|
-
channel.modulationEffect.lfo.frequency
|
|
1095
|
-
.cancelScheduledValues(now)
|
|
1096
|
-
.setValueAtTime(channel.vibratoRate, now);
|
|
1097
1172
|
}
|
|
1098
1173
|
setVibratoDepth(channelNumber, vibratoDepth) {
|
|
1099
|
-
const now = this.audioContext.currentTime;
|
|
1100
1174
|
const channel = this.channels[channelNumber];
|
|
1101
1175
|
channel.vibratoDepth = vibratoDepth / 127;
|
|
1102
|
-
channel.modulationEffect.lfoGain.gain
|
|
1103
|
-
.cancelScheduledValues(now)
|
|
1104
|
-
.setValueAtTime(channel.vibratoDepth, now);
|
|
1105
1176
|
}
|
|
1106
1177
|
setVibratoDelay(channelNumber, vibratoDelay) {
|
|
1107
1178
|
// Access Virus: 0-10sec
|
|
@@ -1182,8 +1253,8 @@ class Midy {
|
|
|
1182
1253
|
const velocity = 0;
|
|
1183
1254
|
const stopPedal = true;
|
|
1184
1255
|
const promises = [];
|
|
1185
|
-
channel.scheduledNotes.forEach((
|
|
1186
|
-
const activeNote = this.
|
|
1256
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1257
|
+
const activeNote = this.getActiveNote(noteList, now);
|
|
1187
1258
|
if (activeNote) {
|
|
1188
1259
|
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
1189
1260
|
promises.push(notePromise);
|
|
@@ -1200,8 +1271,8 @@ class Midy {
|
|
|
1200
1271
|
const velocity = 0;
|
|
1201
1272
|
const stopPedal = false;
|
|
1202
1273
|
const promises = [];
|
|
1203
|
-
channel.scheduledNotes.forEach((
|
|
1204
|
-
const activeNote = this.
|
|
1274
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1275
|
+
const activeNote = this.getActiveNote(noteList, now);
|
|
1205
1276
|
if (activeNote) {
|
|
1206
1277
|
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
1207
1278
|
promises.push(notePromise);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"+esm.d.ts","sourceRoot":"","sources":["../../../../../../src/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.1/+esm.js"],"names":[],"mappings":";;AAMszX;IAAQ,oBAA2H;IAAd,YAAa;IAAC,qDAAoJ;IAAA,mCAAoP;IAAA,uCAAwQ;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAAi/D;IAAA,qBAA0I;CAAC;AAAA,mCAAwC;AAAl+H,+BAA8F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAA98D;;;;;;;;;;;;;;;;EAA27B;AAAr4I;IAAqQ,wBAAwD;IAArT,4BAAyN;IAApB,QAAS;IAAC,QAAS;IAAC,oBAAoC;CAAyD;AAAllG;IAAwjC,gCAA8d;CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"+esm.d.ts","sourceRoot":"","sources":["../../../../../../src/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.1/+esm.js"],"names":[],"mappings":";;AAMszX;IAAQ,oBAA2H;IAAd,YAAa;IAAC,qDAAoJ;IAAA,mCAAoP;IAAA,uCAAwQ;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAAi/D;IAAA,qBAA0I;CAAC;AAAA,mCAAwC;AAAl+H,+BAA8F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAA98D;;;;;;;;;;;;;;;;EAA27B;AAAr4I;IAAqQ,wBAAwD;IAArT,4BAAyN;IAApB,QAAS;IAAC,QAAS;IAAC,oBAAoC;CAAyD;AAAllG;IAAwjC,gCAA8d;CAAC"}
|