-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
124 lines (104 loc) · 5.46 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<!DOCTYPE html>
<html>
<head>
<title>Audio Visualizer with Three.js</title>
<style>
body { margin: 0; }
canvas { display: block; }
#startButton { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
#frequencySlider, #volumeSlider, #heartRateSlider { position: absolute; width: 30px; height: 80%; writing-mode: bt-lr; -webkit-appearance: slider-vertical; }
#frequencySlider { top: 10%; right: 10%; }
#volumeSlider { top: 10%; right: 5%; }
#heartRateSlider { top: 10%; right: 15%; }
#oscillatorTypeContainer { position: absolute; top: 90%; left: 10%; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<button id="startButton">Start</button>
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="0.2" orient="vertical">
<input type="range" id="frequencySlider" min="1" max="440" step="1" value="220" orient="vertical">
<input type="range" id="heartRateSlider" min="0" max="1" step="0.01" value="0.5" orient="vertical">
<div id="oscillatorTypeContainer">
<input type="radio" id="sine" name="oscillatorType" value="sine" checked>
<label for="sine">Sine</label>
<input type="radio" id="square" name="oscillatorType" value="square">
<label for="square">Square</label>
<input type="radio" id="sawtooth" name="oscillatorType" value="sawtooth">
<label for="sawtooth">Sawtooth</label>
<input type="radio" id="triangle" name="oscillatorType" value="triangle">
<label for="triangle">Triangle</label>
</div>
<script>
let scene, camera, renderer;
let geometry, material, mesh;
let targetX = 0, direction = 0.1;
let heartFrequency = 1;
let frequencySlider, volumeSlider, heartRateSlider;
let oscillator, gainNode, audioContext, panner;
let oscillatorTypes = ['sine', 'square', 'sawtooth', 'triangle'];
let currentOscillatorType = 0;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
geometry = new THREE.SphereGeometry( 0.5, 32, 32 );
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
camera.position.z = 5;
volumeSlider = document.querySelector("#volumeSlider");
frequencySlider = document.querySelector("#frequencySlider");
heartRateSlider = document.querySelector("#heartRateSlider");
volumeSlider.addEventListener("input", function() {
gainNode.gain.value = this.value;
}, false);
frequencySlider.addEventListener("input", function() {
oscillator.frequency.value = this.value;
}, false);
heartRateSlider.addEventListener("input", function() {
heartFrequency = this.value * 10;
}, false);
document.querySelector("#startButton").addEventListener("click", function() {
this.style.display = "none";
audioContext = new (window.AudioContext || window.webkitAudioContext)();
oscillator = audioContext.createOscillator();
gainNode = audioContext.createGain();
panner = audioContext.createStereoPanner();
oscillator.connect(gainNode);
gainNode.connect(panner);
panner.connect(audioContext.destination);
oscillator.type = "sine";
oscillator.frequency.value = 220;
gainNode.gain.value = 0.2;
oscillator.start();
let oscillatorTypeInputs = document.querySelectorAll('input[name="oscillatorType"]');
oscillatorTypeInputs.forEach((input) => {
input.addEventListener('change', () => {
oscillator.type = input.value;
});
});
});
}
function animate() {
requestAnimationFrame( animate );
targetX += direction * heartFrequency;
if(targetX > 4) {
direction = -0.1;
} else if(targetX < -4) {
direction = 0.1;
}
mesh.position.x = targetX;
panner.pan.value = Math.max(-1, Math.min(1, 2 * (targetX / 4)));
gainNode.gain.value = volumeSlider.value * (0.2 + 0.8 * Math.abs(targetX / 4));
renderer.render( scene, camera );
}
init();
animate();
</script>
</body>
</html>