Noises

The page hosts generative ambient music designed for focus. While each track is (slightly) different, they all feature a pink-brown noise substrate, a pentatonic drone, and Karplus-Strong plucks. This work was heavily inspired by Endel's design principles and informed by the research of Lin (2022) and Haruvi et al. (2022). Best experienced at low volume through speakers. Enjoy!

SuperCollider was used to generate these tracks; source code is available here.
// ============================================================
// noise.scd — local generative ambient / focus music
//
// HOW TO USE:
//   1. Open SuperCollider IDE
//   2. Cmd+Shift+B to boot audio server, wait for "Server ready"
//   3. Select ALL (Cmd+A), then Cmd+Enter to evaluate
//   4. Ctrl+. to stop everything
// ============================================================

s.waitForBoot {

    ~bpm        = 65;
    ~rootHz     = 55.0;
    ~masterVol  = 0.7;
    ~reverbRoom = 0.85;
    ~reverbDamp = 0.6;

    ~penta = [0, 7, 12, 16, 19, 24];

    ~markovWeights = [
        [0, 4, 2, 1, 1, 0],
        [3, 0, 4, 2, 1, 0],
        [2, 3, 0, 4, 2, 1],
        [1, 2, 4, 0, 3, 1],
        [1, 1, 3, 4, 0, 3],
        [0, 1, 2, 2, 4, 0],
    ];

    SynthDef(\noiseLayer, { |out=0, amp=0.06, lfoRate=0.04, lpFreq=220|
        var pink, brown, blend, lfo;
        pink  = PinkNoise.ar(1);
        brown = BrownNoise.ar(1);
        blend = (pink * 0.1) + (brown * 0.9);
        lfo   = SinOsc.kr(lfoRate, 0, 0.12, 0.88);
        Out.ar(out, [blend * lfo * amp, blend * lfo * amp]);
    }).add;

    // Lin (2022): thin white noise for stochastic resonance.
    // _some_ brains may benefit from SR — white noise pushes sub-threshold
    // signals over detection threshold. Keep amp LOW: dose-dependent.
    // Routed DRY — reverb would smear the SR temporal structure.
    SynthDef(\srLayer, { |out=0, amp=0.018, lpFreq=2000|
        var sig = WhiteNoise.ar(1);
        sig = LPF.ar(sig, lpFreq);
        Out.ar(out, [sig * amp, sig * amp]);
    }).add;

    SynthDef(\droneVoice, { |out=0, freq=110, amp=0.12, detuneCents=0,
                              attack=4.0, release=6.0, lpFreq=800|
        var sig, env;
        freq = freq * (2 ** (detuneCents / 1200));
        sig  = SinOsc.ar(freq) + (SinOsc.ar(freq * 2) * 0.15);
        sig  = LPF.ar(sig, lpFreq);
        env  = EnvGen.kr(Env.asr(attack, 1.0, release), doneAction: 2);
        Out.ar(out, [sig * env * amp, sig * env * amp]);
    }).add;

    SynthDef(\pluck, { |out=0, freq=220, amp=0.25, pan=0, decay=2.5, brightness=0.5|
        var ks, env, sig;
        ks  = Pluck.ar(WhiteNoise.ar(0.3), Impulse.kr(0),
                       1/freq, 1/freq, decay, brightness);
        env = EnvGen.kr(
            Env.new([0, 1, 1, 0], [0.005, decay * 0.8, decay * 0.2]),
            doneAction: 2
        );
        sig = Pan2.ar(ks * env * amp, pan);
        Out.ar(out, sig);
    }).add;

    SynthDef(\pad, { |out=0, freq=110, amp=0.07, attack=3.0, sustain=80, release=5.0|
        var sigs, sig, env;
        sigs = Mix.fill(4, { |i|
            SinOsc.ar(freq + ((i - 1.5) * 0.3)) * 0.25
        });
        sig = LPF.ar(sigs, 1200);
        env = EnvGen.kr(
            Env.new([0, 1, 1, 0], [attack, sustain, release]),
            doneAction: 2
        );
        Out.ar(out, [sig * env * amp, sig * env * amp]);
    }).add;

    SynthDef(\reverbBus, { |in=2, out=0, room=0.85, damp=0.6, mix=0.25, amp=1.0|
        var sig = In.ar(in, 2);
        sig = FreeVerb2.ar(sig[0], sig[1], mix, room, damp);
        Out.ar(out, sig * amp);
    }).add;

    s.sync;

    ~reverbBus = Bus.audio(s, 2);

    ~reverb = Synth(\reverbBus, [
        \in, ~reverbBus.index, \out, 0,
        \room, ~reverbRoom, \damp, ~reverbDamp,
        \mix, 0.25, \amp, ~masterVol
    ]);

    ~noise = Synth(\noiseLayer, [
        \out, ~reverbBus.index,
        \amp, 0.06, \lfoRate, 0.038, \lpFreq, 220
    ]);

    ~whiteNoise = Synth(\srLayer, [
        \out, 0, \amp, 0.018, \lpFreq, 2000
    ]);

    s.sync;

    ~droneNoteIdx = 0;

    ~nextMarkov = { |currentIdx|
        var weights, cumulative, roll;
        weights    = ~markovWeights[currentIdx].normalizeSum;
        cumulative = weights.integrate;
        roll       = 1.0.rand;
        (cumulative.indexOfGreaterThan(roll) ? (weights.size - 1))
            .clip(0, ~penta.size - 1)
    };

    ~spawnDrone = { |idx|
        var freq = ~rootHz * (2 ** (~penta[idx] / 12));
        Synth(\droneVoice, [\out, ~reverbBus.index, \freq, freq, \detuneCents, -3]);
        Synth(\droneVoice, [\out, ~reverbBus.index, \freq, freq, \detuneCents,  3]);
    };

    ~spawnDrone.(~droneNoteIdx);

    ~droneDrift = Routine({
        loop {
            rrand(60, 120).wait;
            ~droneNoteIdx = ~nextMarkov.(~droneNoteIdx);
            ~spawnDrone.(~droneNoteIdx);
        }
    }).play;

    ~padChords   = [[0,7,12], [0,7,19], [7,12,16], [0,12,19]];
    ~padChordIdx = 0;

    ~spawnPad = { |idx|
        ~padChords[idx].do({ |semi|
            Synth(\pad, [
                \out, ~reverbBus.index,
                \freq, ~rootHz * (2 ** (semi / 12)),
                \amp, 0.07, \attack, 3.5, \sustain, 80, \release, 6
            ]);
        });
    };

    ~spawnPad.(~padChordIdx);

    ~padDrift = Routine({
        loop {
            rrand(80, 110).wait;
            ~padChordIdx = (~padChordIdx + [1, 1, 1, -1].choose)
                           .wrap(0, ~padChords.size - 1);
            ~spawnPad.(~padChordIdx);
        }
    }).play;

    ~melodyNoteIdx = 2;

    ~melodyRoutine = Routine({
        loop {
            var noteIdx, freq, iot;
            iot = exprand(0.4, 2.8) * (60 / ~bpm);

            if (0.25.coin) {
                noteIdx        = ~nextMarkov.(~melodyNoteIdx);
                ~melodyNoteIdx = noteIdx;
                freq           = ~rootHz * (2 ** (~penta[noteIdx] / 12));
                if (0.2.coin) { freq = freq * 2 };

                Synth(\pluck, [
                    \out,        ~reverbBus.index,
                    \freq,       freq,
                    \amp,        exprand(0.20, 0.45),
                    \pan,        rrand(-0.5, 0.5),
                    \decay,      rrand(1.5, 3.5),
                    \brightness, noteIdx.linlin(0, 5, 0.3, 0.65)
                ]);
            };

            iot.wait;
        }
    }).play;

    // Haruvi (2022): low within-session variance is key.
    // 20-min cosine breath cycle keeps energy moving without
    // triggering orienting response.
    ~breathRoutine = Routine({
        var t = 0;
        loop {
            var phase   = (t % 1200) / 1200;
            var density = 0.6 + (0.4 * cos(2pi * phase));
            ~bpm = (65 * density).clip(45, 80);
            ~noise.set(\amp, density.linlin(0.6, 1.0, 0.05, 0.08));
            t = t + 5;
            5.wait;
        }
    }).play;
};
  
- Noise No. 1
- Noise No. 2
- Noise No. 3
- Noise No. 4
0:00:00 1:00:00
Select a Track
NOTE — I knew nothing about generative noise before I was served an Endel ad last week. The .scd file used to generate this work was produced by Claude Sonnet 4.6, and can be run locally to produce audio in real time. That said, this is a hobbyist implementation, and certainly not a clinical tool. The designers, engineers, and researchers at Endel have thought deeply about generative music for years. If you enjoyed this...imitation, you should seriously consider trying Endel.