LibWeb: Implement AudioBuffer.copyToChannel

This commit is contained in:
Shannon Booth 2024-05-26 16:33:27 +12:00 committed by Andreas Kling
parent 848d6f5074
commit 17ae65cedc
Notes: sideshowbarker 2024-07-17 05:21:12 +09:00
4 changed files with 109 additions and 5 deletions

View File

@ -0,0 +1,9 @@
Error calling copyToChannel: IndexSizeError: Channel index is out of range
Error calling copyToChannel: TypeError: Not an object of type Float32Array
5,5,5,5,5,5,5
1,1,1,1,1,1,1
1,1,1,1,1,1,1
1,1,1,1,1,1,1
2,2,3,3,3,3,3
2,2,3,3,3,3,3
Done.

View File

@ -0,0 +1,75 @@
<script src="../include.js"></script>
<script>
test(() => {
// Create an empty AudioBuffer
let audioBuffer = new AudioBuffer({
numberOfChannels: 2,
length: 7,
sampleRate: 8000,
});
// Fill channel 0 with 5
let channel0Data = audioBuffer.getChannelData(0);
for (let i = 0; i < channel0Data.length; i++) {
channel0Data[i] = 5;
}
// Fill channel 1 with 2
let channel1Data = audioBuffer.getChannelData(1);
for (let i = 0; i < channel1Data.length; i++) {
channel1Data[i] = 2;
}
// Copy to out of range channel
try {
let errorBuffer = new Float32Array(channel0Data.length);
audioBuffer.copyToChannel(errorBuffer, 2);
} catch (e) {
println(`Error calling copyToChannel: ${e}`);
}
// Copy from a non-Float32Array
try {
let notFloatArray = new Uint8Array(channel0Data.length);
audioBuffer.copyToChannel(notFloatArray, 1, 2);
} catch (e) {
println(`Error calling copyToChannel: ${e}`);
}
// Copy full buffer into channel 0
let fullBuffer = new Float32Array(channel0Data.length);
for (let i = 0; i < fullBuffer.length; i++) {
fullBuffer[i] = 1;
}
println(channel0Data);
audioBuffer.copyToChannel(fullBuffer, 0);
println(audioBuffer.getChannelData(0));
// Copy buffer with bigger size into channel 0
let biggerBuffer = new Float32Array(channel0Data.length + 3);
for (let i = 0; i < biggerBuffer.length; i++) {
biggerBuffer[i] = 1;
}
println(channel0Data);
audioBuffer.copyToChannel(biggerBuffer, 0);
println(audioBuffer.getChannelData(0));
// Copy buffer into channel 1 with offset
let offsetBuffer = new Float32Array(channel1Data.length);
for (let i = 0; i < offsetBuffer.length; i++) {
offsetBuffer[i] = 3;
}
audioBuffer.copyToChannel(offsetBuffer, 1, 2);
println(audioBuffer.getChannelData(1));
// Copy buffer into channel 1 with offset bigger than channel size.
audioBuffer.copyToChannel(offsetBuffer, 1, channel1Data.length + 1);
println(audioBuffer.getChannelData(1));
// Copy buffer into detached buffer (no crash)
let detachedBuffer = new Float32Array(channel0Data.length);
const transferred = detachedBuffer.buffer.transfer();
audioBuffer.copyToChannel(detachedBuffer, 0);
println("Done.");
});
</script>

View File

@ -105,11 +105,31 @@ WebIDL::ExceptionOr<void> AudioBuffer::copy_from_channel(JS::Handle<WebIDL::Buff
}
// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
WebIDL::ExceptionOr<void> AudioBuffer::copy_to_channel(JS::Handle<WebIDL::BufferSource>&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset) const
WebIDL::ExceptionOr<void> AudioBuffer::copy_to_channel(JS::Handle<WebIDL::BufferSource> const& source, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset)
{
(void)channel_number;
(void)buffer_offset;
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement AudioBuffer:copy_to_channel:"_fly_string);
// The copyToChannel() method copies the samples to the specified channel of the AudioBuffer from the source array.
//
// A UnknownError may be thrown if source cannot be copied to the buffer.
//
// Let buffer be the AudioBuffer with Nb frames, let Nf be the number of elements in the source array, and k be the value
// of bufferOffset. Then the number of frames copied from source to the buffer is max(0,min(Nbk,Nf)). If this is less than Nf,
// then the remaining elements of buffer are not modified.
auto& vm = this->vm();
if (!is<JS::Float32Array>(*source->raw_object()))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float32Array");
auto const& float32_array = static_cast<JS::Float32Array const&>(*source->raw_object());
auto channel = TRY(get_channel_data(channel_number));
auto channel_length = channel->data().size();
if (buffer_offset >= channel_length)
return {};
u32 count = min(float32_array.data().size(), channel_length - buffer_offset);
float32_array.data().slice(0, count).copy_to(channel->data().slice(buffer_offset, count));
return {};
}
AudioBuffer::AudioBuffer(JS::Realm& realm, AudioBufferOptions const& options)

View File

@ -38,7 +38,7 @@ public:
WebIDL::UnsignedLong number_of_channels() const;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Float32Array>> get_channel_data(WebIDL::UnsignedLong channel) const;
WebIDL::ExceptionOr<void> copy_from_channel(JS::Handle<WebIDL::BufferSource> const&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset = 0) const;
WebIDL::ExceptionOr<void> copy_to_channel(JS::Handle<WebIDL::BufferSource>&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset = 0) const;
WebIDL::ExceptionOr<void> copy_to_channel(JS::Handle<WebIDL::BufferSource> const&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset = 0);
private:
explicit AudioBuffer(JS::Realm&, AudioBufferOptions const&);