import { describe, expect, it } from 'vitest'; import { newTrack } from '../../src/core/music/song'; import { cappedTake, MAX_TAKE_BYTES, maxTakeSamples, sampleCount, takeName, takeStart, takeTrack, takeTrackIndex, toPcm16, trimmedTake, wavBytes, } from '../../src/core/music/take'; const pcm = (...values: number[]) => Int16Array.from(values); describe('a recorded take (#342)', () => { it('turns samples into 16 bits, clipped at full scale', () => { expect([...toPcm16(Float32Array.from([0, 1, -1, 0.5, 2, -3]))]).toEqual([ 0, 32767, -32768, 16384, 32767, -32768, ]); }); it('starts where the song is heard back through the input', () => { expect(takeStart(10, 0.02, 0.01)).toBeCloseTo(10.03, 9); expect(takeStart(10, -1, -1)).toBe(10); }); it('drops what came before the start and cuts the chunk it falls in', () => { const chunks = [ { frame: 0, samples: pcm(1, 2, 3, 4) }, { frame: 4, samples: pcm(5, 6, 7, 8) }, { frame: 8, samples: pcm(9, 10) }, ]; expect(trimmedTake(chunks, 6).map((part) => [...part])).toEqual([ [7, 8], [9, 10], ]); expect(trimmedTake(chunks, 4).map((part) => [...part])).toEqual([ [5, 6, 7, 8], [9, 10], ]); expect(sampleCount(trimmedTake(chunks, 0))).toBe(10); expect(trimmedTake(chunks, 20)).toEqual([]); }); it('keeps no more than a sound may hold', () => { expect(cappedTake([pcm(1, 2, 3), pcm(4, 5, 6)], 4).map((part) => [...part])).toEqual([[1, 2, 3], [4]]); expect(maxTakeSamples() * 2 + 44).toBeLessThanOrEqual(MAX_TAKE_BYTES); expect(MAX_TAKE_BYTES).toBeLessThan(256 * 1024 * 1024); }); it('writes a mono 16-bit PCM WAV the server knows by its RIFF header', () => { const bytes = wavBytes([pcm(1, -2), pcm(300)], 48000); const view = new DataView(bytes.buffer); const text = (at: number) => String.fromCharCode(...bytes.subarray(at, at + 4)); expect(bytes.length).toBe(44 + 6); expect([text(0), text(8), text(12), text(36)]).toEqual(['RIFF', 'WAVE', 'fmt ', 'data']); expect(view.getUint32(4, true)).toBe(36 + 6); expect(view.getUint16(20, true)).toBe(1); expect(view.getUint16(22, true)).toBe(1); expect(view.getUint32(24, true)).toBe(48000); expect(view.getUint32(28, true)).toBe(96000); expect(view.getUint16(34, true)).toBe(16); expect(view.getUint32(40, true)).toBe(6); expect([view.getInt16(44, true), view.getInt16(46, true), view.getInt16(48, true)]).toEqual([1, -2, 300]); }); it('is numbered past the takes its song keeps (#355)', () => { expect(takeName([])).toBe('Take 1'); expect(takeName(['Take 1', 'Take 2', 'Intro'])).toBe('Take 3'); expect(takeName(['Take 2'])).toBe('Take 1'); }); it('gets a track of its own under the one clicked last, else at the bottom', () => { const tracks = [newTrack(1), newTrack(2), newTrack(3)]; expect(takeTrackIndex(tracks, tracks[0]!.id)).toBe(1); expect(takeTrackIndex(tracks, tracks[2]!.id)).toBe(3); expect(takeTrackIndex(tracks, '')).toBe(3); expect(takeTrack().name).toBe('Recording'); expect(takeTrack().id).not.toBe(takeTrack().id); }); });