spessasynth_core 4.3.5 → 4.3.6
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/dist/index.d.ts +43 -5
- package/dist/index.js +82 -28
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -1663,7 +1663,8 @@ interface ChannelMIDIParameter {
|
|
|
1663
1663
|
/**
|
|
1664
1664
|
* If the channel is in the poly mode.
|
|
1665
1665
|
* - `true` - POLY ON - regular playback.
|
|
1666
|
-
* - `false` - MONO ON - one note per channel,
|
|
1666
|
+
* - `false` - MONO ON - one note per channel,
|
|
1667
|
+
* highest still pressed note is restored after releasing the currently playing one.
|
|
1667
1668
|
*/
|
|
1668
1669
|
polyMode: boolean;
|
|
1669
1670
|
/**
|
|
@@ -2045,6 +2046,20 @@ declare class MIDIChannel {
|
|
|
2045
2046
|
*/
|
|
2046
2047
|
protected readonly octaveTuning: Int8Array;
|
|
2047
2048
|
protected readonly _midiParameters: Readonly<ChannelMIDIParameter>;
|
|
2049
|
+
/**
|
|
2050
|
+
* Note On message tracking, for grouping voices for specific Note On messages.
|
|
2051
|
+
* Used for overlapping Note Ons.
|
|
2052
|
+
* MIDI note: current note on ID
|
|
2053
|
+
* @protected
|
|
2054
|
+
*/
|
|
2055
|
+
protected readonly noteOnID: number[];
|
|
2056
|
+
/**
|
|
2057
|
+
* Note Off message tracking, for grouping voices for specific Note On messages.
|
|
2058
|
+
* Used for overlapping Note Ons.
|
|
2059
|
+
* MIDI note: current note on ID
|
|
2060
|
+
* @protected
|
|
2061
|
+
*/
|
|
2062
|
+
protected readonly noteOffID: number[];
|
|
2048
2063
|
/**
|
|
2049
2064
|
* If the last Parameter was RPN.
|
|
2050
2065
|
* If false then the last parameter was NRPN.
|
|
@@ -2080,21 +2095,39 @@ declare class MIDIChannel {
|
|
|
2080
2095
|
*/
|
|
2081
2096
|
protected currentGain: number;
|
|
2082
2097
|
/**
|
|
2083
|
-
* The last pressed note on this channel.
|
|
2098
|
+
* The last pressed note on this channel for portamento tracking.
|
|
2084
2099
|
* -1 means none.
|
|
2085
2100
|
* This is not a `ChannelMIDIParameter` and is strictly internal,
|
|
2086
2101
|
* mostly because we don't want to send events for every note on message.
|
|
2087
2102
|
* It can be set with Portamento Control CC anyway.
|
|
2088
2103
|
* @protected
|
|
2089
2104
|
*/
|
|
2090
|
-
protected
|
|
2105
|
+
protected lastPortamentoNote: number;
|
|
2091
2106
|
/**
|
|
2092
2107
|
* If the portamento should be executed once regardless of Portamento on/off.
|
|
2093
2108
|
* Adhering to the MIDI spec, CC#84 ignores on/off.
|
|
2094
|
-
* This is also not a `ChannelMIDIParameter` for the same reason as `
|
|
2109
|
+
* This is also not a `ChannelMIDIParameter` for the same reason as `lastPortamentoNote`
|
|
2095
2110
|
* @protected
|
|
2096
2111
|
*/
|
|
2097
2112
|
protected portamentoForce: boolean;
|
|
2113
|
+
/**
|
|
2114
|
+
* The last pressed note on this channel in mono mode.
|
|
2115
|
+
* Used for tracking and releasing this note on a new Note On event.
|
|
2116
|
+
* -1 means none.
|
|
2117
|
+
* @protected
|
|
2118
|
+
*/
|
|
2119
|
+
protected lastMonoNote: number;
|
|
2120
|
+
/**
|
|
2121
|
+
* The last pressed note's velocity on this channel in mono mode.
|
|
2122
|
+
* @protected
|
|
2123
|
+
*/
|
|
2124
|
+
protected lastMonoVelocity: number;
|
|
2125
|
+
/**
|
|
2126
|
+
* For Mono Mode restoring notes.
|
|
2127
|
+
* playingNotes[midiNote]
|
|
2128
|
+
* @protected
|
|
2129
|
+
*/
|
|
2130
|
+
protected readonly playingNotes: boolean[];
|
|
2098
2131
|
protected readonly generators: ChannelGenerators;
|
|
2099
2132
|
protected readonly computeModulator: (voice: Voice, pitchWheel: number, modulatorIndex: number) => number;
|
|
2100
2133
|
protected readonly computeModulators: (voice: Voice, sourceUsesCC?: 0 | 1 | -1 | undefined, sourceIndex?: number | undefined) => void;
|
|
@@ -3070,6 +3103,11 @@ declare class Voice {
|
|
|
3070
3103
|
* MIDI channel number of the voice.
|
|
3071
3104
|
*/
|
|
3072
3105
|
channel: number;
|
|
3106
|
+
/**
|
|
3107
|
+
* Grouping voices for specific Note On messages.
|
|
3108
|
+
* Used for overlapping Note Ons.
|
|
3109
|
+
*/
|
|
3110
|
+
noteID: number;
|
|
3073
3111
|
/**
|
|
3074
3112
|
* MIDI note number of the voice.
|
|
3075
3113
|
* Direct number from the Note On message and is
|
|
@@ -3183,7 +3221,7 @@ declare class Voice {
|
|
|
3183
3221
|
* @param minNoteLength minimum note length in seconds
|
|
3184
3222
|
*/
|
|
3185
3223
|
releaseVoice(currentTime: number, minNoteLength?: number): void;
|
|
3186
|
-
setup(currentTime: number, channel: number, midiNote: number): void;
|
|
3224
|
+
setup(currentTime: number, channel: number, midiNote: number, noteID: number): void;
|
|
3187
3225
|
}
|
|
3188
3226
|
//#endregion
|
|
3189
3227
|
//#region src/soundbank/basic_soundbank/modulator_source.d.ts
|
package/dist/index.js
CHANGED
|
@@ -2585,13 +2585,13 @@ function getNoteTimesInternal(midi, minDrumLength = 0) {
|
|
|
2585
2585
|
const unfinishedNotes = [];
|
|
2586
2586
|
for (let i = 0; i < 16; i++) unfinishedNotes.push(/* @__PURE__ */ new Map());
|
|
2587
2587
|
const noteOff = (midiNote, channel) => {
|
|
2588
|
-
const
|
|
2589
|
-
|
|
2588
|
+
const noteIndexes = unfinishedNotes[channel].get(midiNote);
|
|
2589
|
+
if (noteIndexes === void 0) return;
|
|
2590
|
+
const noteIndex = noteIndexes.shift();
|
|
2590
2591
|
if (noteIndex === void 0) return;
|
|
2591
2592
|
const note = noteTimes[channel][noteIndex];
|
|
2592
2593
|
const time = elapsedTime - note.start;
|
|
2593
2594
|
note.length = channel === 9 ? Math.max(time, minDrumLength) : time;
|
|
2594
|
-
ch.delete(midiNote);
|
|
2595
2595
|
unfinished--;
|
|
2596
2596
|
};
|
|
2597
2597
|
const { timeline, tracks } = midi;
|
|
@@ -2606,7 +2606,6 @@ function getNoteTimesInternal(midi, minDrumLength = 0) {
|
|
|
2606
2606
|
const velocity = event.data[1];
|
|
2607
2607
|
if (velocity === 0) noteOff(midiNote, channel);
|
|
2608
2608
|
else {
|
|
2609
|
-
noteOff(midiNote, channel);
|
|
2610
2609
|
const noteTime = {
|
|
2611
2610
|
midiNote,
|
|
2612
2611
|
start: elapsedTime,
|
|
@@ -2615,14 +2614,17 @@ function getNoteTimesInternal(midi, minDrumLength = 0) {
|
|
|
2615
2614
|
};
|
|
2616
2615
|
const times = noteTimes[channel];
|
|
2617
2616
|
times.push(noteTime);
|
|
2618
|
-
unfinishedNotes[channel]
|
|
2617
|
+
const unfinishedChannel = unfinishedNotes[channel];
|
|
2618
|
+
if (!unfinishedChannel.has(midiNote)) unfinishedChannel.set(midiNote, []);
|
|
2619
|
+
unfinishedNotes[channel].get(midiNote)?.push(times.length - 1);
|
|
2619
2620
|
unfinished++;
|
|
2620
2621
|
}
|
|
2621
2622
|
} else if (event.statusByte === 81) oneTickToSeconds = 60 / (getTempo(event) * midi.timeDivision);
|
|
2622
2623
|
if (++i >= timeline.length) break;
|
|
2623
|
-
|
|
2624
|
+
const nextTimeline = timeline[i];
|
|
2625
|
+
elapsedTime += oneTickToSeconds * (tracks[nextTimeline.tr].events[nextTimeline.ev].ticks - event.ticks);
|
|
2624
2626
|
}
|
|
2625
|
-
if (unfinished > 0) for (let channel = 0; channel < unfinishedNotes.length; channel++) for (const
|
|
2627
|
+
if (unfinished > 0) for (let channel = 0; channel < unfinishedNotes.length; channel++) for (const noteIndexes of unfinishedNotes[channel].values()) for (const noteIndex of noteIndexes) {
|
|
2626
2628
|
const note = noteTimes[channel][noteIndex];
|
|
2627
2629
|
note.length = elapsedTime - note.start;
|
|
2628
2630
|
}
|
|
@@ -4665,7 +4667,7 @@ function loadNewSequenceInternal(parsedMIDI) {
|
|
|
4665
4667
|
//#endregion
|
|
4666
4668
|
//#region src/synthesizer/audio_engine/channel/reset.ts
|
|
4667
4669
|
function resetPortamento() {
|
|
4668
|
-
this.
|
|
4670
|
+
this.lastPortamentoNote = this.channelSystem === "xg" ? 60 : -1;
|
|
4669
4671
|
}
|
|
4670
4672
|
/**
|
|
4671
4673
|
* An array with the default MIDI controller values.
|
|
@@ -4733,6 +4735,7 @@ function resetChannelInternal(sendCCEvents = true) {
|
|
|
4733
4735
|
this.resetGeneratorOffsets();
|
|
4734
4736
|
this.dynamicModulators.resetModulators();
|
|
4735
4737
|
this.sf2NRPNGeneratorLSB = 0;
|
|
4738
|
+
this.playingNotes.fill(false);
|
|
4736
4739
|
this.lastParameterIsRegistered = true;
|
|
4737
4740
|
this._midiControllers[MIDIControllers.nonRegisteredParameterLSB] = 0;
|
|
4738
4741
|
this._midiControllers[MIDIControllers.nonRegisteredParameterMSB] = 0;
|
|
@@ -7389,6 +7392,11 @@ var Voice = class {
|
|
|
7389
7392
|
*/
|
|
7390
7393
|
channel = 0;
|
|
7391
7394
|
/**
|
|
7395
|
+
* Grouping voices for specific Note On messages.
|
|
7396
|
+
* Used for overlapping Note Ons.
|
|
7397
|
+
*/
|
|
7398
|
+
noteID = 0;
|
|
7399
|
+
/**
|
|
7392
7400
|
* MIDI note number of the voice.
|
|
7393
7401
|
* Direct number from the Note On message and is
|
|
7394
7402
|
* used for Note Off and external parameters:
|
|
@@ -7511,7 +7519,7 @@ var Voice = class {
|
|
|
7511
7519
|
this.releaseStartTime = currentTime;
|
|
7512
7520
|
if (this.releaseStartTime - this.startTime < minNoteLength) this.releaseStartTime = this.startTime + minNoteLength;
|
|
7513
7521
|
}
|
|
7514
|
-
setup(currentTime, channel, midiNote) {
|
|
7522
|
+
setup(currentTime, channel, midiNote, noteID) {
|
|
7515
7523
|
this.isActive = true;
|
|
7516
7524
|
this.isInRelease = false;
|
|
7517
7525
|
this.hasRendered = false;
|
|
@@ -7526,6 +7534,7 @@ var Voice = class {
|
|
|
7526
7534
|
this.startTime = currentTime;
|
|
7527
7535
|
this.channel = channel;
|
|
7528
7536
|
this.midiNote = midiNote;
|
|
7537
|
+
this.noteID = noteID;
|
|
7529
7538
|
}
|
|
7530
7539
|
};
|
|
7531
7540
|
//#endregion
|
|
@@ -12170,7 +12179,7 @@ function controllerChange(controller, value, sendEvent = true) {
|
|
|
12170
12179
|
}
|
|
12171
12180
|
break;
|
|
12172
12181
|
case MIDIControllers.portamentoControl:
|
|
12173
|
-
this.
|
|
12182
|
+
this.lastPortamentoNote = value;
|
|
12174
12183
|
this.portamentoForce = true;
|
|
12175
12184
|
break;
|
|
12176
12185
|
default:
|
|
@@ -12583,8 +12592,9 @@ const clamp = (num, min, max) => Math.max(min, Math.min(max, num));
|
|
|
12583
12592
|
* Sends a "MIDI Note on" message and starts a note.
|
|
12584
12593
|
* @param midiNote The MIDI note number (0-127).
|
|
12585
12594
|
* @param velocity The velocity of the note (0-127). If less than 1, it will send a note off instead.
|
|
12595
|
+
* @param emit If the note on should be updated and emitted (non-internal)
|
|
12586
12596
|
*/
|
|
12587
|
-
function noteOn(midiNote, velocity) {
|
|
12597
|
+
function noteOn(midiNote, velocity, emit = true) {
|
|
12588
12598
|
if (velocity < 1) {
|
|
12589
12599
|
this.noteOff(midiNote);
|
|
12590
12600
|
return;
|
|
@@ -12601,7 +12611,7 @@ function noteOn(midiNote, velocity) {
|
|
|
12601
12611
|
const keyVel = this.synthCore.keyModifierManager.getVelocity(this.channel, midiNote);
|
|
12602
12612
|
if (keyVel > -1) velocity = keyVel;
|
|
12603
12613
|
let voiceGain = this.synthCore.keyModifierManager.getGain(this.channel, midiNote);
|
|
12604
|
-
const previousNote = this.
|
|
12614
|
+
const previousNote = this.lastPortamentoNote;
|
|
12605
12615
|
const portamentoEnabled = this.portamentoForce || this._midiControllers[MIDIControllers.portamentoOnOff] >= 8192;
|
|
12606
12616
|
const portamentoTime = this._midiControllers[MIDIControllers.portamentoTime] >> 7;
|
|
12607
12617
|
const canApplyPortamento = portamentoEnabled && !this._drumChannel && previousNote >= 0 && previousNote !== midiNote && portamentoTime > 0;
|
|
@@ -12613,15 +12623,12 @@ function noteOn(midiNote, velocity) {
|
|
|
12613
12623
|
portaTime = portamentoTimeToSeconds(portamentoTime, keyDistance);
|
|
12614
12624
|
this.portamentoForce = false;
|
|
12615
12625
|
}
|
|
12616
|
-
this.
|
|
12626
|
+
this.lastPortamentoNote = midiNote;
|
|
12627
|
+
this.playingNotes[midiNote] = true;
|
|
12617
12628
|
if (!this._midiParameters.polyMode) {
|
|
12618
|
-
|
|
12619
|
-
|
|
12620
|
-
|
|
12621
|
-
v.exclusiveRelease(this.synthCore.currentTime, 0);
|
|
12622
|
-
if (++vc >= this._voiceCount) break;
|
|
12623
|
-
}
|
|
12624
|
-
}
|
|
12629
|
+
if (this.lastMonoNote >= 0 && this.lastMonoNote !== midiNote) this.killNote(this.lastMonoNote);
|
|
12630
|
+
this.lastMonoNote = midiNote;
|
|
12631
|
+
this.lastMonoVelocity = velocity;
|
|
12625
12632
|
}
|
|
12626
12633
|
const voices = this.synthCore.getVoices(this.channel, soundBankNote, velocity);
|
|
12627
12634
|
let panOverride = 0;
|
|
@@ -12647,10 +12654,11 @@ function noteOn(midiNote, velocity) {
|
|
|
12647
12654
|
delaySend = p.delayGain;
|
|
12648
12655
|
if (voiceGain === 1) voiceGain = p.gain;
|
|
12649
12656
|
}
|
|
12657
|
+
const noteID = emit ? this.noteOnID[midiNote]++ : this.noteOnID[midiNote];
|
|
12650
12658
|
for (const cached of voices) {
|
|
12651
12659
|
const voice = this.synthCore.assignVoice();
|
|
12652
12660
|
const now = this.synthCore.currentTime;
|
|
12653
|
-
voice.setup(now, this.channel, midiNote);
|
|
12661
|
+
voice.setup(now, this.channel, midiNote, noteID);
|
|
12654
12662
|
voice.wavetable = voice.oscillators[this._systemParameters.interpolationType ?? this.synthCore.systemParameters.interpolationType];
|
|
12655
12663
|
voice.targetKey = cached.targetKey;
|
|
12656
12664
|
voice.velocity = cached.velocity;
|
|
@@ -12723,7 +12731,7 @@ function noteOn(midiNote, velocity) {
|
|
|
12723
12731
|
voice.currentPan = Math.max(-500, Math.min(500, panOverride || voice.modulatedGenerators[GeneratorTypes.pan]));
|
|
12724
12732
|
}
|
|
12725
12733
|
this._voiceCount += voices.length;
|
|
12726
|
-
this.synthCore.callEvent("noteOn", {
|
|
12734
|
+
if (emit) this.synthCore.callEvent("noteOn", {
|
|
12727
12735
|
midiNote,
|
|
12728
12736
|
channel: this.channel,
|
|
12729
12737
|
velocity
|
|
@@ -12747,10 +12755,14 @@ function noteOff(midiNote) {
|
|
|
12747
12755
|
});
|
|
12748
12756
|
return;
|
|
12749
12757
|
}
|
|
12750
|
-
|
|
12758
|
+
this.playingNotes[midiNote] = false;
|
|
12759
|
+
const mono = !this._midiParameters.polyMode;
|
|
12760
|
+
const sustain = this._midiControllers[MIDIControllers.sustainPedal] >= 8192 && !mono;
|
|
12751
12761
|
let vc = 0;
|
|
12762
|
+
const noteID = this.noteOffID[midiNote];
|
|
12763
|
+
if (noteID < this.noteOnID[midiNote]) this.noteOffID[midiNote]++;
|
|
12752
12764
|
if (this._voiceCount > 0) {
|
|
12753
|
-
for (const v of this.synthCore.voices) if (v.channel === this.channel && v.isActive && v.midiNote === midiNote && !v.isInRelease) {
|
|
12765
|
+
for (const v of this.synthCore.voices) if (v.channel === this.channel && v.isActive && v.midiNote === midiNote && v.noteID === noteID && !v.isInRelease) {
|
|
12754
12766
|
if (sustain) v.isHeld = true;
|
|
12755
12767
|
else v.releaseVoice(this.synthCore.currentTime);
|
|
12756
12768
|
if (++vc >= this._voiceCount) break;
|
|
@@ -12760,6 +12772,11 @@ function noteOff(midiNote) {
|
|
|
12760
12772
|
midiNote,
|
|
12761
12773
|
channel: this.channel
|
|
12762
12774
|
});
|
|
12775
|
+
if (mono) {
|
|
12776
|
+
const highest = this.playingNotes.lastIndexOf(true);
|
|
12777
|
+
if (highest === -1) this.lastMonoNote = -1;
|
|
12778
|
+
else if (this.lastMonoNote === midiNote) this.noteOn(highest, this.lastMonoVelocity, false);
|
|
12779
|
+
}
|
|
12763
12780
|
}
|
|
12764
12781
|
//#endregion
|
|
12765
12782
|
//#region src/synthesizer/audio_engine/channel/program_change.ts
|
|
@@ -13281,6 +13298,20 @@ var MIDIChannel = class {
|
|
|
13281
13298
|
*/
|
|
13282
13299
|
_systemParameters = { ...DEFAULT_CHANNEL_SYSTEM_PARAMETERS };
|
|
13283
13300
|
/**
|
|
13301
|
+
* Note On message tracking, for grouping voices for specific Note On messages.
|
|
13302
|
+
* Used for overlapping Note Ons.
|
|
13303
|
+
* MIDI note: current note on ID
|
|
13304
|
+
* @protected
|
|
13305
|
+
*/
|
|
13306
|
+
noteOnID = new Array(128).fill(0);
|
|
13307
|
+
/**
|
|
13308
|
+
* Note Off message tracking, for grouping voices for specific Note On messages.
|
|
13309
|
+
* Used for overlapping Note Ons.
|
|
13310
|
+
* MIDI note: current note on ID
|
|
13311
|
+
* @protected
|
|
13312
|
+
*/
|
|
13313
|
+
noteOffID = new Array(128).fill(0);
|
|
13314
|
+
/**
|
|
13284
13315
|
* If the last Parameter was RPN.
|
|
13285
13316
|
* If false then the last parameter was NRPN.
|
|
13286
13317
|
* @protected
|
|
@@ -13315,21 +13346,39 @@ var MIDIChannel = class {
|
|
|
13315
13346
|
*/
|
|
13316
13347
|
currentGain = 0;
|
|
13317
13348
|
/**
|
|
13318
|
-
* The last pressed note on this channel.
|
|
13349
|
+
* The last pressed note on this channel for portamento tracking.
|
|
13319
13350
|
* -1 means none.
|
|
13320
13351
|
* This is not a `ChannelMIDIParameter` and is strictly internal,
|
|
13321
13352
|
* mostly because we don't want to send events for every note on message.
|
|
13322
13353
|
* It can be set with Portamento Control CC anyway.
|
|
13323
13354
|
* @protected
|
|
13324
13355
|
*/
|
|
13325
|
-
|
|
13356
|
+
lastPortamentoNote = -1;
|
|
13326
13357
|
/**
|
|
13327
13358
|
* If the portamento should be executed once regardless of Portamento on/off.
|
|
13328
13359
|
* Adhering to the MIDI spec, CC#84 ignores on/off.
|
|
13329
|
-
* This is also not a `ChannelMIDIParameter` for the same reason as `
|
|
13360
|
+
* This is also not a `ChannelMIDIParameter` for the same reason as `lastPortamentoNote`
|
|
13330
13361
|
* @protected
|
|
13331
13362
|
*/
|
|
13332
13363
|
portamentoForce = false;
|
|
13364
|
+
/**
|
|
13365
|
+
* The last pressed note on this channel in mono mode.
|
|
13366
|
+
* Used for tracking and releasing this note on a new Note On event.
|
|
13367
|
+
* -1 means none.
|
|
13368
|
+
* @protected
|
|
13369
|
+
*/
|
|
13370
|
+
lastMonoNote = -1;
|
|
13371
|
+
/**
|
|
13372
|
+
* The last pressed note's velocity on this channel in mono mode.
|
|
13373
|
+
* @protected
|
|
13374
|
+
*/
|
|
13375
|
+
lastMonoVelocity = 0;
|
|
13376
|
+
/**
|
|
13377
|
+
* For Mono Mode restoring notes.
|
|
13378
|
+
* playingNotes[midiNote]
|
|
13379
|
+
* @protected
|
|
13380
|
+
*/
|
|
13381
|
+
playingNotes = new Array(128).fill(false);
|
|
13333
13382
|
generators = {
|
|
13334
13383
|
offsets: new Int16Array(GENERATORS_AMOUNT),
|
|
13335
13384
|
offsetsEnabled: false,
|
|
@@ -13442,6 +13491,9 @@ var MIDIChannel = class {
|
|
|
13442
13491
|
* @param force If true, stops all notes immediately, otherwise applies release time.
|
|
13443
13492
|
*/
|
|
13444
13493
|
stopAllNotes(force = false) {
|
|
13494
|
+
this.noteOnID.fill(0);
|
|
13495
|
+
this.noteOffID.fill(0);
|
|
13496
|
+
this.playingNotes.fill(false);
|
|
13445
13497
|
if (force) {
|
|
13446
13498
|
let vc = 0;
|
|
13447
13499
|
if (this._voiceCount > 0) {
|
|
@@ -13644,6 +13696,8 @@ var MIDIChannel = class {
|
|
|
13644
13696
|
*/
|
|
13645
13697
|
killNote(midiNote, releaseTime = -12e3) {
|
|
13646
13698
|
let vc = 0;
|
|
13699
|
+
this.noteOffID[midiNote] = 0;
|
|
13700
|
+
this.noteOnID[midiNote] = 0;
|
|
13647
13701
|
if (this._voiceCount > 0) {
|
|
13648
13702
|
for (const v of this.synthCore.voices) if (v.channel === this.channel && v.isActive && v.midiNote === midiNote) {
|
|
13649
13703
|
v.overrideReleaseVolEnv = releaseTime;
|
|
@@ -13674,7 +13728,7 @@ var MIDIChannel = class {
|
|
|
13674
13728
|
* @param midiNote
|
|
13675
13729
|
*/
|
|
13676
13730
|
setLastNote(midiNote) {
|
|
13677
|
-
this.
|
|
13731
|
+
this.lastPortamentoNote = midiNote;
|
|
13678
13732
|
}
|
|
13679
13733
|
/**
|
|
13680
13734
|
* @internal
|