24
1
2
<html>
3
<head>
4
<meta charset="utf-8">
5
<meta name="viewport" content="width=device-width">
6
<title>Sine wave</title>
7
</head>
8
<body>
9
10
<div class="flex">
11
<span id="range-value"></span>
12
<input type="range" id="freq" min=440 max=12000 value=440>
13
</div>
14
15
<div class="flex">
16
<span id="volume-value"></span>
17
<input type="range" id="volume" min=0 max=100 value=0>
18
</div>
19
20
<button>Toggle sound</button>
21
22
<main><canvas></canvas></main>
23
</body>
24
</html>
55
1
* {
2
box-sizing: border-box;
3
background: white;
4
font-family: sans-serif;
5
font-size: 14px;
6
}
7
8
input[type=range] {
9
width: 100%;
10
}
11
12
.flex {
13
display: flex;
14
}
15
16
div {
17
position: relative;
18
}
19
20
#range-value,
21
#volume-value {
22
width: 80px;
23
text-align: right;
24
}
25
26
#range-value:after {
27
content: 'hz'
28
}
29
30
#volume-value:after {
31
content: '%'
32
}
33
34
#volume-value:before {
35
content: 'vol '
36
}
37
38
39
button {
40
margin: 10px 0;
41
cursor: pointer;
42
border: 0;
43
background: rgb(3, 169, 244);
44
color: white;
45
padding: 10px 20px;
46
border-radius: 5px;
47
}
48
49
button:hover {
50
background: #1976d2;
51
}
52
53
canvas {
54
border: 1px solid rgb(3, 169, 244);
55
}
121
1
//noprotect
2
3
// apologies for the horrible code, I was being lazy
4
5
// globalsFTW ¯\_(ツ)_/¯
6
let gainNode;
7
let context;
8
let audio;
9
let analyser;
10
let bufferLength;
11
let dataArray;
12
13
const updatePosition = (input, output) => () => {
14
output.innerHTML = input.value;
15
output.style.left = `calc(${(input.value - input.min) / (input.max - input.min) * 95}%)`;
16
}
17
18
function getAudio() {
19
// create web audio api context
20
context = new (window.AudioContext || window.webkitAudioContext)();
21
22
// create Oscillator node
23
const oscillator = context.createOscillator();
24
25
oscillator.type = 'sine';
26
oscillator.frequency.value = range.value; // value in hertz
27
// oscillator.connect(audioCtx.destination);
28
29
gainNode = context.createGain();
30
// Connect the source to the gain node.
31
oscillator.connect(gainNode);
32
// Connect the gain node to the destination.
33
gainNode.connect(context.destination);
34
35
const fraction = parseInt(volume.value) / parseInt(volume.max);
36
gainNode.gain.value = fraction * fraction;
37
38
analyser = context.createAnalyser();
39
gainNode.connect(analyser);
40
41
bufferLength = analyser.frequencyBinCount;
42
dataArray = new Uint8Array(bufferLength);
43
44
analyser.fftSize = 1024;
45
46
oscillator.start();
47
48
return oscillator;
49
}
50
51
function draw() {
52
requestAnimationFrame(draw);
53
54
if (!analyser) {
55
return;
56
}
57
58
ctx.clearRect(0, 0, WIDTH, HEIGHT);
59
// analyser.getByteTimeDomainData(dataArray);
60
analyser.getByteFrequencyData(dataArray);
61
62
var barWidth = ((WIDTH) / bufferLength) * 1.5;
63
var barHeight;
64
var x = 0;
65
66
for (var i = 0; i < bufferLength; i++) {
67
barHeight = dataArray[i];
68
69
ctx.fillStyle = 'rgb(3,169,244)';
70
ctx.fillRect(x+.5,HEIGHT-barHeight/2+.5,barWidth,barHeight);
71
72
x += barWidth + 1;
73
}
74
75
}
76
77
78
const $$ = q => Array.from(document.querySelectorAll(q));
79
const $ = document.querySelector.bind(document);
80
81
//-----
82
83
const position = $('#range-value');
84
const range = $('#freq');
85
const updateFreq = updatePosition(freq, position);
86
range.oninput = () => {
87
updateFreq();
88
if (audio) audio.frequency.value = range.value; // value in hertz
89
}
90
updateFreq();
91
92
const vposition = $('#volume-value');
93
const volume = $('#volume');
94
const updateVolume = updatePosition(volume, vposition);
95
volume.oninput = () => {
96
updateVolume();
97
const fraction = parseInt(volume.value) / parseInt(volume.max);
98
99
gainNode.gain.value = fraction * fraction;
100
}
101
updateVolume();
102
103
// button
104
const button = $('button');
105
let running = false;
106
button.onclick = function () {
107
if (running) {
108
audio.stop();
109
} else {
110
audio = getAudio();
111
}
112
running = !running;
113
}
114
115
// canvas
116
const canvas = $('canvas');
117
const ctx = canvas.getContext('2d');
118
const WIDTH = canvas.width = canvas.parentNode.offsetWidth;
119
const HEIGHT = canvas.height = canvas.parentNode.offsetHeight;
120
121
draw();
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |