I'm looking for some help translating this JS code into Delphi, using the WebAudio wrapper. This quote is from a book published last year about the Web Audio API (WAA). The example loads a single MP3 file and plays it. (The playrate is irrelevant.) The second example below loads up two tracks and plays them sequentially using a similar approach.
The problem I'm having is the fetch()
method, which does not appear to be part of WAA, but just something in the browser somewhere. Where do I find it to use in Delphi?
My question is, how can I write this code in Delphi using the WebAudio wrapper?
Alternatively, how can I create a Delphi method that contains the JS expression fetch().then().then().then()
that takes the needed parameters to make it work with other methods in the WAA wrapper?
XMLHttpRequest is still widely used, and most examples that you might find online for decodeAudioData will also use an XMLHttpRequest. But a more modern way to do it is using fetch(), which has been adopted in popular browsers since about 2015. This has the same core functionality (and a few extras) as XMLHttpRequest but the syntax of its use is very different. It’s built around promises, typically chained in a sequence so that each step happens after the last one is complete. Perhaps the best way to explain this is with an example, Code example 8.5. Filling the audio buffer with the data from an mp3 file is now a sequence of steps. The fetch() method responds with an object. This is then turned into an array buffer. Since the next two steps happen sequentially, and each one returns a promise, we simply extend the chain. So once the arrayBuffer is created, we then decode this buffer into an audioBuffer which we have called data. Finally, we select this as the buffer for our BufferSourceNode.
Code example 8.5.decodeWithFetch.html, showing use of decodeAudioData and fetch() to load an audio file, and playbackRate to play it back at a variable rate.
<button id='play' onclick='context.resume()'>Play</button><br>
Playback rate
<input id='playRate' type='range' min=0.3 max=3 step=0.05 value=1>
<script>
let context = new AudioContext()
let source = context.createBufferSource()
source.start()
source.connect(context.destination)
fetch('beat1.mp3')
.then(response => response.arrayBuffer())
.then(buffer => context.decodeAudioData(buffer))
.then(data => source.buffer = data)
playRate.oninput = ()=> source.playbackRate.value = playRate.value
</script>
Here's the second snippet of code:
<button id='play' onclick='Start()'>Start()</button><br>
<script>
let context = new AudioContext()
let source1 = context.createBufferSource()
let source2 = context.createBufferSource()
source1.connect(context.destination)
source2.connect(context.destination)
fetch('track1.mp3')
.then(response => response.arrayBuffer())
.then(buffer => context.decodeAudioData(buffer))
.then(data => source1.buffer = data)
fetch('track2.mp3')
.then(response => response.arrayBuffer())
.then(buffer => context.decodeAudioData(buffer))
.then(data => source2.buffer = data)
function Start() {
context.resume()
now = context.currentTime
source1.start(now)
source2.start(now+source1.buffer.duration)
context.resume()
}
</script>