1+ import { getCurrentTabId , runScriptInTab } from "./helpers/utils.js" ;
2+
13export default {
24 icon : "" ,
35 name : {
@@ -11,9 +13,65 @@ export default {
1113
1214 // whiteList: ["https://www.google.com/*"],
1315
14- onClick : async ( ) => {
16+ onClickExtension : async ( ) => {
17+ // https://developer.chrome.com/docs/extensions/reference/api/tabCapture#preserving-system-audio
18+ try {
19+ const currentTabID = await getCurrentTabId ( ) ;
20+ const newTab = await chrome . windows . create ( {
21+ url : "/scripts/_test.html" ,
22+ type : "popup" ,
23+ width : 800 ,
24+ height : 600 ,
25+ } ) ;
26+
27+ const streamId = await chrome . tabCapture . getMediaStreamId ( {
28+ consumerTabId : newTab . id ,
29+ targetTabId : currentTabID ,
30+ } ) ;
31+
32+ alert ( streamId ) ;
33+
34+ runScriptInTab ( {
35+ func : ( streamId ) => {
36+ window . setStreamId ?. ( streamId ) ;
37+ } ,
38+ args : [ streamId ] ,
39+ tabId : newTab . id ,
40+ } ) ;
41+ } catch ( e ) {
42+ console . error ( e ) ;
43+ }
44+ } ,
45+
46+ onClick_ : async ( ) => {
1547 //https://www.youtube.com/watch?v=uk96O7N1Yo0
48+ // https://www.skilldrick.co.uk/fft/
49+ // https://stackoverflow.com/a/61301293/23648002
50+ // https://www.renderforest.com/music-visualisations
51+
1652 javascript: ( function ( ) {
53+ var ctx ;
54+ var width = 1000 ;
55+ var fftHeight = 250 ;
56+ var height = fftHeight + 20 ;
57+ var fftSize = 2048 ; // number of samples used to generate each FFT
58+ var frequencyBins = fftSize / 2 ; // number of frequency bins in FFT
59+ var video ;
60+
61+ function requestPIPCanvas ( canvas ) {
62+ const stream = canvas . captureStream ( ) ;
63+ if ( ! video ) {
64+ video = document . createElement ( "video" ) ;
65+ video . autoplay = true ;
66+ video . style . display = "none" ;
67+ }
68+ video . srcObject = stream ;
69+ document . body . appendChild ( video ) ;
70+ setTimeout ( ( ) => {
71+ video . requestPictureInPicture ?. ( ) ;
72+ } , 500 ) ;
73+ }
74+
1775 function draggable ( ele ) {
1876 // Variables to store the position of the canvas
1977 var offsetX , offsetY ;
@@ -27,7 +85,7 @@ export default {
2785 } ) ;
2886
2987 // Function to handle mouse move event
30- ele . addEventListener ( "mousemove" , function ( event ) {
88+ document . addEventListener ( "mousemove" , function ( event ) {
3189 if ( ! isDragging ) return ;
3290 var x = event . clientX - offsetX ;
3391 var y = event . clientY - offsetY ;
@@ -36,7 +94,7 @@ export default {
3694 } ) ;
3795
3896 // Function to handle mouse up event
39- ele . addEventListener ( "mouseup" , function ( ) {
97+ document . addEventListener ( "mouseup" , function ( ) {
4098 isDragging = false ;
4199 } ) ;
42100 }
@@ -47,32 +105,172 @@ export default {
47105 ) ;
48106 }
49107
108+ function applyLog ( fftArray ) { }
109+
110+ function smoothFFT ( fftArray , smoothingFactor = 0.8 ) {
111+ let smoothedFFT = [ ] ;
112+ smoothedFFT [ 0 ] = fftArray [ 0 ] ;
113+ for ( let i = 1 ; i < fftArray . length ; i ++ ) {
114+ smoothedFFT [ i ] =
115+ fftArray [ i ] * smoothingFactor +
116+ smoothedFFT [ i - 1 ] * ( 1 - smoothingFactor ) ;
117+ }
118+ return smoothedFFT ;
119+ }
120+
121+ function highlightBass (
122+ fftArray ,
123+ samplingRate = 44100 ,
124+ bassRange = [ 20 , 200 ]
125+ ) {
126+ const fftSize = fftArray . length ;
127+ const threshold = 0.5 ; // Adjust threshold value as needed (0 for hard removal)
128+
129+ for ( let i = 0 ; i < fftSize ; i ++ ) {
130+ const freq = ( i * samplingRate ) / fftSize ;
131+ if ( freq < bassRange [ 0 ] || freq > bassRange [ 1 ] ) {
132+ fftArray [ i ] *= threshold ; // Apply threshold instead of hard removal
133+ }
134+ }
135+
136+ return fftArray ;
137+ }
138+
139+ function logScale ( fftArray , minDecibels = - 60 , maxDecibels = 0 ) {
140+ let minAmplitude = Math . pow ( 10 , minDecibels / 10 ) ;
141+ let maxAmplitude = Math . pow ( 10 , maxDecibels / 10 ) ;
142+
143+ const scale = ( val ) => {
144+ const scaledValue =
145+ 10 * Math . log10 ( Math . max ( val , minAmplitude ) ) -
146+ 10 * Math . log10 ( minAmplitude ) ;
147+ return Math . min ( scaledValue , maxDecibels ) ; // Cap the output at maxDecibels
148+ } ;
149+
150+ return fftArray . map ( ( val ) => scale ( val ) ) ;
151+ }
152+
153+ function drawLinearFFT ( dataArray , canvasCtx ) {
154+ canvasCtx . clearRect ( 0 , 0 , width , height ) ;
155+ canvasCtx . beginPath ( ) ;
156+
157+ var sliceLength = width / frequencyBins ;
158+
159+ for ( var i = 0 ; i < frequencyBins ; i ++ ) {
160+ var x = i * sliceLength ;
161+ var y = fftHeight - ( dataArray [ i ] * fftHeight ) / 256 ;
162+ canvasCtx . lineTo ( x , y ) ;
163+ }
164+
165+ canvasCtx . stroke ( ) ;
166+ }
167+
168+ function drawLogarithmicFFT ( dataArray , canvasCtx ) {
169+ canvasCtx . clearRect ( 0 , 0 , width , height ) ;
170+ canvasCtx . beginPath ( ) ;
171+
172+ var scale = Math . log ( frequencyBins - 1 ) / width ;
173+ var binWidthFreq = ctx . sampleRate / ( frequencyBins * 2 ) ;
174+ var firstBinWidthPixels = Math . log ( 2 ) / scale ;
175+
176+ for ( var i = 1 ; i < frequencyBins ; i ++ ) {
177+ var x = Math . log ( i ) / scale ;
178+ var y = fftHeight - ( dataArray [ i ] * fftHeight ) / 256 ;
179+ canvasCtx . lineTo ( x , y ) ;
180+ }
181+
182+ canvasCtx . stroke ( ) ;
183+ }
184+
185+ function drawLinearScale ( canvasCtx ) {
186+ canvasCtx . save ( ) ;
187+ canvasCtx . fillStyle = "black" ;
188+
189+ for ( var x = 0 ; x < width ; x += 100 ) {
190+ canvasCtx . beginPath ( ) ;
191+ canvasCtx . moveTo ( x , fftHeight ) ;
192+ canvasCtx . lineTo ( x , fftHeight + 4 ) ;
193+ canvasCtx . stroke ( ) ;
194+ canvasCtx . fillText (
195+ Math . floor ( ( ( ctx . sampleRate / 2 ) * x ) / width ) ,
196+ x ,
197+ height
198+ ) ;
199+ }
200+
201+ canvasCtx . restore ( ) ;
202+ }
203+
204+ function drawLogarithmicScale ( canvasCtx ) {
205+ canvasCtx . save ( ) ;
206+ canvasCtx . fillStyle = "black" ;
207+
208+ var scale = Math . log ( frequencyBins - 1 ) / width ;
209+ var binWidthInHz = ctx . sampleRate / ( frequencyBins * 2 ) ;
210+ var firstBinWidthInPx = Math . log ( 2 ) / scale ;
211+
212+ for (
213+ var x = 0 , freq = binWidthInHz ;
214+ x < width ;
215+ x += firstBinWidthInPx , freq *= 2
216+ ) {
217+ canvasCtx . beginPath ( ) ;
218+ canvasCtx . moveTo ( x , fftHeight ) ;
219+ canvasCtx . lineTo ( x , fftHeight + 4 ) ;
220+ canvasCtx . stroke ( ) ;
221+ canvasCtx . fillText ( Math . floor ( freq ) , Math . floor ( x ) , height ) ;
222+ }
223+
224+ canvasCtx . restore ( ) ;
225+ }
226+
50227 function createAudioContext ( ) {
51228 const audioContext = new ( window . AudioContext ||
52229 window . webkitAudioContext ) ( ) ;
230+ ctx = audioContext ;
53231 const analyser = audioContext . createAnalyser ( ) ;
54- analyser . fftSize = 2048 ;
232+ analyser . fftSize = fftSize ;
55233 const bufferLength = analyser . frequencyBinCount ;
56234 const dataArray = new Uint8Array ( bufferLength ) ;
57235
58236 const canvas = document . createElement ( "canvas" ) ;
237+ canvas . width = width ;
238+ canvas . height = height ;
59239 canvas . style . cssText =
60- "position: fixed; top: 0; left: 0; width: 600px; height: 400px; z-index: 2147483647;" ;
240+ "position: fixed; top: 0; left: 0; z-index: 2147483647; background: #333a ;" ;
61241 document . body . appendChild ( canvas ) ;
62- const ctx = canvas . getContext ( "2d" ) ;
242+ const canvasCtx = canvas . getContext ( "2d" ) ;
63243 draggable ( canvas ) ;
64244
245+ canvas . onclick = function ( ) {
246+ requestPIPCanvas ( canvas ) ;
247+ } ;
248+
65249 function draw ( ) {
66250 analyser . getByteFrequencyData ( dataArray ) ;
67- ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
68- const barWidth = ~ ~ ( bufferLength / canvas . width ) ;
69- for ( let x = 0 ; x < canvas . width ; x ++ ) {
70- let i = x * barWidth ;
71- let item = dataArray [ i ] ;
72- const barHeight = map ( item , 0 , 255 , 0 , canvas . height ) ;
73- ctx . fillStyle = `rgba(255, 255, 255, ${ map ( item , 0 , 255 , 0 , 1 ) } )` ;
74- ctx . fillRect ( x , canvas . height - barHeight , 1 , barHeight ) ;
75- }
251+
252+ canvasCtx . strokeStyle = "rgba(255, 255, 255, 0.9)" ;
253+ drawLogarithmicFFT ( dataArray , canvasCtx ) ;
254+
255+ // canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
256+ // const barWidth = ~~(bufferLength / canvas.width);
257+
258+ // const arr = highlightBass(dataArray, audioContext.sampleRate);
259+ // canvasCtx.beginPath();
260+ // canvasCtx.strokeStyle = "rgba(255, 255, 255, 0.9)";
261+
262+ // for (let x = 0; x < canvas.width; x++) {
263+ // let i = x * barWidth;
264+ // let item = arr[i];
265+ // const barHeight = map(item, 0, 255, 0, canvas.height);
266+
267+ // // line
268+ // canvasCtx.lineTo(x, canvas.height - barHeight);
269+
270+ // // canvasCtx.fillStyle = `rgba(255, 255, 255, ${map(item, 0, 255, 0, 1)})`;
271+ // // canvasCtx.fillRect(x, canvas.height - barHeight, 1, barHeight);
272+ // }
273+ // canvasCtx.stroke();
76274 requestAnimationFrame ( draw ) ;
77275 }
78276
@@ -103,19 +301,19 @@ export default {
103301 } ) ;
104302
105303 // Keep checking for new videos on the page
106- setInterval ( ( ) => {
107- const newVideos = document . querySelectorAll ( "video" ) ;
108- newVideos . forEach ( ( videoElement ) => {
109- const exists = contexts . some (
110- ( context ) => context . videoElement === videoElement
111- ) ;
112- if ( ! exists ) {
113- const { handleVideoAudio, canvas } = createAudioContext ( ) ;
114- handleVideoAudio ( videoElement ) ;
115- contexts . push ( { canvas, videoElement } ) ;
116- }
117- } ) ;
118- } , 2000 ) ;
304+ // setInterval(() => {
305+ // const newVideos = document.querySelectorAll("video");
306+ // newVideos.forEach((videoElement) => {
307+ // const exists = contexts.some(
308+ // (context) => context.videoElement === videoElement
309+ // );
310+ // if (!exists) {
311+ // const { handleVideoAudio, canvas } = createAudioContext();
312+ // handleVideoAudio(videoElement);
313+ // contexts.push({ canvas, videoElement });
314+ // }
315+ // });
316+ // }, 2000);
119317 }
120318
121319 startAudioAnalysis ( ) ;
0 commit comments