diff --git a/package.json b/package.json index 57d198f..6f26bd6 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,9 @@ "resolve-url-loader": "3.1.0", "sass-loader": "7.2.0", "sdp-transform": "^2.14.0", - "semver": "6.3.0", + "semver": "7.3.2", + "serialize-javascript": "^5.0.1", + "stereo-analyser-node": "^1.0.0", "strict-event-emitter-types": "^2.0.0", "style-loader": "1.0.0", "terser-webpack-plugin": "1.4.1", diff --git a/src/mixer/audio.ts b/src/mixer/audio.ts index 31f3929..dfe3dc8 100644 --- a/src/mixer/audio.ts +++ b/src/mixer/audio.ts @@ -7,6 +7,9 @@ import RegionsPlugin from "wavesurfer.js/dist/plugin/wavesurfer.regions.min.js"; import NewsEndCountdown from "../assets/audio/NewsEndCountdown.wav"; import NewsIntro from "../assets/audio/NewsIntro.wav"; +import StereoAnalyserNode from "stereo-analyser-node"; + + interface PlayerEvents { loadComplete: (duration: number) => void; timeChange: (time: number) => void; @@ -183,20 +186,20 @@ export class AudioEngine extends ((EngineEmitter as unknown) as { micMedia: MediaStream | null = null; micSource: MediaStreamAudioSourceNode | null = null; micCalibrationGain: GainNode; - micPrecompAnalyser: AnalyserNode; + micPrecompAnalyser: StereoAnalyserNode; micCompressor: DynamicsCompressorNode; micMixGain: GainNode; - micFinalAnalyser: AnalyserNode; + micFinalAnalyser: StereoAnalyserNode; finalCompressor: DynamicsCompressorNode; streamingDestination: MediaStreamAudioDestinationNode; - player0Analyser: AnalyserNode; - player1Analyser: AnalyserNode; - player2Analyser: AnalyserNode; - playerAnalysers: AnalyserNode[]; + player0Analyser: StereoAnalyserNode; + player1Analyser: StereoAnalyserNode; + player2Analyser: StereoAnalyserNode; + playerAnalysers: StereoAnalyserNode[]; - streamingAnalyser: AnalyserNode; + streamingAnalyser: StereoAnalyserNode; newsStartCountdownEl: HTMLAudioElement; newsStartCountdownNode: MediaElementAudioSourceNode; @@ -204,7 +207,6 @@ export class AudioEngine extends ((EngineEmitter as unknown) as { newsEndCountdownEl: HTMLAudioElement; newsEndCountdownNode: MediaElementAudioSourceNode; - analysisBuffer: Float32Array; constructor() { super(); @@ -220,16 +222,21 @@ export class AudioEngine extends ((EngineEmitter as unknown) as { this.finalCompressor.release.value = 0.2; this.finalCompressor.knee.value = 0; - this.player0Analyser = this.audioContext.createAnalyser(); + this.player0Analyser = new StereoAnalyserNode(this.audioContext); this.player0Analyser.fftSize = ANALYSIS_FFT_SIZE; - this.player1Analyser = this.audioContext.createAnalyser(); + this.player1Analyser = new StereoAnalyserNode(this.audioContext); this.player1Analyser.fftSize = ANALYSIS_FFT_SIZE; - this.player2Analyser = this.audioContext.createAnalyser(); + this.player2Analyser = new StereoAnalyserNode(this.audioContext); this.player2Analyser.fftSize = ANALYSIS_FFT_SIZE; + + + + this.playerAnalysers = [this.player0Analyser, this.player1Analyser, this.player2Analyser]; - this.streamingAnalyser = this.audioContext.createAnalyser(); + this.streamingAnalyser = new StereoAnalyserNode(this.audioContext); this.streamingAnalyser.fftSize = ANALYSIS_FFT_SIZE; + // this.streamingAnalyser.maxDecibels = 0; this.streamingDestination = this.audioContext.createMediaStreamDestination(); @@ -242,16 +249,14 @@ export class AudioEngine extends ((EngineEmitter as unknown) as { this.micCalibrationGain = this.audioContext.createGain(); - this.micPrecompAnalyser = this.audioContext.createAnalyser(); + this.micPrecompAnalyser = new StereoAnalyserNode(this.audioContext); this.micPrecompAnalyser.fftSize = ANALYSIS_FFT_SIZE; this.micPrecompAnalyser.maxDecibels = 0; - this.micFinalAnalyser = this.audioContext.createAnalyser(); + this.micFinalAnalyser = new StereoAnalyserNode(this.audioContext); this.micFinalAnalyser.fftSize = ANALYSIS_FFT_SIZE; this.micFinalAnalyser.maxDecibels = 0; - this.analysisBuffer = new Float32Array(ANALYSIS_FFT_SIZE); - this.micCompressor = this.audioContext.createDynamicsCompressor(); this.micCompressor.ratio.value = 3; // mic compressor - fairly gentle, can be upped this.micCompressor.threshold.value = -18; @@ -264,6 +269,7 @@ export class AudioEngine extends ((EngineEmitter as unknown) as { this.micCalibrationGain .connect(this.micPrecompAnalyser) + this.micCalibrationGain .connect(this.micCompressor) .connect(this.micMixGain) .connect(this.micFinalAnalyser) @@ -337,34 +343,46 @@ export class AudioEngine extends ((EngineEmitter as unknown) as { this.micMixGain.gain.value = value; } - getLevel(source: LevelsSource) { + getLevels(source: LevelsSource, stereo: boolean) { + let analysisBuffer = new Float32Array(ANALYSIS_FFT_SIZE); + let analysisBuffer2 = new Float32Array(ANALYSIS_FFT_SIZE); switch (source) { case "mic-precomp": - this.micPrecompAnalyser.getFloatTimeDomainData(this.analysisBuffer); + this.micPrecompAnalyser.getFloatTimeDomainData(analysisBuffer, analysisBuffer2); break; case "mic-final": - this.micFinalAnalyser.getFloatTimeDomainData(this.analysisBuffer); + this.micFinalAnalyser.getFloatTimeDomainData(analysisBuffer, analysisBuffer2); break; case "master": - this.streamingAnalyser.getFloatTimeDomainData(this.analysisBuffer); + this.streamingAnalyser.getFloatTimeDomainData(analysisBuffer, analysisBuffer2); break; case "player-0": - this.player0Analyser.getFloatTimeDomainData(this.analysisBuffer); + this.player0Analyser.getFloatTimeDomainData(analysisBuffer, analysisBuffer2); break; case "player-1": - this.player1Analyser.getFloatTimeDomainData(this.analysisBuffer); + this.player1Analyser.getFloatTimeDomainData(analysisBuffer, analysisBuffer2); break; case "player-2": - this.player2Analyser.getFloatTimeDomainData(this.analysisBuffer); + this.player2Analyser.getFloatTimeDomainData(analysisBuffer, analysisBuffer2); break; default: throw new Error("can't getLevel " + source); } - let peak = 0; - for (let i = 0; i < this.analysisBuffer.length; i++) { - peak = Math.max(peak, Math.abs(this.analysisBuffer[i])); + let peakL = 0; + for (let i = 0; i < analysisBuffer.length; i++) { + peakL = Math.max(peakL, Math.abs(analysisBuffer[i])); } - return 20 * Math.log10(peak); + peakL = 20 * Math.log10(peakL); + + if (stereo) { + let peakR = 0; + for (let i = 0; i < analysisBuffer2.length; i++) { + peakR = Math.max(peakR, Math.abs(analysisBuffer2[i])); + } + peakR = 20 * Math.log10(peakR); + return [peakL, peakR] + } + return [peakL]; } async playNewsEnd() { diff --git a/src/navbar/index.tsx b/src/navbar/index.tsx index 2811212..d5c9b29 100644 --- a/src/navbar/index.tsx +++ b/src/navbar/index.tsx @@ -269,7 +269,7 @@ export function NavBarWebStudio() { )}