Testing
The test receiver stands in for LA2L in Ableton Live, for whoever has no Ableton at hand: you, your CI, or an AI agent. It shows a code, imports every package you send as LA2L in Live would, and acks it, so your app sees the same status as with Live. Per sound it says what Live would do:
Beat test (Web808): imported 2 of 2 sounds
Beat (Web808): loop, warped in Beats mode at 120 BPM, 4 beats. 48 kHz, 16-bit, stereo, 2 s
Hit (Web808): one-shot, plays as it is. 48 kHz, 16-bit, mono, 0.1 s
A loop that shows up as a one-shot lacks kind: 'loop'. A loop at an odd length, such as 4.37 beats, is not rendered a whole number of beats long.
In a browser
Open the test receiver. It shows a code; pair your app with it as you would with Live, and send. Each package gets a report on the page. It works against the real server, so your app needs no change at all.
In a terminal
npx @lloydstellar/la2l test-receiver
The same, in a terminal. With --local it starts an LA2L server in memory on 127.0.0.1 as well: no internet and no rate limits. Point your app at the address it prints:
npx @lloydstellar/la2l test-receiver --local
# LA2L test receiver, with an LA2L server in memory: http://127.0.0.1:41234/api
# In your app, use that address as the server and pair with code K7P 42Q.
const la2l = new LA2L({ appName: 'Web808', server: 'http://127.0.0.1:41234/api' });
The button takes it as an attribute: <la2l-send-button server="http://127.0.0.1:41234/api">.
In your tests
startTestReceiver() from @lloydstellar/la2l/testing does the same inside a test, in Node.js:
import test from 'node:test';
import assert from 'node:assert/strict';
import { LA2L, memoryStorage } from '@lloydstellar/la2l';
import { startTestReceiver } from '@lloydstellar/la2l/testing';
test('the beat arrives in Live as a loop of one bar', async () => {
const receiver = await startTestReceiver();
try {
const la2l = new LA2L({ appName: 'Web808', server: receiver.server, storage: memoryStorage() });
await la2l.pair(receiver.code);
const delivery = await la2l.send({ title: 'Beat', bpm: 120, sounds: [{ name: 'Beat', audio: renderBeat(), kind: 'loop', role: 'drums' }] });
await delivery.imported();
const { plan } = (await receiver.nextReport()).sounds[0];
assert.deepEqual([plan.warp, plan.bpm, plan.lengthBeats], [true, 120, 4]);
} finally {
await receiver.close();
}
});
nextReport() resolves to the next report; reports holds them all. Each sound has its plan (the track name, warp, warp mode, tempo and length in beats), the info of its WAV header, or the error Live would give.
By hand
The five calls of the REST API work against the test receiver too. With --local, use the address it prints as the base address.