License

This project is licensed under AGPL-3.0 and is inspired by strudel (https://strudel.cc/) and hydra (https://hydra.ojack.xyz/).


It integrates strudel's uzu patterns for sequencing and it also integrates superdough (strudel's webaudio engine) as a sampler.


Reference

Generator

Functions that generate a new signal

ad
ad envelope.

ad(trigger, attack, decay, curve='e') => Signal

trigger [Signal|Pattern|Number]
attack [Number]
decay [Number]
curve [String] = 'e'

d1: sine(sig(30).add(ad("[1*8?0.75]*2",0,0.25).mul(200))).coarse(8).out()

adr
adr envelope.

adr(trigger, attack, decay, release=0, curve='e') => Signal

trigger [Signal|Pattern|Number]
attack [Number]
decay [Number]
release [Number] = 0
curve [String] = 'e'

d1: tri(100).mul(adr("[t ~ ~ t ~ ~ t ~]",0,1,0,'l')).out()

adsr
adsr envelope.

adsr(trigger, attack, decay, sustain=0, release=0, curve='e') => Signal

trigger [Signal|Pattern|Number]
attack [Number]
decay [Number]
sustain [Number] = 0
release [Number] = 0
curve [String] = 'e'

d1: tri(100).mul(adsr("[t ~ ~ ~ t ~ ~ ~]*0.75",0.125,1,0.25,0.125,'e')).out()

and
and from signal array

and(args) => Signal

args [Signal]

d1: and(saw(99),supersaw(50)).out()

brown
brown noise oscillator

brown() => Signal

d1: brown().out()

bytebeat
bytebeat expression oscillator

bytebeat(frequency, expression) => Signal

frequency [Signal|Pattern|Number]
expression [string|number]

d1: bytebeat(40,'(t*(t*8%60 <= 300)|(-t)*(t*4%512 < 256))+t/400').out()

crackle
crackling Generator

crackle(density=0.02) => Signal

density [Number] = 0.02

d1: crackle(0.05).out()

d
Sends a strudel pattern to superdough, receives the audio and return it as a signal.

d(pattern) => Signal

pattern [Pattern]

d1: d(s("bd").fast(8)).out()

env
define an envelope.

env(trigger, points="1-0:0-1", defaultType='e') => Signal

trigger [Signal|Pattern|Number]
points [String] = "1-0:0-1"
defaultType [String] = 'e'

d1: saw(50).mul(env(sine(1),'1-0:0-1')).out()

d1: sine(200).mul(env("1 ~ ~ 1 ~ ~ 1 ~",'1-0:0-1')).out()

gran
granular synthesizer

gran(s, options={rate=1, pos=0, rpos=0, size=0.125, dens=8}) => Signal

s [Signal|Pattern|Number]
options [Object] = {
rate [Signal|Pattern|Number] = 1
pos [Signal|Pattern|Number] = 0
rpos [Signal|Pattern|Number] = 0
size [Signal|Pattern|Number] = 0.125
dens [Signal|Pattern|Number] = 8 }

d1: gran("nvox:3", {rate: -1, pos: 0.5, rpos: 0, size: 0.25, dens: 8}).send((x) => x.datorro(1)).out();

input
receive audio from an out bus.

input(index=0) => Signal

index [Number] = 0

d1: saw(50).nlpf(0.25).out(1); d2: input(1).out();

d1: plaits(43, {harm: 0.4, morph: uperlin(0.1)}) .out(1) .nbpf(uperlin(0.01),0.125) .mul(2) .mul(input(1).nbpf(uperlin(0.1,835),0.125).mul(2)) .send(x=>x.datorro(1)) .out()

lad
alias for ad() where the envelope curve is linear.

lad(trigger, attack, decay) => Signal

trigger [Signal|Pattern|Number]
attack [Number]
decay [Number]

sine(200).mul(lad("[t ~ ~ t ~ ~ t ~]*2",0,1)).out()

ladr
alias for adr() where the envelope curve is linear.

ladr(trigger, attack, decay, release=0) => Signal

trigger [Signal|Pattern|Number]
attack [Number]
decay [Number]
release [Number] = 0

d1: saw(50).mul(ladr("[t ~ ~ t ~ ~ t ~]",0,1,0.25)).lpf(0.25).out()

ladsr
alias for adsr() where the envelope curve is linear.

ladsr(trigger, attack, decay, sustain=0, release=0) => Signal

trigger [Signal|Pattern|Number]
attack [Number]
decay [Number]
sustain [Number] = 0
release [Number] = 0

d1: tri(100).mul(ladsr("[t ~ ~ ~ t ~ ~ ~]*0.75",0,1,0.25,0.125)).out()

lenv
alias for env() where default type is linear.

lenv(trigger, points='1-0:0-1') => Signal

trigger [Signal|Pattern|Number]
points [String] = '1-0:0-1'

d1: sine(200).mul(lenv("1 ~ ~ 1 ~ ~ 1 ~",'1-0:0-1')).out()

max
max from signal array

max(args) => Signal

args [Signal]

d1: max(saw(99),supersaw(50)).out()

min
min from signal array

min(args) => Signal

args [Signal]

d1: min(saw(99),supersaw(50)).out()

mix
mixes multiple signals into one.

mix(args) => Signal

args [Signal]

d1: mix(saw(50),saw(100),saw(200)).lpf(0.25).out()

mtof
converts midinote value to frequency value

mtof(note, transpose=0) => Signal

note [Signal|Pattern|Number]
transpose [Number] = 0

d1: sine(mtof("[0 3 5 7 12]*[2|3|4|5]",48)).out()

nosc
wavemorphing oscillator with sync

nosc(frequency, options={wave=0, sync=0, samt=1, sratio=1, pw=0.5}) => Signal

frequency [Signal|Pattern|Number]
options [Object] = {
wave [Signal|Pattern|Number] = 0
sync [Signal|Pattern|Number] = 0
samt [Signal|Pattern|Number] = 1
sratio [Signal|Pattern|Number] = 1
pw [Signal|Pattern|Number] = 0.5 }

d1: nosc(50, {wave: 3, pw: uperlin(0.125)}).lpf(0.4).out()

d1: nosc(sig(30).add(perlin(1).mul(10)), { wave: 2, sync: sine(40), samt: uperlin(1) }).bpf(uperlin(0.1),.125).mul(2) .send(x=>x.datorro(0.5)) .out()

or
or from signal array

or(args) => Signal

args [Signal]

d1: or(saw(99),supersaw(50)).out()

perlin
perlin noise generator

perlin(frequency, offset) => Signal

frequency [Signal|Pattern|Number]
offset [Signal|Pattern|Number]

d1: plaits(40, {harm: 0.4, morph: perlin(1).map(-1,1,0,1)}).out()

pink
pink noise oscillator

pink() => Signal

d1: pink().mul("[0 0 0 0 1 0 0 0]*2").add(pink().mul("[[1 0 0 0]*16]").mul(0.5)).out()

pulse
pulse wave oscillator

pulse(frequency, pulsewidth=0) => Signal

frequency [Signal|Pattern|Number]
pulsewidth [Signal|Pattern|Number] = 0

d1: pulse(50,sine(0.01)).lpf(0.5).out()

saw
sawtooth wave oscillator

saw(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: saw(50).mul(saw(49.9)).lpf(0.5).out()

sig
converts a value into a signal.

sig(value) => Signal

value [Signal|Pattern|Number]

d1: saw(sig(50).mul(2)).lpf(0.25).out()

sine
sine wave oscillator

sine(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: sine(200).mul(saw(sig(50).add(1))).out()

slide
slide enveloppe generator

slide(pattern, curve) => Signal

pattern [Pattern]
curve [Signal|Pattern|Number]

d1: saw(50).nlpf(slide("[0 0.5 0 0.5]")).out()

square
square wave oscillator

square(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: square(mtof("[0 7 12 19 24]*4",36)).lpf(sine(0.1).mul(0.25).add(0.5)).out()

supersaw
supersaw oscillator

supersaw(frequency, detune=0.125, voices=5) => Signal

frequency [Signal|Pattern|Number]
detune [Signal|Pattern|Number] = 0.125
voices [Signal|Pattern|Number] = 5

d1: supersaw(50,sig(0.125).add(sine(0.1).mul(0.125)),5).out()

tri
triangle wave oscillator

tri(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: tri(100).mul(tri(sig(50).add(1))).out()

uperlin
unipolar perlin noise generator

uperlin(frequency, offset) => Signal

frequency [Signal|Pattern|Number]
offset [Signal|Pattern|Number]

d1: plaits(40, {harm: 0.4, morph: uperlin(1)}).out()

usaw
unipolar sawtooth wave oscillator

usaw(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: saw(50).lpf(usaw(1)).out()

usine
unipolar sine wave oscillator

usine(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: saw(50).lpf(usaw(usine(0.1)).mul(0.5)).out()

usquare
unipolar square wave oscillator

usquare(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: saw(50).lpf(usquare(1)).out()

utri
unipolar triangle wave oscillator

utri(frequency) => Signal

frequency [Signal|Pattern|Number]

d1: saw(50).lpf(utri(1)).out()

white
white noise oscillator

white() => Signal

d1: white().mul("[0 0 0 0 1 0 0 0]*2").add(white().mul("[[1 0 0 0]*16]").mul(0.5)).out()

wt
wavetable oscillator

wt(frequency, options={s='bd:0', pos=0, detune=0.125, voices=3, spread=0.5, mode=0, warp=0}) => Signal

frequency [Signal|Pattern|Number]
options [Object] = {
s [String] = 'bd:0'
pos [Signal|Pattern|Number] = 0
detune [Signal|Pattern|Number] = 0.125
voices [Signal|Pattern|Number] = 3
spread [Signal|Pattern|Number] = 0.5
mode [Signal|Pattern|Number] = 0
warp [Signal|Pattern|Number] = 0 }

d1: wt(40,{s: 'bd:0', pos: sine(0.01), detune: 0.125, voices: 3}).out()

d1: wt(20, {s: "nwt:0", pos: uperlin(0.1)}).out(1) .nbpf(uperlin(0.01),0.125).mul(2) .mul(input(1).nbpf(uperlin(0.1,835),0.125).mul(2)) .send(x=>x.datorro(1, {decay: 0.5, rate: 0.5, depth: 1})) .send(y=>y.delay(0.33,0.25)).out()

xand
xand from signal array

xand(args) => Signal

args [Signal]

d1: xand(saw(99),supersaw(50)).out()

xor
xor from signal array

xor(args) => Signal

args [Signal]

d1: xor(saw(99),supersaw(50)).out()

Processor

Functions that are chainable to a signal

abs
absolute value of a signal

abs() => Signal

d1: sine(200).abs().out()

add
add signal with a given value

add(value) => Signal

value [Signal|Pattern|Number]

d1: sine(mtof(48)).add(sine(mtof(55))).out()

d1: sine(mtof(sig(48).add("[0 3 5 7 12]*4"))).out()

asym
asym distortion algorithm

asym(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).asym(2,1).out()

atan
atan function of a signal

atan() => Signal

d1: sine(200).atan().out()

bip
converts a unipolar signal to a bipolar signal

bip() => Signal

d1: saw(50).djf(usine(0.5).bip()).out()

bpf
standard band pass filter (frequency in Hz)

bpf(frequency, resonance=1, amount=1) => Signal

frequency [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 1
amount [Number] = 1

d1: supersaw(mtof(36)).bpf(mtof([48,48+7]).add(sine(mtof(36+7)).mul(300)),1).out()

chebyshev
chebyshev distortion algorithm

chebyshev(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).chebyshev(2,1).out()

clamp
clamp a signal between a range

clamp(min, max) => Signal

min [Signal|Pattern|Number]
max [Signal|Pattern|Number]

d1: sine(200).clamp(-0.5,0.5).out(1)

coarse
sample-rate resampling

coarse(factor) => Signal

factor [Signal|Pattern|Number]

d1: sine(100).coarse(irand(32,1).fast(16)).out()

compressor
dynamics compressor

compressor(pregain=1, threshold=-9, ratio=6, knee=3, attack=0.001, release=0.01) => Signal

pregain [Signal|Pattern|Number] = 1
threshold [Signal|Pattern|Number] = -9
ratio [Signal|Pattern|Number] = 6
knee [Signal|Pattern|Number] = 3
attack [Signal|Pattern|Number] = 0.001
release [Signal|Pattern|Number] = 0.01

d1: saw(200).compressor().out()

cos
cos function of a signal

cos() => Signal

d1: sine(200).cos().out()

crush
bit-crusher

crush(depth) => Signal

depth [Signal|Pattern|Number]

d1: sine(50).crush(irand(16,1).fast(16)).out()

cubic
cubic distortion algorithm

cubic(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).cubic(2,1).out()

datorro
datorro reverb

datorro(volume, options={decay=0.5, damp=0.5, indiff=0.5, decdiff=0.5, band=1, predel=0, rate=0.5, depth=1}) => Signal

volume [Signal|Pattern|Number]
options [Object] = {
decay [Signal|Pattern|Number] = 0.5
damp [Signal|Pattern|Number] = 0.5
indiff [Signal|Pattern|Number] = 0.5
decdiff [Signal|Pattern|Number] = 0.5
band [Signal|Pattern|Number] = 1
predel [Signal|Pattern|Number] = 0
rate [Signal|Pattern|Number] = 0.5
depth [Signal|Pattern|Number] = 1 }

d1: plaits(43, {harm: 0.4, morph: uperlin(0.1)}).send(x=>x.datorro(1, {decay: 0.5, rate: 0.5, depth: 1})).out()

delay
delay line

delay(time=0.33, feedback=0.5) => Signal

time [Signal|Pattern|Number] = 0.33
feedback [Signal|Pattern|Number] = 0.5

d1: saw(30).djf(saw(0.5).map(-1,1,0,0.3)).send(x=>x.delay(0.3,0.6).mul(0.7)).out()

diode
diode distortion algorithm

diode(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).diode(2,1).out()

distort
distortion algorithm

distort(amount, postgain=1, algorithm='scurve') => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1
algorithm [String] = 'scurve'

d1: sine(50).distort(2,1).out()

djf
2-pole dj filter (below 0.5 lpf, above 0.5 hpf)

djf(value, resonance=0.125, amount=1) => Signal

value [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 0.125
amount [Number] = 1

d1: supersaw(40,0.125).djf(sine(0.03).map(-1,1,0,1)).out()

eqh
highshelf frequency booster / attenuator

eqh(frequency, gain) => Signal

frequency [Signal|Pattern|Number]
gain [Signal|Pattern|Number]

eql
lowshelf frequency booster / attenuator

eql(frequency, gain) => Signal

frequency [Signal|Pattern|Number]
gain [Signal|Pattern|Number]

eqm
peaking frequency band booster / attenuator

eqm(frequency, gain, resonance=1) => Signal

frequency [Signal|Pattern|Number]
gain [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 1

exp
exp function of a signal

exp() => Signal

d1: sine(200).exp().out()

fold
fold distortion algorithm

fold(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).fold(2,1).out()

hard
hard distortion algorithm

hard(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).hard(2,1).out()

hpf
standard high pass filter (frequency in Hz)

hpf(frequency, resonance=1, amount=1) => Signal

frequency [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 1
amount [Number] = 1

limiter
dynamics limiter

limiter(threshold=0, attack=0.001, release=0.01) => Signal

threshold [Signal|Pattern|Number] = 0
attack [Signal|Pattern|Number] = 0.001
release [Signal|Pattern|Number] = 0.01

d1: saw(48).limiter().out()

log
log10 function of a signal

log() => Signal

d1: sine(200).log().out()

lpf
standard low pass filter (frequency in Hz)

lpf(frequency, resonance=1, amount=1) => Signal

frequency [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 1
amount [Number] = 1

d1: saw(50).lpf(sine(49*2).mul(100).add(101)).out()

map
maps a signal from the given input range to the given output range

map(inMin=-1, inMax=1, outMin=0, outMax=1) => Signal

inMin [Signal|Pattern|Number] = -1
inMax [Signal|Pattern|Number] = 1
outMin [Signal|Pattern|Number] = 0
outMax [Signal|Pattern|Number] = 1

d1: saw(50).djf(sine(0.5).map(-1,1,0.2,0.4)).out()

mapx
maps a signal from the given input range to the given output exponential range

mapx(inMin=-1, inMax=1, outMin=0, outMax=1) => Signal

inMin [Signal|Pattern|Number] = -1
inMax [Signal|Pattern|Number] = 1
outMin [Signal|Pattern|Number] = 0
outMax [Signal|Pattern|Number] = 1

d1: saw(50).djf(sine(0.5).mapx(-1,1,0.2,0.4)).out()

mod
modulo function of a signal

mod(value) => Signal

value [Signal|Pattern|Number]

d1: sine(200).mod(1).out(1)

mul
multiply signal with a given value

mul(value) => Signal

value [Signal|Pattern|Number]

d1: saw(50).mul(sine(199)).out()

d1: tri(100).mul(2).out()

d1: pulse(50).mul(lad("1 0",0,1)).out()

nbpf
frequency scaled (0-1) band pass filter

nbpf(value, resonance=0.125, amount=1) => Signal

value [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 0.125
amount [Number] = 1

d1: pulse(40,sine(0.01)).nbpf(usine(0.01)).out()

nhpf
frequency scaled (0-1) high pass filter

nhpf(scaledfreq, resonance=0.125, amount=1) => Signal

scaledfreq [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 0.125
amount [Number] = 1

d1: supersaw(50).nhpf(usine(49.9).mul(0.875)).out()

nlpf
frequency scaled (0-1) low pass filter

nlpf(value, resonance=0.125, amount=1) => Signal

value [Signal|Pattern|Number]
resonance [Signal|Pattern|Number] = 0.125
amount [Number] = 1

d1: supersaw(50).nlpf(usine(49.9).mul(0.875)).out()

out
send signal to an output bus (if .out() or .out(0) sends signal to the master output)

out(index=0) => Signal

index [Number] = 0

sine(200).out()

d1: sine(200).out(1) d2: input(1).out(0)

range
scales a bipolar value (-1 to 1) into the given output range

range(min=0, max=1) => Signal

min [Signal|Pattern|Number] = 0
max [Signal|Pattern|Number] = 1

d1: saw(50).djf(sine(0.5).range(0.2,0.4)).out()

rangex
scales a bipolar value (-1 to 1) into the given exponential output range

rangex(min=0, max=1) => Signal

min [Signal|Pattern|Number] = 0
max [Signal|Pattern|Number] = 1

d1: saw(50).djf(sine(0.5).rangex(0.2,0.4)).out()

room
room reverb

room(duration=5, predelay=0, lowpass=15000, dim=1000) => Signal

duration [Signal|Pattern|Number] = 5
predelay [Signal|Pattern|Number] = 0
lowpass [Signal|Pattern|Number] = 15000
dim [Signal|Pattern|Number] = 1000

sine(mtof("[0|3|5|7|12|15|17|19|24]*16?0.875",48)).mul(0.5).send(x=>x.room(5)).out()

scurve
scurve distortion algorithm

scurve(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).scurve(2,1).out()

self
passes the signal value to a lambda function

self(func) => Signal

func [Signal|Pattern|Number]

d1: sine(50).self(x=>x.mul(sine(x.mul(50).add(1)))).out()

send
passes the signal value to a lambda function that goes into a parallel chain, gets processed and is then mixed back into the original chain

send(func, dry=1) => Signal

func [Signal|Pattern|Number]
dry [Signal|Pattern|Number] = 1

d1: supersaw(50,sine(0.1).map(-1,1,1/16,1/8)).send(x=>x.delay(0.25,0.25).room(0.5)).out()

sin
sin function of a signal

sin() => Signal

d1: sine(200).sin().out()

sinefold
sinefold distortion algorithm

sinefold(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).sinefold(2,1).out()

slew
limit the change rate of a signal

slew(rate) => Signal

rate [Signal|Pattern|Number]

d1: saw(100).nlpf(sig("1 0 1 0").slew(1/1000)).out()

soft
soft distortion algorithm

soft(amount, postgain=1) => Signal

amount [Signal|Pattern|Number]
postgain [Signal|Pattern|Number] = 1

d1: sine(50).soft(2,1).out()

stretch
phase-vocoder realtime pitch-shifter

stretch(factor) => Signal

factor [Signal|Pattern|Number]

d1: saw(50).add(saw(50).stretch(1)).out()

tan
tan function of a signal

tan() => Signal

d1: sine(200).tan().out()

uni
converts a bipolar signal to a unipolar signal

uni() => Signal

d1: saw(50).djf(sine(0.5).uni()).out()

urange
scales a unipolar value (0 to 1) into the given output range

urange(min=0, max=1) => Signal

min [Signal|Pattern|Number] = 0
max [Signal|Pattern|Number] = 1

d1: saw(50).djf(usine(0.5).urange(0.2,0.4)).out()

urangex
scales a unipolar value (0 to 1) into the given exponential output range

urangex(min=0, max=1) => Signal

min [Signal|Pattern|Number] = 0
max [Signal|Pattern|Number] = 1

d1: saw(50).djf(usine(0.5).urangex(0.2,0.4)).out()

vowel
vowel filter

vowel(vowel) => Signal

vowel [String]

d1: saw(100).vowel('a').mul(4).out()

wcompressor
webaudio dynamics compressor

wcompressor(threshold=-6, ratio=9, knee=3, attack=0.001, release=0.01) => Signal

threshold [Signal|Pattern|Number] = -6
ratio [Signal|Pattern|Number] = 9
knee [Signal|Pattern|Number] = 3
attack [Signal|Pattern|Number] = 0.001
release [Signal|Pattern|Number] = 0.01

d1: saw(50).wcompressor().out()

Sequencer

Functions that generate a sequence

p
Creates a new uzu pattern that can sequence parameters

p(pattern) => Pattern

pattern [Pattern]

d1: sine(mtof(p(0,3,5,7,12).fast(4),48)).out()

step
Creates a new uzu pattern that can sequence parameters

step(pattern) => Pattern

pattern [Pattern]

d1: d(step("x..x..x.").s("bd:4")).out()

d1: d(stack( step("x..x..x.").fast(2).s("bd:4"), step("....x...").fast(2).s("sd:4").clip(0.25).gain(0.25), step("..x...x.").fast(2).s("oh:2").clip(0.25).gain(0.25), )).out()