فهرست منبع

LibWeb: Implement AudioBuffer.copyToChannel

Shannon Booth 1 سال پیش
والد
کامیت
17ae65cedc

+ 9 - 0
Tests/LibWeb/Text/expected/WebAudio/AudioBuffer-copyToChannel.txt

@@ -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.

+ 75 - 0
Tests/LibWeb/Text/input/WebAudio/AudioBuffer-copyToChannel.html

@@ -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>

+ 24 - 4
Userland/Libraries/LibWeb/WebAudio/AudioBuffer.cpp

@@ -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(Nb−k,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)

+ 1 - 1
Userland/Libraries/LibWeb/WebAudio/AudioBuffer.h

@@ -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&);