Skip to content

Commit 5e7678d

Browse files
shannonboothawesomekling
authored andcommitted
LibWeb: Implement AudioBuffer.copyFromChannel
1 parent 8bcaf68 commit 5e7678d

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Error calling copyFromChannel: IndexSizeError: Channel index is out of range
2+
Error calling copyFromChannel: TypeError: Not an object of type Float32Array
3+
0,0,0,0,0,0,0
4+
5,5,5,5,5,5,5
5+
0,0,0,0,0,0,0,0,0,0
6+
5,5,5,5,5,5,5,0,0,0
7+
2,2,2,2,2,5,5,0,0,0
8+
2,2,2,2,2,5,5,0,0,0
9+
Done.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<script src="../include.js"></script>
2+
<script>
3+
test(() => {
4+
// Create an empty AudioBuffer
5+
let audioBuffer = new AudioBuffer({
6+
numberOfChannels: 2,
7+
length: 7,
8+
sampleRate: 8000,
9+
});
10+
11+
// Fill channel 0 with 5
12+
let channel0Data = audioBuffer.getChannelData(0);
13+
for (let i = 0; i < channel0Data.length; i++) {
14+
channel0Data[i] = 5;
15+
}
16+
17+
// Fill channel 1 with 2
18+
let channel1Data = audioBuffer.getChannelData(1);
19+
for (let i = 0; i < channel1Data.length; i++) {
20+
channel1Data[i] = 2;
21+
}
22+
23+
// Copy into out of range channel
24+
try {
25+
let errorBuffer = new Float32Array(channel0Data.length);
26+
audioBuffer.copyFromChannel(errorBuffer, 2);
27+
} catch (e) {
28+
println(`Error calling copyFromChannel: ${e}`);
29+
}
30+
31+
// Copy into a non-Float32Array
32+
try {
33+
let notFloatArray = new Uint8Array(channel0Data.length);
34+
audioBuffer.copyFromChannel(notFloatArray, 1, 2);
35+
} catch (e) {
36+
println(`Error calling copyFromChannel: ${e}`);
37+
}
38+
39+
// Copy full channel
40+
let fullBuffer = new Float32Array(channel0Data.length);
41+
println(fullBuffer);
42+
audioBuffer.copyFromChannel(fullBuffer, 0);
43+
println(fullBuffer);
44+
45+
// Copy channel 0 into buffer with bigger size
46+
let biggerBuffer = new Float32Array(channel0Data.length + 3);
47+
println(biggerBuffer);
48+
audioBuffer.copyFromChannel(biggerBuffer, 0);
49+
println(biggerBuffer);
50+
51+
// Copy channel into buffer with offset
52+
audioBuffer.copyFromChannel(biggerBuffer, 1, 2);
53+
println(biggerBuffer);
54+
55+
// Copy channel into buffer with offset bigger than channel size.
56+
audioBuffer.copyFromChannel(biggerBuffer, 1, channel1Data.length + 1);
57+
println(biggerBuffer);
58+
59+
// Copy channel into detached buffer (no crash)
60+
let detachedBuffer = new Float32Array(channel0Data.length);
61+
const transferred = detachedBuffer.buffer.transfer();
62+
audioBuffer.copyFromChannel(detachedBuffer, 0);
63+
println("Done.");
64+
});
65+
</script>

Userland/Libraries/LibWeb/WebAudio/AudioBuffer.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,29 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Float32Array>> AudioBuffer::get_channel
7979
}
8080

8181
// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
82-
WebIDL::ExceptionOr<void> AudioBuffer::copy_from_channel(JS::Handle<WebIDL::BufferSource> const&, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset) const
82+
WebIDL::ExceptionOr<void> AudioBuffer::copy_from_channel(JS::Handle<WebIDL::BufferSource> const& destination, WebIDL::UnsignedLong channel_number, WebIDL::UnsignedLong buffer_offset) const
8383
{
84-
(void)channel_number;
85-
(void)buffer_offset;
86-
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement AudioBuffer:copy_from_channel:"_fly_string);
84+
// The copyFromChannel() method copies the samples from the specified channel of the AudioBuffer to the destination array.
85+
//
86+
// Let buffer be the AudioBuffer with Nb frames, let Nf be the number of elements in the destination array, and k be the value
87+
// of bufferOffset. Then the number of frames copied from buffer to destination is max(0,min(Nb−k,Nf)). If this is less than Nf,
88+
// then the remaining elements of destination are not modified.
89+
auto& vm = this->vm();
90+
91+
if (!is<JS::Float32Array>(*destination->raw_object()))
92+
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float32Array");
93+
auto& float32_array = static_cast<JS::Float32Array&>(*destination->raw_object());
94+
95+
auto const channel = TRY(get_channel_data(channel_number));
96+
97+
auto channel_length = channel->data().size();
98+
if (buffer_offset >= channel_length)
99+
return {};
100+
101+
u32 count = min(float32_array.data().size(), channel_length - buffer_offset);
102+
channel->data().slice(buffer_offset, count).copy_to(float32_array.data());
103+
104+
return {};
87105
}
88106

89107
// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel

0 commit comments

Comments
 (0)