From 4e1415aa1ce333f648ba171d43cde32d6256f2df Mon Sep 17 00:00:00 2001 From: Jage9 Date: Mon, 23 Feb 2026 01:20:27 -0500 Subject: [PATCH] Make struck piano instruments decay while held --- client/public/version.js | 2 +- client/src/audio/pianoSynth.ts | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/client/public/version.js b/client/public/version.js index 1a59211..d1514d6 100644 --- a/client/public/version.js +++ b/client/public/version.js @@ -1,5 +1,5 @@ // Maintainer-controlled web client version. // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) -window.CHGRID_WEB_VERSION = "2026.02.23 R212"; +window.CHGRID_WEB_VERSION = "2026.02.23 R213"; // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. window.CHGRID_TIME_ZONE = "America/Detroit"; diff --git a/client/src/audio/pianoSynth.ts b/client/src/audio/pianoSynth.ts index d703f70..d4193cc 100644 --- a/client/src/audio/pianoSynth.ts +++ b/client/src/audio/pianoSynth.ts @@ -40,6 +40,7 @@ type InstrumentPreset = { filter?: { type: BiquadFilterType; frequency: number; q?: number }; gain: number; sustainRatio?: number; + holdSustain?: boolean; releaseScale?: number; vibrato?: { rateHz: number; depthCents: number }; }; @@ -53,6 +54,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 5200, q: 0.7 }, gain: 0.32, sustainRatio: 0.5, + holdSustain: false, releaseScale: 0.9, }, electric_piano: { @@ -63,6 +65,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 4200, q: 0.8 }, gain: 0.3, sustainRatio: 0.52, + holdSustain: false, releaseScale: 0.8, }, guitar: { @@ -73,6 +76,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 3200, q: 0.9 }, gain: 0.24, sustainRatio: 0.48, + holdSustain: false, releaseScale: 0.7, }, organ: { @@ -84,6 +88,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 6500, q: 0.6 }, gain: 0.18, sustainRatio: 0.72, + holdSustain: true, releaseScale: 1.4, }, bass: { @@ -94,6 +99,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 1500, q: 1.1 }, gain: 0.28, sustainRatio: 0.45, + holdSustain: false, releaseScale: 0.9, }, violin: { @@ -104,6 +110,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 3600, q: 1.0 }, gain: 0.24, sustainRatio: 0.68, + holdSustain: true, releaseScale: 1.5, vibrato: { rateHz: 5.7, depthCents: 12 }, }, @@ -115,6 +122,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 5400, q: 0.9 }, gain: 0.2, sustainRatio: 0.6, + holdSustain: true, releaseScale: 1, vibrato: { rateHz: 6.8, depthCents: 9 }, }, @@ -126,6 +134,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 3300, q: 1.05 }, gain: 0.22, sustainRatio: 0.62, + holdSustain: true, releaseScale: 0.92, vibrato: { rateHz: 5.1, depthCents: 5 }, }, @@ -137,6 +146,7 @@ const PRESETS: Record, InstrumentPreset> filter: { type: 'lowpass', frequency: 5200, q: 1.2 }, gain: 0.22, sustainRatio: 0.62, + holdSustain: true, releaseScale: 0.65, }, }; @@ -292,8 +302,14 @@ export class PianoSynth { voiceGain.gain.setValueAtTime(0.0001, now); const peakGain = Math.max(0.0001, preset.gain * spatialMix.gain); const sustainGain = Math.max(0.0001, peakGain * (preset.sustainRatio ?? 0.55)); + const holdsSustain = preset.holdSustain !== false; voiceGain.gain.exponentialRampToValueAtTime(peakGain, now + attackSeconds); - voiceGain.gain.exponentialRampToValueAtTime(sustainGain, now + attackSeconds + decaySeconds * 0.6); + if (holdsSustain) { + voiceGain.gain.exponentialRampToValueAtTime(sustainGain, now + attackSeconds + decaySeconds * 0.6); + } else { + // Struck/plucked timbres naturally decay even if the key remains held. + voiceGain.gain.exponentialRampToValueAtTime(0.0001, now + attackSeconds + decaySeconds); + } let tailNode: AudioNode = voiceGain; if (preset.filter) {