Skip to content

Commit fc5583b

Browse files
committed
add audio visualizer to the demo page [ci skip]
1 parent 2553724 commit fc5583b

File tree

1 file changed

+107
-29
lines changed

1 file changed

+107
-29
lines changed

demo/index.html

Lines changed: 107 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
.error-message { color: #a94442; border: none; box-shadow: none }
2323
.CodeMirror { font-family: 'Courier', monospace; border: solid 1px #ddd; height: 800px }
2424
#app { margin-top: 15px }
25+
#canvas { background: #2c3e50; width: 100%; height: 160px }
2526
</style>
2627
</head>
2728
<body>
@@ -34,42 +35,50 @@ <h1>web-audio-engine :: demo</h1>
3435
</div>
3536
<div id="app" class="form-horizontal">
3637
<div class="form-group">
37-
<label class="col-sm-1 control-label"></label>
38-
<div class="col-sm-4">
39-
<button class="btn" v-bind:class="isPlaying ? 'btn-success' : 'btn-default'" v-on:click="run">Run</button>
40-
<button class="btn btn-default" v-on:click="stop">Stop</button>
41-
</div>
42-
<div class="col-sm-6"><div class="form-control error-message">{{ error }}</div></div>
43-
</div>
38+
<div class="col-sm-7" class="form-group">
39+
<div class="form-group">
40+
<label class="col-sm-2 control-label"></label>
41+
<div class="col-sm-10">
42+
<button class="btn" v-bind:class="isPlaying ? 'btn-success' : 'btn-default'" v-on:click="run">Run</button>
43+
<button class="btn btn-default" v-on:click="stop">Stop</button>
44+
</div>
45+
</div>
4446

45-
<div class="form-group">
46-
<label class="col-sm-1 control-label">api</label>
47-
<div class="col-sm-11">
48-
<div class="radio-inline">
49-
<input type="radio" id="engine" value="web-audio-engine" v-model="engine">
50-
<label for="engine">web-audio-engine</label>
47+
<div class="form-group">
48+
<label class="col-sm-2 control-label">api</label>
49+
<div class="col-sm-10">
50+
<div class="radio">
51+
<label for="engine">
52+
<input type="radio" id="engine" value="web-audio-engine" v-model="engine">
53+
web-audio-engine
54+
</label>
55+
</div>
56+
<div class="radio">
57+
<label for="native">
58+
<input type="radio" id="native" value="native" v-model="engine">
59+
native Web Audio API
60+
</label>
61+
</div>
62+
</div>
5163
</div>
52-
<div class="radio-inline">
53-
<input type="radio" id="native" value="native" v-model="engine">
54-
<label for="native">native Web Audio API</label>
64+
65+
<div class="form-group">
66+
<label class="col-sm-2 control-label">demo</label>
67+
<div class="col-sm-10">
68+
<select class="form-control" v-model="selected" v-on:change="loadScript">
69+
<option v-for="name in list" v-bind:value="name">{{ name }}</option>
70+
</select>
71+
</div>
5572
</div>
56-
</div>
57-
</div>
5873

59-
<div class="form-group">
60-
<label class="col-sm-1 control-label">demo</label>
61-
<div class="col-sm-11">
62-
<select class="form-control" v-model="selected" v-on:change="loadScript">
63-
<option v-for="name in list" v-bind:value="name">{{ name }}</option>
64-
</select>
74+
</div>
75+
<div class="col-sm-5">
76+
<canvas id="canvas"></canvas>
6577
</div>
6678
</div>
6779

6880
<div class="form-group">
69-
<label class="col-sm-1 control-label">code</label>
70-
<div class="col-sm-11">
71-
<textarea id="code"></textarea>
72-
</div>
81+
<textarea id="code"></textarea>
7382
</div>
7483
</div>
7584
</div>
@@ -95,6 +104,13 @@ <h1>web-audio-engine :: demo</h1>
95104
];
96105
var audioContext = new AudioContext();
97106
var destination = audioContext.destination;
107+
var timerId = 0;
108+
var canvas = document.getElementById("canvas");
109+
110+
canvas.width = 320;
111+
canvas.height = 160;
112+
113+
canvas.context = canvas.getContext("2d");
98114

99115
Object.defineProperty(audioContext, "destination", {
100116
value: null, enumerate: false, writable: true, configurable: true
@@ -149,8 +165,11 @@ <h1>web-audio-engine :: demo</h1>
149165
return;
150166
}
151167

152-
audioContext.destination = audioContext.createGain();
168+
var audioAnalyser = audioContext.createAnalyser();
169+
170+
audioContext.destination = audioAnalyser;
153171
audioContext.destination.connect(destination);
172+
canvas.audioAnalyser = audioAnalyser;
154173

155174
var context = null;
156175

@@ -173,18 +192,77 @@ <h1>web-audio-engine :: demo</h1>
173192
}
174193

175194
promise.then(function() {
195+
if (timerId === 0) {
196+
timerId = timerAPI.setInterval.call(window, capture, 100);
197+
}
176198
context.resume();
177199
});
178200
}
179201

180202
function stop() {
203+
if (timerId !== 0) {
204+
clearInterval(timerId);
205+
timerId = 0;
206+
}
181207
if (audioContext.destination) {
182208
audioContext.destination.disconnect();
183209
audioContext.destination = null;
184210
}
185211
timerAPI.reset();
186212
}
187213

214+
function capture() {
215+
var analyser = canvas.audioAnalyser;
216+
var context = canvas.context;
217+
var fft, sig;
218+
var width = canvas.width;
219+
var height = canvas.height;
220+
var i, imax;
221+
222+
// fft
223+
analyser.fftSize = 64;
224+
fft = new Uint8Array(analyser.frequencyBinCount);
225+
analyser.getByteFrequencyData(fft);
226+
227+
context.fillStyle = "#2c3e50";
228+
context.fillRect(0, 0, width, height);
229+
230+
var w = width / fft.length;
231+
232+
for (i = 0, imax = fft.length; i < imax; i++) {
233+
var x = w * i;
234+
var y = linlin(fft[i], 0, 255, height, 0);
235+
var r = linlin(fft[i], 0, 255, 100, 255)|0;
236+
237+
context.fillStyle = "rgb(" + r + ", 76, 60)";
238+
context.fillRect(x, y, w - 1, height - y);
239+
}
240+
241+
// signal
242+
analyser.fftSize = 2048;
243+
sig = new Uint8Array(analyser.fftSize);
244+
analyser.getByteTimeDomainData(sig);
245+
246+
context.strokeStyle = "#2ecc71";
247+
context.beginPath();
248+
249+
for (i = 0, imax = sig.length; i < imax; i++) {
250+
var x = linlin(i, 0, imax, 0, width);
251+
var y = linlin(sig[i], 0, 255, height, 0);
252+
253+
if (i === 0) {
254+
context.moveTo(x, y);
255+
} else {
256+
context.lineTo(x, y);
257+
}
258+
}
259+
context.stroke();
260+
}
261+
262+
function linlin(value, inMin, inMax, outMin, outMax) {
263+
return (value - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
264+
}
265+
188266
var vue = new Vue({
189267
el: "#app",
190268
data: {

0 commit comments

Comments
 (0)