Skip to content

Commit

Permalink
De-XHR-ify (#116)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
wbamberg and teoli2003 authored Nov 20, 2023
1 parent 41775fb commit f58f98b
Show file tree
Hide file tree
Showing 21 changed files with 610 additions and 532 deletions.
43 changes: 43 additions & 0 deletions audio-buffer-source-node/loop/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />

<title>Web Audio API examples: looping a track</title>

<script src="script.js" defer></script>
</head>

<body>
<h1>Web Audio API examples: looping a track</h1>

<button id="play">Play</button>
<button id="stop" disabled>Stop</button>

<h2>Set loop start and loop end</h2>
<input
id="loopstart-control"
type="range"
min="0"
max="20"
step="1"
value="0"
disabled />
Starts at <span id="loopstart-value">0</span> s.
<br />
<input
id="loopend-control"
type="range"
min="0"
max="20"
step="1"
value="0"
disabled />
Stops at <span id="loopend-value">0</span> s.
<p>
If the stop time is lower or equal to the start time, it'll loop over the
whole track.
</p>
</body>
</html>
Binary file not shown.
62 changes: 62 additions & 0 deletions audio-buffer-source-node/loop/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
let audioCtx;
let buffer;
let source;

const play = document.getElementById("play");
const stop = document.getElementById("stop");

const loopstartControl = document.getElementById("loopstart-control");
const loopstartValue = document.getElementById("loopstart-value");

const loopendControl = document.getElementById("loopend-control");
const loopendValue = document.getElementById("loopend-value");

async function loadAudio() {
try {
// Load an audio file
const response = await fetch("rnb-lofi-melody-loop.wav");
// Decode it
buffer = await audioCtx.decodeAudioData(await response.arrayBuffer());
const max = Math.floor(buffer.duration);
loopstartControl.setAttribute("max", max);
loopendControl.setAttribute("max", max);
} catch (err) {
console.error(`Unable to fetch the audio file. Error: ${err.message}`);
}
}

play.addEventListener("click", async () => {
if (!audioCtx) {
audioCtx = new AudioContext();
await loadAudio();
}
source = audioCtx.createBufferSource();
source.buffer = buffer;
source.connect(audioCtx.destination);
source.loop = true;
source.loopStart = loopstartControl.value;
source.loopEnd = loopendControl.value;
source.start();
play.disabled = true;
stop.disabled = false;
loopstartControl.disabled = false;
loopendControl.disabled = false;
});

stop.addEventListener("click", () => {
source.stop();
play.disabled = false;
stop.disabled = true;
loopstartControl.disabled = true;
loopendControl.disabled = true;
});

loopstartControl.addEventListener("input", () => {
source.loopStart = loopstartControl.value;
loopstartValue.textContent = loopstartControl.value;
});

loopendControl.addEventListener("input", () => {
source.loopEnd = loopendControl.value;
loopendValue.textContent = loopendControl.value;
});
29 changes: 29 additions & 0 deletions audio-buffer-source-node/playbackrate/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />

<title>Web Audio API examples: setting playback rate</title>

<script src="script.js" defer></script>
</head>

<body>
<h1>Web Audio API examples: setting playback rate</h1>

<button id="play">Play</button>
<button id="stop" disabled>Stop</button>

<h2>Set playback rate</h2>
<input
id="playback-rate-control"
type="range"
min="0.25"
max="3"
step="0.05"
value="1"
disabled />
<span id="playback-rate-value">1.0</span> × the original rate.
</body>
</html>
Binary file not shown.
48 changes: 48 additions & 0 deletions audio-buffer-source-node/playbackrate/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
let audioCtx;
let buffer;
let source;

const play = document.getElementById("play");
const stop = document.getElementById("stop");

const playbackControl = document.getElementById("playback-rate-control");
const playbackValue = document.getElementById("playback-rate-value");

async function loadAudio() {
try {
// Load an audio file
const response = await fetch("rnb-lofi-melody-loop.wav");
// Decode it
buffer = await audioCtx.decodeAudioData(await response.arrayBuffer());
} catch (err) {
console.error(`Unable to fetch the audio file. Error: ${err.message}`);
}
}

play.addEventListener("click", async () => {
if (!audioCtx) {
audioCtx = new AudioContext();
await loadAudio();
}
source = audioCtx.createBufferSource();
source.buffer = buffer;
source.connect(audioCtx.destination);
source.loop = true;
source.playbackRate.value = playbackControl.value;
source.start();
play.disabled = true;
stop.disabled = false;
playbackControl.disabled = false;
});

stop.addEventListener("click", () => {
source.stop();
play.disabled = false;
stop.disabled = true;
playbackControl.disabled = true;
});

playbackControl.oninput = () => {
source.playbackRate.value = playbackControl.value;
playbackValue.textContent = playbackControl.value;
};
53 changes: 53 additions & 0 deletions decode-audio-data/callback/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Web Audio API examples: decodeAudioData() with callback</title>
<script src="script.js" defer></script>
</head>

<body>
<h1>Web Audio API examples: decodeAudioData() with callback</h1>

<button id="play">Play</button>
<button id="stop" disabled>Stop</button>

<h2>Set playback rate</h2>
<input
id="playback-rate-control"
type="range"
min="0.25"
max="3"
step="0.05"
value="1"
disabled />
<span id="playback-rate-value">1.0</span>

<h2>Set loop start and loop end</h2>
<input
id="loopstart-control"
type="range"
min="0"
max="20"
step="1"
value="0"
disabled />
<span id="loopstart-value">0</span>

<input
id="loopend-control"
type="range"
min="0"
max="20"
step="1"
value="0"
disabled />
<span id="loopend-value">0</span>

<p>
If the stop time is lower or equal to the start time, it'll loop over the
whole track.
</p>
</body>
</html>
81 changes: 81 additions & 0 deletions decode-audio-data/callback/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
let audioCtx;
let buffer;
let source;

// Get UI elements
const play = document.getElementById("play");
const stop = document.getElementById("stop");

const playbackControl = document.getElementById("playback-rate-control");
const playbackValue = document.getElementById("playback-rate-value");

const loopstartControl = document.getElementById("loopstart-control");
const loopstartValue = document.getElementById("loopstart-value");

const loopendControl = document.getElementById("loopend-control");
const loopendValue = document.getElementById("loopend-value");

function playBuffer() {
source = audioCtx.createBufferSource();
source.buffer = buffer;
source.playbackRate.value = playbackControl.value;
source.connect(audioCtx.destination);
source.loop = true;
source.loopStart = loopstartControl.value;
source.loopEnd = loopendControl.value;
source.start();
play.disabled = true;
stop.disabled = false;
playbackControl.disabled = false;
loopstartControl.disabled = false;
loopendControl.disabled = false;
}

async function loadAudio() {
try {
const response = await fetch("viper.mp3");
audioCtx.decodeAudioData(await response.arrayBuffer(), (buf) => {
// executes when buffer has been decoded
buffer = buf;
const max = Math.floor(buf.duration);
loopstartControl.max = max;
loopendControl.max = max;
play.disabled = false; // buffer loaded, enable play button
playBuffer();
});
} catch (err) {
console.error(`Unable to fetch the audio file. Error: ${err.message}`);
}
}

play.addEventListener("click", async () => {
if (!audioCtx) {
audioCtx = new AudioContext();
await loadAudio();
} else {
playBuffer();
}
});

stop.addEventListener("click", () => {
source.stop();
play.disabled = false;
playbackControl.disabled = true;
loopstartControl.disabled = true;
loopendControl.disabled = true;
});

playbackControl.addEventListener("input", () => {
source.playbackRate.value = playbackControl.value;
playbackValue.textContent = playbackControl.value;
});

loopstartControl.addEventListener("input", () => {
source.loopStart = loopstartControl.value;
loopstartValue.textContent = loopstartControl.value;
});

loopendControl.oninput = () => {
source.loopEnd = loopendControl.value;
loopendValue.textContent = loopendControl.value;
};
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit f58f98b

Please sign in to comment.