Signatur
Beschreibung
cancelAndHoldAtTime() gehört zur Automations-API von AudioParam in der Web Audio API. Die Methode löscht alle Ereignisse, deren Startzeit bei oder nach cancelTime liegt. Anders als bei cancelScheduledValues() springt der Parameter dabei nicht auf einen früheren Wert zurück: Er behält den Wert, den er zu cancelTime hat, bis Sie neue Automationsereignisse planen.
Am meisten bringt die Methode, wenn eine Rampe gerade läuft, zum Beispiel linearRampToValueAtTime(), exponentialRampToValueAtTime(), setTargetAtTime() oder setValueCurveAtTime(). Die Rampe wird zu cancelTime abgeschnitten. Der dann erreichte Zwischenwert wird als fester Wert gehalten, und neue Rampen setzen genau dort an. So entstehen keine Knackser.
Typischer Einsatz sind Hüllkurven (ADSR) in Synthesizern. Lässt der Nutzer eine Taste los, während Attack oder Decay noch laufen, friert cancelAndHoldAtTime(ctx.currentTime) die Lautstärke auf dem aktuellen Stand ein. Danach kann die Release-Phase sauber von diesem Wert aus beginnen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $cancelTime Pflicht | number | Zeitpunkt in Sekunden auf der Zeitachse des AudioContext (vergleichbar mit ctx.currentTime). Ab diesem Zeitpunkt werden alle geplanten Ereignisse gelöscht, und der Wert zu diesem Zeitpunkt wird gehalten. Der Wert muss endlich und ≥ 0 sein. |
Rückgabewert
AudioParam-Objekt. Dadurch lassen sich Aufrufe verketten, z. B. param.cancelAndHoldAtTime(t).linearRampToValueAtTime(0, t + 0.5).Beispiele
Release-Phase einer ADSR-Hüllkurve ohne Knacksen
const ctx = new AudioContext();
const osc = new OscillatorNode(ctx, { type: 'sawtooth', frequency: 220 });
const amp = new GainNode(ctx, { gain: 0 });
osc.connect(amp).connect(ctx.destination);
osc.start();
const noteOn = () => {
const t = ctx.currentTime;
amp.gain.cancelAndHoldAtTime(t);
amp.gain.linearRampToValueAtTime(1, t + 0.8); // Attack
amp.gain.linearRampToValueAtTime(0.6, t + 1.5); // Decay → Sustain
};
const noteOff = () => {
const t = ctx.currentTime;
// Laufende Attack-/Decay-Rampe einfrieren und von dort ausblenden
amp.gain.cancelAndHoldAtTime(t)
.linearRampToValueAtTime(0, t + 0.4); // Release
};
document.querySelector('#key').addEventListener('pointerdown', async () => {
await ctx.resume();
noteOn();
});
document.querySelector('#key').addEventListener('pointerup', noteOff);
Laufende Rampe mittendrin anhalten
const ctx = new AudioContext();
const osc = new OscillatorNode(ctx, { frequency: 200 });
osc.connect(ctx.destination);
osc.start();
const t0 = ctx.currentTime;
// Frequenz soll in 4 s von 200 auf 1000 Hz steigen
osc.frequency.setValueAtTime(200, t0);
osc.frequency.linearRampToValueAtTime(1000, t0 + 4);
// Nach 2 s abbrechen: Die Frequenz bleibt bei ca. 600 Hz stehen
osc.frequency.cancelAndHoldAtTime(t0 + 2);
setTimeout(() => {
console.log(Math.round(osc.frequency.value));
osc.stop();
}, 3000);
Feature-Erkennung mit Fallback (z. B. für Firefox)
const holdAt = (param, time) => {
if (typeof param.cancelAndHoldAtTime === 'function') {
return param.cancelAndHoldAtTime(time);
}
// Näherung: aktuellen Wert lesen und fest setzen
const current = param.value;
param.cancelScheduledValues(time);
param.setValueAtTime(current, time);
return param;
};
const ctx = new AudioContext();
const gain = new GainNode(ctx);
gain.gain.linearRampToValueAtTime(1, ctx.currentTime + 2);
holdAt(gain.gain, ctx.currentTime)
.linearRampToValueAtTime(0, ctx.currentTime + 0.3);
console.log('Hüllkurve angepasst');
// Wichtig · Fallstricke
- Browser-Kompatibilität: Chromium-Browser (ab Chrome 57) und Safari (ab 14.1) unterstützen die Methode. Firefox unterstützt sie nicht. Prüfen Sie daher vor dem Aufruf mit
typeof param.cancelAndHoldAtTime === 'function'und nutzen Sie sonst einen Fallback auscancelScheduledValues()undsetValueAtTime(param.value, t). Dieser Fallback ist nur eine Näherung, dennparam.valuekann der tatsächlichen Automation etwas hinterherhinken. - Ist
cancelTimenegativ oder nicht endlich (NaN,Infinity), wirft die Methode einenRangeError. - Die Zeit bezieht sich immer auf
AudioContext.currentTime, nicht aufperformance.now()oderDate.now(), und wird in Sekunden angegeben, nicht in Millisekunden. - Unterschied zu
cancelScheduledValues(): Diese Methode entfernt die Ereignisse nur. Liegt der Abbruch mitten in einer Rampe, springt der Wert auf das letzte verbliebene Ereignis zurück, und es knackt hörbar.cancelAndHoldAtTime()vermeidet diesen Sprung. - Rampen, die Sie danach planen, starten beim gehaltenen Wert. Ein zusätzliches
setValueAtTime()ist nicht nötig und würde bei einem falschen Wert sogar wieder einen Sprung verursachen.