Skip to content

Commit

Permalink
De-XHRify AudioBufferSourceNode examples
Browse files Browse the repository at this point in the history
  • Loading branch information
wbamberg committed Nov 20, 2023
1 parent 56bbf28 commit 98294a7
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 188 deletions.
104 changes: 66 additions & 38 deletions files/en-us/web/api/audiobuffersourcenode/loop/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,79 @@ is reached, playback continues at the time specified by

## Examples

In this example, the {{domxref("BaseAudioContext/decodeAudioData", "AudioContext.decodeAudioData()")}} function is used to
decode an audio track and put it into an {{domxref("AudioBufferSourceNode")}}. Buttons
are provided to play and stop the audio playback, and a slider control is used to change
the `playbackRate` property value on the fly. When the audio is played, it
loops.
### Setting `loop`

> **Note:** You can [run the full example live](https://mdn.github.io/webaudio-examples/decode-audio-data/) (or [view the source](https://github.com/mdn/webaudio-examples/blob/master/decode-audio-data/index.html).)
In this example, when the user presses "Play", we load an audio track, decode it, and put it into an {{domxref("AudioBufferSourceNode")}}.

```js
function getData() {
source = audioCtx.createBufferSource();
request = new XMLHttpRequest();

request.open("GET", "viper.ogg", true);

request.responseType = "arraybuffer";
The example then sets the `loop` property to `true`, so the track loops, and plays the track.

request.onload = () => {
const audioData = request.response;
The user can set the `loopStart` and and `loopEnd` properties using [range controls](/en-US/docs/Web/HTML/Element/input/range).

audioCtx.decodeAudioData(
audioData,
(buffer) => {
myBuffer = buffer;
source.buffer = myBuffer;
source.playbackRate.value = playbackControl.value;
source.connect(audioCtx.destination);
source.loop = true;
},
> **Note:** You can [run the full example live](https://mdn.github.io/webaudio-examples/audio-buffer-source-node/loop/) (or [view the source](https://github.com/mdn/webaudio-examples/tree/main/audio-buffer-source-node/loop).)
(e) => console.error(`Error with decoding audio data: ${e.err}`),
);
};

request.send();
```js
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}`);
}
}

// wire up buttons to stop and play audio, and range slider control

play.onclick = () => {
getData();
source.start(0);
play.setAttribute("disabled", "disabled");
playbackControl.removeAttribute("disabled");
};
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;
});
```

## Specifications
Expand Down
112 changes: 63 additions & 49 deletions files/en-us/web/api/audiobuffersourcenode/loopend/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,65 +27,79 @@ The default value is 0.

## Examples

In this example, the {{domxref("BaseAudioContext/decodeAudioData", "AudioContext.decodeAudioData()")}} function is used to
decode an audio track and put it into an {{domxref("AudioBufferSourceNode")}}. Buttons
are provided to play and stop the audio playback, and slider controls are used to change
the `playbackRate`, `loopStart` and `loopEnd`
properties on the fly.
### Setting `loopEnd`

When the audio is played to the end, it loops, but you can control how long the loops
last by altering `loopStart` and `loopEnd`. For example, if you
set their values to 20 and 25, respectively, then begin playback, the sound will play
normally until it reaches the 25 second mark. Then the current play position will loop
back to the 20 second mark and continue playing until the 25 second mark, ad infinitum
(or at least until {{domxref("AudioScheduledSourceNode/stop", "stop()")}} is called).
In this example, when the user presses "Play", we load an audio track, decode it, and put it into an {{domxref("AudioBufferSourceNode")}}.

> **Note:** For a full working example, see [this code running live](https://mdn.github.io/webaudio-examples/decode-audio-data/), or [view the source](https://github.com/mdn/webaudio-examples/tree/master/decode-audio-data).
The example then sets the `loop` property to `true`, so the track loops, and plays the track.

```js
function getData() {
source = audioCtx.createBufferSource();
request = new XMLHttpRequest();

request.open("GET", "viper.ogg", true);

request.responseType = "arraybuffer";

request.onload = () => {
const audioData = request.response;

audioCtx.decodeAudioData(
audioData,
(buffer) => {
myBuffer = buffer;
songLength = buffer.duration;
source.buffer = myBuffer;
source.playbackRate.value = playbackControl.value;
source.connect(audioCtx.destination);
source.loop = true;
The user can set the `loopStart` and and `loopEnd` properties using [range controls](/en-US/docs/Web/HTML/Element/input/range).

loopstartControl.setAttribute("max", Math.floor(songLength));
loopendControl.setAttribute("max", Math.floor(songLength));
},
> **Note:** You can [run the full example live](https://mdn.github.io/webaudio-examples/audio-buffer-source-node/loop/) (or [view the source](https://github.com/mdn/webaudio-examples/tree/main/audio-buffer-source-node/loop).)
(e) => console.error(`Error with decoding audio data: ${e.err}`),
);
};

request.send();
```js
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}`);
}
}

//

loopstartControl.oninput = () => {
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.innerHTML = loopstartControl.value;
};
loopstartValue.textContent = loopstartControl.value;
});

loopendControl.oninput = () => {
loopendControl.addEventListener("input", () => {
source.loopEnd = loopendControl.value;
loopendValue.innerHTML = loopendControl.value;
};
loopendValue.textContent = loopendControl.value;
});
```

## Specifications
Expand Down
109 changes: 63 additions & 46 deletions files/en-us/web/api/audiobuffersourcenode/loopstart/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,62 +22,79 @@ which each loop should begin during playback. This value is only used when the

## Examples

In this example, the {{domxref("BaseAudioContext/decodeAudioData", "AudioContext.decodeAudioData()")}} function is used to
decode an audio track and put it into an {{domxref("AudioBufferSourceNode")}}. Buttons
are provided to play and stop the audio playback, and slider controls are used to change
the `playbackRate`, `loopStart`, and `loopEnd`
properties on the fly.
### Setting `loopStart`

When the audio is played to the end, it loops, but you can control how long the loops
last by altering `loopStart` and `loopEnd`. For example, if you
set their values to 20 and 25, respectively, the audio will start to loop between 20 and
25 seconds in to the track.
In this example, when the user presses "Play", we load an audio track, decode it, and put it into an {{domxref("AudioBufferSourceNode")}}.

> **Note:** For a full working example, see [this code running live](https://mdn.github.io/webaudio-examples/decode-audio-data/), or [view the source](https://github.com/mdn/webaudio-examples/tree/master/decode-audio-data).
The example then sets the `loop` property to `true`, so the track loops, and plays the track.

```js
function getData() {
source = audioCtx.createBufferSource();
request = new XMLHttpRequest();

request.open("GET", "viper.ogg", true);
request.responseType = "arraybuffer";

request.onload = () => {
const audioData = request.response;

audioCtx.decodeAudioData(
audioData,
(buffer) => {
myBuffer = buffer;
songLength = buffer.duration;
source.buffer = myBuffer;
source.playbackRate.value = playbackControl.value;
source.connect(audioCtx.destination);
source.loop = true;

loopstartControl.setAttribute("max", Math.floor(songLength));
loopendControl.setAttribute("max", Math.floor(songLength));
},
The user can set the `loopStart` and and `loopEnd` properties using [range controls](/en-US/docs/Web/HTML/Element/input/range).

(e) => console.error(`Error with decoding audio data: ${e.err}`),
);
};
> **Note:** You can [run the full example live](https://mdn.github.io/webaudio-examples/audio-buffer-source-node/loop/) (or [view the source](https://github.com/mdn/webaudio-examples/tree/main/audio-buffer-source-node/loop).)
request.send();
```js
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}`);
}
}

//

loopstartControl.oninput = () => {
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.innerHTML = loopstartControl.value;
};
loopstartValue.textContent = loopstartControl.value;
});

loopendControl.oninput = () => {
loopendControl.addEventListener("input", () => {
source.loopEnd = loopendControl.value;
loopendValue.innerHTML = loopendControl.value;
};
loopendValue.textContent = loopendControl.value;
});
```

## Specifications
Expand Down
Loading

0 comments on commit 98294a7

Please sign in to comment.