The JavaScript fetch API is described pretty well here. It is essentially an async way to retrieve remote files. The .then
code is what happens once the async part is done.
So fetch('track1.mp3')
will asynchronously go and get the file. When the file is available, it processes whatever is in the attached .then()
code. In this case, it is response => resonse.arrayBuffer()
which is followed by subsequent .then()
code. This all works pretty well, but of course this is also all JavaScript code.
When it comes to Delphi, it depends on what level of abstraction you want to work with, or what parameters you want to pass in to control this kind of behavior. You could drop a button on the form and then include this code (everything between the <script>
tags) verbatim in the onclick
event, just wrapped in an asm... ...end
block and it would work.
For the controls, they're using a range slider, so any of the TMS WEB Core sliders could work (there are several). If you want access to the variables like context
and source
you could define them as Form variables of type JSValue
(and add the JSDelphiSystem
unit to your uses clause). Then in the method, you would reference these as this.somecontext
or this.somesource
or whatever name you called them, rather than creating new instances. This would also make it possible to access them from beyond the JavaScript asm... ...end
block.
So something like this. Not tested, just roughly the gist of it.
Unit somethingorother;
uses ..., JSDelphisystem, ....
var
somesource: JSValue;
somecontext: JSValue;
...
procedure PlayMeASong(audioclip: String);
begin
asm
this.somecontext = new AudioContext();
this.somesource = somecontext.createBufferSource();
this.somesource.start();
this.somesource.connect(this.somecontext.destination);
fetch(audioclip)
.then(response => response.arrayBuffer())
.then(buffer => this.somecontext.decodeAudioData(buffer))
.then(data => this.somesource.buffer = data);
end;
end;
procedure TWebSliderMoved(sender:TObject);
var
playratevalue: Integer;
begin
playratevalue := WebSlider.value;
if (somesource <> nil) then
begin
asm
this.somesource.playbackRate.value = playratevalue;
end;
end;
end
procedure TWebButtonClick(sender:TObject);
begin
PlayMeASong('something1.mp3');
end;
If you wanted to keep track of multiple instances of source and context, then you could create an array of JSValues for each. Whether this is necessary depends on what else you plan to do with them. A one-off play event probably doesn't need this. But if you're playing an arbitrary number of files and want to adjust them individually, then this might be the better approach. Or if you just need three, define three form variables and call it a day.