How it works
Nullsample writes music the way a synthesiser makes sound, not the way a sampler does. There is no audio in this website. There are no loops, no one-shot samples, no impulse responses, and no trained model. Every sound you hear was computed from arithmetic on your own device, a few milliseconds before it reached your speakers.
What a track is made of
Sound is a list of numbers — 44,100 of them per second, per channel. Everything below is a rule for producing the next number.
- Oscillators produce a repeating shape: a sawtooth, a pulse, a triangle, a sine. Naive versions of these alias badly, so the engine uses band-limited forms that correct the waveform at each discontinuity. Aliasing here is a deliberate choice, never an accident.
- Noise is a stream of pseudo-random numbers. Filtered hard, it becomes a hi-hat. Filtered gently and enveloped, it becomes a snare's rattle or a riser.
- Envelopes shape loudness and pitch over the life of a note. A kick drum is a sine whose pitch falls from 180 Hz to 46 Hz in about 30 milliseconds; that fall is the entire character of the sound.
- Filters remove or emphasise parts of the spectrum. The one used here is a state-variable design that stays stable when its cutoff is swept quickly, which a naive filter does not.
- Nonlinear stages — saturation, waveshaping, clipping — add harmonics that were not there. They also add frequencies above what the sample rate can represent, which fold back as inharmonic noise, so each of them runs inside a region computed at four times the normal rate and filtered back down.
- Reverb is a network of eight delay lines feeding back through a mixing matrix, with line lengths chosen to be mutually prime so the tail never settles into an audible pattern. It is generated, not recorded — shipping a recorded impulse response would be shipping a sample.
Why the same seed always gives the same track
A seed is the only input. It is expanded into a random number generator, and every decision — tempo, key, chord loop, which arrangement, where the kick lands, how far the filter opens — is drawn from it. Paste the same seed and you get the same track, on any machine, in any browser.
That is harder than it sounds. JavaScript specifies +, -,
* and / exactly, but it explicitly leaves Math.sin,
Math.exp, Math.log, Math.pow and Math.sqrt as
"implementation-approximated". Different browser engines really do differ in the last bit. One
differing bit inside a filter's feedback path becomes an audible difference within a second.
So the engine does not call any of them. It rebuilds sine, exponential, logarithm and square root from exact arithmetic — polynomial series and a fixed number of Newton steps — accurate to about one part in a quadrillion, and identical everywhere. A lint rule fails the build if any file under the engine calls the built-in versions, and a test renders the same seeds in Node and in headless Chrome and compares the files byte for byte.
Why zero samples matters
Most "AI music" and most loop-based generators are built on recordings. That raises questions about what was in the training set or the sample pack, and who owns the result. Nullsample has nothing to be unclear about: there is no recorded audio anywhere in it, so there is nothing in your track that came from someone else's.
It is also why the whole thing fits in about 70 kilobytes and runs with no server. A sample library would be hundreds of megabytes and would have to be hosted. An algorithm is small.
What runs where
Everything runs on your device. The page is static files; there is no backend, no queue and no storage. Rendering happens in a background thread so the interface stays responsive, and playback begins after the first few bars while the rest is still being computed. The audio you hear and the file you download are produced by the same code in the same order, so they are the same bytes.
The honest limitations
- One genre. A preset that sounds convincing takes a long time to tune, and ten shallow ones would be worse than one deep one.
- A full two-minute track takes roughly 25 seconds of computation on a laptop. Playback starts long before that, but the download is only ready when the render is.
- The melodies are generated under constraints, not composed. They are shaped — a contour, a bounded interval jump, a resolution — but they are not going to surprise you the way a person would.