diff --git a/src/content/CloningController/CloningController.ts b/src/content/CloningController/CloningController.ts
index 2299936a..c034bb55 100644
--- a/src/content/CloningController/CloningController.ts
+++ b/src/content/CloningController/CloningController.ts
@@ -17,6 +17,7 @@ export type ControllerSettings =
| 'soundedSpeed'
| 'marginBefore'
| 'marginAfter'
+ | 'muteSilence'
| 'enableDesyncCorrection'
> & {
silenceSpeed: number,
diff --git a/src/content/StretchingController/StretcherAndPitchCorrectorNode.ts b/src/content/StretchingController/StretcherAndPitchCorrectorNode.ts
index ada5313c..c3573405 100644
--- a/src/content/StretchingController/StretcherAndPitchCorrectorNode.ts
+++ b/src/content/StretchingController/StretcherAndPitchCorrectorNode.ts
@@ -42,6 +42,7 @@ export default class StretcherAndPitchCorrectorNode {
private slowDownPitchShift: PitchShift;
private originalPitchCompensationDelay: DelayNode;
private delayNode: DelayNode;
+ // private silenceMuter: GainNode;
lastScheduledStretch?: StretchInfo & { speedupOrSlowdown: PitchSetting.SPEEDUP | PitchSetting.SLOWDOWN };
private lastElementSpeedChangeAtInputTime?: Time;
@@ -89,9 +90,16 @@ export default class StretcherAndPitchCorrectorNode {
this.delayNode = context.createDelay(maxDelay);
this.delayNode.delayTime.value = initialDelay;
+ // this.silenceMuter = context.createGain();
+
+ // this.delayNode.connect(this.silenceMuter);
+
this.delayNode.connect(this.speedUpGain);
this.delayNode.connect(this.slowDownGain);
this.delayNode.connect(this.normalSpeedGain);
+ // this.silenceMuter.connect(this.speedUpGain);
+ // this.silenceMuter.connect(this.slowDownGain);
+ // this.silenceMuter.connect(this.normalSpeedGain);
ToneConnect(this.speedUpGain, this.speedUpPitchShift);
ToneConnect(this.slowDownGain, this.slowDownPitchShift);
@@ -119,7 +127,10 @@ export default class StretcherAndPitchCorrectorNode {
}
connect = this.connectOutputTo;
- onSilenceEnd(elementSpeedSwitchedAt: Time): void {
+ /**
+ * @returns marginBeforeStartOutputTime
+ */
+ onSilenceEnd(elementSpeedSwitchedAt: Time): Time {
// TODO all this does look like it may cause a snowballing floating point error. Mathematically simplify this?
// Or just use if-else?
@@ -213,8 +224,15 @@ export default class StretcherAndPitchCorrectorNode {
// if (isLogging(this)) {
// this._log({ type: 'stretch', lastScheduledStretch: this.lastScheduledStretch });
// }
+
+ // this.silenceMuter.gain.setValueAtTime(1, marginBeforeStartOutputTime);
+
+ return marginBeforeStartOutputTime;
}
- onSilenceStart(elementSpeedSwitchedAt: Time) {
+ /**
+ * @returns marginAfterEndOutputTime
+ */
+ onSilenceStart(elementSpeedSwitchedAt: Time): Time {
this.lastElementSpeedChangeAtInputTime = elementSpeedSwitchedAt; // See the same assignment in `onSilenceEnd`.
const settings = this.getSettings();
@@ -245,6 +263,10 @@ export default class StretcherAndPitchCorrectorNode {
// if (isLogging(this)) {
// this._log({ type: 'reset', lastScheduledStretch: this.lastScheduledStretch });
// }
+
+ // this.silenceMuter.gain.setValueAtTime(0, marginAfterEndOutputTime);
+
+ return marginAfterEndOutputTime;
}
private setOutputPitchAt(pitchSetting: PitchSetting, time: Time, oldPitchSetting: PitchSetting) {
diff --git a/src/content/StretchingController/StretchingController.ts b/src/content/StretchingController/StretchingController.ts
index dcad8733..d1a133f5 100644
--- a/src/content/StretchingController/StretchingController.ts
+++ b/src/content/StretchingController/StretchingController.ts
@@ -46,6 +46,7 @@ export type ControllerSettings =
| 'soundedSpeed'
| 'marginBefore'
| 'marginAfter'
+ | 'muteSilence'
| 'enableDesyncCorrection'
> & {
silenceSpeed: number,
@@ -255,6 +256,12 @@ export default class Controller {
this._stretcherAndPitch.connectInputFrom(this._lookahead);
toDestinationChainLastConnectedLink = this._stretcherAndPitch;
}
+ let silenceMuter: undefined | GainNode;
+ if (this.settings.muteSilence) {
+ silenceMuter = audioContext.createGain();
+ toDestinationChainLastConnectedLink.connect(silenceMuter);
+ toDestinationChainLastConnectedLink = silenceMuter;
+ }
toAwait.push(volumeFilterP.then(async volumeFilter => {
mediaElementSource.connect(volumeFilter);
this._onDestroyCallbacks.push(() => {
@@ -313,10 +320,20 @@ export default class Controller {
const elementSpeedSwitchedAt = audioContext.currentTime;
if (silenceStartOrEnd === SilenceDetectorEventType.SILENCE_END) {
this._setSpeedAndLog(SpeedName.SOUNDED);
- this._stretcherAndPitch?.onSilenceEnd(elementSpeedSwitchedAt);
+ const marginBeforeStartOutputTime = this._stretcherAndPitch?.onSilenceEnd(elementSpeedSwitchedAt);
+ // TODO See the problem? When the stretcher is disabled, the change is scheduled to now,
+ // without any lookahead.
+ // TODO we either need to take `_stretcherAndPitch`'s pitch shifters' delays into consideration (instead of
+ // just the `delayNode`) or explain why we don't.
+ const unmuteAt = marginBeforeStartOutputTime ?? audioContext.currentTime;
+ // TODO fade to negate clicking.
+ silenceMuter?.gain.setValueAtTime(1, unmuteAt);
} else {
this._setSpeedAndLog(SpeedName.SILENCE);
- this._stretcherAndPitch?.onSilenceStart(elementSpeedSwitchedAt);
+ const marginAfterEndOutputTime = this._stretcherAndPitch?.onSilenceStart(elementSpeedSwitchedAt);
+ // See comments above, in the if true block.
+ const muteAt = marginAfterEndOutputTime ?? audioContext.currentTime;
+ silenceMuter?.gain.setValueAtTime(0, muteAt);
if (BUILD_DEFINITIONS.BROWSER === 'chromium' && this.settings.enableDesyncCorrection) {
// A workaround for https://github.com/vantezzen/skip-silence/issues/28.
diff --git a/src/content/extensionSettings2ControllerSettings.ts b/src/content/extensionSettings2ControllerSettings.ts
index 26143ea2..ffb023a2 100644
--- a/src/content/extensionSettings2ControllerSettings.ts
+++ b/src/content/extensionSettings2ControllerSettings.ts
@@ -9,6 +9,7 @@ export default function extensionSettings2ControllerSettings(extensionSettings:
volumeThreshold: extensionSettings.volumeThreshold,
marginBefore: extensionSettings.marginBefore,
marginAfter: extensionSettings.marginAfter,
+ muteSilence: extensionSettings.muteSilence,
enableDesyncCorrection: extensionSettings.enableDesyncCorrection,
silenceSpeed: getAbsoluteSilenceSpeed(extensionSettings),
diff --git a/src/popup/App.svelte b/src/popup/App.svelte
index 324d4d48..9984c6fc 100644
--- a/src/popup/App.svelte
+++ b/src/popup/App.svelte
@@ -453,6 +453,23 @@ ${wouldHaveLastedIfSpeedWasIntrinsic} – how long playback would take at intrin
bind:value={settings.silenceSpeedRaw}
disabled={settings.experimentalControllerType === ControllerKind_CLONING}
/>
+
= {
marginAfter: 0.100,
previousMarginAfter: 0.100,
+ muteSilence: false,
+
applyTo: 'videoOnly',
enableHotkeys: true,
diff --git a/src/settings/index.ts b/src/settings/index.ts
index 764ea99e..86174c24 100644
--- a/src/settings/index.ts
+++ b/src/settings/index.ts
@@ -20,6 +20,8 @@ export interface Settings {
marginAfter: number,
previousMarginAfter: number,
+ muteSilence: boolean,
+
applyTo: 'videoOnly' | 'audioOnly' | 'both',
enableHotkeys: boolean,