Skip to content

Commit f58f98b

Browse files
wbambergteoli2003
andauthored
De-XHR-ify (#116)
* 2 new examples for looping and playbackrate * Rename decode-audio-data * Separate files for scripts * Use fetch() in decodeaudiodata/callback * Use fetch() in script-processor-node * Use fetch() in voice-change-o-matic * Delete unused polyfill respond.js * Apply suggestions from code review Co-authored-by: Jean-Yves Perrier <jypenator@gmail.com> * Review comments * Apply suggestions from code review Co-authored-by: Jean-Yves Perrier <jypenator@gmail.com> * Init audio context on play --------- Co-authored-by: Jean-Yves Perrier <jypenator@gmail.com>
1 parent 41775fb commit f58f98b

File tree

21 files changed

+610
-532
lines changed

21 files changed

+610
-532
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width" />
6+
7+
<title>Web Audio API examples: looping a track</title>
8+
9+
<script src="script.js" defer></script>
10+
</head>
11+
12+
<body>
13+
<h1>Web Audio API examples: looping a track</h1>
14+
15+
<button id="play">Play</button>
16+
<button id="stop" disabled>Stop</button>
17+
18+
<h2>Set loop start and loop end</h2>
19+
<input
20+
id="loopstart-control"
21+
type="range"
22+
min="0"
23+
max="20"
24+
step="1"
25+
value="0"
26+
disabled />
27+
Starts at <span id="loopstart-value">0</span> s.
28+
<br />
29+
<input
30+
id="loopend-control"
31+
type="range"
32+
min="0"
33+
max="20"
34+
step="1"
35+
value="0"
36+
disabled />
37+
Stops at <span id="loopend-value">0</span> s.
38+
<p>
39+
If the stop time is lower or equal to the start time, it'll loop over the
40+
whole track.
41+
</p>
42+
</body>
43+
</html>
2.52 MB
Binary file not shown.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
let audioCtx;
2+
let buffer;
3+
let source;
4+
5+
const play = document.getElementById("play");
6+
const stop = document.getElementById("stop");
7+
8+
const loopstartControl = document.getElementById("loopstart-control");
9+
const loopstartValue = document.getElementById("loopstart-value");
10+
11+
const loopendControl = document.getElementById("loopend-control");
12+
const loopendValue = document.getElementById("loopend-value");
13+
14+
async function loadAudio() {
15+
try {
16+
// Load an audio file
17+
const response = await fetch("rnb-lofi-melody-loop.wav");
18+
// Decode it
19+
buffer = await audioCtx.decodeAudioData(await response.arrayBuffer());
20+
const max = Math.floor(buffer.duration);
21+
loopstartControl.setAttribute("max", max);
22+
loopendControl.setAttribute("max", max);
23+
} catch (err) {
24+
console.error(`Unable to fetch the audio file. Error: ${err.message}`);
25+
}
26+
}
27+
28+
play.addEventListener("click", async () => {
29+
if (!audioCtx) {
30+
audioCtx = new AudioContext();
31+
await loadAudio();
32+
}
33+
source = audioCtx.createBufferSource();
34+
source.buffer = buffer;
35+
source.connect(audioCtx.destination);
36+
source.loop = true;
37+
source.loopStart = loopstartControl.value;
38+
source.loopEnd = loopendControl.value;
39+
source.start();
40+
play.disabled = true;
41+
stop.disabled = false;
42+
loopstartControl.disabled = false;
43+
loopendControl.disabled = false;
44+
});
45+
46+
stop.addEventListener("click", () => {
47+
source.stop();
48+
play.disabled = false;
49+
stop.disabled = true;
50+
loopstartControl.disabled = true;
51+
loopendControl.disabled = true;
52+
});
53+
54+
loopstartControl.addEventListener("input", () => {
55+
source.loopStart = loopstartControl.value;
56+
loopstartValue.textContent = loopstartControl.value;
57+
});
58+
59+
loopendControl.addEventListener("input", () => {
60+
source.loopEnd = loopendControl.value;
61+
loopendValue.textContent = loopendControl.value;
62+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width" />
6+
7+
<title>Web Audio API examples: setting playback rate</title>
8+
9+
<script src="script.js" defer></script>
10+
</head>
11+
12+
<body>
13+
<h1>Web Audio API examples: setting playback rate</h1>
14+
15+
<button id="play">Play</button>
16+
<button id="stop" disabled>Stop</button>
17+
18+
<h2>Set playback rate</h2>
19+
<input
20+
id="playback-rate-control"
21+
type="range"
22+
min="0.25"
23+
max="3"
24+
step="0.05"
25+
value="1"
26+
disabled />
27+
<span id="playback-rate-value">1.0</span> × the original rate.
28+
</body>
29+
</html>
2.52 MB
Binary file not shown.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
let audioCtx;
2+
let buffer;
3+
let source;
4+
5+
const play = document.getElementById("play");
6+
const stop = document.getElementById("stop");
7+
8+
const playbackControl = document.getElementById("playback-rate-control");
9+
const playbackValue = document.getElementById("playback-rate-value");
10+
11+
async function loadAudio() {
12+
try {
13+
// Load an audio file
14+
const response = await fetch("rnb-lofi-melody-loop.wav");
15+
// Decode it
16+
buffer = await audioCtx.decodeAudioData(await response.arrayBuffer());
17+
} catch (err) {
18+
console.error(`Unable to fetch the audio file. Error: ${err.message}`);
19+
}
20+
}
21+
22+
play.addEventListener("click", async () => {
23+
if (!audioCtx) {
24+
audioCtx = new AudioContext();
25+
await loadAudio();
26+
}
27+
source = audioCtx.createBufferSource();
28+
source.buffer = buffer;
29+
source.connect(audioCtx.destination);
30+
source.loop = true;
31+
source.playbackRate.value = playbackControl.value;
32+
source.start();
33+
play.disabled = true;
34+
stop.disabled = false;
35+
playbackControl.disabled = false;
36+
});
37+
38+
stop.addEventListener("click", () => {
39+
source.stop();
40+
play.disabled = false;
41+
stop.disabled = true;
42+
playbackControl.disabled = true;
43+
});
44+
45+
playbackControl.oninput = () => {
46+
source.playbackRate.value = playbackControl.value;
47+
playbackValue.textContent = playbackControl.value;
48+
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width" />
6+
<title>Web Audio API examples: decodeAudioData() with callback</title>
7+
<script src="script.js" defer></script>
8+
</head>
9+
10+
<body>
11+
<h1>Web Audio API examples: decodeAudioData() with callback</h1>
12+
13+
<button id="play">Play</button>
14+
<button id="stop" disabled>Stop</button>
15+
16+
<h2>Set playback rate</h2>
17+
<input
18+
id="playback-rate-control"
19+
type="range"
20+
min="0.25"
21+
max="3"
22+
step="0.05"
23+
value="1"
24+
disabled />
25+
<span id="playback-rate-value">1.0</span>
26+
27+
<h2>Set loop start and loop end</h2>
28+
<input
29+
id="loopstart-control"
30+
type="range"
31+
min="0"
32+
max="20"
33+
step="1"
34+
value="0"
35+
disabled />
36+
<span id="loopstart-value">0</span>
37+
38+
<input
39+
id="loopend-control"
40+
type="range"
41+
min="0"
42+
max="20"
43+
step="1"
44+
value="0"
45+
disabled />
46+
<span id="loopend-value">0</span>
47+
48+
<p>
49+
If the stop time is lower or equal to the start time, it'll loop over the
50+
whole track.
51+
</p>
52+
</body>
53+
</html>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
let audioCtx;
2+
let buffer;
3+
let source;
4+
5+
// Get UI elements
6+
const play = document.getElementById("play");
7+
const stop = document.getElementById("stop");
8+
9+
const playbackControl = document.getElementById("playback-rate-control");
10+
const playbackValue = document.getElementById("playback-rate-value");
11+
12+
const loopstartControl = document.getElementById("loopstart-control");
13+
const loopstartValue = document.getElementById("loopstart-value");
14+
15+
const loopendControl = document.getElementById("loopend-control");
16+
const loopendValue = document.getElementById("loopend-value");
17+
18+
function playBuffer() {
19+
source = audioCtx.createBufferSource();
20+
source.buffer = buffer;
21+
source.playbackRate.value = playbackControl.value;
22+
source.connect(audioCtx.destination);
23+
source.loop = true;
24+
source.loopStart = loopstartControl.value;
25+
source.loopEnd = loopendControl.value;
26+
source.start();
27+
play.disabled = true;
28+
stop.disabled = false;
29+
playbackControl.disabled = false;
30+
loopstartControl.disabled = false;
31+
loopendControl.disabled = false;
32+
}
33+
34+
async function loadAudio() {
35+
try {
36+
const response = await fetch("viper.mp3");
37+
audioCtx.decodeAudioData(await response.arrayBuffer(), (buf) => {
38+
// executes when buffer has been decoded
39+
buffer = buf;
40+
const max = Math.floor(buf.duration);
41+
loopstartControl.max = max;
42+
loopendControl.max = max;
43+
play.disabled = false; // buffer loaded, enable play button
44+
playBuffer();
45+
});
46+
} catch (err) {
47+
console.error(`Unable to fetch the audio file. Error: ${err.message}`);
48+
}
49+
}
50+
51+
play.addEventListener("click", async () => {
52+
if (!audioCtx) {
53+
audioCtx = new AudioContext();
54+
await loadAudio();
55+
} else {
56+
playBuffer();
57+
}
58+
});
59+
60+
stop.addEventListener("click", () => {
61+
source.stop();
62+
play.disabled = false;
63+
playbackControl.disabled = true;
64+
loopstartControl.disabled = true;
65+
loopendControl.disabled = true;
66+
});
67+
68+
playbackControl.addEventListener("input", () => {
69+
source.playbackRate.value = playbackControl.value;
70+
playbackValue.textContent = playbackControl.value;
71+
});
72+
73+
loopstartControl.addEventListener("input", () => {
74+
source.loopStart = loopstartControl.value;
75+
loopstartValue.textContent = loopstartControl.value;
76+
});
77+
78+
loopendControl.oninput = () => {
79+
source.loopEnd = loopendControl.value;
80+
loopendValue.textContent = loopendControl.value;
81+
};
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)