Skip to content

Commit c827c21

Browse files
author
hoang.tran12
committed
music visualizer
1 parent ae5a687 commit c827c21

File tree

9 files changed

+1373
-92
lines changed

9 files changed

+1373
-92
lines changed

empty_script.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@ export default {
1111
},
1212
infoLink: "",
1313

14-
changeLogs: [
15-
{
16-
version: "",
17-
date: "",
18-
description: {
19-
en: "",
20-
vi: "",
21-
},
14+
changeLogs: {
15+
["version"]: {
16+
["date"]: "description",
2217
},
23-
],
18+
},
19+
2420
blackList: [],
2521
whiteList: [],
2622

public/README.md

Whitespace-only changes.

public/music-visualizer/index.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
77
<title>Document</title>
8-
<!-- <script src="https://cdn.jsdelivr.net/npm/p5@1.9.3/lib/p5.js"></script> -->
8+
9+
<link rel="stylesheet" href="style.css">
10+
11+
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.3/p5.min.js"></script>
12+
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.3/addons/p5.sound.min.js"></script> -->
913
<script src="./main.js"></script>
1014
</head>
1115

public/music-visualizer/main.js

Lines changed: 104 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,102 @@
1-
window.onload = () => {
2-
checkHref(location.href);
3-
};
1+
// https://editor.p5js.org/jonfroehlich/sketches/d2euV09i
2+
3+
let stream,
4+
canvas,
5+
fps,
6+
analyser,
7+
fftTemp = [],
8+
fft = [],
9+
barWidth = 10;
10+
11+
function setup() {
12+
canvas = createCanvas(windowWidth, windowHeight);
13+
14+
colorMode(HSB, 255);
15+
textAlign(CENTER, CENTER);
16+
frameRate(60);
17+
setInterval(() => {
18+
fps = frameRate().toFixed(0);
19+
}, 1000);
20+
}
21+
22+
function draw() {
23+
if (analyser) {
24+
analyser.getByteFrequencyData(fftTemp);
25+
fft = smoothFFT(fftTemp);
26+
}
27+
28+
background(30);
429

5-
function checkHref(href) {
6-
const streamId = new URL(href).searchParams.get("streamId");
7-
if (streamId) {
8-
start(streamId);
30+
// beginShape();
31+
for (let i = 0; i < width; i += barWidth) {
32+
let index = floor(map(i, 0, width, 0, fft.length));
33+
const barHeight = map(fft[index], 0, 255, 0, height);
34+
fill(fft[index], 255, 255);
35+
rect(i, height - barHeight, barWidth, barHeight);
36+
// vertex(i, height - barHeight);
37+
}
38+
// stroke(255);
39+
// noFill();
40+
// endShape();
41+
42+
let amp = getAmplitute(fftTemp);
43+
let size = map(amp, 0, 255, 0, 400);
44+
noStroke();
45+
fill(255, 200);
46+
circle(width / 2, height / 2, size);
47+
48+
if (!stream) {
49+
fill(255);
50+
text("Click to listen other tab", width / 2, height / 2);
951
}
52+
53+
text(fps, 30, 20);
1054
}
1155

12-
function start(streamId) {
13-
navigator.webkitGetUserMedia(
14-
{
15-
audio: {
16-
mandatory: {
17-
chromeMediaSource: "tab", // The media source must be 'tab' here.
18-
chromeMediaSourceId: streamId,
19-
},
20-
},
21-
video: false,
22-
},
23-
function (stream) {
24-
drawVisualizer(stream);
25-
},
26-
function (error) {
27-
console.error(error);
28-
}
29-
);
56+
function mousePressed() {
57+
if (!stream) {
58+
getStreamFromOtherTab()
59+
.then((_) => {
60+
stream = _;
61+
console.log("stream: ", stream);
62+
connectStreamToP5(stream);
63+
})
64+
.catch((e) => {
65+
console.log("ERROR: ", e);
66+
});
67+
}
3068
}
3169

32-
function drawVisualizer(stream) {
33-
// at this point the sound of the tab becomes muted with no way to unmute it
34-
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
35-
const source = audioCtx.createMediaStreamSource(stream);
36-
const analyser = audioCtx.createAnalyser();
37-
analyser.fftSize = 2048;
38-
source.connect(analyser);
39-
// analyser.connect(audioCtx.destination); // play stream to speaker - we dont need it, original tab already play it
40-
41-
const bufferLength = analyser.frequencyBinCount;
42-
const dataArray = new Uint8Array(bufferLength);
43-
44-
const canvas = document.createElement("canvas");
45-
canvas.width = window.innerWidth;
46-
canvas.height = window.innerHeight;
47-
window.onresize = () => {
48-
canvas.width = window.innerWidth;
49-
canvas.height = window.innerHeight;
50-
};
70+
function windowResized() {
71+
resizeCanvas(windowWidth, windowHeight);
72+
}
5173

52-
canvas.style.cssText =
53-
"position: fixed; top: 0; left: 0; z-index: 2147483647; background: #333a;";
54-
document.body.appendChild(canvas);
55-
const canvasCtx = canvas.getContext("2d");
56-
57-
function draw() {
58-
analyser.getByteFrequencyData(dataArray);
59-
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
60-
canvasCtx.beginPath();
61-
62-
const data = smoothFFT(dataArray);
63-
const barWidth = bufferLength / canvas.width;
64-
for (let x = 0; x < canvas.width; x++) {
65-
let i = ~~(x * barWidth);
66-
let item = data[i];
67-
const barHeight = map(item, 0, 255, 0, canvas.height / 2);
68-
canvasCtx.lineTo(x, canvas.height / 2 - barHeight);
69-
}
70-
canvasCtx.strokeStyle = "rgba(255, 255, 255, 0.9)";
71-
canvasCtx.stroke();
72-
requestAnimationFrame(draw);
73-
}
74+
function getStreamFromOtherTab() {
75+
return navigator.mediaDevices.getDisplayMedia({
76+
video: {
77+
displaySurface: "browser",
78+
},
79+
audio: {
80+
suppressLocalAudioPlayback: false,
81+
},
82+
preferCurrentTab: false,
83+
selfBrowserSurface: "exclude",
84+
systemAudio: "include",
85+
surfaceSwitching: "include",
86+
monitorTypeSurfaces: "include",
87+
});
88+
}
7489

75-
function map(x, in_min, in_max, out_min, out_max) {
76-
return ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min;
77-
}
90+
// https://stackoverflow.com/a/68326540/23648002
91+
function connectStreamToP5(stream) {
92+
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
93+
const mediaSource = audioContext.createMediaStreamSource(stream);
94+
analyser = audioContext.createAnalyser();
95+
analyser.fftSize = 256;
96+
mediaSource.connect(analyser);
7897

79-
requestAnimationFrame(draw);
98+
fft = new Uint8Array(analyser.frequencyBinCount);
99+
fftTemp = new Uint8Array(analyser.frequencyBinCount);
80100
}
81101

82102
function smoothFFT(fftArray, smoothingFactor = 0.8) {
@@ -117,3 +137,17 @@ function logScale(fftArray, minDecibels = -60, maxDecibels = 0) {
117137

118138
return fftArray.map((val) => scale(val));
119139
}
140+
141+
const AmplituteTypes = {
142+
max: "max",
143+
avg: "avg",
144+
};
145+
function getAmplitute(fftArray, type = AmplituteTypes.avg) {
146+
switch (type) {
147+
case AmplituteTypes.avg:
148+
return fftArray.reduce((a, b) => a + b, 0) / fftArray.length;
149+
case AmplituteTypes.max:
150+
return Math.max(...fftArray);
151+
default:
152+
}
153+
}

0 commit comments

Comments
 (0)