Last active
July 21, 2023 09:39
-
-
Save mktwo/100d7b5336cc9b8e2d778c528a7ae144 to your computer and use it in GitHub Desktop.
A userscript that compresses YouTube audio so loud sections (such as intros that are at an average of 0dB when the video is at -6dB) aren't as awful.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name YouTube Audio Compressor/Limiter | |
// @description A somewhat passable solution to YouTubers who don't know how to look at a dB meter while editing their videos... (Makes very loud sections not as deafening!) | |
// @author Tim (@ineedfocus) | |
// @include https://www.youtube.com/* | |
// @include http://www.youtube.com/* | |
// ==/UserScript== | |
//Apply compression to YouTube video | |
function fixAudio(element) { | |
try{ | |
//Set up the audio context | |
var myAudio = element; | |
var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); | |
if(audioCtx != null && myAudio != null){ | |
var source = audioCtx.createMediaElementSource(myAudio); | |
//Set up the audio processing | |
//Compressor: | |
var compressor = audioCtx.createDynamicsCompressor(); | |
compressor.threshold.setValueAtTime(-24, audioCtx.currentTime); //This could probably go up a bit, but that'll make it less effective at canceling out loud sections | |
compressor.knee.setValueAtTime(12, audioCtx.currentTime); | |
compressor.ratio.setValueAtTime(4, audioCtx.currentTime); //Lower this to 2 or 3 if the pumping effect is a bit too strong for your tastes and you're okay with more loudness (1 = no compression) | |
compressor.attack.setValueAtTime(0, audioCtx.currentTime); //Probably don't change this, it'll give you blasts of the original loud stuff before kicking in. | |
compressor.release.setValueAtTime(0.15, audioCtx.currentTime); | |
//Limit volume: | |
var gainNode = audioCtx.createGain(); | |
gainNode.gain.setValueAtTime(0.8, audioCtx.currentTime); //0 = mute, 1 is default | |
//Source audio -> compressor -> gain | |
source.connect(compressor); | |
compressor.connect(gainNode); | |
//Send processed audio to where it needs to be | |
gainNode.connect(audioCtx.destination); | |
} | |
}catch(e){ | |
console.error(e); | |
} | |
} | |
//Wait for YouTube to insert their video element | |
function waitForElement(selector) { | |
return new Promise(function(resolve, reject) { | |
var element = document.querySelector(selector); | |
if(element) { | |
resolve(element); | |
return; | |
} | |
var observer = new MutationObserver(function(mutations) { | |
mutations.forEach(function(mutation) { | |
var nodes = Array.from(mutation.addedNodes); | |
for(var node of nodes) { | |
if(node.matches && node.matches(selector)) { | |
observer.disconnect(); | |
resolve(node); | |
return; | |
} | |
}; | |
}); | |
}); | |
observer.observe(document.documentElement, { childList: true, subtree: true }); | |
}); | |
} | |
//Do the thing! | |
waitForElement("video").then(function(element) { | |
//console.log("Video element found, fixing audio!"); | |
fixAudio(element); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just became aware of this and really appreciate this tool!
Only issue I have is that it seems Youtube's playback speed doesn't work with the script enabled for me