136 lines
3.6 KiB
JavaScript
136 lines
3.6 KiB
JavaScript
import $ from "jquery";
|
|
import * as three from "three";
|
|
|
|
import Background from "../background";
|
|
|
|
class Spectrum extends Background {
|
|
constructor(display, audioManager) {
|
|
super(audioManager, display);
|
|
|
|
this._audioManager = audioManager;
|
|
this._display = display;
|
|
|
|
this._init_analyser();
|
|
this._init_scene();
|
|
this._init_objects();
|
|
this._resize();
|
|
}
|
|
|
|
_get_canvas_height() {
|
|
return (
|
|
this._display.parent().height() -
|
|
this._display
|
|
.siblings()
|
|
.toArray()
|
|
.reduce((a, b) => {
|
|
return a + b.clientHeight;
|
|
}, 0)
|
|
);
|
|
}
|
|
|
|
_resize() {
|
|
this._camera.aspect = this._display.width() / this._get_canvas_height();
|
|
this._camera.updateProjectionMatrix();
|
|
this._renderer.setSize(
|
|
this._display.width(),
|
|
this._get_canvas_height()
|
|
);
|
|
}
|
|
|
|
_init_analyser() {
|
|
let audioManager = this._audioManager;
|
|
|
|
let analyser = audioManager.context.createAnalyser();
|
|
analyser.fftSize = 2048;
|
|
analyser.smoothingTimeConstant = 0.8;
|
|
|
|
let analyser_data = new Float32Array(analyser.frequencyBinCount);
|
|
|
|
audioManager.source.connect(analyser);
|
|
analyser.getFloatFrequencyData(analyser_data);
|
|
|
|
this._analyser = analyser;
|
|
this._analyser_data = analyser_data;
|
|
}
|
|
|
|
_init_scene() {
|
|
let scene = new three.Scene();
|
|
|
|
let camera = new three.PerspectiveCamera(
|
|
70,
|
|
this._display.width() / this._get_canvas_height(),
|
|
0.01,
|
|
10
|
|
);
|
|
camera.position.z = 1;
|
|
scene.add(camera);
|
|
|
|
let renderer = new three.WebGLRenderer({
|
|
antialias: true,
|
|
powerPreference: "low-power"
|
|
});
|
|
|
|
renderer.setSize(this._display.width(), this._display.height());
|
|
|
|
this._display.append(renderer.domElement);
|
|
|
|
this._scene = scene;
|
|
this._camera = camera;
|
|
this._renderer = renderer;
|
|
|
|
// Set the resize handler
|
|
$(window).resize(() => this._resize());
|
|
}
|
|
|
|
_init_objects() {
|
|
let analyser = this._analyser;
|
|
let scene = this._scene;
|
|
|
|
let boxes = Array(analyser.frequencyBinCount);
|
|
let width = 2 / analyser.frequencyBinCount;
|
|
|
|
for (let freq = 0; freq < analyser.frequencyBinCount; freq++) {
|
|
let geometry = new three.BoxGeometry(1, 1, 1);
|
|
let material = new three.MeshBasicMaterial({ color: 0x99d1ce });
|
|
let cube = new three.Mesh(geometry, material);
|
|
|
|
cube.scale.set(width, 1e-6, width);
|
|
cube.position.set(-1 + freq * width, 0, 0);
|
|
|
|
scene.add(cube);
|
|
boxes[freq] = cube;
|
|
}
|
|
|
|
this._boxes = boxes;
|
|
}
|
|
|
|
start() {
|
|
requestAnimationFrame(this._render.bind(this));
|
|
}
|
|
|
|
_render() {
|
|
let analyser = this._analyser;
|
|
let camera = this._camera;
|
|
let renderer = this._renderer;
|
|
let scene = this._scene;
|
|
|
|
for (let freq = 0; freq < analyser.frequencyBinCount; freq++) {
|
|
let height = analyser.maxDecibels / this._analyser_data[freq];
|
|
|
|
if (height > 0.3) {
|
|
height -= 0.3;
|
|
} else {
|
|
height = 1e-6;
|
|
}
|
|
|
|
this._boxes[freq].scale.y = height;
|
|
}
|
|
|
|
renderer.render(scene, camera);
|
|
analyser.getFloatFrequencyData(this._analyser_data);
|
|
requestAnimationFrame(this._render.bind(this));
|
|
}
|
|
}
|
|
|
|
export default Spectrum;
|