| // META: global=window,dedicatedworker | |
| test(t => { | |
| // 2 channels, 10 frames, interleaved f32. | |
| // Layout: [L0, R0, L1, R1, L2, R2, L3, R3, L4, R4, | |
| // L5, R5, L6, R6, L7, R7, L8, R8, L9, R9] | |
| const channels = 2; | |
| const frames = 10; | |
| const data = new Float32Array(channels * frames); | |
| for (let i = 0; i < frames; i++) { | |
| data[i * channels] = i * 0.1; // left | |
| data[i * channels + 1] = -(i * 0.1); // right | |
| } | |
| const audioData = new AudioData({ | |
| timestamp: 0, | |
| data: data, | |
| numberOfFrames: frames, | |
| numberOfChannels: channels, | |
| sampleRate: 44100, | |
| format: 'f32', | |
| }); | |
| t.add_cleanup(() => audioData.close()); | |
| const frameOffset = 3; | |
| const frameCount = 5; | |
| const dest = new Float32Array(channels * frameCount); | |
| audioData.copyTo(dest, { | |
| planeIndex: 0, | |
| format: 'f32', | |
| frameOffset: frameOffset, | |
| frameCount: frameCount, | |
| }); | |
| // Expected: frames 3 through 7, interleaved. | |
| for (let i = 0; i < frameCount; i++) { | |
| const srcFrame = frameOffset + i; | |
| const expectedL = srcFrame * 0.1; | |
| const expectedR = -(srcFrame * 0.1); | |
| assert_approx_equals(dest[i * channels], expectedL, 1e-6, | |
| `frame ${srcFrame} left channel`); | |
| assert_approx_equals(dest[i * channels + 1], expectedR, 1e-6, | |
| `frame ${srcFrame} right channel`); | |
| } | |
| }, 'copyTo interleaved-to-interleaved with non-zero frameOffset'); | |
| test(t => { | |
| // Same test with s16 to ensure it's not float-specific. | |
| const channels = 2; | |
| const frames = 10; | |
| const data = new Int16Array(channels * frames); | |
| for (let i = 0; i < frames; i++) { | |
| data[i * channels] = i * 1000; | |
| data[i * channels + 1] = -(i * 1000); | |
| } | |
| const audioData = new AudioData({ | |
| timestamp: 0, | |
| data: data, | |
| numberOfFrames: frames, | |
| numberOfChannels: channels, | |
| sampleRate: 44100, | |
| format: 's16', | |
| }); | |
| t.add_cleanup(() => audioData.close()); | |
| const frameOffset = 4; | |
| const frameCount = 3; | |
| const dest = new Int16Array(channels * frameCount); | |
| audioData.copyTo(dest, { | |
| planeIndex: 0, | |
| format: 's16', | |
| frameOffset: frameOffset, | |
| frameCount: frameCount, | |
| }); | |
| for (let i = 0; i < frameCount; i++) { | |
| const srcFrame = frameOffset + i; | |
| assert_equals(dest[i * channels], srcFrame * 1000, | |
| `frame ${srcFrame} left channel`); | |
| assert_equals(dest[i * channels + 1], -(srcFrame * 1000), | |
| `frame ${srcFrame} right channel`); | |
| } | |
| }, 'copyTo interleaved-to-interleaved s16 with non-zero frameOffset'); | |
| test(t => { | |
| // 3 channels, interleaved, to cover more than the stereo case. | |
| const channels = 3; | |
| const frames = 8; | |
| const data = new Float32Array(channels * frames); | |
| for (let i = 0; i < frames; i++) { | |
| for (let ch = 0; ch < channels; ch++) { | |
| data[i * channels + ch] = i + ch * 0.01; | |
| } | |
| } | |
| const audioData = new AudioData({ | |
| timestamp: 0, | |
| data: data, | |
| numberOfFrames: frames, | |
| numberOfChannels: channels, | |
| sampleRate: 44100, | |
| format: 'f32', | |
| }); | |
| t.add_cleanup(() => audioData.close()); | |
| const frameOffset = 2; | |
| const frameCount = 4; | |
| const dest = new Float32Array(channels * frameCount); | |
| audioData.copyTo(dest, { | |
| planeIndex: 0, | |
| format: 'f32', | |
| frameOffset: frameOffset, | |
| frameCount: frameCount, | |
| }); | |
| for (let i = 0; i < frameCount; i++) { | |
| const srcFrame = frameOffset + i; | |
| for (let ch = 0; ch < channels; ch++) { | |
| const expected = srcFrame + ch * 0.01; | |
| assert_approx_equals( | |
| dest[i * channels + ch], expected, 1e-6, | |
| `frame ${srcFrame} channel ${ch}`); | |
| } | |
| } | |
| }, 'copyTo interleaved-to-interleaved f32 with 3 channels and frameOffset'); | |
| test(t => { | |
| // 2 channels, 10 frames, planar f32. | |
| // Layout: [L0, L1, ..., L9, R0, R1, ..., R9] | |
| const channels = 2; | |
| const frames = 10; | |
| const data = new Float32Array(channels * frames); | |
| for (let ch = 0; ch < channels; ch++) { | |
| for (let i = 0; i < frames; i++) { | |
| data[ch * frames + i] = (ch + 1) * (i + 1) * 0.1; | |
| } | |
| } | |
| const audioData = new AudioData({ | |
| timestamp: 0, | |
| data: data, | |
| numberOfFrames: frames, | |
| numberOfChannels: channels, | |
| sampleRate: 44100, | |
| format: 'f32-planar', | |
| }); | |
| t.add_cleanup(() => audioData.close()); | |
| const frameOffset = 3; | |
| const frameCount = 5; | |
| const dest = new Float32Array(channels * frameCount); | |
| audioData.copyTo(dest, { | |
| planeIndex: 0, | |
| format: 'f32', | |
| frameOffset: frameOffset, | |
| frameCount: frameCount, | |
| }); | |
| // Expected: frames 3 through 7 from each channel, interleaved. | |
| for (let i = 0; i < frameCount; i++) { | |
| const srcFrame = frameOffset + i; | |
| for (let ch = 0; ch < channels; ch++) { | |
| const expected = (ch + 1) * (srcFrame + 1) * 0.1; | |
| assert_approx_equals( | |
| dest[i * channels + ch], expected, 1e-5, | |
| `frame ${srcFrame} channel ${ch}`); | |
| } | |
| } | |
| }, 'copyTo planar-to-interleaved with non-zero frameOffset'); | |
| test(t => { | |
| // 3 channels, planar s16. | |
| const channels = 3; | |
| const frames = 8; | |
| const data = new Int16Array(channels * frames); | |
| for (let ch = 0; ch < channels; ch++) { | |
| for (let i = 0; i < frames; i++) { | |
| data[ch * frames + i] = (ch + 1) * 1000 + i; | |
| } | |
| } | |
| const audioData = new AudioData({ | |
| timestamp: 0, | |
| data: data, | |
| numberOfFrames: frames, | |
| numberOfChannels: channels, | |
| sampleRate: 44100, | |
| format: 's16-planar', | |
| }); | |
| t.add_cleanup(() => audioData.close()); | |
| const frameOffset = 2; | |
| const frameCount = 4; | |
| const dest = new Int16Array(channels * frameCount); | |
| audioData.copyTo(dest, { | |
| planeIndex: 0, | |
| format: 's16', | |
| frameOffset: frameOffset, | |
| frameCount: frameCount, | |
| }); | |
| for (let i = 0; i < frameCount; i++) { | |
| const srcFrame = frameOffset + i; | |
| for (let ch = 0; ch < channels; ch++) { | |
| const expected = (ch + 1) * 1000 + srcFrame; | |
| assert_equals( | |
| dest[i * channels + ch], expected, | |
| `frame ${srcFrame} channel ${ch}`); | |
| } | |
| } | |
| }, 'copyTo planar-to-interleaved s16 with 3 channels and frameOffset'); | |
| test(t => { | |
| // Verify frameOffset=0 still works correctly for planar-to-interleaved | |
| // (baseline sanity check). | |
| const channels = 2; | |
| const frames = 4; | |
| const data = new Float32Array([ | |
| 1.0, 2.0, 3.0, 4.0, // channel 0 | |
| 5.0, 6.0, 7.0, 8.0, // channel 1 | |
| ]); | |
| const audioData = new AudioData({ | |
| timestamp: 0, | |
| data: data, | |
| numberOfFrames: frames, | |
| numberOfChannels: channels, | |
| sampleRate: 44100, | |
| format: 'f32-planar', | |
| }); | |
| t.add_cleanup(() => audioData.close()); | |
| const dest = new Float32Array(channels * frames); | |
| audioData.copyTo(dest, {planeIndex: 0, format: 'f32'}); | |
| // Expected interleaved: [1, 5, 2, 6, 3, 7, 4, 8] | |
| const expected = new Float32Array([1, 5, 2, 6, 3, 7, 4, 8]); | |
| assert_array_equals(dest, expected, | |
| 'planar-to-interleaved with frameOffset=0'); | |
| }, 'copyTo planar-to-interleaved baseline with frameOffset=0'); |