This commit is contained in:
Andras Schmelczer 2026-05-16 16:15:54 +01:00
commit d2da0d1617
25 changed files with 521 additions and 1026 deletions

View file

@ -1,4 +1,3 @@
import type { GardenAudioEngineConfig } from '../config';
import { clamp, clamp01 } from '../utils/clamp';
import { GardenAudioConfig } from './garden-audio-config';
import { GardenAudioGraph } from './garden-audio-graph';
@ -12,7 +11,6 @@ export class PianoSampler {
public constructor(
private readonly config: GardenAudioConfig,
private readonly engineConfig: GardenAudioEngineConfig,
private readonly graph: GardenAudioGraph
) {}
@ -54,21 +52,20 @@ export class PianoSampler {
}
const scheduledStart = Math.max(
context.currentTime + this.engineConfig.piano.scheduleAheadSeconds,
context.currentTime + this.config.piano.scheduleAheadSeconds,
startTime
);
const noteVelocity = clamp01(velocity);
const noteGainValue = Math.max(
this.engineConfig.piano.minGain,
this.config.piano.minGain,
this.config.piano.gain * noteVelocity
);
const sustainSeconds =
this.config.piano.sustainSeconds *
(this.engineConfig.piano.sustainBase +
noteVelocity * this.engineConfig.piano.sustainVelocityRange);
(this.config.piano.sustainBase +
noteVelocity * this.config.piano.sustainVelocityRange);
const sustainAt =
scheduledStart +
Math.max(this.engineConfig.piano.minDurationSeconds, durationSeconds);
scheduledStart + Math.max(this.config.piano.minDurationSeconds, durationSeconds);
const releaseAt = sustainAt + sustainSeconds;
const releaseSeconds = this.config.piano.releaseSeconds;
const stopAt = releaseAt + releaseSeconds;
@ -88,36 +85,29 @@ export class PianoSampler {
source.buffer = sample.buffer;
source.playbackRate.setValueAtTime(
Math.pow(2, (midi - sample.midi) / this.engineConfig.piano.pitchSemitonesPerOctave),
Math.pow(2, (midi - sample.midi) / this.config.piano.pitchSemitonesPerOctave),
scheduledStart
);
filter.type = 'lowpass';
filter.frequency.setValueAtTime(
clamp(
lowpassHz,
this.engineConfig.piano.lowpassMinHz,
this.engineConfig.piano.lowpassMaxHz
),
clamp(lowpassHz, this.config.piano.lowpassMinHz, this.config.piano.lowpassMaxHz),
scheduledStart
);
filter.Q.value = this.engineConfig.piano.filterQ;
gain.gain.setValueAtTime(this.engineConfig.piano.minGain, scheduledStart);
filter.Q.value = this.config.piano.filterQ;
gain.gain.setValueAtTime(this.config.piano.minGain, scheduledStart);
gain.gain.exponentialRampToValueAtTime(
noteGainValue,
scheduledStart + this.engineConfig.piano.gainAttackSeconds
scheduledStart + this.config.piano.gainAttackSeconds
);
gain.gain.setTargetAtTime(
Math.max(
this.engineConfig.piano.minGain,
noteGainValue * this.config.piano.sustainLevel
),
Math.max(this.config.piano.minGain, noteGainValue * this.config.piano.sustainLevel),
sustainAt,
Math.max(
this.engineConfig.piano.minFadeSeconds,
sustainSeconds * this.engineConfig.piano.sustainBase
this.config.piano.minFadeSeconds,
sustainSeconds * this.config.piano.sustainBase
)
);
gain.gain.setTargetAtTime(this.engineConfig.piano.minGain, releaseAt, releaseSeconds);
gain.gain.setTargetAtTime(this.config.piano.minGain, releaseAt, releaseSeconds);
panner.pan.setValueAtTime(clamp(pan, -1, 1), scheduledStart);
source.connect(filter);
@ -133,7 +123,7 @@ export class PianoSampler {
}
source.start(scheduledStart);
source.stop(stopAt + this.engineConfig.piano.tailStopExtraSeconds);
source.stop(stopAt + this.config.piano.tailStopExtraSeconds);
this.activeVoices.push({ gain, source, startAt: scheduledStart, stopAt });
source.addEventListener(
@ -186,13 +176,13 @@ export class PianoSampler {
}
private stopVoice(voice: ActivePianoVoice, now: number): void {
const stopAt = now + this.engineConfig.piano.voiceStealStopSeconds;
const stopAt = now + this.config.piano.voiceStealStopSeconds;
voice.gain.gain.cancelScheduledValues(now);
voice.gain.gain.setTargetAtTime(
this.engineConfig.piano.minGain,
this.config.piano.minGain,
now,
this.engineConfig.piano.voiceStealFadeSeconds
this.config.piano.voiceStealFadeSeconds
);
voice.stopAt = stopAt;
try {