Skip to content

Commit

Permalink
WIP: feat: add "mute silence" feature
Browse files Browse the repository at this point in the history
  • Loading branch information
WofWca committed Aug 12, 2021
1 parent ec472ce commit 095e3bf
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/content/CloningController/CloningController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type ControllerSettings =
| 'soundedSpeed'
| 'marginBefore'
| 'marginAfter'
| 'muteSilence'
| 'enableDesyncCorrection'
> & {
silenceSpeed: number,
Expand Down
26 changes: 24 additions & 2 deletions src/content/StretchingController/StretcherAndPitchCorrectorNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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?

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down
21 changes: 19 additions & 2 deletions src/content/StretchingController/StretchingController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type ControllerSettings =
| 'soundedSpeed'
| 'marginBefore'
| 'marginAfter'
| 'muteSilence'
| 'enableDesyncCorrection'
> & {
silenceSpeed: number,
Expand Down Expand Up @@ -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(() => {
Expand Down Expand Up @@ -308,10 +315,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.
Expand Down
1 change: 1 addition & 0 deletions src/content/extensionSettings2ControllerSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
17 changes: 17 additions & 0 deletions src/popup/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,23 @@ ${wouldHaveLastedIfSpeedWasIntrinsic} – how long playback would take at intrin
bind:value={settings.silenceSpeedRaw}
disabled={settings.experimentalControllerType === ControllerKind_CLONING}
/>
<label
use:tippyActionAsyncPreload={{
content: '* Bare minimum usability\n'
+ '* Allows skipping silent parts entirely instead of playing them at a faster rate\n'
+ '* Doesn\'t work on many websites (YouTube, Vimeo). Works for local files\n'
+ '* No audio distortion, delay or desync\n',
theme: 'my-tippy white-space-pre-line',
}}
style="margin-top: 1rem; display: inline-flex; align-items: center;"
>
<input
bind:checked={settings.muteSilence}
type="checkbox"
style="margin: 0 0.5rem 0 0;"
>
<span>Mute silence</span>
</label>
<RangeSlider
label="Margin before (side effects: audio distortion & audio delay)"
min="0"
Expand Down
2 changes: 2 additions & 0 deletions src/settings/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const defaultSettings: Readonly<Settings> = {
marginAfter: 0.100,
previousMarginAfter: 0.100,

muteSilence: false,

applyTo: 'videoOnly',

enableHotkeys: true,
Expand Down
2 changes: 2 additions & 0 deletions src/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface Settings {
marginAfter: number,
previousMarginAfter: number,

muteSilence: boolean,

applyTo: 'videoOnly' | 'audioOnly' | 'both',

enableHotkeys: boolean,
Expand Down

0 comments on commit 095e3bf

Please sign in to comment.