-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathToDo.txt
765 lines (727 loc) · 42.8 KB
/
ToDo.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
=================================================================================================================================
=================================================================================================================================
=================================================================================================================================
==== audio ====
WebAudio node graphs as first class values
EXAMPLES Params; eg play=biquad{'lowpass',freq:this.lpf,q:10} >> shape{tanh{}} or playerChain=delay{[0:100ms,1]l@f} or play>>=gain{[1:!200ms,0]e}
•PLAN
?pitchshift very clicky still, and wrong freqs?? And cant control ratio with timevar??
Do pitch shifter again from scratch, maybe built on a granular thing that pulls grains out of a delay with envelope?
!Can't get current player event sound param per frame in process
More operators support nodes
+ becomes an array
* becomes a gain
unary - becomes gain{-1}
- becomes l + -r etc
For all these and >> too, if only one operand is a node, then wrap the other in const{}
Create a helper lib with useful functions (think about namespacing)
mix function eg play=mix{1/2,wet:biquad{'lowpass',freq:440}}
?Expose from js, don't write in limut?
Must used node-connect
Really want to check that wet is @e zero, not just zero at the start. Expose a function to allow this
const wet=1 should also have a custom chain with no gains
filters lpf, hpf, bpf, notch, apf, psf, lowshelf, highshelf, peaking
chop, ring, mono, pan, shapers, compressor
chorus, phaser, flanger, echo, room, reverb
stereoflip, pitchshift
oscillators
maybe refactor existing envelope stuff actually??
More audionode functions
ConvolverNode. Can also have a feedback param, like delay does??
StereoPannerNode
DynamicsCompressorNode
AudioBufferSourceNode - Also allow user def function to create sample
MediaStreamAudioSourceNode - rewrite external as an audiosynth
IIRFilterNode
ChannelSplitterNode/ChannelMergerNode
Support for named outputs; eg for stereo splitter
? analyser node with output that can be read from limut somehow
Basic node functions for all AudioNode types: check all are done
!Better fade out time. If you dont have any delays/reverbs etc you want to stop sooner; eg a audiosynth, process=osc>>gain{0.02}
?What about node function namespacing? Both builtin and lib??
!evalMainParamFrame (and what it calls) should use the REAL event, not the params object
?In evalParamValue for function, do we need to evalRecurse there? Could it be more efficient at the root level somewhere?
!Shouldnt bother with evalRecurse to cancel time modifiers if there weren't any time modifiers (only other modifiers)
Support for process chain on buses
?Rewrite all synths using audiosynth?
!?Pitch: Support for a pitch chain?
!! s audiosynth, play=osc{}>>gain{this.foo}>>gain{0.01}, foo=osc{'sine',freq:2b}
e = ev(0,0,4); e.foo = parseExpression('mockaudionode{test:17}')
assert(17, evalParamFrame(parseExpression('mockaudionode{test:this.foo}'), e, 0).test.connected[0].test.value)
!! So foo is evalling without any context where a destructor makes sense :-/
Placeholders for generalised loops
!!!Actually flanger feedback should be from the mixed signal not just from the delay: so do need full feedback loops??
? Syntax? Representation? Register themself somehow a bit like disconnect?
play=delay{1/4,id:'delay'}>>{gain{0.8}>>'delay',idnode}
Should be scoped with the current chain?
flanger with proper feedback
DOCS
nodes functions
lib functions
connect op >>
(other) ops support nodes +-*, and mixture of nodes and values
process param
audiosynth; play param
log function
user functions(?)
•QUESTIONS
? How to control audioparams with nodes instead of expressions?
Just pass more nodes in instead of value expression
Eg playerChain=delay{saw{1hz}}
? What if you want to use the same LFO to control multiple things?
Can define with set or something; concise syntax is less important for this stuff
? Make envelopes (SetTarget etc) into first class citizens???
Monophonic synths can get event info somehow; eg for pitch or envelopes etc
!!?Limiter permanently showing on??? Only on firefox desktop??
!!!! s causes the k to get filtered somehow! But then p restores to normal!!! Something to do with the `X`?? Reencode sample???
k perc X...
s perc ...s, amp=1/64
p perc ...-, amp=1/64
??Is this also firefox only??
!!! amp=1-pk.playing causes clickyness even when there is no pk
!Need a better way to do sidechain/ducking
! Minimise use of audio per frame update where it's not required
! `this.` is still causing a problem. Is there a way to decide whether it really needs to be per frame?
This is a big problem for presets like ambi, where tons of things are derived params
! Also s saw, dur=1/4, oct=2, amp/=10, lpf=1000*[0,1]l1/4@e is getting per frame on the q!
!!phaser (and psf?) should mix in dry signal, not just 2 allpasses!!!!
Can now rewrite all JS synths using audiosynth? ? Pitch effects tho??
Start oscillator at a whole number of cycles after time zero
To avoid phasing when using pad envelopes, and/or to control the starting phase of an oscillator
Use []e / []es for all envelopes?
?Deprecate att, dec, sus, rel etc params and prefer envelope=[]e??
??Also deprecate other att/rel params; eg in pitchedperc, fm operator etc???
Can pitch effects be segmented? Currently always go per-frame. EG s saw, oct=2, addc=[36:!400ms,0]es, lpf=1000, amp/=4
See evalFuncFrame. Problem is all pitch effects are combined into one function
Can per-frame consistency be improved any further? Still seems odd that there is any inconsistency at all...
Also consider double update rate (or 1/90) for first 150ms???
Pitch shifter
Hpf for chorus
Would be nice to have a unison param with stereo spread for many base synths?
?Treat db as units??? - compressor params in db; what else? This may not even be a good idea; would want to do amp+=3db or 3db+2...
Either way, document clearly
Delay or offset sub-param for glide?
Should be a mix subparam on echo?
Mix param for all filters, want to s saw .75 crop 6 + 68, lpf={100,mix:1-envelope{d:500}}
Players can have an analyser
Created on access
All events connect to it (and disconnect)
Use for player pulse
What about buses that already have an anlyser?
??Use for external synth to detect and warn if mono
House lib
Prodigy patches: https://www.youtube.com/watch?v=KwL2S5LRzFM&t=1272s
Rave stab?
Lately bass - https://youtu.be/b-DNUaekuEo?si=WGWg6XLMgBTmtCmo
more...
Techno include lib
psytrance lead
DOCS
Tinbass control for amount of amp modulation
Reese bass
HPF electric lead (phrack)
Melodic techno lead
Ambient techno pads
Dark techno stuff
Classic detroit techno stuff
more...
!Look at reducing GC for 909: single osc/shaper for bd etc..??
!! Claves cl808 cause breakdown after a while; why??
Made sure everything gets disconnected, but still breaking up :-(
808 lib docs don't have control params
Legato Tie
!? Consider if a monophonic synth type would help, even if that's the only thing that would support legato..??
Allows multiple pattern notes to be played without envelope retrigger
Should allow 303 slide
Either do by extending one note across all tied notes and changing pitch along the way
?But how to calculate pitch changes? And what about other paramas and flags on the tied notes
Or, do by playing multiple notes in such a way that their envelope, envelope{} and []e play subsections
?Nut the timing becomes very complex...
TB303 realism
slide - fixed 88ms
! slide should cause envelopes to NOT retrigger... legato...
? should really start Before the end of the first note...??? THIS IS NOT TRUE?
! But it SHOULD really be specified on the note BEFORE! Is 0s2.. slides the 0 into the 2...
Compare to a real 303 - recreate some famous 303 lines
https://www.youtube.com/watch?v=KwL2S5LRzFM&t=1107s
3#3#ds3#ua3#d3#us3#d3#a3as - but needs legato slide
https://www.audiorealism.se/audiorealism-bass-line-2.html
Half wave rectifier shaper
Symmetric but center half at zero then rise up
Really want user functions and define your own shape
Try a convolution reverb with an envelope where the sound builds then fades instead of just dying away
??can set high/mid/low params on reverb to EQ signal prior to reverb - Also on entry to all waveeffects?
Legato Eg on a 303, When 2 notes slide they are legato, and the amp and filter envelopes do Not reset for the second note...
? Feedback for chorus?
? Freeze delay, or sample recorder, or looper?
!Add=slider still only grabs one value per beat for audio synths (works for visual)
!Calculating pulse from analyser should involve a perceptual loudness curve
!Why does convolver reverb cause stereo bias?
Other audio player pulse should come from an actual FFT same as bus (only create on first read though)
!Pan should be equal power when panned?
Impulse destructor should be snappier? It probably waits too long to clean up
?Same for play???
?Ability to apply effects like compress, drive, reverb etc in bands - So you can compress low, mid and high independantly
?EQ sub Params on input to reverb etc? Eg reverb={2,high:4db,low:-4db}
Allow non-chord multiple bus outputs from one player; (bus1, bus2) etc
Bus subparam for mix level (per frame); eg p ping 0, bus={bus1,mix:1/2}
Also want to be able to split multiband too
In-page example with percussion bus
Cache/transfer bus effect nodes if unchanged?
Should be able to have multiple bandpass and notch filters
?Inline bus param Eg p ping 0, bus={reverb:1}
?Setting to push analyser node FFT size up from 1024
Synthwave preset buses?
External player should be a bus-like player, with no events ?? Will this still have an fxMixChain??
More options for setting up the convolution reverb
Mono/stereo: how much difference between L and R
Some real impulse responses as options??
??? Could use very short loop that moves stepwise on a carefully prepared sample to do wave table synthesis???
!echo={1,feedback:0} should still produce a single delayed echo
!Chop/ring LFO Freq should be per frame
Also use nonchord find: nf (series) and bpf (parallel) for all audio
Docs
!FM operator should support all wave types
Pattern char to set glide?
Percussion player for single sample; value is velocity Eg p playv 90520070, sample=':'
?Or go whole hog and patterns should become expressions and all params should be {} 'info' on the player?
Eg P saw {\0246\, oct=5, lpf=\3<52>4\*1000} or something?
303 synth preset
Pitch shifter effect
Can use https://github.com/Tonejs/Tone.js/blob/c313bc672bcc09a8cee4df97a07ba80155fd1946/Tone/effect/PitchShift.ts
See http://msp.ucsd.edu/techniques/v0.11/book-html/node115.html
Should also be able to insert this into the reverb loop...
Allow adding filters in the room/echo loops eg echo={3/4,lpf:523} - but dont use existing filter handlers as must be per event only!
Pitch shift up an octave to give shimmer reverb (pitch shifter: https://tonejs.github.io/docs/14.7.77/PitchShift.html)
Stereo widener effect: https://www.soundonsound.com/techniques/classic-stereo-widening
envelope exp (exponent) subparam, eg att={1/2,exp:2} ?? Or name it 'pow'? Default to nonzero?
?Really/ideally, everything that uses an lfo (ambi, phaser, prophet etc) etc should just use a parameter so the lfo behaviour is defined in the code
Can specify media stream device
Print list of all devices with IDs
device param to specify required device ID to be used - need to store one stream per device
Same for webcam
echo={1/2,pingpong:1} for stereo ping pong echo; use splitter and merger
Convert pwm and ?noise to webassembly, performance is terrible compared to native oscs
Reverb gate: room={1,gate:1/4}
Multiple unnecessary gain nodes even from default effects chain (that has no effects)
this.freq should also respond to addc
Envelope follower? Pitch follower? for external synth
choke param for play synth to choke one sound off when the next plays (eg hihats)
Env=reverse (slow attack / fast release)
formant/vowel effects for vocal aaa/ooo/choir effects
Is it possible to control rate per frame?
fmpluck
test fm 070604_[21], att=0, dur=1/2, echo=0, oct=4, amp=1, op1target='out', op1ratio=1, op2target=1, op2ratio=1, op2depth=1024, op2att=0, op2rel=8, op3target=1, op3ratio=2, op3depth=768, op3att=0, op3rel=8, op4target=1, op4ratio=3, op4depth=3072, op4att=0, op4rel=1/4, op4wave='sawtooth'
Is play rate per frame?
Allow setting main reverb room size
Look into improving quality of samples playing at slow rates?
AudioWorklet freeverb with webassembly
Drive should be per frame
Constant envelope type to allow specifying per frame envelope with amp?
reverb param allowing to use a convolution reverb with specified duration (at users own risk :-)
Pluck/guitar synths
https://fazli.sapuan.org/blog/electric-guitar-synth-in-html5/
https://github.com/ronkot/ks-guitar-synth/blob/master/src/js/guitar-string.js
https://github.com/mohayonao/pluck-string-node/blob/master/index.js
Nice gentle pads
FM krunchy bass - https://www.youtube.com/watch?v=1XbrTC0NndM
Preload samples immediately after parsing
'add' param for play synth?
AudioWorklet FM operator supporting feedback with webassembly
speech synth
soprano synth - use vib effect - aaah synth: https://github.com/AppGeo/web-audio-examples/blob/master/formant.html
support -ve rate for reverse playback
Normal bass synth
FM ambient synth - https://www.youtube.com/watch?v=_xL3qr-9-ZE
FM wood synth - https://www.youtube.com/watch?v=dXo_493fEpU
=================================================================================================================================
=================================================================================================================================
=================================================================================================================================
==== visual ====
?Chromatic aberration hack col.rgb += dFdx(col.rgb)*vec3(3,0,-3);
!Buffer freezes on code update
?Proper detailed gradients, not just fore/mid/back
?Based on user defined functions populating a lookup texture? or piecewise translating into gradient segments?
?recol=fmb that leaves all pixels white but with fb set, to allow recolouring with fore/mid/back. check it for webcam/image etc too
?Shader palettes from https://github.com/Erkaman/glsl-cos-palette
?A visual synth routed to a buffer should not play at all if the buffer is not there?
Right now, it works except the synth pauses..??
Would be nice for buffer feedback to keep playing until its finished when do StopAll?
!What happens to buffer when it uses eg loc=tile_b ??
It works fine, but should the buffer rez be changed to compensate??
Filter param for all texture based synths (including buffer feedback)
Image and buffer and webcam shader texture lookup supports a filter kernel with controlled size
Kernel options for blur, sharpen, max... etc
Option for additive blur (ie glow/bloom)
?Some kind of antialiasing for perspective distance; even if its user configurable
? point sampled antialiasing? will be very inefficient/slow?
? some kind of hinting to the actual shader?
!Should really multiply feedback params by dt, otherwise the rate of feedback motions will be framerate dependent
Tricky to do; have to eval params first them multiply, and it's very param dependent; eg zoom vs scroll
Generative visual synth
Complementary colours?
Shapes? Noise? NN Dreams?
Digital JPEG corruption filter param - https://www.shadertoy.com/view/Md2GDw
Takes square blocks and maps them to adjacent parts of the image, or colours them randomly green or gray or pixellated
Main param value determines the amount of corruption
Subparam for block scale
Subparam for extremity of effect within corrupted blocks?
Make buffer param work per frame
!!This fails at the moment because the synths are added to only one buffers renderList, and its done per event not per frame
Can set texture repeat for text and image etc synths? Subparam or not?
? Not needed now we have repeat param?
Starfield shader; https://www.shadertoy.com/view/WdyXDm
Should the coord system for text positionin not be -1:1 like for normal loc?
slitscan param for 2001 style slitscan, subparams for shape, rotation
Gradient values should give different types of gradients eg radial etc
video synth (use video element to load video file; don't try and target eg youtube)
can play audio through external audio synth??
Antialias param?? Subpixel supersampling??
Nice shader idea? https://tanck.nl/wallpaper/
Spiral and noise and shimmer predistortions
Possible nice shader https://twitter.com/zozuar/status/1438117355746377728?s=03
Consider pushing data of each event into a texture so a shader could display all events, eg as 2D patterns or voxels or 3D shapes
Disco glowing geometric shapes shader
make vignette work with window
Some form of anti aliasing eg for grid shader in perspective distance?
Add rotate to loc
Handle: aspect ratio, off centre x/y, window
Start image download on parse not on first use
Support echo for visuals? Additive but dimmed, time turned back? Move down??
noise/film grain
Sprites duration should include rel? Or not??
shadertoy synth support textures - MtGSzh
NO CORS!! https://www.shadertoy.com/media/a/f735bee5b64ef98879dc618b016ecf7939a5756040c2cde21ccb15e69a6e1cfb.png
shadertoy synth multiple channels
=================================================================================================================================
=================================================================================================================================
=================================================================================================================================
==== things to test/consider ====
// pattern features (), [], <>, #b, v^, single event pattern
// (), follow, complex durs, simple durs, delay, stutter, overrides, +=, |=, >>=, []
// [], []t, []l/s, []e, []n, []r []{}, []es segmented audioparams
// operators + - * / ^ % | . >>
// var, player.var, this.param, this.voice, var{params}, slider{}, floor{}, .floor{to:}, accum{}, this.time, time, rand, slider
// (...).1, (...).max, max{...}, {foo:...}.foo, (pk,ps).pulse
// modifiers {seed,per,step,0:0}, @e, @f
// subparams {2,mix:1/2}, presets, buses, buffers
// Audionodes osc{} >>
!!!!Remember to update breaking changes link on index when doing a release!!!!
=================================================================================================================================
=================================================================================================================================
=================================================================================================================================
==== other ====
!Commented parse expression unit tests
User defined functions
?How to avoid evalling function call args repeatedly due to them also being treated as modifiers?
!Should be able to access the default e and b params. Can get rid of time global??? And `this.` ?????????
Give each event a unique ID
Use it for ememoisation instead if weak map
And use it for seeding rand for per-event; then follow player can get the same randoms by using the same IDs?
Show matching brackets in editor
!? []es shouldn't be the syntax for segmenting. It should be []e@s ??
!! floor doesn't work with delay: r readout 1234, delay=floor{[0:1]l3@f,to:1/4}
Cooler effect when update code
More time modifiers
offset
rate
time - set time directly to an expression
Random noise rewrite to use piecewise
[]n: []n1 => [ rand{step:2} ,~1; rand{step:2,offset:1} ,~1; ]time*1
Really REALLY want to be able to modify from delay overrides: p saw 0, add=[0:7]r, delay=(0,{1/2,add+:2})
!Actually, this is already possible using delay=(0,{1/2,add:this.add+2}) . but this is ugly :-/
But not sure of syntax
The only other syntax option is to switch to (or allow) = and += for map entries; but this is visually confusing?
Syntax to allow use of clamp and normalise for []{}?
Main bpm param time units
stutter subparam, to set time between stutter events
?Is it possible for addc=[0,[-12,-24]t1/8@f]r@e to still allow the per frame motion, while the r@e selects it per event?
[]r used to select per event by fixing the seed per event rather than by stepping time, so it used to work
!([{x:[1,2]t1/4@f}]t2).x never get a 2 unless add @f to the []t2
!Delayed events appear in the wrong getEventsForBeat, and get the wrong voice assigned
p readout, dur=1/4, delay|=[(),{1,add:5}]r, loc={y:this.voice/2}
!Ordering of players makes this fail; readout doesnt get a chord when it should
r readout, add=p.add, loc={y:this.voice/2}
p readout, oct=(4,4), add=floor{[]r*7}, fore=0
!Not getting the SAME random values that the other player got; eg:
p ping, oct=(3,3), add=floor{[0,14]r}, dur=2
r readout, add=p.add, loc={y:this.voice/2}, dur=1/8
!!Dont get actual values from random on another player
p ping, oct=(3,3), add=[0,14]r, dur=2
r readout, add=p.add, loc={y:this.voice/2}
!Should have operator support for units; eg [0.001s,1hz]e
Voice leading
!!!IDEA: each event should be able to access the previous event (in its voice), and others in its chord? Then could calculate leading?
? Very clever or just noodles with random walks? Experiment...
--- Voice leading experiment
set root=[0,2,3,1]t8
set ch=voice{root+[(0,2,4),(0,2,4,6)]t4}
b techbass .00 crop 16, add=root, cutoff/=4
sp softpad, add=ch
ld chime 070., add=ch.[0,rand,rand,rand], amp*=3/2
Should be able to parse top heavy fractions; eg `1+1/4` is same as 5/4. Parse as number, not operator?
range function eg (0,2,4,6).range{0,to:riser*3}
IOW range{a,to:b} === (a,a+1,a+2,...,b)
!this var lookup failing in various ways:
// m ping 0, bar={'tri',detune:(12,this.foo)}, foo=2
// m ping 0, bar={'tri',detune:(12,-12)}, bar+={detune:this.foo}, foo=1
r readout 0, add=m.bar.detune, loc=sparkle
!Too much recursion: should we either prevent this or support it somehow?: r readout, add=1, delay=(0,{3/4,add:this.add*2/3})
!Readout doesn't work here: p ping 0, foo=[0,1,2,3]t1, add=this.foo \ r readout 0, add=p.add
It's specifically the this.foo that makes it fail; it's using *r*'s event for this, not p's event
!Duration should be calculated on every step, not every beat: cf play t, dur=[1/16:1/128]l[4,0]
!Cannot override dur using `set`, it only changes the sus
root{chord} function that takes a chord and returns the root
?sound param can be overridden, so it defaults to pitch/oct/scale etc but you can override so the pattern can specify chord index etc
?Not necessary because [0,1,2] is effectively a pattern that can be used to select from chords?
Really time{} and b and so on should all return values in beats, not unitless
Should be able to: v gradient 0, fore.g=0 And it navigates or creates maps as needed. or t trance 0, reverb.hpf=0
Needs to work for overrides too eg body.boost+=100
!v readout 0, add=[0,(1,2)]r, loc={y:this.voice/2}
Should get either 1 event with `0` OR 2 events with `1` and `2`, but get all kinds of mixtures
?New timevar for "advance every time its read" eg p ping (00), add=[0,2,1,3]?? same as p ping (02)(13) ?
Should be able to [0:1]n{per:'event',seed:0} ie so the sequence repeats on every event
Pattern update
Generative features:
• brackets for precedence
( 0 + 1 * 2 ) crop 16 - 0110110110110110
• p ping 01 pad 4 - 01..
1234 pad 3 - 123
• p ping 01 prepad 4 - ..01
• Mirror
mirror 012 * 2 - 012210012210
mirror (012 * 2) - 012012210210
mirror 012 crop 16 - 0122100122100122
• p ping choose 01 , 23[45] , . , 7 - Chooses a different subpattern each repeat
• p ping shuffle 01 , [23] , 4 , 5 - Random shuffling of subpatterns every repeat
• sometimes/often/rarely/every before an operator; eg: often mirror 0123 0123 sometimes * 2 every 4 shuffle 0 1 2 3
Eg p ping 0 + ( choice 017 2[34] 52 . ) * 5 crop 5 + [21]7
• Control numbers are not const, they are expressions? Eg p ping 0 + 54 * [2,3]r
Eg p ping 0 + 234 * 3 cropif delta{ch} - when var 'ch' changes value, crop and restart the pattern from 0
!!Need to know this will support more generative operations; eg Schenkerian infill, voice leading..?
?Would define new pattern operators?
?Can the existing pattern syntax support what would be needed?
?What arguments would be passed to a pattern operator definition?
?Probably want voice leading on expressions not patterns anyway??
?P ping 01, add=2 should really be p ping 01, value+=2 ?
ALSO, really would like to be able to be able to P ping 0123, value=ch[this.pattern_value] but nicer somehow...
Support continuations inside chords in pattern literals
Continuation in chord means take up that "voice slot" in the chord by continuing the previous event
So all continuations in a chord are initial continuations
Have to add extra "timing rests" to keep the timing lined up in stepToCount
Test cases: 0(_1__) 0(__) 0(_(_1_)) 0[(_1_)2] 0[(__)2] 0<(_1_)2> (01)(_2) (0[12])(_3_) <[(0)]><[(_)]>
!Follow player event params should be evaluated at the time of the _original_ event for canons
Should support dur chords for polyrythms
?Want pattern language that expresses things like "2 beats anticipation of every 16" etc
?How's about a slider that only gives output when you click/hold it? So you control note duration/rest as well as pitch?
Should be able to stutter={4,dur:1}
!Syntax colouring is case sensitive; eg `Set` does not get coloured correctly
?Can print out list of all current player types to console
Syntax???
Split by audio vs visual
Additional info?
Follow player sort-out
!If we take any params from the original event, then really want them to just work and not be overridden by follow player base events, or be at the wrong time due to follow player delay
!Follow player chooses different random values so it does not copy the original player properly
Need all randoms to be seeded, and the seed to vary between players but be the same for a follow player
OR!! Should the follow player keep a queue of the events from the main player, delayed as needed?
?Do other things like timevars get followed correctly with correct delay?
!`p1 ping 0, dur=4, foo=[100,1000,100]e \n p2 kal 0, dur=1, amp=p1.foo/1000` the []e is evalled in the WRONG players dur
!add=(0,2,4,6)[rand]{per:2,seed:0} doesn't work; rand chord indexer needs to respect time modifiers and seed etc
!Really need a complete audit of time vs count. Need the code to be clear and unambiguous which is which. There will be issues to fix. Look at []e and []e{per}
!Pattern does not have correct timing: <3[45]>_
"on next 4 " / "on next 28 of 32 " syntax to execute a line on the next beat count
- but how not to repeat this if rerun? replace now/next in source with actual count?
"every 4 " / "every 28 of 32 "
"until next 16 set (bass,kd) amp=0" ? - but how not to repeat this if rerun?
"by next 16 set bass amp=0" - lerps to the new value - but how not to repeat this if rerun?
!().accum should work - why doesn't it? I guess the chord voices haven't been split yet?
r readout 0, loc={y:2/3-this.voice/2}, add=([0,1]t1,[0,1]t2).accum
Variable rate expressions somehow EG addc=[-1,1]s[1/8:1]e Or addc=sin{[1/8:1]e*6.28} or something
floor{1.5,2.5} should work??? Or should it?? Probably not? But then it should give an error? But sum{1,2} works?
? (0,2:8) syntax?
!Handle 'cookie blocking' https://blog.tomayac.com/2022/08/30/things-not-available-when-someone-blocks-all-cookies/
Advance param to specify how far in advance events should be generated - Would allow for negative delays
For breakbeats, need a param to switch the pattern step used for an event
This seems tricky with a param, as we don't even know what the params are until the pattern is evalled
Will have to be a pattern syntax instead..?
Unless some params are stored per player? And can be used to modify pattern evaluation? Arguably, dur is already like that?
!Actually apply shuffle in the pattern?
?Functions for making chords?
Some sort of matching or booleans would be handy; eg rel=2+6*(this.value<0) or maybe rel=match{this.value,default:2,-7:8}
?Should be able to stutter with euclidean (or other?) patterns??
?stutter subparam for overriding interval between stuttered notes?
!v glow 0, loc=sparkle, fore=(red,blue)[max]
Allow mixing , and : Eg [0,2:4,5]r meaning 0 or 2 to 4 or 5 Or [0:4,7,9:10]t1 meaning [0,1,2,3,4,7,9,10]t1
!root change using []t is 1 beat late in changing
stutter={4,amp:1/2} - apply overrides
?How to provide overrides per stuttured notes?
stutter={4,dur:1/8,i=>{amp:1/i}}
?Do delayed events have any cost? Do we process them per frame?
I guess we might process any per-frame callbacks every frame while waiting for the event?
allow root param on player to override global root (add or replace?)
?slider{max:(1,2)} should work
!`d dsaw 0 | p ping follow d` the ping is played using the saw wave!!
Pattern: should allow (024)^etc
Fullscreen not working on safari
[0,1]n should randomly choose one of 0 or one then smooth between them, [0:1]n should pick random values between 0 and 1...
In which case, rewrite it as the main random, but then smoothed
Complex durs
overrides - need to apply overrides earlier? Should apply to delay overrides too
chords
var lookup (& player var lookup)
Ignore rests . when setting event.idx (so that `0.1., amp=[1/2,1]` does as expected) - is that expected? It wouldnt be for dur..?
multiline command fix: // should only comment out that one line
Need an additional eval interval; eg @i for 'per instance', so for each individual 'note' instance (each call to play)
Useful for providing variation between (1,2,3,4) multiplied out sub-events without having to go full-on per frame, expecially for eg []r
? Isn't that what @e should be? And then we could have @t for 'eval once for all chord values'
Better syntax highlighting for {} brackets; maybe bracket match highlighting??
Weighted random: nice syntax?: [1,2,{3,weight:1/2}]r
ma{v,window:1} - calculate the moving average of a value over a given time window
Can specify params for all players except those in group 'set !bass amp=0' 'set ![kd,sd] amp=0'
? rl, rt (==r), rs (==n); el (==e), es, et ?
?[1,3,5]n syntax to smoothly transition between randomly chosen values or should be [1,3,5]rs?
[]w for random walk?
Per can default to repeat of thing being modified?
Eg [0:1]l4{0:0} per defaults to 8?
Should Eg [0:1]e{per:1/4,1/2:-1} work??
Sliders
Remember last value even when not shown
Display slider value on UI, instead of logging
Support range overrides? Eg add=[0,1]l2{per:4,0-1:0}
WebMidi
Outputs (to control external synths)
Inputs (like sliders)
Beat sync input?
Have a [0,1][2,3] syntax to apply values to multiple events in a row
Tutorials
? Can automate the copy to clipboard paraphernalia?
Link on this page
Link on README
Can't override dur from set command
Can set value param to override the pattern value
syntax coloring: colour for patterns
Allow variable durations eg [0:1]l(3+[1:2]t4) etc
extending patterns like every/sometimes/offadd/stutter etc
_ extends all notes properly, even across brackets (eg <1[.3]>_ etc)
rests in params
===
===== Interesting shadertoys
-- working
Nixie digits: 4dc3zr
swirl shader 4dX3Rn
scaly shader MdSXzz
bubbles shader 4dl3zn
Fractal: MlGfDG
Fractal zoom: XtlGR2
Fractal tiling: Ml2GWy
3d supershape: 4llGWM
glitchy space patrol: ltlGD8
vector field: MdcyRs
Star tunnel: MdlXWr
dusty nebula: lslyRn
smoke lights: MdyGzR
laser show: MdjyzG
smoke laser: 3lSGDK
nebula smoke: 4ltSRS
disco tunnel: XstfzB
disco balls: lllXWr
sky swoop: lldSWN
Flux core: ltlSWf
candy core: 4sVXDz
core engine: Wsc3W4
warp core: 4lGXzG
80s synthwave: 4t33D2
-- needs textures
synthwave driving shader tsScRK
power sphere MtGSzh
furry shader 4dlGDN
gem tunnel shader ld3Szs
-- needs channels
forge shader based on: llK3Dy
-- extensions
Mechanical: XslXW2
-- shader not found (not published with 'public+api' option)
Raindrops: https://www.shadertoy.com/view/tlVGWK
plant wind https://www.shadertoy.com/view/4lf3Rj
star shader https://www.shadertoy.com/view/4dXGR4
plasma ball https://www.shadertoy.com/view/XsjXRm
Galaxy: https://www.shadertoy.com/view/llSGR1
electric shader https://www.shadertoy.com/view/ldlXRS
lattice shader https://www.shadertoy.com/view/4dsGD7
fireball shader https://www.shadertoy.com/view/lsf3RH
Space: https://www.shadertoy.com/view/lslSDS
Spiral flow: https://www.shadertoy.com/view/MdlXRS
Fractal https://www.shadertoy.com/view/lslGWr
Colour tunnel: https://www.shadertoy.com/view/XdSGzR
Cell flow: https://www.shadertoy.com/view/MlsGWX
---
test fm 020406[79]5, oct=5, att=1/16,
op1={target:'out',ratio:1},
op2={target:1, ratio:1, depth:128, att:0, rel:8},
op3={target:'out',ratio:2, depth:512, att:0, rel:2},
op4={target:3, ratio:2.02, depth:256, att:1/4, rel:2},
op5={target:'out',ratio:1, depth:512, att:1/16, rel:1/4},
op6={target:5, ratio:1, depth:1024, att:0, rel:1/4},
------
- V2 concepts
NOT using WebAudio
Maybe use electron + supercollider ?
Language features
Signals for continuous time variation
Events for discrete actions
Nodes and routing
User defined functions can be evaluated or translated (eg into shaders)
So user functions for wave shaping, colour mapping, shader cores, convolution impulses, etc
Debug any signal by visualising time or frequency domain
Sources and effects and routing, with default routing
Units for everything Hz, bts (beats), ms etc
Build velocity in
Player has an event generator with its own routing
Global metronome providing events, can be used or ignored by event generator
`. 7 2` - defaults to global metronome
bpm*4>>`. 7 2` - global metronome quarter beats
125bpm*4>>`. 7 2` - local metronome at 125bpm, *4 to give quarter beats at 125bpm
`. 0a 1(lpf:300Hz)` - flags and extra params per note
`0 (24)` - chord
Syntax for routing splits and joins Eg defining a multiband compressor or a mixer
?What about monophonc and glides?
Pipeline: metronome >> event generator >> pitch/coord generator >> source >> direct effects >> indirect effects >> buses >> destination
This still doesn't address how monophonic / glide make sense. Are the pitches events or signals?
?What about overrides? Don't want +=, want something to apply any function as an override; eg add:=(a)->a+7
* IDEA: time vars and gradients and waveshapes are really just 1D functions of different variables
What is missing from normal syntax is the ability to easily define functions piecewise
So what is really needed is a generic syntax for defining piece-wise 1D functions cleanly
[red:/1/8,yellow:-1/8,white:/1/4,green:~1/4,blue:/1/4]
[0,2,1,3]t4 - [0,2,1,3]:4
[0,1]t[3,1] - [0:3,1:1]
[0:1]l4 - [0,1]:/4
[0:1]s4 - [0,1]:~4
[0:1]l1@f - [0,1]:/1@f
[0,1]r - [0,1]:?
[0,1]n2 - [0,1]:?~2
[8,1]e - [8:\e,1:.]
envelope{d:250} - [1:^250ms,0]
[0:/20ms, 1:^1/4, this.sus.level:-(this.sus?this.dur-1/2, this.sus.level:/1/4, 0:.]
p saw, shape=x->[0:/1/4, sin{x*20}:1/2, 1:/1/4]x
??What about discontinuity? Eg hold at 1 for 1, then go from 0 to 1/2 for 1 then repeat [1:1,0:0,1/2:/1] - is that good enough?
----
* Actually, ideally need a syntax that supports all this:
Per value: value, additional info, how to progress to this from the previous value (shape, time)
Per bitwise function group: How to choose the next value (sequence, random, index by value), defaults for the per-value data
---
Actually the transition should be separate from the values, eg
adsr - [0 ,/10ms; 1 ,^100ms; this.sus.level ,-this.sus; this.sus.level ,^250ms; 0]e
And this could be added to the existing syntax by making the comma into a "clever" operator
How does this work for a random selector though? [0,~; 1,/10ms;]r
Examples
// Defining effects
let lpf = effect.biquad coeffs=(v) -> a0=,a1=,a2=,b0=...etc, priority=2
let bf = effect.color (in,v) -> back + in * fore, priority=1
let scroll = effect.warp (in,v) -> in+v, priority=1
// Audio preset and player
let saw = source.wavetable wave=(x) -> [-1 ,/1; 1,;].x, f=pitch(note:this.value+this.add, oct:this.oct)+this.addc
play b = bpm*4 >> `. 7 2` >> crop(16) >> saw, lpf=(env(r:100ms)*440Hz*tri(8beats)), add=[0,3,2,4].time/4
// Visual preset and player
let lines = source.shader shader=(x,y) -> (r:1,g:1,b:1)*(x%0.1 < 0.05) + (a:1)
play l = scroll=(x:time), bf=(back:(r:1,g:0,b:0,a:1),fore:#f0f)
//----------------------------------------
What if we just expose audio nodes, audio params, and make piecewise and patterns language features?
s saw .070, dur=1/4, oct=2, lpf=[1000,2000]l8*[1:!200ms,0]e
becomes (without any abstraction)
pattern `.070` >> pitch{oct:2} >> osc{wave:'saw'} >> biquad{type:'lpf',freq:[1000,2000]l8*[1:!200ms,0]e} >> dest
The expression is converted into a series of gain nodes with segmented audioparams that then feeds the control node on the biquad
Thats not very exciting.
Want to setup arbitrary node chains per event, per player, and globally. And then to parameterise them.
And control those parameters easily. And provide abstraction mechanisms for all of this to build everything up.
So a node(graph) must be a first class value
Unabstracted:
let s = bus{} // a player is just a bus to collect related event audio in this scenario
>> reverb{2}
>> dest
play .00{cutoff:4}0 {dur:1/4,oct:(2,3),cutoff:[1,2]l8} // Set pattern dur etc and also params for events to use; can override params inside pattern
>> delay{???}
>> swing{56} // Modify time of events
>> add{[0:8,1:8]t} // Modify value of events
>> scale{'minor',oct:this.oct} // Chord in oct here duplicates the event
>> gain{[-0.2:0.2]n,id:'wow'} // Modify pitch
>> osc{wave:'saw'} // Default input for osc is freq (pitch)
>> gain{[...]e} // Envelope
>> biquad{'lpf',freq:500*this.cutoff*[1:!200ms,0]e}
>> s
\/ \/ \/ This looks better:
OR??! more function based?
Like (unabstracted):
player s { // named player; sugar for "let s = player{...}"
``, // Default param is the pattern, also a first class value, can be used in the onBeat function
, param:p // set params for use in below functions
, onBeat b -> ...generate events for beat (and pattern/delay/swing/pitch/glide are just helper libs you can use if you want)...
, onNote n -> setup node chain (and saw/fm/perc/effects etc are helper libs)
, onAudio a -> setup per player node chain (and reverb/room etc are libs)
}
So you could write:
let saw = player{...} // setup default onXxx functions to play a saw
Then:
saw s { `.070`, dur:1/4 }
...and the pattern and dur would be picked up in the onXxx functions to control the player actions.
Still want the same param combining/overriding, so start with the lowest abstraction and work up to get param value
---------------
This is all nice, but doesn't answer the question of how to set audioparams in a generic, high resolution, but efficient way.
How does [[1000,2000]l8:!200ms,0]e turn into calls on the audionode to actually set an lpf cutoff freq?
Expressions should be parsed into a tree and not evaluated at all at parse time.
Then events can pull them in with combining and overriding into new bigger trees, and partially evaluate everything that is per event.
Then remaining constants can be folded down as far as possible, and what remains is the 'live' updating required.
Eg [[1000,2000]l8:!200ms,0]e becomes [1500:!200ms,0]e in the event.
What about [[1000,2000]l8@f:!200ms,0]e ?? How do we actually get an arbitrary (in fact user defined) function into an audioparam??
• Custom defined audio node for piecewise, that takes all the values/times/param etc as audioparameters
So the expression actually gets built up into a corresponding audionode tree that gets evalled
• Define piecewise as a node graph made out of raw gain nodes for * and +, with param (time) as an input via LinearRamp
• Custom audionode that evaluates arbitrary expression - this does not require parsing to a tree but would be a LOT of evals
• This all sounds very heavyweight and slow. Really need to come up with a segmentation approach for any of this to be worthwhile
Ideas:
• Parse into a single piecewise - is it even possible to combine this way?
100+[[1000,2000]l8:!200ms,0]e : this could be turned into one piecewise, but in general operators/power etc is a problem
Separate into constant/envelope/oscillator/realtime joined with basic + * operators - is it even possible to separate this way?
100+[[1000,2000]l8:!200ms,0]e : 100 + [1000,2000]l8 * [1:!200ms,0]e in general this doesn't work
• Come up with a syntax that forces separation of constant/envelope/oscillator/realtime that are then added together
Syntax would be pretty ugly and inexpressive
• Syntax that reflects what can actually be done with audiiparams - more like supercollider
Would be a lot more restrictive than supercollider
--------
Rewrite from scratch idea:
Function based; each function is compiled into VM code (no tree of predefined node types)
So each event-gen/event/player/bus is a separate function processing an audio stream
And these can be threaded (or even run on GPU compute)
Provide primitives for (ring) buffers, nyquist/aliasing stuff maybe, piecewise?
Electron for frontend/script parse plus c (or rust??) audio backend
player s { // named player; sugar for "let s = player{...}"
`...`, // Default param is the pattern, also a first class value, can be used in the onBeat function
, param: p // set params for use in below functions
, onBeat: b -> ...generate events for beat (and pattern/delay/swing/pitch/glide are just helper libs you can use if you want)...
, onNote: n -> define event audio processing (and saw/fm/perc/effects etc are helper libs)
, onAudio: a -> define per player audio processing (and reverb/room etc are libs)
}
With abstraction such that this can be written as a preset and then instantiated as a player with only params getting set
=================================================================================================================================
Change requirements:
* Tag current version as 0.1-final; publish to a separate URL
* Global, player, this, function-arg, var lookups are all resolved at a post-parse time, including their interval
* User defined functions can be passed without getting evalled
* Replace time modifiers with a single function (??Could that handle seed too???) - can have helper functions for 'per' etc
* Only eval modifiers at the time they're needed, not always?
* this. and p1. get you the player parameters, not the event; you can get array of active events too if you want
* All user functions can access event/b args if they want; get rid of time global var
* Drop blend=max . blend='max' is absolutely fine!
* Add a conditional expression; if/else or ?: or pref some kind of matching
* Add some kind of let expression to define local vars in functions
* What can be cleaned up in eval-params?
=================================================================================================================================
Things that make limut trickier than just implementing a bog standard programming language
* Time aware, Piecewise syntax, Time modification
* Intervals; per frame update
* Hoisting chords from params
* Node graph syntax
* Units
* Event generation
Do we really need better, smarter memoisation? Memoise even for per frame? Eg memoise key is {event,b,options}??
How does that work for function args? Need to also memoise against function args?????