Spaces:
Runtime error
Runtime error
| import { | |
| computeRMS, | |
| computeChunkedRMS, | |
| downsampleIfNeeded, | |
| dropEveryOtherSample | |
| } from '../../../src/lib/audio/audio-util'; | |
| describe('computeRMS', () => { | |
| test('returns 0 when given no samples', () => { | |
| expect(computeRMS([])).toEqual(0); | |
| }); | |
| test('returns the RMS scaled by the given unity value and square rooted', () => { | |
| const unity = 0.5; | |
| const samples = [3, 2, 1]; | |
| expect(computeRMS(samples, unity)).toEqual( | |
| Math.sqrt(Math.sqrt(((3 * 3) + (2 * 2) + (1 * 1)) / 3) / 0.5) | |
| ); | |
| }); | |
| test('uses a default unity value of 0.55', () => { | |
| const samples = [1, 1, 1]; | |
| // raw rms is 1, scaled to (1 / 0.55) and square rooted | |
| expect(computeRMS(samples)).toEqual(Math.sqrt(1 / 0.55)); | |
| }); | |
| }); | |
| describe('computeChunkedRMS', () => { | |
| test('computes the rms for each chunk based on chunk size', () => { | |
| const samples = [2, 1, 3, 2, 5]; | |
| const chunkedLevels = computeChunkedRMS(samples, 2); | |
| // chunked to [2, 0], [3, 0], [5] | |
| // rms scaled with default unity of 0.55 | |
| expect(chunkedLevels.length).toEqual(3); | |
| expect(chunkedLevels).toEqual([ | |
| Math.sqrt(Math.sqrt(((2 * 2) + (1 * 1)) / 2) / 0.55), | |
| Math.sqrt(Math.sqrt(((3 * 3) + (2 * 2)) / 2) / 0.55), | |
| Math.sqrt(Math.sqrt((5 * 5) / 1) / 0.55) | |
| ]); | |
| }); | |
| test('chunk size larger than sample size creates single chunk', () => { | |
| const samples = [1, 1, 1]; | |
| const chunkedLevels = computeChunkedRMS(samples, 7); | |
| // chunked to [1, 1, 1] | |
| // rms scaled with default unity of 0.55 | |
| expect(chunkedLevels.length).toEqual(1); | |
| expect(chunkedLevels).toEqual([Math.sqrt(1 / 0.55)]); | |
| }); | |
| test('chunk size as multiple is handled correctly', () => { | |
| const samples = [1, 1, 1, 1, 1, 1]; | |
| const chunkedLevels = computeChunkedRMS(samples, 3); | |
| // chunked to [1, 1, 1], [1, 1, 1] | |
| // rms scaled with default unity of 0.55 | |
| expect(chunkedLevels.length).toEqual(2); | |
| expect(chunkedLevels).toEqual([Math.sqrt(1 / 0.55), Math.sqrt(1 / 0.55)]); | |
| }); | |
| }); | |
| describe('downsampleIfNeeded', () => { | |
| const samples = {length: 1}; | |
| const sampleRate = 44100; | |
| test('returns given data when no downsampling needed', async () => { | |
| samples.length = 1; | |
| const res = await downsampleIfNeeded({samples, sampleRate}, null); | |
| expect(res.samples).toEqual(samples); | |
| expect(res.sampleRate).toEqual(sampleRate); | |
| }); | |
| test('downsamples to 22050 if that puts it under the limit', async () => { | |
| samples.length = 44100 * 3 * 60; | |
| const resampler = jest.fn(() => 'TEST'); | |
| const res = await downsampleIfNeeded({samples, sampleRate}, resampler); | |
| expect(resampler).toHaveBeenCalledWith({samples, sampleRate}, 22050); | |
| expect(res).toEqual('TEST'); | |
| }); | |
| // TW: We allow resampling even if it would exceed the limit because our GUI handles this better. | |
| test.skip('fails if resampling would not put it under the limit', async () => { | |
| samples.length = 44100 * 4 * 60; | |
| try { | |
| await downsampleIfNeeded({samples, sampleRate}, null); | |
| } catch (e) { | |
| expect(e.message).toEqual('Sound too large to save, refusing to edit'); | |
| } | |
| }); | |
| }); | |
| describe('dropEveryOtherSample', () => { | |
| const buffer = { | |
| samples: [1, 0, 2, 0, 3, 0], | |
| sampleRate: 2 | |
| }; | |
| test('result is half the length', () => { | |
| const {samples} = dropEveryOtherSample(buffer); | |
| expect(samples.length).toEqual(Math.floor(buffer.samples.length / 2)); | |
| }); | |
| test('result contains only even-index items', () => { | |
| const {samples} = dropEveryOtherSample(buffer); | |
| expect(samples).toEqual(new Float32Array([1, 2, 3])); | |
| }); | |
| test('result sampleRate is given sampleRate / 2', () => { | |
| const {sampleRate} = dropEveryOtherSample(buffer); | |
| expect(sampleRate).toEqual(buffer.sampleRate / 2); | |
| }); | |
| }); | |